笔者在尝试使用库实现各种神经网络时,发现网络上大部分的教程都是使用Tensorflow或者是Kears,虽然也有PyTorch,但是比较少,而且教程都过于老旧,有一大部分是直接上来就实现一个卷积神经网络,并不是我想知道的,我想要的只是最简单的模型,具体要怎么操作我自己再改嘛,我是来学习的不是来看你秀技的,最终,在查阅资料与询问大佬后实现了一个最简单的神经网络,准确率有99%,当然这是这训练集上的准确率,测试集还没有试过,因为只是最简单的实现,这些内容也等构建出来再说。
首先描述一下神经网络的结构,只有三层,一层输入层,一层隐藏层,一层输出层,然后每个层之间则是完全相互连通的,输入数据为经典的手写数字识别,具体数据可以在sklearn直接导入,如下所示。
差点忘记了,神经网络与普通的机器学习模型不一样,它是直接可以多分类的,也就是说输出层的数据就是属于哪一类的意思,它是[1,0,0,0,0,...]这样的,当然不同激活函数结果不一样,我只是说明一下过程。因此,你输入的标签是需要转成one-hot编码的,也就是把原来,比如手写数字,标签是0,转成[1,0,0,0,0,0,0,0,0,0],标签是1则是,[0,1,0,0,0,0,0,0,0,0],以此类推,如果是DataFrame格式的话就是直接,y = pd.get_dummies(y).values。
下面介绍如何使用PyTorch构建神经网络(虽然说是PyTorch,但是导入的时候用的是torch):
构建方面,代码如下所示:
class MyNN(torch.nn.Module):
def __init__(self, input_size, hidden_size, output_size):
super(MyNN, self).__init__()
self.linear1 = torch.nn.Linear(input_size, hidden_size)
self.linear2 = torch.nn.Linear(hidden_size, output_size)
self.relu = torch.nn.ReLU()
self.sigmoid = torch.nn.Sigmoid()
def forward(self, x):
out = self.linear1(x)
out = self.sigmoid(out)
out = self.linear2(out)
out = self.sigmoid(out)
return out
MyNN这个类就是神经网络的结构,细节的语法可以不用管,估计可以理解成给普通的类打了torch库的补丁,下面对各个函数的内容进行解释:
对__init__函数,参数字如其名:
其中self.linear1,self.linear2分别表示输入到隐藏与隐藏到输出层的参数,relu与sigmoid应该是激活函数,具体可以根据结果继续更换,事实上也可以直接用torch的F模块直接导出相应的函数,具体可以自行学习。
对forward函数:
没什么参数,可以理解成把数据代入至各个层进行计算,得到预测结果,也就是前向传播的过程,输出就是out,如果到后面复杂使用需要增加层数的话就需要调整计算再加进去,方法类似于上面的,这个不属于本文涉及的范围,不展开。
在构建了神经网络类之后,构建神经网络类,很简单:
model = MyNN(64, 100, 10)
首先是输入层的结点数,也就是你要训练的数据的维数,那么在对sklearn的手写数字进行拆包后发现它的维度是64,而隐藏层设置了100,这个是随便设置的,由于只是一个例子没有对它的取值做过多的思考,取不同的值对模型的准确率有较大的影响,最后的10是输出层,因为是手写数字识别,就是0,1,...,9,也就是十个标签,所以输出层是十个结点。
如果完成了上面的操作,恭喜你,你已经完成了最基本的神经网络的构建,接下来要开始训练模型了,代码如下所示。
criterion = torch.nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=1)
X = torch.from_numpy(X).float()
y = torch.from_numpy(y).float()
for epoch in range(5000):
optimizer.zero_grad()
y_pred = model(X)
loss = criterion(y_pred, y)
loss.backward()
optimizer.step()
第一个是损失函数,第二个是优化器,具体就直接这么写就行了,而至于optimizer中有多个优化函数,一个是直接SGD,或者是Adam等等,而lr表示学习率,一般最大是1,普遍来说,学习率越低达到最优解所需的迭代次数越高。
接下来很重要,注意,如果是直接从pd.DataFrame格式导入的,不要直接使用torch.tensor(),最好是先把数据转为numpy格式后再变为tensor()格式,如何导入也是使用torch.from_numpy()即可,而且由于硬性要求,数据类型需要相同,这里设置成float,即浮点数。
剩下就是循环训练了,数学原理是求偏导,首先使用optimizer.zero_grad(),将偏导设置为0,接下来计算当前模型的预测与目标值的差异,也就是损失函数,最后根据损失函数进行反向传播,然后更新参数,就是这么多(想到当时手工实现写了一大堆,这里几句就实现了,多少有点难受)。一般这个过程要比较久,如果怕没有结果的可以输出一下loss,直接再loss.backward()前面加个print(loss)或者直接print(epoch)就可以知道运行到哪一步了。
那么在完成上述所有操作后,你已经完整的训练完一个神经网络模型了,可喜可贺可喜可贺。接下来则是如何计算准确率的问题,很简单,也是直接调用库即可。
具体代码如下所示:
from sklearn.metrics import accuracy_score
y_pred = model(X)
y_pred = y_pred.detach().numpy()
y_pred = np.argmax(y_pred, axis=1)
print(accuracy_score(y_pred, load_digits().target))
没什么好解释的,就是直接调用库算准确率,结果是99%,当然和我最开始说的一样,这个玩意的准确率说的是在训练集上面的准确率,意思是把这个跑出来的模型,丢用来训练的数据进去看他效果如何,不是说它在测试集上的表现。
使用PyTorch构建最简单的神经网络的所有代码如下所示:
import torch
from sklearn.metrics import accuracy_score
from sklearn.datasets import load_digits
import numpy as np
import pandas as pd
X = load_digits().data
y = load_digits().target
#将y转换为one-hot编码
y = pd.get_dummies(y).values
class MyNN(torch.nn.Module):
def __init__(self, input_size, hidden_size, output_size):
super(MyNN, self).__init__()
self.linear1 = torch.nn.Linear(input_size, hidden_size)
self.linear2 = torch.nn.Linear(hidden_size, output_size)
self.relu = torch.nn.ReLU()
self.sigmoid = torch.nn.Sigmoid()
def forward(self, x):
out = self.linear1(x)
out = self.sigmoid(out)
out = self.linear2(out)
out = self.sigmoid(out)
return out
model = MyNN(64, 100, 10)
criterion = torch.nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=1)
X = torch.from_numpy(X).float()
y = torch.from_numpy(y).float()
for epoch in range(5000):
optimizer.zero_grad()
y_pred = model(X)
loss = criterion(y_pred, y)
loss.backward()
optimizer.step()
from sklearn.metrics import accuracy_score
y_pred = model(X)
y_pred = y_pred.detach().numpy()
y_pred = np.argmax(y_pred, axis=1)
print(accuracy_score(y_pred, load_digits().target))
以此为基础,我也做了一个手写字母识别的,准确率是97%:
import torch
import torch.nn as nn
import torch.nn.functional as F
import pandas as pd
#将数据转为tensor
data = pd.read_csv("all_alphas.csv")
data = data[data.iloc[:, -1].isin(["A", "B", "C", "D", "E", "F", "G", "H", "I", "J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X", "Y", "Z"])]
x = data.iloc[:,:-1].values
y= data.iloc[:,-1]
y = pd.get_dummies(y)
x = torch.from_numpy(x).float()
y = torch.from_numpy(y.values).float()
class Net(nn.Module):
def __init__(self, input_size, hidden_size, output_size):
super(Net, self).__init__()
self.linear1 = torch.nn.Linear(input_size, hidden_size)
self.linear2 = torch.nn.Linear(hidden_size, output_size)
self.relu = torch.nn.ReLU()
self.sigmoid = torch.nn.Sigmoid()
def forward(self, x):
out = self.linear1(x)
out = self.sigmoid(out)
out = self.linear2(out)
out = self.sigmoid(out)
return out
net = Net(100,100,26)
optimizer = torch.optim.SGD(net.parameters(),lr = 1)
loss_func = torch.nn.MSELoss()
for t in range(5000):
prediction = net.forward(x)
loss = loss_func(prediction,y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
#准确率
prediction = net(x)
pred = torch.argmax(prediction,1)
y = torch.argmax(y,1)
correct = torch.eq(pred,y)
correct = correct.sum().float()
accuracy = correct/len(y)
print("accuracy:",accuracy)
以上的代码的灵感来源于Z与某篇在知乎上找到的文章,具体网页找不到了,是讲怎么构建二维的神经网络的,代码也放上来,直接搞个py文件跑一下效果很好看。
import torch
import torch.nn as nn
import torch.nn.functional as F
import matplotlib.pyplot as plt
from torch.autograd import Variable
x = torch.unsqueeze(torch.linspace(-1,1,100),dim=1)
y = x.pow(3)+0.1*torch.randn(x.size())
x , y =(Variable(x),Variable(y))
# plt.scatter(x,y)
# plt.scatter(x.data,y.data)
# plt.scatter(x.data.numpy(),y.data.numpy())
# plt.show()
class Net(nn.Module):
def __init__(self,n_input,n_hidden,n_output):
super(Net,self).__init__()
self.hidden1 = nn.Linear(n_input,n_hidden)
self.hidden2 = nn.Linear(n_hidden,n_hidden)
self.predict = nn.Linear(n_hidden,n_output)
def forward(self,input):
out = self.hidden1(input)
out = F.relu(out)
out = self.hidden2(out)
out = F.sigmoid(out)
out =self.predict(out)
return out
net = Net(1,20,1)
print(net)
optimizer = torch.optim.SGD(net.parameters(),lr = 0.1)
loss_func = torch.nn.MSELoss()
plt.ion()
plt.show()
for t in range(5000):
prediction = net(x)
loss = loss_func(prediction,y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if t%50 ==0:
plt.cla()
plt.scatter(x.data.numpy(), y.data.numpy())
plt.plot(x.data.numpy(), prediction.data.numpy(), 'r-', lw=5)
plt.text(0.5, 0, 'Loss = %.4f' % loss.data, fontdict={'size': 20, 'color': 'red'})
plt.pause(0.05)
plt.ioff()
plt.show()
有任何疑问或交流欢迎联系我的邮箱或者直接评论:
okura_machi@126.com