2.1 使用pytorch构建一个神经网络

步骤:

构建神经网络的典型流程
定义一个拥有可学习参数的神经网络
遍历训练数据集
处理输入数据使其流经神经网络
计算损失值
将网络参数的梯度进行反向传播
以一定的规则更新网络的权重
以cnn为例
##首先定义一个pytorch实现的神经网洛
# 导入工具包
import torch
import torch.nn as nn
import torch.nn.functional as F
# 定义一个简单的网络类
# 卷积计算(W-F+2P)/S+1
# 此公式中各个元素含义如下所示:
#
# W代表输入图像大小WxW;
#
# F代表Filter大小FxF;
#
# P代表padding的像素数;
#
# S代表步长;
#
# 新矩阵的通道数为设置的卷积核的个数.
class Net(nn.Module):
    def __init__(self):
        super(Net,self).__init__()
        # 输入通道指的是输入了几个二维信息
        # 定义第一层卷积神经网络,输入通道=1,输出通道=6,卷积核大小3*3
        self.conv1=nn.Conv2d(1,6,3,stride=1,padding=0)
        # 定义第二层卷积神经网络,输入通道=6,输出通道=16,卷积核大小3*3
        self.conv2=nn.Conv2d(6,16,3)
        # 定义三层全连接网络
        # 输入图像为32*32 经过3*3卷积为6*6再乘上16个通道???答因为后面有2*2的池化层
        self.fc1=nn.Linear(16*6*6,120)
        self.fc2=nn.Linear(120,84)
        self.fc3=nn.Linear(84,10)
    def forward(self,x):
        #  在(2,2)的池化窗口下执行最大池化操作
        x=F.max_pool2d(F.relu(self.conv1(x)),(2,2))
        print("x1=",x.size())
        x=F.max_pool2d(F.relu(self.conv2(x)),2)
        print("x2=",x.size())
        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):
        # 计算size,除了第0个维度上的batch_size
        size=x.size()[1:]
        num_features = 1
        for s in size:
            num_features *=s
        return num_features

net=Net()
print(net)

Net(
  (conv1): Conv2d(1, 6, kernel_size=(3, 3), stride=(1, 1))
  (conv2): Conv2d(6, 16, kernel_size=(3, 3), stride=(1, 1))
  (fc1): Linear(in_features=576, out_features=120, bias=True)
  (fc2): Linear(in_features=120, out_features=84, bias=True)
  (fc3): Linear(in_features=84, out_features=10, bias=True)
)

## 模型中所有可训练参数可以通过net.parameters()来获得
params = list(net.parameters())
print(len(params))
# print(params)
print(params[0].size())
10
torch.Size([6, 1, 3, 3])

输入数据

input=torch.randn(1,1,32,32)
print(input.size())
out=net(input)
print(out)

torch.Size([1, 1, 32, 32])
x1= torch.Size([1, 6, 15, 15])
x2= torch.Size([1, 16, 6, 6])
tensor([[-0.0311,  0.0812,  0.0231, -0.0665, -0.1095, -0.0343,  0.0829, -0.1456,
          0.0823, -0.0481]], grad_fn=<AddmmBackward0>)

# 有了输出张量后,就可以执行梯度归零和反向传播的操作
net.zero_grad()
out.backward(torch.randn(1,10))
## 注意torch.nn构建的神经网络支支持mini-batch的输入,不支持单一样本的输入
## 比如:nn.conv2d需要一个4D的Tensor,形状为(nsample,nchnnels,height,,width)如果输入只有单一样本形式,
## 则需要执行input.unsqueeze(0),主动将3D Tensor扩充成4D Tensor
损失函数:
##  损失函数是用真实值与预测值算loss反向更新权重
out=net(input)
target=torch.randn(10)
print("output=",out)
print("target=",target)
# 改变target的形状为二维张量,为了和output匹配
target=target.view(1,-1)
print(target)
criterion=nn.MSELoss()

loss=criterion(out,target)
print(loss)

x1= torch.Size([1, 6, 15, 15])
x2= torch.Size([1, 16, 6, 6])
output= tensor([[-0.0311,  0.0812,  0.0231, -0.0665, -0.1095, -0.0343,  0.0829, -0.1456,
          0.0823, -0.0481]], grad_fn=<AddmmBackward0>)
target= tensor([-1.1732, -1.1593, -0.1919,  0.4548, -0.1894, -0.8209,  0.0904,  0.3107,
        -0.4256, -0.9506])
tensor([[-1.1732, -1.1593, -0.1919,  0.4548, -0.1894, -0.8209,  0.0904,  0.3107,
         -0.4256, -0.9506]])
tensor(0.5067, grad_fn=<MseLossBackward0>)

## 跟踪loss反向传播的方向,使用.grad_fn属性打印,可以看到一张完整的计算图
# 下面是正向传播
# input->conv2d->relu->maxpool2d->conv2d->relu->maxpool3d
# ->view->linear->relu->linear->relu->linear
# ->MSELoss
# ->loss
## 当调用loss.backward()时,所有属性requires_grad()=True的tensor都会参与计算,并将其累积到.grad属性
print(loss.grad_fn)
print(loss.grad_fn.next_functions[0][0])#Linear
print(loss.grad_fn.next_functions[0][0].next_functions[0][0])#relu

<MseLossBackward0 object at 0x0000017C80763B08>
<AddmmBackward0 object at 0x0000017C80763A48>
<AccumulateGrad object at 0x0000017C80763B08>

## 反向传播,直接使用loss.backward()
## 每次执行钱需要梯度清零,否则梯度会在不同批次之间被累加

# 清零
net.zero_grad()

print("conv1.bias.grad before backward")
print(net.conv1.bias.grad)
##Pytorch执行反向传播的代码
loss.backward()
print("conv1.bias.grad after backward")
print(net.conv1.bias.grad)

conv1.bias.grad before backward
tensor([0., 0., 0., 0., 0., 0.])
conv1.bias.grad after backward
tensor([ 0.0065,  0.0051, -0.0055,  0.0043,  0.0023, -0.0050])

更新参数

1,传统方法

## 更新参数最简单的方法就是使用SGD
## 计算方法为weight=weight-lr*gradient
## 首先使用原始python代码实现SGD
learningrate=0.01
for f in net.parameters():
    f.data.sub_(f.grad.data * learningrate)#做差计算

2,pytorch推荐使用方法

## 使用pytorch推荐标准代码
import torch.optim as optim
## 通过optim创建优化器对象
optimizer = optim.SGD(net.parameters(),lr=0.01) ##重要

## 将优化器执行梯度清零的操作
optimizer.zero_grad()## 重要

output=net(input)
loss=criterion(output,target)

## 对损失值执行反向传播的操作
loss.backward()###重要

##参数的更新通过一行标准代码执行
optimizer.step()###重要

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值