PyTorch教程 层和块
Posted LolitaAnn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PyTorch教程 层和块相关的知识,希望对你有一定的参考价值。
写在最前边
虽然这个文章叫PyTorch教程,但是零基础应该是看不懂的(即使我每一行代码都写详细解释)。我感觉还是在零基础的时候先看《动手学深度学习》的前几章,先不管懂不懂,先知道怎么写,再回来看这个教程。就是按照书的顺序看。
就比如我们刚学C++的时候。
#include<iostream>
using namespace std;
int main()
{
cout<<"hello world";
return 0;
}
我们只需要知道#include<>
是头文件,不需要知道他现在具体要求干什么。不需要知道什么是using namespace
,也不需要知道什么是函数什么是返回值。我们只需要知道cout
是输出,后面引号里加一个字符串类型就可以输出,endl
是换行,这就足够了。
这只是我的一点见解而已。因为作为一个自学入门的人。我说一下我学pytorch的路径(当然因为我是小垃圾,那种大佬直接忽略我的说法就好了。)
-
去看龙良曲的pytorch教程,号称史上最好的pytorch教程。但是那时候我只看了吴恩达,龙良曲提到的一些东西对于我这种真·零基础还是有困难的,所以第一集我就放弃了。
-
又去看了刘二大人,讲的也挺好一共13集,我看了五集,看不下去了。因为他讲怎么继承
nn.Module
来写自己的神经网络,听得我云里雾里的。 - 后来师哥推荐去看pytorch的官网教程。毕竟官方肯定是最新最权威的。我就去看了。看到
nn
的时候我又看不动了。
至此,只有机器学习基础的我看pytorch的教程全部失败。
这个时候我是不了解pytorch吗? 不是,简单的我也能写。
那我是了解pytorch吗?不是,我自己也写不出来什么东西。
然后我就闲着没事开始看《动手学深度学习》循序渐进,突然发现就get到了该怎么用了。
所以不要急着上来就看什么教程啊之类的。好了就说这些。(废话有点多)
正文
对于多层感知机而言,整个模型做的事情就是接收输入生成输出。但是并不是所有的多层神经网络都一样,所以为了实现复杂的神经网络就需要神经网络块,块可以描述单个层、由多个层组成的组件或整个模型本身。使用块进行抽象的一个好处是可以将一些块组合成更大的组件。
从编程的角度来看,块由类(class)表示。它的任何子类都必须定义一个将其输入转换为输出的正向传播函数,并且必须存储任何必需的参数。注意,有些块不需要任何参数。最后,为了计算梯度,块必须具有反向传播函数。幸运的是,在定义我们自己的块时,由于autograd
中引入)提供了一些后端实现,我们只需要考虑正向传播函数和必需的参数。
这一部分我们就要自定义自己的层和块。
先用实现一个简单的多层感知机:
import torch
from torch import nn
from torch.nn import functional as F
net = nn.Sequential(nn.Linear(20, 256), nn.ReLU(), nn.Linear(256, 10))
X = torch.rand(2, 20)
net(X)
原文可以看这里:动手学深度学习4.3 多层感知机的简洁实现
这个多层感知机包含一个具有256个单元和ReLU激活函数的全连接的隐藏层,然后是一个具有10个隐藏单元且不带激活函数的全连接的输出层。
通过实例化nn.Sequential
来构建我们的模型,层的执行顺序就是传入参数的顺序。
-
nn.Sequential
定义了一种特殊的Module
,即在PyTorch中表示一个块的类。它维护了一个由Module
组成的有序列表(Linear
类是Module
的子类)。 -
正向传播(
forward
)函数:将列表中的每个块连接在一起,将每个块的输出作为下一个块的输入。 - 通过
net(X)
调用我们的模型来获得模型的输出。是net.__call__(X)
的简写。(这一句先不管他有什么,继续往下看。)
我们也可以自己手写一个多层感知机:
class MLP(nn.Module):
def __init__(self):
# 调用`MLP`的父类的构造函数来执行必要的初始化。
# 这样,在类实例化时也可以指定其他函数参数,例如模型参数`params`(稍后将介绍)
super().__init__()
self.hidden = nn.Linear(20, 256) # 隐藏层
self.out = nn.Linear(256, 10) # 输出层
# 定义模型的正向传播,即如何根据输入`X`返回所需的模型输出
def forward(self, X):
# 注意,这里我们使用ReLU的函数版本,其在nn.functional模块中定义。
return self.out(F.relu(self.hidden(X)))
net = MLP()
net(X)
-
通过
super().__init__()
调用父类的__init__
函数,省去了重复编写适用于大多数块的模版代码的痛苦。 -
实例化两个全连接层,分别为
self.hidden
和self.out
。-
除非我们实现一个新的运算符,否则我们不用担心反向传播函数或参数初始化,系统将自动生成这些。
- 前边说调用
net()
就相当于调用net.__call__(X)
,因为我们在自己的MLP中写了forward,但是我们没有调用,只使用net()
他就自动执行forward了。就是因为会自动调用.__call__
函数使forward执行。
-
说完后两条说第一条:
有序是怎么实现的,构建构一个简化的MySequential
:
class MySequential(nn.Module):
def __init__(self, *args):
super().__init__()
for block in args:
# 这里,`block`是`Module`子类的一个实例。我们把它保存在Module类的成员变量
# `_modules` 中。`block`的类型是OrderedDict。
self._modules[block] = block
def forward(self, X):
# OrderedDict保证了按照成员添加的顺序遍历它们
for block in self._modules.values():
X = block(X)
return X
MySequential
类提供了与默认Sequential
类相同的功能。
net = MySequential(nn.Linear(20, 256), nn.ReLU(), nn.Linear(256, 10))
net(X)
用MySequential
类实现的多层感知机和Sequential
类实现的一样。
注意这里只是写出了其执行顺序,是简化版的Sequential
类!
笔记Github地址:DeepLearningNotes/d2l(github.com)
以上是关于PyTorch教程 层和块的主要内容,如果未能解决你的问题,请参考以下文章
<code> vs <pre> vs <samp> 用于内联和块代码片段