简单的BP神经网络和pytorch实现


(我个人刚开始学pytorch,所以代码是对照着github上敲得,https://github.com/MorvanZhou/PyTorch-Tutorial

(这里关于神经网络的优化方法并没有讲,需要的同学可以看误差逆传播算法和梯度下降法)

啥是神经网络

神经网络是用来做分类/回归的,长得和人的神经组织差不多。神经网络是由一层层的结构,每层都有$N$个神经元,正如神经细胞一样,神经网络中每个神经元都有输入和输出。比如下图,该神经元的输入来自其他神经元的输出,不同的输入有不同的权重,按照权重进行求和计算,再减上阈值,再将计算结果作为输出。在学习网络的时候,学习的参数就是各个神经元的权重和阈值

然后把这些神经元按照层组成网络结构,如下图

最左边开始数,第一层是输入层,可以看出有4个神经元,第二层是隐层,有6个神经元,第三层是输出层有4个神经元,也就是说,权重有46+64=48个参数,权重有6+4=10个参数,总共有58个参数要学习。

本次模型

需要分类的数据

在本次分类的模型中,对于这种简单的(结构简单)神经网络,输出层的神经元数量一般看有几个类别,比如数据集中有4种类要分,那输出神经元就要4个,比如四种类型0,1,2,3,输出如果是[1,0,0,0]的话就算类型0,如果是[0,0,1,0]的话就算类型2,也就是看1的索引位置。我们这次需要分两类,所以输出层的神经元就2个。
隐层的神经元一般来讲层数越高、神经元越多,分类效果就越好,但是到一定程度分类效果就上升很慢了,计算耗时也会很多,所以不宜过多,我们这里就用10个神经元
输入层一般是看数据的维度有几个,本次分类也就两个特征横坐标和纵坐标,所以输入层2个神经元。

用torch写网络结构

class Net(torch.nn.Module):
    def __init__(self, n_features, n_hidden, n_output):
        # n_features输入层神经元数量,也就是特征数量
        # n_hidden隐层神经元数量
        # n_output输出层神经元数量
        super(Net, self).__init__()
        self.hidden = torch.nn.Linear(n_features, n_hidden)
        self.predict = torch.nn.Linear(n_hidden, n_output)

    def forward(self, x):
        x = F.relu(self.hidden(x))
        x = self.predict(x)
        return x

forward是指网络的前向传播,也就输出是怎么得到输出值的;backward是指网络的反向传播,根据输出结果和标准结果的差(也就是loss,神经网络的目标是优化也就是最小化loss),计算出其误差并反向传播。具体数学原理在这里不说了,想看的可以去查误差逆传播算法。

建立网络和优化

net = Net(2, 10, 2)
print(net)
optimizer = torch.optim.SGD(net.parameters(), lr=0.02)
loss_func = torch.nn.CrossEntropyLoss()

optimizer为优化器,这里使用SGD优化(Stochastic gradient descent)也就是随机梯度下降法,lr为学习率。同时还有个loss函数,这里用的是交叉熵损失函数(Cross Entropy Loss)

开始迭代优化

for t in range(30):
    out = net(x)
    loss = loss_func(out, y)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

这里的步骤:
1. 计算现有的参数计算出来的结果out
2. 结果和标准结果y计算loss进行比对
3. 把上一次迭代结果的梯度设为0
4. 反向传播误差
5. 迭代更新参数

完整代码

import torch
from torch.autograd import Variable
import torch.nn.functional as F
import matplotlib.pyplot as plt

n_data = torch.ones(1000, 2)
x0 = torch.normal(2 * n_data, 1)
y0 = torch.zeros(1000)
x1 = torch.normal(-2 * n_data, 1)
y1 = torch.ones(1000)
x = torch.cat((x0, x1), ).type(torch.FloatTensor)
y = torch.cat((y0, y1), ).type(torch.LongTensor)

# plt.scatter(x.data.numpy(), y.data.numpy())
# plt.show()


class Net(torch.nn.Module):
    def __init__(self, n_features, n_hidden, n_output):
        # n_features输入层神经元数量,也就是特征数量
        # n_hidden隐层神经元数量
        # n_output输出层神经元数量
        super(Net, self).__init__()
        self.hidden = torch.nn.Linear(n_features, n_hidden)
        self.predict = torch.nn.Linear(n_hidden, n_output)

    def forward(self, x):
        x = F.relu(self.hidden(x))
        x = self.predict(x)
        return x

net = Net(2, 10, 2)
print(net)
optimizer = torch.optim.SGD(net.parameters(), lr=0.02)
loss_func = torch.nn.CrossEntropyLoss()
plt.ion()
for t in range(30):
    out = net(x)
    loss = loss_func(out, y)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    if t % 2 == 0:
        # plot and show learning process
        plt.cla()
        prediction = torch.max(out, 1)[1]
        pred_y = prediction.data.numpy()
        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 = float((pred_y == target_y).astype(int).sum()) / float(target_y.size)
        plt.text(1.5, -4, 'Accuracy=%.2f' % accuracy, fontdict={'size': 20, 'color': 'red'})
        plt.pause(0.1)
plt.ioff()
plt.show()

可以看出torch框架的代码和神经网络的优化思路基本一致,还是很适合做科研用的框架的……

(哦对了为了视觉效果我把数据量放大成1000个了)

发表评论

电子邮件地址不会被公开。 必填项已用*标注