Pytorch入门

Pytorch学习-1

  • 基础
    • tensor基本语法(与NumPy相似)
    • Tensor的运算
    • 一个简易神经网络
      • 导入包
      • 初始化权重
      • 定义训练次数和学习效率
      • 梯度下降优化神经网络的参数
    • 自动梯度
      • torch.autograd和Variable
      • 导入包
      • 初始化权重
      • 定义训练次数和学习效率
      • 新的模型训练和参数优化
      • 自定义传播函数
    • 转载自

基础

tensor基本语法(与NumPy相似)

  1. torch.FloatTensor,传递给torch.FloatTensor的参数可以是一个列表,也可以是一个维度值。
a = torch.FloatTensor(2,3)
b = torch.FloatTensor([2,3,4,5])
  1. torch.IntTensor,语法和1. 一样。
  2. torch.rand,随机生成的浮点数据在0~1区间均匀分布,括号里写size。
  3. torch.randn,随机生成的浮点数的取值满足均值为0,方差为1的正太分布。括号里写size
  4. torch.range,传递给torch.range的参数有三个,分别是范围的起始值,范围的结束值和步长,其中,步长用于指定从起始值到结束值的每步的数据间隔。
  5. torch.zeros,括号里写size

Tensor的运算

  1. torch.abs。输出参数必须是一个Tensor数据类型的变量。
  2. torch.add。可以两个tensor相加,也可以和一个标量或者向量相加
  3. torch.clamp。对输入参数按照自定义的范围进行裁剪,最后将参数裁剪的结果作为输出。所以输入参数一共有三个,分别是需要进行裁剪的Tensor数据类型的变量、裁剪的上边界和裁剪的下边界,具体的裁剪过程是:使用变量中的每个元素分别和裁剪的上边界及裁剪的下边界的值进行比较,如果元素的值小于裁剪的下边界的值,该元素就被重写成裁剪的下边界的值;同理,如果元素的值大于裁剪的上边界的值,该元素就被重写成裁剪的上边界的值。
mport torch
 
a = torch.randn(2,3)
print(a)
 
b = torch.clamp(a,-0.1,0.1)
print(b)
 
tensor([[ 0.0251,  1.8832,  1.5243],
        [-0.1365,  1.2307,  0.0640]])
 
tensor([[ 0.0251,  0.1000,  0.1000],
        [-0.1000,  0.1000,  0.0640]])
 
Process finished with exit code 0
  1. torch.div。将参数传递到torch.div后返回输入参数的求商结果作为输出,参与运算的参数与add相同。
  2. torch.mul。按位乘
  3. torch.pow。
  4. torch.mm。 前一个矩阵的行数必须和后一个矩阵的列数相等。点乘。
  5. torch.mv。将参数传递到torch.mv后返回输入参数的求积结果作为输出,torch.mv运用矩阵与向量之间的乘法规则进行计算,被传入的参数中的第1个参数代表矩阵,第2个参数代表向量,顺序不能颠倒。

一个简易神经网络

导入包

batch_n = 100
hidden_layer = 100
input_data = 1000
output_data = 10

我们先通过import torch 导入必要的包,然后定义4个整型变量,其中:batch_n是在一个批次中输入数据的数量,值是100,这意味着我们在一个批次中输入100个数据,同时,每个数据包含的数据特征有input_data个,因为input_data的值是1000,所以每个数据的特征就是1000个,hidden_layer用于定义经过隐藏层后保留的数据特征的个数,这里有100个,因为我们的模型只考虑一层隐藏层,所以在代码中仅仅定义了一个隐藏层的参数;output_data是输出的数据,值是10,我们可以将输出的数据看作一个分类结果值得数量,个数10表示我们最后要得到10个分类结果值。
先输入100个具有1000个特征的数据,经过隐藏层后变成100个具有100个特征的数据,再经过输出层后输出100个具有10个分类结果值的数据,在得到输出结果之后计算损失并进行后向传播,这样一次模型的训练就完成了,然后训练这个流程就可以完成指定次数的训练,并达到优化模型参数的目的。

初始化权重

x = torch.randn(batch_n,input_data)
y = torch.randn(batch_n,output_data)
 
w1 = torch.randn(input_data,hidden_layer)
w2 = torch.randn(hidden_layer,output_data)

在以上的代码中定义的从输入层到隐藏层,从隐藏层到输出层对应的权重参数,同在之前说到的过程中使用的参数维度是一致的,由于我们现在并没有好的权重参数的初始化方法,尽管这并不是一个好主意,可以看到,在代码中定义的输入层维度为(100,1000),输出层维度为(100,10),同时,从输入层到隐藏层的权重参数维度为(1000,100),从隐藏层到输出层的权重参数维度为(100,10)。在代码中我们的真实值y也是通过随机的方式生成的,所以一开始在使用损失函数计算损失值时得到的结果会较大。

定义训练次数和学习效率

epoch_n = 20  #训练次数
learning_rate = 1e-6

梯度下降优化神经网络的参数

for epoch in range(epoch_n):
    h1 = x.mm(w1)  # 100*1000
    h1 = h1.clamp(min=0) #ReLU
    y_pred = h1.mm(w2)  # 100*10
    # print(y_pred)
 
    loss = (y_pred - y).pow(2).sum()
    print("Epoch:{} , Loss:{:.4f}".format(epoch, loss))
 
    gray_y_pred = 2 * (y_pred - y) #求导
    gray_w2 = h1.t().mm(gray_y_pred)
 
    grad_h = gray_y_pred.clone()
    grad_h = grad_h.mm(w2.t())
    grad_h.clamp_(min=0)  #ReLU求导
    grad_w1 = x.t().mm(grad_h)
 
    w1 -= learning_rate * grad_w1
    w2 -= learning_rate * gray_w2

自动梯度

在PyTorch中提供了一种非常方便的方法,可以帮助我们实现对模型中后向传播梯度的自动计算,避免了“重复造轮子”,这就是接下来要学习的torch.autograd包,通过torch.autograd包,可以使模型参数自动计算在优化过程中需要用到的梯度值,在很大程度上帮助降低了实现后向传播代码的复杂度。

torch.autograd和Variable

在实践中完成自动梯度需要用到torch.autograd包中的Variable类对我们定义的Tensor数据类型变量进行封装,在封装后,计算图中的各个节点就是一个variable 对象,这样才能应用自动梯度的功能。autograd package是PyTorch中所有神经网络的核心。先了解一些基本知识,然后开始训练第一个神经网络。autograd package提供了Tensors上所有运算的自动求导功能。它是一个按运行定义(define-by-run)的框架,这意味着反向传播是依据代码运行情况而定义的,并且每一个单次迭代都可能不相同。

autograd.Variable 是这个package的中心类。它打包了一个Tensor,并且支持几乎所有运算。一旦你完成了你的计算,可以调用.backward(),所有梯度就可以自动计算。
  你可以使用.data属性来访问原始tensor。相对于变量的梯度值可以被积累到.grad中。
  这里还有一个类对于自动梯度的执行是很重要的:Function(函数)
  变量和函数是相互关联的,并且建立一个非循环图。每一个变量有一个.grad_fn属性,它可以引用一个创建了变量的函数(除了那些用户创建的变量——他们的grad_fn是空的)。
  如果想要计算导数,可以调用Variable上的.backward()。如果变量是标量(只有一个元素),你不需要为backward()确定任何参数。但是,如果它有多个元素,你需要确定grad_output参数(这是一个具有匹配形状的tensor)。

如果已经按照如上的方式完成了相关操作,则在选中了计算图中的某个节点时,这个节点必定是一个Variable对象,用X表示我们选中的节点,那么X.data代表Tensor数据类型 的变量,X.grad也是一个Variable对象,不过他代表的是X的梯度,在想访问梯度值的时候需要X.grad.data

下面通过一个自动剃度的实例来看看如何使用torch.autograd.Variable类和torch.autograd包,我们同样搭建一个二层结构的神经网络模型,这有利于我们之前搭建的简易神经网络模型的训练和优化过程进行对比,重新实现。

导入包

import torch
from torch.autograd import Variable
 
# 批量输入的数据量
batch_n = 100
# 通过隐藏层后输出的特征数
hidden_layer = 100
# 输入数据的特征个数
input_data = 1000
# 最后输出的分类结果数
output_data = 10

初始化权重

x = Variable(torch.randn(batch_n , input_data) , requires_grad = False)
y = Variable(torch.randn(batch_n , output_data) , requires_grad = False)
 
w1 = Variable(torch.randn(input_data,hidden_layer),requires_grad = True)
w2 = Variable(torch.randn(hidden_layer,output_data),requires_grad = True)

定义训练次数和学习效率

epoch_n = 20
learning_rate = 1e-6

新的模型训练和参数优化

for epoch in range(epoch_n):
 
    y_pred = x.mm(w1).clamp(min= 0 ).mm(w2)
    loss = (y_pred - y).pow(2).sum()
    print("Epoch:{} , Loss:{:.4f}".format(epoch, loss.data[0]))
 
    loss.backward()
    w1.data -= learning_rate * w1.grad.data
    w2.data -= learning_rate * w2.grad.data
 
    w1.grad.data.zero_()
    w2.grad.data.zero_()

在代码的最后还要将本次计算得到的各个参数节点的梯度值通过grad.data.zero_()全部置零,如果不置零,则计算的梯度值会被一直累加,这样就会影响到后续的计算。

自定义传播函数

#_*_coding:utf-8_*_
import torch
from torch.autograd import Variable
 
# 批量输入的数据量
batch_n = 100
# 通过隐藏层后输出的特征数
hidden_layer = 100
# 输入数据的特征个数
input_data = 1000
# 最后输出的分类结果数
output_data = 10

class Model(torch.nn.Module):
    def __init__(self):
        super(Model,self).__init__()
     
    def forward(self,input,w1,w2):
        x = torch.mm(input,w1)
        x = torch.clamp(x,min=0)
        x = torch.mm(x,w2)
        return x
     
    def backward(self):
        pass
 
 model = Model()

这一系列操作相当于完成了对简易神经网络的搭建,然后就只剩下对模型进行训练和对参数进行优化的部分了,代码如下:

#_*_coding:utf-8_*_
import torch
from torch.autograd import Variable
 
# 批量输入的数据量
batch_n = 100
# 通过隐藏层后输出的特征数
hidden_layer = 100
# 输入数据的特征个数
input_data = 1000
# 最后输出的分类结果数
output_data = 10
 
x = Variable(torch.randn(batch_n , input_data) , requires_grad = False)
y = Variable(torch.randn(batch_n , output_data) , requires_grad = False)
 
w1 = Variable(torch.randn(input_data,hidden_layer),requires_grad = True)
w2 = Variable(torch.randn(hidden_layer,output_data),requires_grad = True)
 
# 训练次数设置为20
epoch_n = 20
# 将学习效率设置为0.000001
learning_rate = 1e-6
 
for epoch in range(epoch_n):
 
    y_pred = x.mm(w1).clamp(min= 0 ).mm(w2)
    loss = (y_pred - y).pow(2).sum()
    print("Epoch:{} , Loss:{:.4f}".format(epoch, loss.data[0]))
 
    loss.backward()
    w1.data -= learning_rate * w1.grad.data
    w2.data -= learning_rate * w2.grad.data
 
    w1.grad.data.zero_()
    w2.grad.data.zero_()

这里,变量的赋值、训练次数和学习速率的定义,以及模型训练和参数优化使用的代码,和在 6.2.1节中使用的代码没有太大的差异,不同的是,我们的模型通过“y_pred =model(x, w1, w2)”来完成对模型预测值的输出,并且整个训练部分的代码被简化了。

转载自

链接: [link](https://www.cnblogs.com/wj-1314/p/9830950.html )

你可能感兴趣的:(Pytorch)