梯度的计算
对于pytorch来说,可能对于我们而言最实用的功能就是它的梯度自动计算功能,因为有了这个功能,我们可以在逻辑允许的范围内随意定义模型的结构(所以会出现什么200多层的神经网络),而不用担心梯度计算的问题。
pytorch计算梯度的方式为反向传播,也就是从结尾那里开始计算,因为高数曾经告诉我们,导数是有法则的 ,所以有了这样一个形象的名字。下面来一个小例子
x = torch.tensor([[1., 0.], [-1., 1.]], requires_grad=True)
z = x.pow(2).sum()
z.backward()
x.grad
上面的例子就相当于
ps:在pytorhc中用tensor 建立的张量默认requires_grad是false,所以要进行手动置位
测试与训练模型(Pytorch版)
然后就到了我们的主角了
这张图也是参考的LHY老师的PPT,根据之后介绍的内容,首先先定义,然后再定义损失,最后再定义优化函数
对于pytorh来说比较方便的一点是它已经帮我们把常用的模型已经定义好了,比如FC,RNN,LSTM,GRU等,已经到了开箱即用的地步,可谓相当方便。
例如我们想用一个FC层
import torch.nn as nn
_ = nn.Linear(32, 64)
相当于上面这个图
你也可以直接输出FC层的bias与weight
_.weight
_.bias
十分方便
然后是关于激活函数的,激活函数按照LHY老师上课的话来说就是以激活来对原函数进行拟合,即利用激活函数的组合来表示函数,如果没有激活函数的话,因为线性层就相当于是矩阵相乘,因此再多的矩阵相乘,最后的结果也只是相当于一个矩阵。
import torch.nn as nn
class MyModel(nn.Module):
def __init__(self):
super(MyModel, self).__init__()
self.net = nn.Sequential(
nn.Linear(10, 32),
nn.Sigmoid(),
nn.Linear(32, 1)
)
def forward(self, x):
return self.net(x)
# class MyModel(nn.Module): 这种写法比较麻烦,不过和上面的写法是一样的
# def __init__(self):
# super(MyModel, self).__init__()
# self.layer1 = nn.Linear(10, 32)
# self.layer2 = nn.Sigmoid(),
# self.layer3 = nn.Linear(32,1)
# def forward(self, x):
# out = self.layer1(x)
# out = self.layer2(out)
# out = self.layer3(out)
# return out
然后对于损失函数,一般常用的损失函数有三种
即MSE,BCE,CE,Mean squared error,binary cross entropy,cross entropy,其实后面两种差不多之所以分开列举是自己恰好在毕设里面用了BCE。用法的话就像下面一样
criterion = nn.CrossEntropyLoss()
loss = criterion(model_output, expected_value)
然后就是那个优化算法了,一般优化算法都是围绕梯度下降法进行的优化,如ADAMS等,因为基于梯度下降法的话计算公式里需要学习率与梯度的乘积,因此一般可以通过改变学习率或者梯度(如动量法)的方法来进行。
一般的步骤可以归于以下三步:
- Call optimizer.zero_grad() to reset gradients of model parameters.
- Call loss.backward() to backpropagate gradients of prediction loss.
- Call optimizer.step() to adjust model parameters.
因为pytorch默认会将梯度累加,因此在每一步的计算时需要将梯度置零
然后在模型的训练与测试的时候还有两个地方需要注意
- eval()的问题,
将对模型使用eval相当于model.train(false),这个主要是在模型的评估上面用,据官方的文档好像是对dropout,batchnorm的操作有用,因为在评估时我们希望每次输出的东西都是相同的,不要出现随机值。 - with torch.no_grad()
这个主要是防止pytorch计算梯度,在validation 的时候计算梯度已经没有什么意义,可能一不小心还把参数更新了,相当于模型偷看到了validation的数据,因此为了永绝后患,直接将梯度置零。