终于要开始搭建神经网络了开心
神经网络是通过torch.nn包来构建的
通过上一章我们知道了怎么前向传播,怎么反向传播的的了,这些基本就够了
然后我们先看一个神经网络的处理流程:
1 定义网络架构
2 将输入喂入神经网络
3 神经网络计算输入得出输出
3对比输出与真实标签数据
4计算第3步中输出与真实标签的差距,也就是loss
5 如果loss太大,就反向传播回去调整网络参数。再重复、2,3,4,知道loss小到我们的要求为止。
调整参数
我们用最简单的,以前人工智能课上老师讲的方法更新参数。w = w - l*gradient
w 是参数, l 是学习率, gradient 是梯度,也就是对输入求的导数。
先定义前向传播网络,文中给了很详细的注释
import torch
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
#定义卷积核 1是输入通道数,6是输出通道数,5是指5×5的卷积
#所以类推就是第一个参数是输入通道,第二个是输出通道,第三个是卷积核尺寸
self.conv1 = nn.Conv2d(1, 6, 5)
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):
#将第一层卷积后的结果放入激活函数relu 再 最大池化一下,(2,2)是池化的步长
x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
#同上一层一样,不过有一点不一样就是如果x是正方形,也就是长宽都相等的话,步长可以只指定一个数字
x = F.max_pool2d(F.relu(self.conv2(x)), 2)
# 这个是将x变成一维数组,为全连接层做准备
x = x.view(-1, self.num_flat_features(x))
#全连接层
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
def num_flat_features(self, x):
#第一个维度不要,因为第一个维度是输入数据的batch,batch也就是一次输入多少张图片
size = x.size()[1:]
num_features = 1
for s in size:
num_features*=s
return num_features
net = Net()
print(net)
查看参数:
params = list(net.parameters())
print(len(params))#输出10,一个有10层的参数
print(params[0].size())#输出一层的参数形状
#自定义一个输入32*32的数据
input = torch.randn(1, 1, 32, 32)
out = net(input)
print(out)
#将所有梯度清零,然后反向传播
net.zero_grad()
out.backward(torch.randn(1, 10))
我们上面已经做完了定义一个神经网络
给定输入,并完成了反向传播。现在要做计算loss和更行参数了。
损失函数:
损失函数就是计算神经网络输出的和我们真实值的差距。
这里使用均方误差。
output = net(input)
target = torch.randn(10) #我们定义的真实值
target = target.view(1, -1)#将真实值的维度改成和输出值的维度
criterion = nn.MSELoss()
loss = criterion(output, target)
print(loss)

loss
print(loss.grad_fn) # MSELoss
print(loss.grad_fn.next_functions[0][0]) # Linear
print(loss.grad_fn.next_functions[0][0].next_functions[0][0])
用这种方法可以查看反向传播的路径
我们现在要把loss反向传递回去修改参数,首先要将梯度清零。不然所有梯度会一直累加就会越来越大。
我们反向传播一下 看一下第一层卷积层的偏置项在传播之前和之后的变化。
net.zero_grad()
#清零梯度
net.zero_grad()
print('反向传播前第一层参数b')
print(net.conv1.bias.grad)
loss.backward()
print('反向传播后第一层参数b')
print(net.conv1.bias.grad)
反向传播求出来的这个就是梯度。
我们现在用这个梯度来更新参数
w = w - l*gradient
gradient就是梯度
learning_rate = 0.01
for f in net.parameters():
f.data.sub_(f.grad.data * learning_rate)
知道怎么用就好了,这个是最简单的更新方法。然后还有很多其他的方法比如SGD,Adam等等,这些方法torch已经封装好了,我们直接调用就行。
调用方法
import torch.optim as optim
optimizer = optim.SGD(net.parameters(), lr=0.01)
optimizer.step()
就这样一个神经网络搭建好了
完整代码:
import torch
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
#定义卷积核 1是输入通道数,6是输出通道数,5是指5×5的卷积
#所以类推就是第一个参数是输入通道,第二个是输出通道,第三个是卷积核尺寸
self.conv1 = nn.Conv2d(1, 6, 5)
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):
#将第一层卷积后的结果放入激活函数relu 再 最大池化一下,(2,2)是池化的步长
x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
#同上一层一样,不过有一点不一样就是如果x是正方形,也就是长宽都相等的话,步长可以只指定一个数字
x = F.max_pool2d(F.relu(self.conv2(x)), 2)
# 这个是将x变成一维数组,为全连接层做准备
x = x.view(-1, self.num_flat_features(x))
#全连接层
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
def num_flat_features(self, x):
#第一个维度不要,因为第一个维度是输入数据的batch,batch也就是一次输入多少张图片
size = x.size()[1:]
num_features = 1
for s in size:
num_features*=s
return num_features
net = Net()
print(net)
params = list(net.parameters())
print(len(params))
print(params[0].size())
#自定义一个输入32*32的数据
input = torch.randn(1, 1, 32, 32)
out = net(input)
print(out)
#将所有梯度清零,然后反向传播
net.zero_grad()
out.backward(torch.randn(1, 10))
output = net(input)
target = torch.randn(10) #我们定义的真实值
target = target.view(1, -1)#将真实值的维度改成和输出值的维度
criterion = nn.MSELoss()
loss = criterion(output, target)
print(loss)
print(loss.grad_fn) # MSELoss
print(loss.grad_fn.next_functions[0][0]) # Linear
print(loss.grad_fn.next_functions[0][0].next_functions[0][0])
#清零梯度
net.zero_grad()
print('反向传播前第一层参数b')
print(net.conv1.bias.grad)
loss.backward()
print('反向传播后第一层参数b')
print(net.conv1.bias.grad)
learning_rate = 0.01
for f in net.parameters():
f.data.sub_(f.grad.data * learning_rate)
import torch.optim as optim
optimizer = optim.SGD(net.parameters(), lr=0.01)
optimizer.step()
关注我们,我们会每天坚持推送学到的新知识给你