当前位置:   article > 正文

pyTorch——基础学习笔记_pytorch学习

pytorch学习
pytorch基础学习笔记博文,在整理的时候借鉴的大量的网上资料,存在和一部分图片定义的直接复制黏贴,在本博文的最后将会表明所有的参考链接。由于参考的内容众多,所以博文的更新是一个长久的过程,如果大佬发现没有在博文的最后声明应用的来源,请不用着急,因为目前的博文正在不断的更新过程中,请稍微的等待几天。并且这是我第一次写有关于pyTorch的博文,在以后会根据阅读书籍的增多做出更多模块的读书笔记记录。本博文2022年8月15日开始更新。

目录

 

一、pytorch环境的安装

二、pytorch的介绍

三、基本数据:Tensor

3.1Tensor的创建

 3.2 torch.FloatTensor

3.3 torch.IntTensor

四、Tensor的运算

4.1 torch.abs

4.2 torch.add

4.3 torch.div

4.4 torch.pow

4.5torch.clamp

4.6torch.mm

4.7torch.mul

4.8torch.mv

4.9将Tensor与Numpy进行转化

五、pyTorch自动求导(torch.autograd和Variable)

5.1计算图

5.2自动求导案例

5.2实现y=wx+b的自动求导的案例操作

5.3自动求导的数学原理

六、神经网络工具箱torch.nn

6.1nn.Module

6.2自定义构建传播函数

 6.3搭建简易的神经网络

七、pyTorch之torch.nn实现一个完整的神经网络

7.1 torch.nn.Sequential

7.2 torch.nn.Linear

7.3 torch.nn.ReLU

7.4torch.nn.MSELoss

7.5 torch.nn.L1Loss

7.6 torch.nn.CrossEntropyLoss

7.7使用损失函数的神经网络(案列)

 八、pyTorch之torch.optim(自动优化)

总结

参考文献


一、pytorch环境的安装

我查阅了很多的博文,最终觉得博文:pytorch的安装介绍的最全面,大家可以点击参看,并根据自己本地的实际情况进行安装。

二、pytorch的介绍

pytorch是一个基于Python的科学计算包,它主要有两个用途:

  • 类似于Numpy但是能利用GPU加速
  • 一个非常灵活和快速用于深度学习的研究平台。

目前学习深度学习一个好的框架十分的重要,现在主流的就是Pytorch和tf,今天让我们一起来学习pytorch。

三、基本数据:Tensor

Tensor在pttorch中负责存储基本数据,ptyTorch针对Tensor也提供了丰富的函数和方法,所以pyTorch中的Tensor与Numpy的数组具有极高的相似性。Tensor是一种高级的API。

Tensor,即张量,是PyTorch中的基本操作对象,可以看做是包含单一数据类型元素的多维矩阵。从使用角度来看,Tensor与NumPy的ndarrays非常类似,相互之间也可以自由转换,只不过Tensor还支持GPU的加速。

3.1Tensor的创建

 3.2 torch.FloatTensor

torch.FloatTensor用于生成数据类型为浮点型的Tensor,传递给torch.FloatTensor的参数可以是列表,也可以是一个维度值。

  1. import torch
  2. a=torch.FloatTensor(2,3)#生成一个2行3列的float类型的张量
  3. print(a)
  4. b=torch.FloatTensor([1,2,3,4,5,6])#使用列表的形式创建一个张量
  5. print(b)
  6. print(type(a),type(b))#显示a,b的类型

得到的结果是

  1. tensor([[4.6241e+30, 1.0552e+24, 5.0711e-14],
  2. [1.6109e-19, 1.8888e+31, 4.1051e-41]])
  3. tensor([1., 2., 3., 4., 5., 6.])
  4. <class 'torch.Tensor'> <class 'torch.Tensor'>

3.3 torch.IntTensor

torch.IntTensor用于生成数据类型为整型的Tensor,传递给传递给torch.IntTensor的参数可以是列表,也可以是一个维度值。

  1. import torch
  2. a=torch.IntTensor(2,3)#生成一个2行3列的float类型的张量
  3. print(a)
  4. b=torch.IntTensor([1,2,3,4,5,6])#使用列表的形式创建一个张量
  5. print(b)
  6. print(type(a),type(b))#显示a,b的类型

显示的结果如下

  1. tensor([[0, 0, 0],
  2. [0, 0, 0]], dtype=torch.int32)
  3. tensor([1, 2, 3, 4, 5, 6], dtype=torch.int32)
  4. <class 'torch.Tensor'> <class 'torch.Tensor'>

张量的属性

从张量属性我们可以得到张量的维数、数据类型以及它们所存储的设备(CPU或GPU)。

四、Tensor的运算

每一个张量tensor都有一个相应的torch.Storage用来保存其数据。类tensor提供了一个存储的多维的、横向视图,并且定义了在数值运算。

有超过100种张量相关的运算操作, 例如转置、索引、切片、数学运算、线性代数、随机采样等。

!注意:
会改变tensor的函数操作会用一个下划线后缀来标示。比如,torch.FloatTensor.abs_()会在原地计算绝对值,并返回改变后的tensor,而tensor.FloatTensor.abs()将会在一个新的tensor中计算结果。

4.1 torch.abs

将参数传递到torch.abs后返回输入参数的绝对值作为输出,输入参数必须是一个Tensor数据类型的变量,如:

  1. import torch
  2. a=torch.tensor([-1,-2,-3,-4,-5,-6])
  3. print(torch.abs(a))
  4. print(a)#并没有改变a的实际值
  5. print(torch.abs_(a))
  6. print(a)#改变了a的实际值

4.2 torch.add

将参数传递到torch.add后返回输入参数的求和结果作为输出,输入参数既可以全部是Tensor数据类型的变量,也可以一个是Tensor数据类型的变量,另一个是标量。

  1. import torch
  2. a=torch.rand(3,4)
  3. b=torch.rand(4)
  4. print(a+b)

4.3 torch.div

torch.div是将参数传递到torch.div后返回输入参数的求商结果作为输出,同样,参与运算的参数可以全部是Tensor数据类型的变量,也可以是Tensor数据类型的变量和标量的组合。具体我们看例子。

  1. import torch
  2. a=torch.tensor([-1,-2,-3,-4,-5,-6])
  3. b=torch.tensor([1,1,1,1,1,1])
  4. c=torch.div(a,b)
  5. print(c)
  6. tensor([-1., -2., -3., -4., -5., -6.])

4.4 torch.pow

torch.pow:将参数传递到torch.pow后返回输入参数的求幂结果作为输出,参与运算的参数可以全部是Tensor数据类型的变量,也可以是Tensor数据类型的变量和标量的组合。

  1. import torch
  2. a=torch.tensor([-1,-2,-3,-4,-5,-6])
  3. print(torch.pow(a,2))
  4. tensor([ 1, 4, 9, 16, 25, 36])

4.5torch.clamp

torch.clamp是对输入参数按照自定义的范围进行裁剪,最后将参数裁剪的结果作为输出,所以输入参数一共有三个,分别是需要进行裁剪的Tensor数据类型的变量、裁剪的上上边界和裁剪的下边界,具体的裁剪过程是:使用变量中的每个元素分别和裁剪的上边界及裁剪的下边界的值进行比较,如果元素的值小于裁剪的下边界的值,该元素被重写成裁剪的下边界的值;同理,如果元素的值大于裁剪的上边界的值,该元素就被重写成裁剪的上边界的值。我们直接看例子:

  1. import torch
  2. a=torch.rand(2,3)
  3. print(a)
  4. b=torch.clamp(a,-0.1,0.1)
  5. print(b)
  6. tensor([[0.0363, 0.5267, 0.7623],
  7. [0.9937, 0.5232, 0.2946]])
  8. tensor([[0.0363, 0.1000, 0.1000],
  9. [0.1000, 0.1000, 0.1000]])

4.6torch.mm

torch.mm:将参数传递到torch.mm后返回输入参数的求积结果作为输出,不过这个求积的方式和之前的torch.mul运算方式不太一样,torch.mm运用矩阵之间的乘法规则进行计算,所以被传入的参数会被当作矩阵进行处理,参数的维度自然也要满足矩阵乘法的前提条件,即前一个矩阵的行数必须和后一个矩阵列数相等

  1. import torch
  2. a=torch.rand(2,3)
  3. b=torch.rand(3,2)
  4. c=torch.mm(a,b)
  5. print(c)
  6. tensor([[1.7444, 0.8730],
  7. [0.9394, 0.4821]])

4.7torch.mul

张量对应位置数据的相乘,区别于直接的矩阵相乘运算。

  1. import torch
  2. a=torch.tensor([[1,2,3],[4,5,6]])
  3. b=torch.tensor([[1,1,1],[1,1,1]])
  4. print(torch.mul(a,b))
  5. tensor([[1, 2, 3],
  6. [4, 5, 6]])

4.8torch.mv

将参数传递到torch.mv后返回输入参数的求积结果作为输出,torch.mv运用矩阵与向量之间的乘法规则进行计算,被传入的第1个参数代表矩阵,第2个参数代表向量,循序不能颠倒。

  1. a = torch.randn(2,3)
  2. a
  3. #我们得到a为:
  4. #tensor([[ 1.0909, -1.1679, 0.3161],
  5. # [-0.8952, -2.1351, -0.9667]])
  6. b = torch.randn(3)
  7. b
  8. #我们得到b为:
  9. #tensor([-1.4689, 1.6197, 0.7209])
  10. c = torch.mv(a,b)
  11. c
  12. #tensor([-3.2663, -2.8402])

4.9将Tensor与Numpy进行转化

张量和Numpy array数组在CPU上可以共用一块内存区域, 改变其中一个另一个也会随之改变。

  1. import torch
  2. t = torch.ones(5)
  3. print(f"t: {t}")
  4. n = t.numpy()#张量转化成Numpy
  5. print(f"n: {n}")
  6. t=t.add_(1)
  7. print(t,n)
  8. a=torch.from_numpy(n)#将Numpy转化成Tensor
  9. print(a,type(a))
  10. 输出的结果如下所示:
  11. t: tensor([1., 1., 1., 1., 1.])
  12. n: [1. 1. 1. 1. 1.]
  13. tensor([2., 2., 2., 2., 2.]) [2. 2. 2. 2. 2.]
  14. tensor([2., 2., 2., 2., 2.]) <class 'torch.Tensor'>

五、pyTorch自动求导(torch.autograd和Variable)

autograd 是Pytorch框架中一个重要的包,它为张量上的所有操作提供自动求导功能。

实现自动梯度功能的大致过程大致为

1.通过输入的Tensor数据类型的变量在神经网络的前向传播过程中生成一张计算图

2.根据前向传播生成的计算图和输出的结果准确计算出每个参数需要更新的梯度。

3.最后通过后向传播完成对参数的梯度更新。

x.requires_grad_(bool):是否需要定义空间保存梯度信息
x.grad:该属性用来获取空间中保存的梯度信息
x.grad.zero_():清空之前存储的梯度信息
backward():进行反向传播
x.detach():detach后相当于把变量常数化,用于需要固定参数时是很有用的

5.1计算图

给定一个表达式z = wx + b,可将其分解两个表达式,分别是z = y + b和y = wx,则其正向传播计算图如下所示:

 在这个计算图中,可以看出变量w,x,b均为用户创建的,它们不依赖与其他的变量,我们称之为叶子节点,而y和z是计算得到的变量,即非叶子节点,其中z为根节点,MUL和ADD称为算子(操作或函数)。

我们的目标是更新各个叶子节点的梯度,即w,x和b,由链式法则可以推出,各叶子节点的梯度计算如下:

Pytorch中实现自动求导,需要了解一下几点:

    对于叶子节点的Tensor,使用requires_grad参数指定是否记录对其的操作,以便后续调用backward()方法求梯度。requires_grad默认为false,若要对其求导,则设置为True,这样与之有依赖关系的节点也会自动变为True
    通过requires_grad()方法来修改Tensor的requires_grad属性,也可以调用.detach()将某些张量排除在外,例如上述z = y + b和y = wx,若张量y调用了y.detach(),则计算梯度时将 y 视为一个常数,并且只考虑到 x 在y被计算后发挥的作用
    使用with torch.no_grad():包裹代码块的形式阻止autograd跟踪张量的历史记录
    对于非叶子节点,会自动被赋予grad_fn属性,用于存储记录相关的计算操作,叶子节点的grad_fn值为None
    Tensor执行backward函数计算各变量的梯度值,结果会累加至grad属性中,计算完成后,非叶子节点的梯度值自动释放
    对非标量求导时,backward()需接收gradient参数,该参数应与调用backward的Tensor维度相同,实际上对于标量调用backward函数,该参数是隐含的,例如标量out自动求导,out.backward() 等同于out.backward(torch.tensor(1))
    若需要多次反向传播,需要指定backward中的参数retain_graph=True,在多次反向传播时,梯度是累加的

需要特别注意的是,在默认情况下,PyTorch会累积梯度,我们需要清除之前的值,可以调用grad.zero_()方法清除记录。

5.2自动求导案例

对于上述理论,给出几个示例
x为一个向量,计算y = y=2x⊤ x的导数

  1. x = torch.arange(4.0, requires_grad=True)
  2. print(x)
  3. y = 2*torch.dot(x,x)
  4. print(y)
  5. y.backward()
  6. x.grad
  7. # outputs
  8. # x的requires_grad为True
  9. tensor([0., 1., 2., 3.], requires_grad=True)
  10. # y为非叶子节点,会自动赋予grad_fn属性
  11. tensor(28., grad_fn=<MulBackward0>)
  12. # 最终结果,y = 4x,符合推导
  13. tensor([ 0., 4., 8., 12.])

 此时如果继续对向量x的另一个函数计算,则需要先清除之前计算的梯度值,否则Pytorch会累加计算

  1. print(x.grad)
  2. x.grad.zero_()
  3. print(x.grad)
  4. y = x.sum()
  5. print(y)
  6. y.backward()
  7. x.grad
  8. # outputs
  9. # 上次计算的梯度
  10. tensor([ 0., 4., 8., 12.])
  11. # 梯度清零后的x.grad
  12. tensor([0., 0., 0., 0.])
  13. # 新函数y = x.sum()
  14. tensor(6., grad_fn=<SumBackward0>)
  15. # 计算y关于x的梯度
  16. tensor([1., 1., 1., 1.])

在计算过程中,若希望将某些计算移动到记录的计算图之外,可以使用detach函数。假设y是作为x的函数计算的,而z则是作为y和x的函数计算的。 现在我们需要计算 z 关于 x 的梯度,但由于某种原因,希望将 y 视为一个常数,我们可以分离 y 来返回一个新变量 u,该变量与 y 具有相同的值,但丢弃计算图中如何计算 y 的任何信息。
 

  1. x.grad.zero_()
  2. y = x * x
  3. u = y.detach()
  4. z = u * x
  5. z.sum().backward()
  6. # z = u*x,关于x求导,理论结果为u
  7. x.grad == u
  8. # output
  9. tensor([True, True, True, True])

 backward()的前提是x必须是标量,而不是向量,

如果x是向量,那么,backward函数里就要加参数

5.2实现y=wx+b的自动求导的案例操作

下面我们根据y=wx+b这一个非常简单的线性回归做一个自动性质的求导操作。

  1. #构建一个简单版本的y=wx+b线性函数,然后进行
  2. import torch
  3. x = torch.tensor(3.,requires_grad=True) # 数字
  4. w = torch.tensor(4., requires_grad=True) # 数字
  5. b = torch.tensor(5., requires_grad=True) # 数字
  6. y=torch.mul(w,x).add(b)#17
  7. y.backward()
  8. print(x.grad)

最后输出的结果是 tensor(4.)。对于这个结果我们同样可以通过人为的计算进行得出。

现在我们将数据稍微的复杂一点,简单来说就是x,w,b这些数据不在是简单的一个数值而是多个数值的向量

  1. import torch
  2. x=torch.tensor([1.,2.],requires_grad=True)
  3. w=torch.tensor([[1.],[2.]],requires_grad=True)
  4. b=torch.tensor([[1.,2.],[3.,4.]],requires_grad=True)
  5. y=torch.mul(w,x).add(b)#这个时候的y是一个2X2的值
  6. #这个位置有个问题,因为此时的y是向量,不是标量,在这种情况下是不可以直接进行backward()的
  7. #所以我们需要对backward()添加参数,所添加的参数就是此时y的tensor(r,w)
  8. #y.backward(torch.tensor([[1,1],[1,1]]))
  9. #或者采用y.sum().backward()形式将y从向量变成标量在进行计算梯度
  10. y.sum().backward()
  11. print(x.grad)

 然后继续的进行复杂化的计算

  1. #coding = utf-8
  2. import torch
  3. input_data=100
  4. batch_n=10
  5. hidden_layer=10
  6. output_data=10
  7. w=torch.rand(batch_n,input_data,requires_grad=True)#w:10-100
  8. x=torch.rand(input_data,hidden_layer,requires_grad=True)#x100-10
  9. b=torch.rand(hidden_layer,output_data,requires_grad=True)#b:10-10
  10. z=torch.mm(w,x).add(b)
  11. y=torch.rand(output_data,output_data,requires_grad=True)
  12. print(w.is_leaf,x.is_leaf,b.is_leaf)#判断w,x,b是不是叶子节点
  13. print(w.grad_fn)
  14. print(z.grad_fn)
  15. '''
  16. grad_fn:表示梯度函数
  17. 对于叶子节点,梯度值为空,非叶子节点可以返回梯度值
  18. '''
  19. z.sum().backward()
  20. print("x的梯度是:",x.grad)
  21. print("w的梯度是:",w.grad)

5.3自动求导的数学原理

在上面5.2中,我们可以通过代码直接的算出导数,但是我们却并不知道具体是怎么样的计算过程,本部分比较复杂,只需要确定这个计算是合理的没问题的即可,不需要自己手动能够计算出来。下面大致的计算下自动求导的原理。

对神经网络有一定了解的同学知道:一般的神经网络的具体实现都是通过矩阵实现的,包括误差反向传导,梯度计算和更新等等,比如,这里的所有变量都是矩阵,我们通常会叫和为参数矩阵,矩阵相乘首先效率比较高,然后也比较好操作,那么对于矩阵形式的导数该怎么计算?比如矩阵的具体导数应该如何计算?

首先我们来看一个只有输入和输出层的网络,我们输入矩阵大小为 , 为batch的大小,也就是一次性输入的样本数,为输入数据的维度,也就是输入层神经元的个数,出矩阵大小为,为输出数据的维度,也就是输出层神经元的个数, 可以看成输入数据X经过这个网络的变换,数据维度由映射到了维,那么矩阵的大小自然就是


上图中表示第j个样本输入数据的第一个值,我们现在就考虑这个值的梯度要如何求,表示第j个样本回传梯度的第一个值(通过链式法则,梯度是一层一层向后传递,你可以理解这个就是从下一层的网络传回的梯度),现在我们已知和传回的,那么这个理论上分析肯定等于(因为对的导数就是,而回传的梯度其实是损失函数对的导数, 即 ,对于来说,它的梯度为跟它连接的参数与第j个样本所有乘积的求和

那么我们把在公式中关于计算梯度需要的w参数和在正向传播的矩阵计算中标示出来如下,根据计算公式,我们发现的值正好等于矩阵与转置矩阵相乘后的第一行第一列的值,这不是偶然,其实矩阵与转置矩阵的相乘正好就是梯度矩阵
6

 

 公式类似的计算公式我们也可以推出,因为参数每次只与这个样本的第一个输入数据发生相乘关系,因此如果有个样本,那么就等于相应样本的与此样本第一个输入数据的乘积然后求和

 

 

下面采用矩阵乘法作为例子,回顾一下上述过程。这时候 X 矩阵是一个 2×2 的矩阵,Y 是一个 2×2 的矩阵,Z是一个 2×2 的矩阵,f 函数表示 X 矩阵和 Y 矩阵乘法。通过上述过程我们可以得到以下结果:

 以上起码可以验证自动求导机制是完全没有问题的,即使是我们手动的进行运算也是完全可以的。

六、神经网络工具箱torch.nn

torch.autograd库虽然实现了自动求导与梯度反向传播,但如果我们要完成一个模型的训练,仍需要手写参数的自动更新、训练过程的控制等,还是不够便利。为此,PyTorch进一步提供了集成度更高的模块化接口torch.nn,该接口构建于Autograd之上,提供了网络模组、优化器和初始化策略等一系列功能。除了nn之外,我们还会介绍神经网络中常用的工具,比如优化器option、初始化init等

6.1nn.Module

    使用aut o g i a d 可 实 现 深 度 学 习 模 型 , 但 其 抽 象 程 度 较 低 , 如 果 用其 来 实 现 深 度 学 习 模 型 , 则 需 要 编 写 的 代 码 量 极 大 。 在 这 种 情 况 下 , t o r c h . n n 应 运 而 生 ,其 是 专 门 为 深 度 学 习 设 计 的 模 块 。 t o r c h . n n 的 核 心 数 据 结 构 是 M o d u l e , 它 是 一 个 抽 象 的概 念 , 既 可 以 表 示 神 经 网 络 中 的 某 个 层 ( l a y e r ) , 也 可 以 表 示 一 个 包 含 很 多 层 的 神 经 网络 。 在 实 际 使 用 中 , 最 常 见 的 做 法 是 继 承 皿 . Module , 撰 写 自 己 的 网 络 / 层 。

   nn.Module是PyTorch提供的神经网络类,并在类中实现了网络各层的定义及前向计算与反向传播机制。在实际使用时,如果想要实现某个神经网络,只需继承nn.Module,在初始化中定义模型结构与参数,在函数forward()中编写网络前向过程即可。

1.nn.Parameter函数

2.forward()函数与反向传播

3.多个Module的嵌套

4.nn.Module与nn.functional库

5.nn.Sequential()模块

6.2自定义构建传播函数

其实除了可以采用自动梯度方法,我们还可以通过构建一个继承了torch.nn.Module的新类,来完成对前向传播函数和后向传播函数的重写。在这个新类中,我们使用forward作为前向传播函数的关键字,使用backward作为后向传播函数的关键字。下面我们进行自定义传播函数:

  1. import torch
  2. from torch.autograd import Variable
  3. batch_n = 64#一个批次输入数据的数量
  4. hidden_layer = 100
  5. input_data = 1000#每个数据的特征为1000
  6. output_data = 10
  7. class Model(torch.nn.Module):#完成类继承的操作
  8. def __init__(self):
  9. super(Model,self).__init__()#类的初始化
  10. def forward(self,input,w1,w2):
  11. x = torch.mm(input,w1)
  12. x = torch.clamp(x,min = 0)
  13. x = torch.mm(x,w2)
  14. return x
  15. def backward(self):
  16. pass
  17. model = Model()
  18. x = Variable(torch.randn(batch_n,input_data),requires_grad=False)
  19. y = Variable(torch.randn(batch_n,output_data),requires_grad=False)
  20. #用Variable对Tensor数据类型变量进行封装的操作。requires_grad如果是F,表示该变量在进行自动梯度计算的过程中不会保留梯度值。
  21. w1 = Variable(torch.randn(input_data,hidden_layer),requires_grad=True)
  22. w2 = Variable(torch.randn(hidden_layer,output_data),requires_grad=True)
  23. epoch_n=30
  24. for epoch in range(epoch_n):
  25. y_pred = model(x,w1,w2)
  26. loss = (y_pred-y).pow(2).sum()
  27. print("epoch:{},loss:{:.4f}".format(epoch,loss.data))
  28. loss.backward()
  29. w1.data -= lr*w1.grad.data
  30. w2.data -= lr*w2.grad.data
  31. w1.grad.data.zero_()
  32. w2.grad.data.zero_()

 构建一个y=wx+b的自定义传播函数,如下所示

  1. #coding = utf-8
  2. import torch
  3. class Model(torch.nn.Module):#自定义构建一个传播函数
  4. def __init__(self):
  5. super(Model,self).__init__()
  6. def forward(self,w,x,b):
  7. #y=wx+b返回结果值
  8. return torch.mm(w,x).add(b)
  9. def backward(self):
  10. pass
  11. input_data=100
  12. batch_n=10
  13. hidden_layer=10
  14. output_data=10
  15. w=torch.rand(batch_n,input_data,requires_grad=True)#w:10-100
  16. x=torch.rand(input_data,hidden_layer,requires_grad=True)#x100-10
  17. b=torch.rand(hidden_layer,output_data,requires_grad=True)#b:10-10
  18. y=torch.rand(hidden_layer,output_data,requires_grad=True)
  19. model=Model()
  20. epoch_n=3
  21. learn_rate=1e-6
  22. for epoch in range(epoch_n):
  23. y_pred=model.forward(w,x,b)
  24. loss=(y_pred-y).pow(2).sum()
  25. print("Epoch:{},Loss:{}".format(epoch,loss))
  26. loss.backward()
  27. w.data=w.data-learn_rate*w.grad.data
  28. w.grad.zero_()

 6.3搭建简易的神经网络

下面我们用torch搭一个简易神经网络:
1、我们设置输入节点为1000,隐藏层的节点为100,输出层的节点为10
2、输入100个具有1000个特征的数据,经过隐藏层后变成100个具有10个分类结果的特征,然后将得到的结果后向传播

  1. import torch
  2. batch_n = 100#一个批次输入数据的数量
  3. hidden_layer = 100
  4. input_data = 1000#每个数据的特征为1000
  5. output_data = 10
  6. x = torch.randn(batch_n,input_data)
  7. y = torch.randn(batch_n,output_data)
  8. w1 = torch.randn(input_data,hidden_layer)
  9. w2 = torch.randn(hidden_layer,output_data)
  10. epoch_n = 20
  11. lr = 1e-6
  12. for epoch in range(epoch_n):
  13. h1=x.mm(w1)#(100,1000)*(1000,100)-->100*100
  14. print(h1.shape)
  15. h1=h1.clamp(min=0)
  16. y_pred = h1.mm(w2)
  17. loss = (y_pred-y).pow(2).sum()
  18. print("epoch:{},loss:{:.4f}".format(epoch,loss))
  19. grad_y_pred = 2*(y_pred-y)
  20. grad_w2 = h1.t().mm(grad_y_pred)
  21. grad_h = grad_y_pred.clone()
  22. grad_h = grad_h.mm(w2.t())
  23. grad_h.clamp_(min=0)#将小于0的值全部赋值为0,相当于sigmoid
  24. grad_w1 = x.t().mm(grad_h)
  25. w1 = w1 -lr*grad_w1
  26. w2 = w2 -lr*grad_w2
  1. torch.Size([100, 100])
  2. epoch:0,loss:112145.7578
  3. torch.Size([100, 100])
  4. epoch:1,loss:110014.8203
  5. torch.Size([100, 100])
  6. epoch:2,loss:107948.0156
  7. torch.Size([100, 100])
  8. epoch:3,loss:105938.6719
  9. torch.Size([100, 100])
  10. epoch:4,loss:103985.1406
  11. torch.Size([100, 100])
  12. epoch:5,loss:102084.9609
  13. torch.Size([100, 100])
  14. epoch:6,loss:100236.9844
  15. torch.Size([100, 100])
  16. epoch:7,loss:98443.3359
  17. torch.Size([100, 100])
  18. epoch:8,loss:96699.5938
  19. torch.Size([100, 100])
  20. epoch:9,loss:95002.5234
  21. torch.Size([100, 100])
  22. epoch:10,loss:93349.7969
  23. torch.Size([100, 100])
  24. epoch:11,loss:91739.8438
  25. torch.Size([100, 100])
  26. epoch:12,loss:90171.6875
  27. torch.Size([100, 100])
  28. epoch:13,loss:88643.1094
  29. torch.Size([100, 100])
  30. epoch:14,loss:87152.6406
  31. torch.Size([100, 100])
  32. epoch:15,loss:85699.4297
  33. torch.Size([100, 100])
  34. epoch:16,loss:84282.2500
  35. torch.Size([100, 100])
  36. epoch:17,loss:82899.9062
  37. torch.Size([100, 100])
  38. epoch:18,loss:81550.3984
  39. torch.Size([100, 100])
  40. epoch:19,loss:80231.1484
  41. [点击并拖拽以移动]

七、pyTorch之torch.nn实现一个完整的神经网络

torch.nn模块中包含着torch已经准备好的层,方便使用者调用构建网络。

7.1 torch.nn.Sequential

torch.nn.Sequential类是torch.nn中的一种序列容器,通过在容器中嵌套各种实现神经网络模型的搭建,最主要的是,参数会按照我们定义好的序列自动传递下去。

  1. #coding = utf-8
  2. import torch
  3. from torch.autograd import Variable
  4. from collections import OrderedDict
  5. batch_n = 100
  6. hidden_layer = 100
  7. input_data = 1000
  8. output_data = 10
  9. x=torch.randn(batch_n,input_data,requires_grad=False)
  10. y=torch.randn(batch_n,output_data,requires_grad=False)
  11. #orch.nn.Sequential类是torch.nn中的一种序列容器,通过在容器中嵌套各种实现神经网络模型的搭建,
  12. # 最主要的是,参数会按照我们定义好的序列自动传递下去。
  13. models=torch.nn.Sequential(
  14. torch.nn.Linear(input_data,hidden_layer),
  15. torch.nn.ReLU(),
  16. torch.nn.Linear(hidden_layer,output_data)
  17. )
  18. #torch.nn.Sequential括号内就是我们搭建的神经网络模型的具体结构,Linear完成从隐藏层到输出层的线性变换,再用ReLU激活函数激活
  19. #torch.nn.Sequential类是torch.nn中的一种序列容器,通过在容器中嵌套各种实现神经网络模型的搭建,
  20. #最主要的是,参数会按照我们定义好的序列自动传递下去。
  21. print(models)

 输出的结果

  1. Sequential(
  2. (0): Linear(in_features=1000, out_features=100, bias=True)
  3. (1): ReLU()
  4. (2): Linear(in_features=100, out_features=10, bias=True)
  5. )

7.2 torch.nn.Linear

torch.nn.Linear类用于定义模型的线性层,即完成前面提到的不同的层之间的线性变换。 线性层接受的参数有3个:分别是输入特征数、输出特征数、是否使用偏置,默认为True,使用torch.nn.Linear类,会自动生成对应维度的权重参数和偏置,对于生成的权重参数和偏置,我们的模型默认使用一种比之前的简单随机方式更好的参数初始化方式。

7.3 torch.nn.ReLU

torch.nn.ReLU属于非线性激活分类,在定义时默认不需要传入参数。当然,在torch.nn包中还有许多非线性激活函数类可供选择,比如PReLU、LeaKyReLU、Tanh、Sigmoid、Softmax等。

7.4torch.nn.MSELoss

torch.nn.MSELoss类使用均方误差函数对损失值进行计算,定义类的对象时不用传入任何参数,但在使用实例时需要输入两个维度一样的参数方可进行计算。

  1. import torch
  2. from torch.autograd import Variable
  3. loss_f = torch.nn.MSELoss()
  4. x = Variable(torch.randn(100,100))
  5. y = Variable(torch.randn(100,100))
  6. loss = loss_f(x,y)
  7. loss.data
  8. #tensor(1.9529)

7.5 torch.nn.L1Loss

torch.nn.L1Loss类使用平均绝对误差函数对损失值进行计算,定义类的对象时不用传入任何参数,但在使用实例时需要输入两个维度一样的参数方可进行计算。

  1. import torch
  2. from torch.autograd import Variable
  3. loss_f = torch.nn.L1Loss()
  4. x = Variable(torch.randn(100,100))
  5. y = Variable(torch.randn(100,100))
  6. loss = loss_f(x,y)
  7. loss.data
  8. #tensor(1.1356)

7.6 torch.nn.CrossEntropyLoss

torch.nn.CrossEntropyLoss类用于计算交叉熵,定义类的对象时不用传入任何参数,但在使用实例时需要输入两个满足交叉熵的计算条件的参数。

  1. import torch
  2. from torch.autograd import Variable
  3. loss_f = torch.nn.CrossEntropyLoss()
  4. x = Variable(torch.randn(3,5))
  5. y = Variable(torch.LongTensor(3).random_(5))#3个0-4的随机数字
  6. loss = loss_f(x,y)
  7. loss.data
  8. #tensor(2.3413)

7.7使用损失函数的神经网络(案列)

  1. #coding = utf-8
  2. import torch
  3. from torch.autograd import Variable
  4. from collections import OrderedDict
  5. batch_n = 100
  6. hidden_layer = 100
  7. input_data = 1000
  8. output_data = 10
  9. x=torch.randn(batch_n,input_data,requires_grad=False)
  10. y=torch.randn(batch_n,output_data,requires_grad=False)
  11. #orch.nn.Sequential类是torch.nn中的一种序列容器,通过在容器中嵌套各种实现神经网络模型的搭建,
  12. # 最主要的是,参数会按照我们定义好的序列自动传递下去。
  13. models=torch.nn.Sequential(
  14. torch.nn.Linear(input_data,hidden_layer),
  15. torch.nn.ReLU(),
  16. torch.nn.Linear(hidden_layer,output_data)
  17. )
  18. #torch.nn.Sequential括号内就是我们搭建的神经网络模型的具体结构,Linear完成从隐藏层到输出层的线性变换,再用ReLU激活函数激活
  19. #torch.nn.Sequential类是torch.nn中的一种序列容器,通过在容器中嵌套各种实现神经网络模型的搭建,
  20. #最主要的是,参数会按照我们定义好的序列自动传递下去。
  21. #print(models)
  22. #自己建立一个神经网络模型
  23. loss_f=torch.nn.CrossEntropyLoss()#用于计算交叉熵
  24. epoch_n=100#循环训练次数
  25. learn_rate=1e-6
  26. for epoch in range(epoch_n):
  27. y_pred=models(x)
  28. loss=loss_f(y_pred,y)
  29. print("Epoch:{},LOss:{}".format(epoch,loss))
  30. models.zero_grad()
  31. loss.backward()
  32. for param in models.parameters():
  33. param.data=param.data-param.grad.data*learn_rate
  34. #因为使用了模型搭建的方法,所以访问模型中的全部数据是通过对models.parameters()
  35. #进行全部遍历完成的

 八、pyTorch之torch.optim(自动优化)

torch.optim包提供非常多的可实现参数自动优化的类,如SGD、AdaGrad、RMSProp、Adam等使用自动优化的类实现神经网络:

pyTorch 将深度学习 常用的优 方法全部封装在 torch optim 中, 设计十分活,能 够很 方便地扩 自定 义的优化 方法。
所有的 优化 方法都是继承基-类 optim Optimizer 并实现了自己 的优化 步骤。
  1. import torch
  2. from torch.autograd import Variable
  3. batch_n=100
  4. hidden_layer=100
  5. input_data=1000
  6. output_data=10
  7. x=Variable(torch.randn(batch_n,input_data),requires_grad=False)
  8. y=Variable(torch.randn(batch_n,output_data),requires_grad=True)
  9. models=torch.nn.Sequential(
  10. torch.nn.Linear(input_data,hidden_layer),
  11. torch.nn.ReLU(),
  12. torch.nn.Linear(hidden_layer,output_data)
  13. )
  14. loss_f=torch.nn.MSELoss()
  15. epoch_n =100
  16. learning_rate=1e-4
  17. #使用优化函数
  18. optimzer=torch.optim.Adam(models.parameters(),lr=learning_rate)
  19. for epoch in range(epoch_n):
  20. y_pred=models(x)
  21. loss = loss_f(y_pred,y)
  22. print("Epoch:{},Loss:{}".format(epoch,loss))
  23. optimzer.zero_grad()
  24. loss.backward()
  25. optimzer.step()
  26. '''
  27. for param in models.parameters():
  28. param.data-=param.grad.data*learning_rate
  29. '''
  30. '''
  31. optimzer.zero_grad()来完成对模型参数梯度的归零;并且在以上代码中增加了optimzer.step(),
  32. 它的主要功能是使用计算得到的梯度值对各个节点的参数进行梯度更新。
  33. '''

总结

本篇博文只是稍微的简洁的介绍一下pyTorch的基础知识,甚至是基础都算不上,可以说是对pyTorch的扫盲博文吧,在后续的过程中,我将继续对博文中的一些部分进行详细的整理。最近在读各种有关于深度学习、pyTorch的相关书籍,后续也将会对读书笔记做出相应的记录。最后对本次博文中借鉴的所有大佬表示感谢。

参考文献

PyTorch自动求导_没有胡子的猫的博客-CSDN博客_pytorch 自动求导

Pytorch自动求导_yizhi_hao的博客-CSDN博客_pytorch 自动求导

狂肝两万字带你用pytorch搞深度学习!!!_CC-Mac的博客-CSDN博客

详解神经网络中矩阵实现的梯度计算_ppp8300885的博客-CSDN博客_矩阵求梯度

https://www.jianshu.com/p/d0110f242b64

深度学习入门-基于python的理论与实现

深度学习之pyTorch实战计算机视觉  唐进民编著

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/671092
推荐阅读
相关标签
  

闽ICP备14008679号