a = torch.FloatTensor(2,3)
b = torch.FloatTensor([2,3,4,5])
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
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类对我们定义的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 )