搭建一个分类网络
对下图这种平面上的点根据颜色进行分类
导入所需库
分别导入torch库,宏定义神经元类型(自动梯度)Variable,定义激励函数库F,由于希望过程可视化所以导入matplotlib库
import torch
from torch.autograd import Variable
import torch.nn.functional as F
import matplotlib.pyplot as plt
生成所需数据
生成被拟合数据x0和x1
n_data = torch.ones(100,2) #生成一个全为1的100行2列的张量,一列横坐标,一列纵坐标
x0 = torch.normal(2*n_data,1) #x~N(2,1)的正态分布
y0 = torch.zeros(100) #x0的标签y0全部设为0,一维数组100个0
x1 = torch.normal(-2*n_data,1) #同样,x1内包含了的横坐标和纵坐标,X1~N(-2,1)的正态分布
y1 = torch.ones(100) #x1的标签y1全部设为1,一维数组100个1
- 因为是对一个平面内的点进行分类,所以
n_data = torch.ones(100,2)
生成一个全为1的100行2列的张量,一列横坐标,一列纵坐标,n_data类型含有两个同时变量 - torch.normal(A,B)意为从正态分布X~N(A,B)中生成张量,由于n_data都是1,所以X0~N(2,1)的正态分布
- y0和y1分别是x0和x1的标签,我们最终目标是分辨哪些点的标签是1,哪些是0
拼接坐标以及标签
x=torch.cat((x0,x1),0).type(torch.FloatTensor) # 将x0和x1上下拼接变成待处理数据(200行2列),坐标要定义为浮点数,用.type()将结果转换为浮点数
y=torch.cat((y0,y1),).type(torch.LongTensor) # 将标签定义为整形类型(一维200个数字,前100个是0,后100个是1)
- cat函数:cat((A,B),0)把A张量和B张量上下拼接,若为1则左右拼接。若 , 后没有设置,则默认是0,进行上下拼接。
cat()函数例子:
A=torch.ones(2,3) #2x3的张量(矩阵)
print("A:\n",A,"\nA.shape:\n",A.shape,"\n")
B=2*torch.ones(3,3) #4x3的张量(矩阵)
print("B:\n",B,"\nB.shape:\n",B.shape,"\n")
C=torch.cat((A,B),0) #按维数0(行,即上下)拼接
print("C:\n",C,"\nC.shape:\n",C.shape,"\n")
输出:
A:
tensor([[1., 1., 1.],
[1., 1., 1.]])
A.shape:
torch.Size([2, 3])
B:
tensor([[2., 2., 2.],
[2., 2., 2.],
[2., 2., 2.]])
B.shape:
torch.Size([3, 3])
C:
tensor([[1., 1., 1.],
[1., 1., 1.],
[2., 2., 2.],
[2., 2., 2.],
[2., 2., 2.]])
C.shape:
torch.Size([5, 3])
搭建网络
与前一篇定义基本相同,解读可参照上一篇文章
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(2,10,2)
由于输入某个点有横纵坐标,所以输入是2个特征,设置10个神经元,又因为这是二分类问题,输出向量 [0,1]代表输出1,[1,0]代表输出0。
优化网络
optimizer = torch.optim.SGD(net.parameters(),lr=0.01)
调用torch的优化方法,选择常用的SGD优化器。 parameters是net的所有参数 lr是梯度下降速度(也就是学习速度,过快过慢都不行)
loss_function=torch.nn.CrossEntropyLoss()
定义处理误差的方法 分类一般用交叉熵损失处理方法。
交叉熵知识稍后补充。
使用网络进行回归
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
n_data = torch.ones(100,2) #生成一个全为1的100行2列的张量,一列横坐标,一列纵坐标
x0 = torch.normal(2*n_data,1) #因为n_data是二维张量,所以x0内包含了某点的横坐标和纵坐标,x~N(2,1)的正态分布
#torch.normal(A,B)意为从正态分布N~(A,B)中生成张量
y0 = torch.zeros(100) #x0的标签y0全部设为0,一维数组100个0
x1 = torch.normal(-2*n_data,1) #同样,x1内包含了的横坐标和纵坐标,x~N(-2,1)的正态分布
y1 = torch.ones(100) #x1的标签y1全部设为1,一维数组100个1
#分辨哪一类是0,哪一类是1
x=torch.cat((x0,x1),).type(torch.FloatTensor) # 将x0和x1上下拼接变成待处理数据(200行2列),坐标要定义为浮点数,用.type()将结果转换为浮点数
y=torch.cat((y0,y1),).type(torch.LongTensor) # 将标签定义为整形类型(一维200个数字,前100个是0,后100个是1)
#cat函数,cat((A,B),0)把A张量和B张量上下拼接,若为1则左右拼接
x=Variable(x)
y=Variable(y)
'''
# 绘图查看数据(一半红一半绿)
plt.scatter(x.data.numpy()[:, 0], x.data.numpy()[:, 1], c=y.data.numpy(), s=100, lw=0, cmap='RdYlGn')
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(2,10,2) #输入某个点的横纵坐标2个特征,10个神经元,这是二分类问题输出向量[0,1]代表输出1,[1,0]代表输出0。
# 有点像线代求特征向量,三分类问题就要[0,0,1],四分类就是[0,1,0,0]。ont-hot
'''
print(net) #查看网络
Net(
(hidden): Linear(in_features=2, out_features=10, bias=True)
(predict): Linear(in_features=10, out_features=2, bias=True)
)
输入某点的横纵坐标,得到对应的向量[0,1] or [1,0]
隐藏层输入2个变量,输出10个神经元
预测层输入10个神经元,输出向量
'''
plt.ion() #实时打印过程
plt.show()
# 优化神经网络
optimizer = torch.optim.SGD(net.parameters(),lr=0.01)
# 调用torch的优化方法中,选择常用的SGD优化器。 parameters是net的所有参数 lr是梯度下降速度
loss_function=torch.nn.CrossEntropyLoss() #定义处理误差的方法 分类一般用交叉熵损失处理方法
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%2==0: #每2步打印一次
plt.cla()
# 过了一道 softmax 的激励函数后的最大概率才是预测值
prediction = torch.max(F.softmax(prediction), 1)[1] #用softmax将向量转换为概率,输出索引为1的地方 ↑那个向量一样的东西
pred_y = prediction.data.numpy().squeeze()
target_y = y.data.numpy()
plt.scatter(x.data.numpy()[:, 0], x.data.numpy()[:, 1], c=pred_y, s=100, lw=0, cmap='RdYlGn')
accuracy = sum(pred_y == target_y)/200. # 预测中有多少和真实值一样
plt.text(1.5, -4, 'Accuracy=%.2f' % accuracy, fontdict={'size': 20, 'color': 'red'})
plt.pause(0.1)