tensor.cuda()
在使用GPU的情况下,一般会将所有相关tensor都放到GPU上计算,所以如果仅仅model=model.cuda(),程序将不能正确执行,因为输入tensor和输出tensor还没布置到GPU上,还需要:

x=x.cuda()
y=y.cuda()
model=model.cuda()

注意,这样的迁移比较特殊,在完成设备迁移的同时,叶子张量属性is_leaf并不会发生变化,虽然x=x.cuda()不是in-place,但叶子节点并没有变成非叶子节点,这对训练有重要作用
torch.nn.CrossEntropyLoss
对于一般的分类训练,会写:

loss_fn=torch.nn.CrossEntropyLoss()
...
loss=loss_fn(y_pred,target)

注意到:
y_pred.shape:(batch_size,class_number);
target.shape:(batch_size);
所以target的每个元素需要是整数(一般是int64),取值范围为[0,class_number-1],这才能被函数认为是真实类别
注意一个细节:当使用了torch.nn.CrossEntropyLoss的时候,其实不需要在model最后一层添加torch.nn.Softmax(),因为在官方文档中,pytorch使用CrossEntropyLoss计算交叉熵的公式为:

这也正好解释了前面target值在[0,class_number-1]的奇怪规则
torch.no_grad()
torch.no_grad()的作用是使在with关键字下的计算图不被追踪,此时,就算叶子张量的requires_grad=True,也可以进行in-place操作:

x = torch.tensor([1],dtype=torch.float,requires_grad=True)
with torch.no_grad():x-=0.1

另一方面,计算图不被追踪的言外之意是Disabling gradient calculation(禁用梯度计算),相当于在torch.no_grad()下,显存不必将资源用于梯度计算,节省了显存,适用于inference;


model.eval()与torch.no_grad():model.eval()不开启BN和Dropout,注意只有torch.no_grad()可以关闭梯度计算,用于节省显存。为了确保梯度传播的准确,在loss.backward()前执行optimizer.zero_grad()即可。


tensor.max()
常用于索引分类结果:

tensor.max(dim=None)->(Tensor,Tensor)

dim用于选择对哪个轴方向进行操作,返回对象元组有两个元素,一个是索引到的最大值结果,一个是最大值所在轴上的位置;
假设现有前向传播的结果pred(N,4),N个样本,4个类别,若写pred.max(dim=1)代表沿着第二轴(列轴即水平方向)求最大值
torch.bmm
批处理张量乘法bmm:batch matrix multiplication,在batch中,两组张量对应相乘:

(b,m,n)*(b,n,p)->(b,m,p)

tensor.unsqueeze和tensor.squeeze
tensor.unsqueeze用于增加维度,增加在哪一维度由关键字参数dim确定:

x=torch.randn(5,3)
x.unsqueeze(dim=2).size()
#>torch.Size([5, 3, 1])x=torch.randn(5,3)
x.unsqueeze(dim=1).size()
#>torch.Size([5, 1, 3])

对应的,tensor.squeeze用于去除冗余维度(某个维度shape为1):

x=torch.randn(5,3,1)
x.squeeze(dim=2).size()
#>torch.Size([5, 3])x=torch.randn(5,3,1)
x.squeeze(dim=0).size()
#>torch.Size([5, 3, 1])

注意squeeze和unsqueeze不是in-place的
反向传播公式的简单解释
在pytorch入门中,简要给出了反向传播计算权重梯度的公式:
∂J∂W=∂J∂za\frac{\partial J}{\partial W}=\frac{\partial J}{\partial z}a∂W∂J​=∂z∂J​a
为什么要乘z前面的输出a?其实上式可以理解为:
∂J∂W=∂J∂z∂z∂W\frac{\partial J}{\partial W}=\frac{\partial J}{\partial z}\frac{\partial z}{\partial W}∂W∂J​=∂z∂J​∂W∂z​
因为下一个激活前的输入值z为:z=WTaz=W^Taz=WTa
torch.randint
用于生成随机的整数张量(dtype=torch.int64):

randint(low=0, high, size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) -> Tensor

值在low到high之间,形状由size决定:

torch.randint(6,(2,2))
"""
tensor([[5, 1],[4, 3]])
"""

tensor.fill_
属于in-place操作,将张量内部的值进行替换,内存地址不变,fill_只支持0维张量(元素是一个数值),fill_不改变数据类型:

x=torch.tensor(1)
y=torch.tensor(2.)
x.fill_(y)
print(x)
x.dtype#tensor(2)
#torch.int64

torch.multinomial
常用于随机采样:

multinomial(input, num_samples, replacement=False, out=None) -> LongTensor

input通常是概率序列(其实只要是浮点型的一维张量就行),返回为LongTensor,内容是采样序列的索引,值越大越容易被采样到;
replacement代表有放回,设为True可以无限次采样:

x=torch.tensor([8.,9.,11.,23.,100.])
torch.multinomial(x,10,replacement=True)
#tensor([4, 0, 2, 3, 4, 3, 4, 4, 4, 0])

tensor.transpose和tensor.permute
transpose只能选择两个维度进行调整,permute可以任意设置维度的顺序:

transpose(dim0, dim1) -> Tensor
permute(*dims) -> Tensor

实例如下:

x=torch.randn(5,3,2)
x.transpose(1,2).size()#torch.Size([5, 2, 3])x=torch.randn(5,3,2)
x.permute(2,1,0).size()#torch.Size([2, 3, 5])

torch.nn.BCEWithLogitsLoss
这个损失函数只能用于二分类问题,该损失函数包括两个部分:一个sigmoid函数和BinaryCrossEntropy函数;
使用举例:

crit = nn.BCEWithLogitsLoss()
# preds [batch_size]
# batch.label [batch_size]
loss = crit(preds, batch.label)

可见网络输出与标签的shape都是[batch_size],假设对于batch中的一组数,网络输出xix_{i}xi​,标签为yiy_{i}yi​,则loss计算为:
loss=−[yilogσ(xi)+(1−yi)log(1−σ(xi))]loss=-[y_{i}log \sigma (x_{i})+(1-y_{i})log(1- \sigma (x_{i}))]loss=−[yi​logσ(xi​)+(1−yi​)log(1−σ(xi​))]
损失函数两个项反应了属于第0类的对象被分为第0类,属于第1类的对象被分到第1类,才能最小化loss
torch.round
对结果四舍五入:

x=torch.randn(5,3)
print(x)
y=torch.round(x)
print(y)
"""
tensor([[ 1.3226, -0.6480, -1.0701],[-1.4932, -0.6328,  1.0331],[ 0.9444,  0.4172,  0.8942],[-0.3619,  0.1024, -1.8857],[-3.2601,  1.2551, -0.5345]])
tensor([[ 1., -1., -1.],[-1., -1.,  1.],[ 1.,  0.,  1.],[-0.,  0., -2.],[-3.,  1., -1.]])
"""

张量拼接torch.cat
张量可以通过cat拼接:

torch.cat(tensors, dim=0, *, out=None) → Tensor

dim决定了拼接操作基于的轴,比如:

hidden=torch.randn(4,2,3)#[4,batch_size,hidden_size]
print(hidden.size())
hidden=torch.cat((hidden[-1],hidden[-2]),dim=1)
print(hidden.size())#torch.Size([4, 2, 3])
#torch.Size([2, 6])x=torch.randn(2,3)
y=torch.randn(2,6)
torch.cat((x,y),dim=1).size()
#torch.Size([2, 9])

torch.nn.LogSoftmax和torch.nn.NLLLoss
torch.nn.LogSoftmax的本质就是对每个元素都计算LogSoftmax:
LogSoftmax(xi)=log(exp(xi)∑jexp(xj))LogSoftmax(x_{i})=log(\frac{exp(x_{i})}{\sum_{j}exp(x_{j})})LogSoftmax(xi​)=log(∑j​exp(xj​)exp(xi​)​)
输入输出张量的shape不会改变:

x=torch.randn(6,3)
print(x)
# 沿着列轴方向操作
F.log_softmax(x,dim=1)
"""
tensor([[ 0.5185, -0.4387,  0.8417],[ 1.0252,  0.8140, -0.1921],[ 0.6522,  0.2619, -1.5904],[-0.1942, -0.5435,  0.5055],[-1.3790,  0.2573,  0.5489],[ 1.4560,  1.9608,  0.5123]])tensor([[-1.0172, -1.9744, -0.6940],[-0.7446, -0.9558, -1.9620],[-0.5783, -0.9686, -2.8209],[-1.3133, -1.6626, -0.6136],[-2.5658, -0.9295, -0.6379],[-1.1137, -0.6090, -2.0575]])
"""torch.log(torch.exp(x[0][1])/(torch.exp(x[0][0])+torch.exp(x[0][1])+torch.exp(x[0][2])))
"""
tensor(-1.9744)
"""

一般与logsoftmax配合使用的损失函数为NLL loss(负对数似然损失),因为logsoftmax取相反数正好就是交叉熵;
把交叉熵拆分开的原因是为了给类别加上权重信息,这样可以通过训练加强某些类别的分辨能力;常用于数据量不平衡的训练集;

torch.nn.NLLLoss(weight: Optional[torch.Tensor] = None, reduction: str = 'mean')

可选参数weight是一个向量,如果数据集共C个类别,则weight的元素个数为C,它反映了每个类别的重要程度;
假设现在调用一次NLLLoss:

"""
input (N,C)
traget (N)
output 一个值,具体值取决于reduction是sum还是mean,默认mean
如果reduction=None,则返回tensor (N)
"""functional.nll_loss(pred,target)

pred应该是来自LogSoftmax计算后的张量,假设这个batch的tensor形状为[N,C][N,C][N,C],则target应该是[N][N][N],类似CrossEntropyLoss,target就像一个索引,其中每个元素值在0到C−1C-1C−1之间;
负对数似然损失NLL loss的计算为:
1.reduction=None
l(pred,target)={l1,...,lN}l(pred,target)=\left \{ l_{1},...,l_{N} \right \}l(pred,target)={l1​,...,lN​}
li=−(weight[target[i]])×(x[i][y[i]])l_{i}=-(weight[target[i]])\times (x[i][y[i]])li​=−(weight[target[i]])×(x[i][y[i]])
2.reduction=sum
l(pred,target)=∑i=1Nlil(pred,target)=\sum_{i=1}^{N}l_{i}l(pred,target)=i=1∑N​li​
3.reduction=mean
l(pred,target)=1∑j=1Nweight[target[j]]∑i=1Nlil(pred,target)=\frac{1}{\sum_{j=1}^{N}weight[target[j]]}\sum_{i=1}^{N}l_{i}l(pred,target)=∑j=1N​weight[target[j]]1​i=1∑N​li​

tensor.data_ptr()
在pytorch中,想要获取张量对象的地址,一般不使用id(),而是使用tensor.data_ptr()
tensor.data_ptr()可以返回tensor第一个元素所在的物理地址:

data_ptr() → int

tensor.clone和tensor.detach
1.tensor.clone()
返回tensor的拷贝,返回的新tensor和原来的tensor具有同样的大小和数据类型;
但是,clone()返回的tensor是非叶子节点(有计算图连接);即:如果原tensor.requires_grad=True,则新tensor的梯度会流向原tensor,即新tensor的梯度会叠加在原tensor上:

>>> import torch
>>> a = torch.tensor(1.0, requires_grad=True)
>>> b = a.clone()>>> a.data_ptr(), b.data_ptr() # 不指向同一物理地址
(94724519502912, 94724519533952)>>> a.requires_grad, b.requires_grad  # 但b的requires_grad属性和a的一样,同样是True
(True, True)
>>> c = a * 2
>>> c.backward()
>>> a.grad
tensor(2.)
>>> d = b * 3
>>> d.backward()
>>> b.grad  # b的梯度值为None,因为是非叶子节点,梯度值不会被保存
>>> a.grad  # b的梯度叠加在a上
tensor(5.)

2.tensor.detach()
返回一个新的tensor,新的tensor和原来的tensor共享内存,但不涉及梯度计算,即requires_grad=False,相当于从计算图中分离出来了;
因为是共享同一物理地址,修改其中一个tensor的值,另一个也会改变,但如果对其中一个tensor执行内置操作,则会报错,例如resize_、resize_as_、set_、transpose_:

>>> import torch
>>> a = torch.rand((3, 4), requires_grad=True)
>>> b = a.detach()>>> a.data_ptr(), b.data_ptr()  # 指向同一物理地址
(94724518609856, 94724518609856)>>> a.requires_grad, b.requires_grad  # b的requires_grad为False
(True, False)>>> b[0][0] = 1
>>> a[0][0]  # 修改b的值,a的值也会改变
tensor(1., grad_fn=<SelectBackward>)>>> b.resize_((4, 3))  # 报错

关于梯度在计算图中的流动
属于同一个计算图的张量,其梯度在反向传播中累乘,对于两个不同的计算图,即计算图出现了分支,对两个分支分别计算梯度,两计算图共享张量的梯度需要求和:

import torchx=torch.tensor(1.0, requires_grad=True)
y=2*xa=torch.tensor(3.0, requires_grad=True)
b=3*a# 两个计算图,共同依赖张量x
z=4*y+b
m=3*xz.backward()
m.backward()x.grad # tensor(11.) 11=4*2+3

torch.nn.Dropout
Dropout定义为:

torch.nn.Dropout(p: float = 0.5, inplace: bool = False)

在训练期间,按照概率ppp从伯努利分布中采样将输入张量的元素置0,输出张量的元素再乘缩放系数11−p\frac{1}{1-p}1−p1​;
inplace如果为True,输入张量会被设置为需要in-place操作:

import torch.nn as nn
import torchm = nn.Dropout(p=0.5)
input = torch.randn(5,3)
output = m(input)print(input)
print(output)"""
tensor([[-1.2560, -1.3158,  0.3405],[ 1.4020, -1.3544, -2.8470],[-1.4518, -0.5322,  0.8935],[-1.3207,  0.9328, -0.3308],[-1.5071,  0.6539, -1.6561]])
tensor([[-2.5120, -2.6316,  0.0000],[ 0.0000, -2.7088, -0.0000],[-2.9037, -0.0000,  1.7870],[-2.6415,  1.8656, -0.6615],[-3.0143,  1.3078, -0.0000]])
"""

torchvision:tensor与PILImage
pytorch中tensor形状为(c,h,w)(c,h,w)(c,h,w),而PILImage形状为(h,w,c)(h,w,c)(h,w,c),所以在不使用torchvision的transforms时,需要注意形状的转换

附录:PyTorch记事本相关推荐

  1. 第三课.使用简单的NN模拟fizzbuzz

    游戏介绍 这个游戏非常简单,名叫fizzbuzz,我猜测应该起源于早期的聚会活动,游戏规则如下:从1开始计数,当遇到是3的倍数的时候,就说fizz,当遇到是5的倍数的时候,就说buzz,当遇到是3和5 ...

  2. 第八课.简单的图像分类(二)

    目录 常见的卷积神经网络架构 卷积网络的平移不变性 卷积网络的识别原理简述 卷积神经网络的缺陷 CNN的迁移学习 迁移学习简介 数据集 使用dataloader生成batch 设置超参数 使用data ...

  3. 第七课.简单的图像分类(一)

    第七课目录 图像分类基础 卷积神经网络 Pooling layer BatchNormalization BatchNormalization与归一化 torch.nn.BatchNorm2d MNI ...

  4. 第六课.NLP文本分类任务

    第六课目录 NLP文本分类简介 IMDB数据集准备 设置随机种子 下载IMDB并划分数据集 构建词汇表 使用torchtext生成batch WordAveraging 模型定义 加载由glove.6 ...

  5. HWC格式(Torch)

    人工智能小白,不对之处,希望各位大佬不吝赐教^_^ 目录 前言 正文 1.关于HWC维度的理解 2.为什么pytorch中transforms.ToTorch要把(H,W,C)的矩阵转为(C,H,W) ...

  6. Pytorch 小白记事本 1

    Pytorch 小白记事本 1 Python pip 安装与使用 下载就不多说了,我们从判断是否安装开始记录: pip --version pip 最常用命令 显示版本和路径 pip --versio ...

  7. 附录1:python记事本

    dir()函数:函数不带参数时,返回当前范围内的变量.方法和定义的类型列表:带参数时,返回参数的属性.方法列表. notebook中的line型开关%:针对全局 cell型开关%%:针对当前cell ...

  8. 364 页 PyTorch 版《动手学深度学习》分享(全中文,支持 Jupyter 运行)

    1 前言 最近有朋友留言要求分享一下李沐老师的<动手学深度学习>,小汤本着一直坚持的"好资源大家一起分享,共同学习,共同进步"的初衷,于是便去找了资料,而且还是中文版的 ...

  9. pytorch无坑超详细图文CPU版小白安装教程(配gpu版链接、conda命令教程)

    想安装gpu版本的朋友们请移步gpu版pytorchan安装教程直达 文章目录 创建.激活.退出.删除环境 法一:官网默认指令安装(可能比较慢) 法二:更换清华源下载 法三:下载包安装 版本对应问题 ...

最新文章

  1. 记录一下从标定模型中读取参数
  2. [OpenGL ES 03]3D变换:模型,视图,投影与Viewport
  3. java基础—几种for循环编程思想
  4. elementui树状菜单tree_Vue+Element UI 树形控件整合下拉功能菜单(tree + dropdown +input)...
  5. 光纤交换机巡检配置常用命令
  6. Android_adb_Wifi_无线调试,脱离数据线/
  7. 神经网络中的Epoch、Iteration、Batchsize
  8. python图片保存为txt文件_python实现对文件中图片生成带标签的txt文件方法
  9. 计算机应用系统统考配书光盘,统考配书光盘计算机应用基础使用手册
  10. 英文名字大全解释 (详)
  11. jquery设置css样式、style属性 示例(超强解析)
  12. c语言程序设计施莹答案,C语言课件-位运算.ppt
  13. jenkins中maven的安装及配置,如何在jenkins中创建maven任务。
  14. ESP8266读取网络时间TM1637显示时间
  15. 价值投资要做段王爷,不要做杨过
  16. 第四讲:各种形态的描述
  17. 搭建wiki oracle,Wiki系统搭建 JspWiki
  18. html带颜色方块,HTML5 彩色方块组合动画
  19. 【Visual C++】游戏开发笔记三十六 浅墨DirectX提高班之四 顶点缓存的逆袭
  20. java校园导航_Java实现的具有GUI的校园导航系统

热门文章

  1. MySQL高级篇:控制流函数
  2. 一份很不错的敏捷产品需要文档模板
  3. 为了拿捏 Redis 数据结构,我画了 40 张图
  4. 《快速搞垮一个技术团队的20个“必杀技”》
  5. Redis5新特性Streams作消息队列
  6. session一致性架构设计极简教程
  7. 强烈推荐8个值得下载的神仙软件,每一个都让人惊喜
  8. 当前国内有哪些公司是做OKR管理软件做的比较好的?
  9. IDEA 显示类结构图
  10. 先进先出置换算法(FIFO)