需要特别注意的一点
很多博客或非官方教程中提到了pytorch中的tensor基本上和numpy中的array是一样的,可以直接通过函数相互转化,同时pytorch中有variable变量,variable是对tensor的一个封装,用于构建计算图,并进行迭代。但是对0.4.1版本来说,Variable不再被支持使用。
可以理解为Variable合并到了Tensor中。 我开始时一些博客和文档同时看,一直以为tensor没法求梯度,没有注意到这一点,所以很困惑。。。
- 数据加载和预处理
- 模型定义,一般就两个函数 。
__init__(self)
函数中对要进行的计算进行初始化,即设置每层输入输出的数量,每层的计算类型。
__forward__(self,x)
函数中定义具体的计算关系,即每层之间如何连接,是否要pool,relu还是sigmoid等。
如下
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(3, 6, 5)
self.pool = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(6, 16, 5)
self.fc1 = nn.Linear(16 * 5 * 5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
x = x.view(-1, 16 * 5 * 5)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
net = Net()
- 定义损失函数和优化方式 。
之后计算loss时,使用loss = criterion(outputs, labels)
import torch.optim as optim
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
- 训练,每次迭代都是四行代码,对应训练的四个步骤,非常明确。这也是PyTorch的优势。
四个步骤分别是,前向传播,计算loss,反向传播(计算所有参数的梯度),更新参数。
# forward + backward + optimize
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
- 这里有个不太明白的地方,为什么
backward()
是loss的函数? 反向传播求梯度时,是需要知道神经网络的结构,但是神经网络的结构是定义在Net()
这个类中的,loss没有获得神经网络的结构啊,只是通过 output和labels这两个向量进行了计算。 - 查看了部分源码,大概知道每一句做了什么。
(1) 首先了解一下python类中的__call__()
函数,__call__()
函数是python类中的特殊函数,初始化对象后,如net = Net()
,执行net()
,这是就会调用Net
这个()类中的__call__()
函数。
(2) 执行outputs = net(inputs)
时就调用了父类Module中的__call__()
函数,其中调用了forward()
函数,forward()
函数返回类型是Tensor。
之后通过loss = criterion(outputs, labels)
来计算损失,这里也调用了CrossEntropyLoss
类中的forward()
函数,返回类型为Variable,即loss类型为Tensor。
(3)loss.backward()
执行了tensor.backward()
, 其中其实是执行了torch.autograd.backward()
- 这里看着每一步很明确,就像在python中一步一步的来做运算。但还是跟tensorflow一样构建了计算图,不然没办法反向传播。