跟着视频写一个回归神经网络
看一下最终目标
导入所需库
分别导入torch库,宏定义神经元类型(自动梯度)Variable,定义激励函数库F,由于希望过程可视化所以导入matplotlib库
import torch
from torch.autograd import Variable
import torch.nn.functional as F
import matplotlib.pyplot as plt
生成所需数据
生成被拟合数据x
x = torch.unsqueeze(torch.linspace(-1,1,100),dim=1)
- 原本linspace(-1,1,100)产生的是一维数据,是-1到1的100个数字。
查看维度是一维数组:torch.Size([100]) - 使用unsqueeze()并指定在下标1的位置增加一个维度,扩展后变成100行1列 。
查看维度是二维矩阵: torch.Size([100, 1])
设置单个x对应的y坐标
处理输出y的情况:x取平方+一些噪点:
y=x.pow(2)+0.2*torch.rand(x.size())
转换为variable形式,新版本不用写
x=Variable(x)
y=Variable(y)
可以查看一下效果:
plt.scatter(x.numpy(),y.numpy()) #转化为numpy类型
plt.show()
最重要的定义网络
类Net用torch.nn.Module
从torch继承了Module类。
class Net(torch.nn.Module): #从torch继承了Module类
def __init__(self,n_feature,n_hidden,n_output): #初始化时定义的,输入个数,隐藏层神经元个数,输出个数
super().__init__() #继承父类功能(官方步骤)
self.hidden = torch.nn.Linear(n_feature,n_hidden) #隐藏层:输入数据个数,隐藏层神经元个数,
self.predict = torch.nn.Linear(n_hidden,n_output) #预测层:输入是前面的hidden,输出个数
#神经元之间传递是线性,非线性是由激励函数实现的
def forward(self,x): # 前向传递,输入信息是x
x=F.relu(self.hidden(x)) #使用一个hidden层加工x,输出n个神经元,进入relu函数激活
x=self.predict(x) #将x放入预测层,并不希望结果被截断,所以不用外面套一层F.relu()
return x
神经元之间传递是线性,非线性是由激励函数实现的
关键定义两个方法:__init__
和forward
- __init__ () 初始化函数的参数:默认的self,输入个数,隐藏层神经元个数,输出个数。
然后要用规定代码super().__init__()
继承父类功能
最后定义隐藏层和预测层。 - forward() 前向传播函数的参数是输入x。在前向传播中,使用一个hidden层加工x,输出n个神经元,再进入F.relu()函数激活。最终把这个x放入预测层。
搭建网络
net = Net(1,10,1)
因为只输入x值,输入个数为1,设定10个隐藏层,最终输出唯一的y,即1个输出。
可使用print(net)
查看网络,输出:
Net(
(hidden): Linear(in_features=1, out_features=10, bias=True)
(predict): Linear(in_features=10, out_features=1, bias=True)
)
优化网络
optimizer = torch.optim.SGD(net.parameters(),lr=0.5)
调用torch的优化方法,选择常用的SGD优化器。 parameters是net的所有参数 lr是梯度下降速度(也就是学习速度,过快过慢都不行)
loss_function=torch.nn.MSELoss()
定义处理误差的方法 这里MSE是均方差处理损失,分类一般用其他的损失处理方法
使用网络进行回归
for t in range(100): # 训练100次
prediction = net(x) # 预测结果=100个数字经过net正向传播的100个值
loss = loss_function(prediction,y)
optimizer.zero_grad() #因为梯度累加,先要梯度降为0
loss.backward() #反向传递
optimizer.step() #优化梯度,其实就是找正确结果
整体代码及注释
建议复制到编辑器,配合高亮看。
其中matplotlib相关绘图代码我也看不懂,也不是重点
import torch
from torch.autograd import Variable
import torch.nn.functional as F
import matplotlib.pyplot as plt
x = torch.unsqueeze(torch.linspace(-1,1,100),dim=1)
#原本linspace产生的是一维数据:torch.Size([100])
#扩展后变成100行1列 torch.Size([100, 1])
#unsqueeze对数据维度进行扩充,用dim指定位置,给指定位置维度加1
y=x.pow(2)+0.2*torch.rand(x.size()) #x平方+一些噪点
x=Variable(x) #转换为variable形式,新版本不用写
y=Variable(y)
#只是作图查看一下
#plt.scatter(x.numpy(),y.numpy()) #转化为numpy类型
#plt.show()
class Net(torch.nn.Module): #从torch继承了Module类
def __init__(self,n_feature,n_hidden,n_output): #初始化时定义的,输入个数,隐藏层神经元个数,输出个数
super().__init__() #继承父类功能(官方步骤)
self.hidden = torch.nn.Linear(n_feature,n_hidden) #隐藏层:输入数据个数,隐藏层神经元个数,
self.predict = torch.nn.Linear(n_hidden,n_output) #预测层:输入是前面的hidden,输出个数
#神经元之间传递是线性,非线性是由激励函数实现的
def forward(self,x): # 前向传递,输入信息是x
x=F.relu(self.hidden(x)) #使用一个hidden层加工x,输出n个神经元,进入relu函数激活
x=self.predict(x) #将x放入预测层,并不希望结果被截断,所以不用外面套一层F.relu()
return x
net = Net(1,10,1) #因为只输入x值,输入个数为1,设定10个隐藏层,最终输出唯一的y,即1个输出。
'''
print(net) #查看网络
Net(
(hidden): Linear(in_features=1, out_features=10, bias=True)
(predict): Linear(in_features=10, out_features=1, bias=True)
)
输入一个x值,得到对应的y值
隐藏层输入1,输出10
预测层输入10,输出1
'''
plt.ion() #实时打印过程
plt.show()
# 优化神经网络
optimizer = torch.optim.SGD(net.parameters(),lr=0.5)
# 调用torch的优化方法中,选择常用的SGD优化器。 parameters是net的所有参数 lr是梯度下降速度
loss_function=torch.nn.MSELoss() #定义处理误差的方法 这里MSE是均方差处理损失,分类一般用其他的损失处理方法
for t in range(100): # 训练100次
prediction = net(x) # 预测结果=100个数字经过net正向传播的100个值
loss = loss_function(prediction,y)
optimizer.zero_grad() #因为梯度累加,先要梯度降为0
loss.backward() #反向传递
optimizer.step() #优化梯度,其实就是找正确结果
# 使整个过程可视化
if t%5==0: #每五步打印一次
plt.cla()
plt.scatter(x.numpy(),y.numpy())
plt.plot(x.detach().numpy(),prediction.detach().numpy(),'r-',lw=5)
#当计算中的数据类型为tensor时,想要获取其具体的数值,由于它带梯度值时,不能直接转为numpy格式,所以最好不论如何都调用一下a.detach().numpy(),其中a是要转换的数据。
plt.text(0.5,0,'loss=%.4f'%loss.data,fontdict={'size':20,'color':'red'})
plt.pause(0.2)