目录

PyTorch之nn模块

PyTorch之optim模块

自定义nn模块

控制流和权重共享


PyTorch之nn模块

计算图和autograd是十分强大的工具,可以定义复杂的操作并自动求导;然而对于大规模的网络,autograd太过于底层。在构建神经网络是,我们经常考虑将计算安排成层,其中一些具有可学习的参数,他们将在隵过程中进行优化。

Tensorflow里面,有类似于Keras,TensorFlow-Slim和FLearn这些封装了底层计算图的高层抽象接口,这使得构建网络是否方便。

在PyTorch中,包nn完成了同样的功能。nn包中定义了一组大致等价于层的模块。一个模块接受输入的tensor,计算输出的tensor,而且还保存了一些内部状态比如学习的tensor的参数等等。nn包中也定义了一组损失函数loss functions,用来训练神经网络。

在下面的例子中,我们用nn包实现两层的网络:

#!/usr/bin/env torch
# -*- coding:utf-8 -*-
# @Time  : 2021/2/7, 12:24
# @Author: Lee
# @File  : nn_module.pyimport torch# N是批带下;D是输入维度;H是隐藏层维度;D_out是输出维度
N, D_in, H, D_out = 64, 1000, 100, 10# 创建输入和输出随机张量
x = torch.randn(N, D_in)
y = torch.randn(N, D_out)# 使用nn包将我们的模型定义为一系列的层
# nn.sequential是包含了其他模块的模块,并按顺序应用这些模块来产生输出
# 每个线性模块使用线性函数从输入计算输出,并保存其内部的权重和偏差张量
# 在构造模型之后,我们使用.to()方法将其移动到所需的设备上
model = torch.nn.Sequential(torch.nn.Linear(D_in, H),torch.nn.ReLU(),torch.nn.Linear(H, D_out),
)# nn包还包含常用的损失函数的定义:
# 在这种情况下,我们使用均方差(MSE)作为损失函数
# 设置reduction='sum',表示计算的是平方误差的和,而不是平均值
# 这是为了与前面手工计算损失的例子保持一致
# 但在实践中,通过设置reduction'elementwise_mean'来使用均方误差作为损失更为常见
loss_fn = torch.nn.MSELoss(reduction='sum')learning_rate = 1e-4
for t in range(500):# 前向传播:通过模型传入x计算预测的y# 模块对象重载了__call__运算符,所以可以向函数那样调用它们# 这么重相当于向模块传入了一个张量,然后它返回了一个输出张量y_pred = model(x)# 计算并打印损失# 传递包含y的预测值和真实的张量,损失函数返回包含损失的张量loss = loss_fn(y_pred, y)if (t+1) % 50 == 0:print("第", t, "次:loss.item() = ", loss.item(), "  loss = ", loss)# 反向传播之前清零梯度model.zero_grad()# 反向传播:计算模型的损失对所有可学习参数的导数(梯度)# 在内部,每个模块的参数存储的requires_grad=True的张量中# 因此这个调用将计算模型中所有可学习参数的梯度loss.backward()# 使用梯度下降更新权重# 每个参数都是张量,所以我们可以像以前那样可以得到它的数值和梯度with torch.no_grad():for param in model.parameters():param -= learning_rate * param.grad

运行结果如下:

第 49 次:loss.item() =  26.66609764099121   loss =  tensor(26.6661, grad_fn=<MseLossBackward>)
第 99 次:loss.item() =  1.8744418621063232   loss =  tensor(1.8744, grad_fn=<MseLossBackward>)
第 149 次:loss.item() =  0.20531243085861206   loss =  tensor(0.2053, grad_fn=<MseLossBackward>)
第 199 次:loss.item() =  0.026159264147281647   loss =  tensor(0.0262, grad_fn=<MseLossBackward>)
第 249 次:loss.item() =  0.003675416810438037   loss =  tensor(0.0037, grad_fn=<MseLossBackward>)
第 299 次:loss.item() =  0.0005623005563393235   loss =  tensor(0.0006, grad_fn=<MseLossBackward>)
第 349 次:loss.item() =  9.252542804460973e-05   loss =  tensor(9.2525e-05, grad_fn=<MseLossBackward>)
第 399 次:loss.item() =  1.6242187484749593e-05   loss =  tensor(1.6242e-05, grad_fn=<MseLossBackward>)
第 449 次:loss.item() =  3.0295095712062903e-06   loss =  tensor(3.0295e-06, grad_fn=<MseLossBackward>)
第 499 次:loss.item() =  5.997063681206782e-07   loss =  tensor(5.9971e-07, grad_fn=<MseLossBackward>)

PyTorch之optim模块

到目前为止,我们已经通过手动改变可学习参数的张量来更新模型的权重。对于随机梯度下降(SGD/stochastic gradient descent)等简单的优化算法来说,这不是一个很大的负担,但在实践中,我们常用AdaGrad,RMSPro,Adam等更复杂的优化器来训练网络。

#!/usr/bin/env torch
# -*- coding:utf-8 -*-
# @Time  : 2021/2/7, 12:47
# @Author: Lee
# @File  : torch_optim.pyimport torch# N是批带下;D是输入维度;H是隐藏层维度;D_out是输出维度
N, D_in, H, D_out = 64, 1000, 100, 10# 创建输入和输出随机张量
x = torch.randn(N, D_in)
y = torch.randn(N, D_out)# 使用nn包含定义模型和损失函数
model = torch.nn.Sequential(torch.nn.Linear(D_in, H),torch.nn.ReLU(),torch.nn.Linear(H, D_out),
)
loss_fn = torch.nn.MSELoss(reduction='sum')# 使用optim包定义优化器(Optimizer)。Opitmizer将会为我们更新模型的权重
# 这里我们使用Adam优化方法;optim还包含了很多别的优化方法
# Adam构造函数的第一个参数告诉优化其应该更新哪些张量
learning_rate = 1e-4
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)for t in range(500):# 前向传播:通过模型传入x计算预测的yy_pred = model(x)# 计算并打印损失loss = loss_fn(y_pred, y)if (t+1) % 50 == 0:print("第", t, "次:loss.item() = ", loss.item(), "  loss = ", loss)# 反向传播之前清零梯度model.zero_grad()# 反向传播:计算模型的参数loss对可学习参数的梯度loss.backward()# 调用Optimizer的step函数使它所有参数更新optimizer.step()

运行结果如下:

第 49 次:loss.item() =  171.713134765625   loss =  tensor(171.7131, grad_fn=<MseLossBackward>)
第 99 次:loss.item() =  35.17428970336914   loss =  tensor(35.1743, grad_fn=<MseLossBackward>)
第 149 次:loss.item() =  4.378096103668213   loss =  tensor(4.3781, grad_fn=<MseLossBackward>)
第 199 次:loss.item() =  0.41847413778305054   loss =  tensor(0.4185, grad_fn=<MseLossBackward>)
第 249 次:loss.item() =  0.03814450651407242   loss =  tensor(0.0381, grad_fn=<MseLossBackward>)
第 299 次:loss.item() =  0.00488114170730114   loss =  tensor(0.0049, grad_fn=<MseLossBackward>)
第 349 次:loss.item() =  0.0008024392882362008   loss =  tensor(0.0008, grad_fn=<MseLossBackward>)
第 399 次:loss.item() =  0.00012188169785076752   loss =  tensor(0.0001, grad_fn=<MseLossBackward>)
第 449 次:loss.item() =  1.5356104995589703e-05   loss =  tensor(1.5356e-05, grad_fn=<MseLossBackward>)
第 499 次:loss.item() =  1.5737085732325795e-06   loss =  tensor(1.5737e-06, grad_fn=<MseLossBackward>)

自定义nn模块

有时候需要指定比现有模块序列更复杂的模型,对于这些情况,可以通过集成nnModule并定义forward函数,这个forward函数可以试用期他模块或者其他的自动求导运算来接收输入的tensor,产生输出tensor。

这个例子中,我们用自定义Module的子类构建两层网络:

#!/usr/bin/env torch
# -*- coding:utf-8 -*-
# @Time  : 2021/2/7, 13:00
# @Author: Lee
# @File  : custom_nn_module.pyimport torchclass TwoLayerNet(torch.nn.Module):def __init__(self, D_in, H, D_out):""":param D_in: 输入维度:param H: 隐藏层维度:param D_out: 输出维度在构造函数中,我们实例化了两个nn.Linear模块,并将它们作为成员变量"""super(TwoLayerNet, self).__init__()self.linear1 = torch.nn.Linear(D_in, H)self.linear2 = torch.nn.Linear(H, D_out)def forward(self, x):""":param x: 输入值:return: 预测值在前向传播的函数中,我们接收一个输入的张量,也必须返回一个输出张量。我们可以使用构造函数中定义的模块以及张量上的任意的可微分的操作"""h_relu = self.linear1(x).clamp(min=0)y_pred = self.linear2(h_relu)return y_pred# N是批带下;D是输入维度;H是隐藏层维度;D_out是输出维度
N, D_in, H, D_out = 64, 1000, 100, 10# 创建输入和输出随机张量
x = torch.randn(N, D_in)
y = torch.randn(N, D_out)# 使用nn包含定义模型和损失函数
model = TwoLayerNet(D_in, H, D_out)# 构造损失函数和优化器
# SGD构造函数中对model.parameters()的调用
# 将包含模型的一部分,即两个nn.Linear模块的可学习参数
loss_fn = torch.nn.MSELoss(reduction='sum')
optimizer = torch.optim.SGD(model.parameters(), lr=1e-4)for t in range(500):# 前向传播:通过模型传入x计算预测的yy_pred = model(x)# 计算并打印损失loss = loss_fn(y_pred, y)if (t+1) % 50 == 0:print("第", t, "次:loss.item() = ", loss.item(), "  loss = ", loss)# 清零梯度, 反向传播, 更新权重model.zero_grad()loss.backward()optimizer.step()

运行结果如下:

第 49 次:loss.item() =  34.36606979370117   loss =  tensor(34.3661, grad_fn=<MseLossBackward>)
第 99 次:loss.item() =  2.108647346496582   loss =  tensor(2.1086, grad_fn=<MseLossBackward>)
第 149 次:loss.item() =  0.22304271161556244   loss =  tensor(0.2230, grad_fn=<MseLossBackward>)
第 199 次:loss.item() =  0.03183714672923088   loss =  tensor(0.0318, grad_fn=<MseLossBackward>)
第 249 次:loss.item() =  0.005248690489679575   loss =  tensor(0.0052, grad_fn=<MseLossBackward>)
第 299 次:loss.item() =  0.0009347241139039397   loss =  tensor(0.0009, grad_fn=<MseLossBackward>)
第 349 次:loss.item() =  0.00017452010069973767   loss =  tensor(0.0002, grad_fn=<MseLossBackward>)
第 399 次:loss.item() =  3.358458343427628e-05   loss =  tensor(3.3585e-05, grad_fn=<MseLossBackward>)
第 449 次:loss.item() =  6.600801498279907e-06   loss =  tensor(6.6008e-06, grad_fn=<MseLossBackward>)
第 499 次:loss.item() =  1.3166297776479041e-06   loss =  tensor(1.3166e-06, grad_fn=<MseLossBackward>)

控制流和权重共享

作为动态图和权重共享的例子,这里有一个非常奇怪的模型:一个全连接的ReLU网络,在每一册前向传播时,它的隐藏层的层数为随机1到4之间的数,这样可以多次重复相同的权重来计算。

因为这个模型可以使用普通的Python流控制来实现循环,并且我们可以通过在定义转发时多次重用同一个模块来实现最易内层之间的权重共享。

我们利用Module的子类来实现这个模型:

#!/usr/bin/env torch
# -*- coding:utf-8 -*-
# @Time  : 2021/2/7, 13:13
# @Author: Lee
# @File  : share_weight.pyimport random
import torch# 自定义网络
class DynamicNet(torch.nn.Module):def __init__(self, D_in, H, D_out):""":param D_in: 输入维度:param H: 隐藏层维度:param D_out: 输出维度在构造函数中,我们实例化了三个nn.Linear模块,他们将在前向传播中被使用"""super(DynamicNet, self).__init__()self.input_linear = torch.nn.Linear(D_in, H)self.middle_linear = torch.nn.Linear(H, H)self.output_linear = torch.nn.Linear(H, D_out)def forward(self, x):""":param x: 输入值:return: 预测值对于模型的前向传播,我们随机选择0,1,2,3,并重用了多次计算隐藏层的middle_linear模块由于每次前向传播构建一个动态计算图我们可以在定义模型的前向传播时使用常规Python控制流运算符,如循环或条件语句在这里,我们还看到,在定义计算图形时多次重用一个模块是完全安全的这是对Lua Torch的一大改进,因为Lua Torch中每个模块只能使用一次"""h_relu = self.input_linear(x).clamp(min=0)for _ in range(random.randint(0, 3)):h_relu = self.middle_linear(h_relu).clamp(min=0)y_pred = self.output_linear(h_relu)return y_pred# N是批带下;D是输入维度;H是隐藏层维度;D_out是输出维度
N, D_in, H, D_out = 64, 1000, 100, 10# 创建输入和输出随机张量
x = torch.randn(N, D_in)
y = torch.randn(N, D_out)# 使用nn包含定义模型和损失函数
model = DynamicNet(D_in, H, D_out)# 构造损失函数和优化器
# 用平凡的随机梯度下降训练这个奇怪的模型是困难的,所以我们使用了momentum方法
loss_fn = torch.nn.MSELoss(reduction='sum')
optimizer = torch.optim.SGD(model.parameters(), lr=1e-4, momentum=0.9)for t in range(500):# 前向传播:通过模型传入x计算预测的yy_pred = model(x)# 计算并打印损失loss = loss_fn(y_pred, y)if (t+1) % 50 == 0:print("第", t, "次:loss.item() = ", loss.item(), "  loss = ", loss)# 清零梯度, 反向传播, 更新权重model.zero_grad()loss.backward()optimizer.step()

运行结果如下:

第 49 次:loss.item() =  54.70349884033203   loss =  tensor(54.7035, grad_fn=<MseLossBackward>)
第 99 次:loss.item() =  30.16559600830078   loss =  tensor(30.1656, grad_fn=<MseLossBackward>)
第 149 次:loss.item() =  7.247811317443848   loss =  tensor(7.2478, grad_fn=<MseLossBackward>)
第 199 次:loss.item() =  30.601959228515625   loss =  tensor(30.6020, grad_fn=<MseLossBackward>)
第 249 次:loss.item() =  3.3245818614959717   loss =  tensor(3.3246, grad_fn=<MseLossBackward>)
第 299 次:loss.item() =  1.3237444162368774   loss =  tensor(1.3237, grad_fn=<MseLossBackward>)
第 349 次:loss.item() =  3.976801872253418   loss =  tensor(3.9768, grad_fn=<MseLossBackward>)
第 399 次:loss.item() =  0.22191806137561798   loss =  tensor(0.2219, grad_fn=<MseLossBackward>)
第 449 次:loss.item() =  0.40976208448410034   loss =  tensor(0.4098, grad_fn=<MseLossBackward>)
第 499 次:loss.item() =  0.07099712640047073   loss =  tensor(0.0710, grad_fn=<MseLossBackward>)

Pytorch基础(五)nn模块及optimizer相关推荐

  1. [Pytorch系列-28]:神经网络基础 - torch.nn模块功能列表

    作者主页(文火冰糖的硅基工坊):文火冰糖(王文兵)的博客_文火冰糖的硅基工坊_CSDN博客 本文网址:https://blog.csdn.net/HiWangWenBing/article/detai ...

  2. 【小白学习PyTorch教程】三、Pytorch中的NN模块并实现第一个神经网络模型

    「@Author:Runsen」 在PyTorch建立模型,主要是NN模块. nn.Linear nn.Linear是创建一个线性层.这里需要将输入和输出维度作为参数传递. linear = nn.L ...

  3. PyTorch基础之激活函数模块中Sigmoid、Tanh、ReLU、LeakyReLU函数讲解(附源码)

    需要源码请点赞关注收藏后评论区留言私信~~~ 激活函数是神经网络中的重要组成部分.在多层神经网络中,上层节点的输出和下层节点的输入之间有一个函数关系.如果这个函数我们设置为非线性函数,深层网络的表达能 ...

  4. python3.x 基础五:模块

    1.定义 模块:本质是.py结尾的python文件,从逻辑上组织python代码,可以是变量,函数,类,逻辑,目的是实现一个功能,test.py 对应模块名:test 包:从逻辑上组织模块的,本质就是 ...

  5. pytorch学习(五)---torch.nn模块

            本篇自学笔记来自于b站<PyTorch深度学习快速入门教程(绝对通俗易懂!)[小土堆]>,Up主讲的非常通俗易懂,文章下方有视频连接,如有需要可移步up主讲解视频,如有侵权 ...

  6. 【PyTorch基础教程9】优化器optimizer和训练过程

    学习总结 (1)每个优化器都是一个类,一定要进行实例化才能使用,比如: class Net(nn.Moddule):··· net = Net() optim = torch.optim.SGD(ne ...

  7. Pytorch学习(二)—— nn模块

    torch.nn nn.Module 常用的神经网络相关层 损失函数 优化器 模型初始化策略 nn和autograd nn.functional nn和autograd的关系 hooks简介 模型保存 ...

  8. Pytorch 神经网络nn模块

    文章目录 1. nn模块 2. torch.optim 优化器 3. 自定义nn模块 4. 权重共享 参考 http://pytorch123.com/ 1. nn模块 import torch N, ...

  9. Python基础语法(五)—常用模块和模块的安装和导入

    Python基础语法(五)-常用模块的使用和模块的安装和导入,本文介绍的Python模块有:os.sys.time.datetime.random.pickle.json.hashlib.shutil ...

最新文章

  1. 少标签数据学习,54页ppt
  2. ^和$ emeditor
  3. 使用dstat命令的插件查看mysql的io状态
  4. oracle 压缩 插入速度,求助大佬:向压缩表插入数据,压缩未生效
  5. ARP欺骗:先认识再防御
  6. spring学习(45):util名称空间注入
  7. html-简单验证、滑块、搜索框
  8. 精通Android自定义View(二十)自定义仿微信扫一扫效果
  9. 排序——分数线划定(洛谷 P1068)
  10. 1.12 梯度的数值逼近
  11. 田永强:优秀的JavaScript模块是怎样炼成的
  12. word2vec原理_初识word2vec词向量
  13. 关于synchronized
  14. 基于javaweb,springboot银行管理系统
  15. 重庆—java互联网架构软件工程师学习记录—Day11(API 1)
  16. php大道至简之框架
  17. 拓嘉启远电商:拼多多缺货会降权吗?如何处理
  18. ACAD和dll资源切换
  19. ubuntu 编译安装opencv官网教程
  20. 如何安装 Composer

热门文章

  1. ehd边缘直方图描述子 matlab,一种新的图像空间特征提取方法
  2. ubuntu 14.04配置lamp粗略
  3. Spring Boot的SpringApplication类详解
  4. linux自学笔记--DNS服务器
  5. Css3新特性应用之形状
  6. 从哪些角度进行手机软件测试
  7. 网站被k的症状原因有哪些-怎么恢复
  8. 华为机试HJ13:句子逆序
  9. Android程序暂停sh,init进程 解析Android启动脚本init.rc 修改它使不启动android init.rc中启动一个sh文件...
  10. 剑指offer面试题[41]-和为s的两个数VS和为s的连续正数序列