PyTorch基础
没想到我也有开始炼丹的一天
主要的参考资料是这个
PyTorch基础
张量
numpy中的基础单位是ndarray,PyTorch里面的基础单位是tensor,tensor可以在gpu里进行计算
基本操作都一样,比如ones_like,zeros,size,索引方式也一样
基本的数据类型有五种
- 32位浮点型:torch.FloatTensor。 (默认)
- 64位整型:torch.LongTensor。
- 32位整型:torch.IntTensor。
- 16位整型:torch.ShortTensor。
- 64位浮点型:torch.DoubleTensor。
除以上数字类型外,还有 byte和chart型
张量的一些特殊操作
加法1:
1 | y = torch.rand(5, 3) |
加法2
1 | print(torch.add(x, y)) |
提供输出tensor作为参数
1 | result = torch.empty(5, 3) |
替换
1 | # adds x to y |
Note
任何 以_
结尾的操作都会用结果替换原变量. 例如: x.copy_(y)
, x.t_()
, 都会改变 x
.
改变维度
1 | x = torch.randn(4, 4) |
如果你有只有一个元素的张量,使用.item()
来得到Python数据类型的数值
1 | x = torch.randn(1) |
与numpy的转换
Torch Tensor与NumPy数组共享底层内存地址,修改一个会导致另一个的变化。
将一个Torch Tensor转换为NumPy数组
1 | a = torch.ones(5) |
1 | b = a.numpy() |
观察numpy数组的值是如何改变的。
1 | a.add_(1) |
NumPy Array 转化成 Torch Tensor
使用from_numpy自动转化
1 | import numpy as np |
所有的 Tensor 类型默认都是基于CPU, CharTensor 类型不支持到 NumPy 的转换.
使用.to
方法 可以将Tensor移动到任何设备中
1 | # is_available 函数判断是否有cuda可以使用 |
自动求导
没太看懂这里是用来干嘛的
神经网络包&优化器
torch.nn是专门为神经网络设计的模块化接口。nn构建于 Autograd之上,可用来定义和运行神经网络。 这里我们主要介绍几个一些常用的类
约定:torch.nn 我们为了方便使用,会为他设置别名为nn,本章除nn以外还有其他的命名约定
1 | # 首先要引入相关的包 |
1 | '1.0.0' |
除了nn别名以外,我们还引用了nn.functional,这个包中包含了神经网络中使用的一些常用函数,这些函数的特点是,不具有可学习的参数(如ReLU,pool,DropOut等),这些函数可以放在构造函数中,也可以不放,但是这里建议不放。
一般情况下我们会将nn.functional 设置为大写的F,这样缩写方便调用
1 | import torch.nn.functional as F |
定义一个网络
PyTorch中已经为我们准备好了现成的网络模型,只要继承nn.Module,并实现它的forward方法,PyTorch会根据autograd,自动实现backward函数,在forward函数中可使用任何tensor支持的函数,还可以使用if、for循环、print、log等Python语法,写法和标准的Python写法一致。
In [3]:
1 | class Net(nn.Module): |
1 | Net( |
网络的可学习参数通过net.parameters()返回
1 | for parameters in net.parameters(): |
1 | Parameter containing: |
net.named_parameters可同时返回可学习的参数及名称。
1 | for name,parameters in net.named_parameters(): |
1 | conv1.weight : torch.Size([6, 1, 3, 3]) |
1 | input = torch.randn(1, 1, 32, 32) # 这里的对应前面fforward的输入是32 |
1 | torch.Size([1, 10]) |
1 | input.size() |
1 | torch.Size([1, 1, 32, 32]) |
在反向传播前,先要将所有参数的梯度清零
1 | net.zero_grad() |
注意:torch.nn只支持mini-batches,不支持一次只输入一个样本,即一次必须是一个batch。
也就是说,就算我们输入一个样本,也会对样本进行分批,所以,所有的输入都会增加一个维度,我们对比下刚才的input,nn中定义为3维,但是我们人工创建时多增加了一个维度,变为了4维,最前面的1即为batch-size
我感觉我需要去补一下coursera,而不是在这里看代码
前向传播,后向传播,神经网络
翻出来了这个
这是一个没有隐藏层的神经网络,左侧输入,右侧输出,前向就是从输入到输出,反向就是从后面获取的Loss传到前面的那个输出层里(比如logistic)
这是一个带有隐藏层的神经网络,像之前没有隐藏层的时候,我们改一个东西的参数就可以了,现在我们还要改小女孩的参数,所以要用链式求导梯度下降。
这些中间层和output就是传说中的激活函数,如果不用激活函数,每一层输出都是上一层输入的线性函数,没法拟合非线性函数。
输入数据乘以权重(weight)加上一个偏置(bias),然后应用激活函数得到该神经元的输出,再将此输出传给下一层的神经元。这些weight和bias,再加上L1 L2 batch size之类的 就是超参数。
损失函数
损失函数
在nn中PyTorch还预制了常用的损失函数,下面我们用MSELoss用来计算均方误差
1 | y = torch.arange(0,10).view(1,10).float() |
28.92203712463379
优化器
优化器
在反向传播计算完所有参数的梯度后,还需要使用优化方法来更新网络的权重和参数,例如随机梯度下降法(SGD)的更新策略如下:
weight = weight - learning_rate * gradient
在torch.optim中实现大多数的优化方法,例如RMSProp、Adam、SGD等,下面我们使用SGD做个简单的样例
In [10]:
1 | import torch.optim |
1 | out = net(input) # 这里调用的时候会打印出我们在forword函数中打印的x的大小 |
1 | torch.Size([1, 1, 32, 32]) |
这样,神经网络的数据的一个完整的传播就已经通过PyTorch实现了。
后面就没有再细看了
Fine tuning
这个目前恰好切中自己的需求。
针对于某个任务,自己的训练数据不多,那怎么办? 没关系,我们先找到一个同类的别人训练好的模型,把别人现成的训练好了的模型拿过来,换成自己的数据,调整一下参数,再训练一遍,这就是微调(fine-tune)。 PyTorch里面提供的经典的网络模型都是官方通过Imagenet的数据集与训练好的数据,如果我们的数据训练数据不够,这些数据是可以作为基础模型来使用的。
- 新数据集和原始数据集合类似,那么直接可以微调一个最后的FC层或者重新指定一个新的分类器
- 新数据集比较小和原始数据集合差异性比较大,那么可以使用从模型的中部开始训练,只对最后几层进行fine-tuning
- 新数据集比较小和原始数据集合差异性比较大,如果上面方法还是不行的化那么最好是重新训练,只将预训练的模型作为一个新模型初始化的数据
- 新数据集的大小一定要与原始数据集相同,比如CNN中输入的图片大小一定要相同,才不会报错
- 如果数据集大小不同的话,可以在最后的fc层之前添加卷积或者pool层,使得最后的输出与fc层一致,但这样会导致准确度大幅下降,所以不建议这样做
- 对于不同的层可以设置不同的学习率,一般情况下建议,对于使用的原始数据做初始化的层设置的学习率要小于(一般可设置小于10倍)初始化的学习率,这样保证对于已经初始化的数据不会扭曲的过快,而使用初始化学习率的新层可以快速的收敛。
更具体的可以看这里
还有一些可视化的内容,后面用到了再补充