本篇主讲神经网络,涉及感知机、激活函数、计算图、CNN等,以笔记与实践形式展开。
感知机是最早的监督式学习算法,是神经网络和支持向量机的基础。感知机接收多个输入信号,输出一个信号。
神经网络由输入层、中间层、输出层结构组成。与感知机不同是多输入多输出。
激活函数是连接感知机和神经网络的桥梁。神经网络使用的激活函数有 :Sigmoid函数;阶跃函数;ReLU函数。
神经网络实现:先定义一些符号,如定义权重、神经元及输入层神经元等。在此上各层信号实现传递
下面用神经网络进行手写数字识别,分别介绍MNIST 数据集、神经网络的推理处理和批处理。过程步骤为:装数据,构建神经网络,训练网络及可视化。
MNIST数据集由从0到9的数字图像构成。MNIST数据集的一般使用方法是,先用训练图像进行学习,再用学习到的模型衡量能多大程度地对测试图像进行正确的分类。
import torch
from torch import nn
from torch.nn import functional as F
from torch import optim
import torchvision
from matplotlib import pyplot as plot
from utils import plot_image, plot_curve, one_hot, save_data
# step1 装数据
batch_size = 512
# step1. load dataset
train_loader = torch.utils.data.DataLoader(
torchvision.datasets.MNIST('mnist_data', train=True, download=True,
transform=torchvision.transforms.Compose([
torchvision.transforms.ToTensor(),
torchvision.transforms.Normalize(
(0.1307,), (0.3081,))
])),
batch_size=batch_size, shuffle=True)
test_loader = torch.utils.data.DataLoader(
torchvision.datasets.MNIST('mnist_data/', train=False, download=True,
transform=torchvision.transforms.Compose([
torchvision.transforms.ToTensor(),
torchvision.transforms.Normalize(
(0.1307,), (0.3081,))
])),
batch_size=batch_size, shuffle=False)
x,y = next(iter(train_loader))
print(x.shape,y.shape,x.min(),y.min())
# plot_image(x,y,'sample')
# step2 构建神经网络
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
# xw+b
self.fc1 = nn.Linear(28*28, 256)
self.fc2 = nn.Linear(256, 64)
self.fc3 = nn.Linear(64, 10)
def forward(self, x):
# x: [b, 1, 28, 28]
# h1 = relu(xw1+b1)
x = F.relu(self.fc1(x))
# h2 = relu(h1w2+b2)
x = F.relu(self.fc2(x))
# h3 = h2w3+b3
x = self.fc3(x)
return x
def backward(self, x):
# x: [b, 1, 28, 28]
# h1 = relu(xw1+b1)
x = F.relu(self.fc1(x))
# h2 = relu(h1w2+b2)
x = F.relu(self.fc2(x))
# h3 = h2w3+b3
x = self.fc3(x)
return x
# step3 训练网络
net = Net()
optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9)
train_loss = []
for epoch in range(10):
for idx,(x,y) in enumerate(train_loader):
x = x.view(x.size(0),28*28)
# =>[b,10]
out = net(x)
y_onehot = one_hot(y)
loss = F.mse_loss(out,y_onehot)
optimizer.zero_grad()
loss.backward()
optimizer.step()
train_loss.append(loss.item())
if idx %10 ==0:
print(epoch,idx,loss.item())
# step4 可视化显示
save_data(train_loss,'train_loss.csv')
plot_curve(train_loss)
total_correct = 0
for x,y in test_loader:
x = x.view(x.size(0),28*28)
out = net(x)
pred = out.argmax(dim = 1)
correct = pred.eq(y).sum().float().item()
total_correct+=correct
total_num = len(test_loader.dataset)
acc = total_correct / total_num
print("acuccy",acc)
x,y = next(iter(test_loader))
out = net(x.view(x.size(0),28*28))
pred = out.argmax(dim = 1)
plot_image(x,pred,"test")
仿真运行,第一次会下载MNIST数据集,随后生成可视化训练迭代损失曲线,可以看到是下降趋势,并将数据保存到train_loss.csv文件。
图1:训练迭代损失曲线
图2:测试手写数字识别结果
可以看到仿真在从0到9一直比对完,然后打印出了准确率。对数字识别很直观。
计算图可以将计算过程用图形表示,图形指数据结构图,由多节点和边表示。链式法则的定义如下;如果某个函数由复合函数表示,那么其导数可以用构成复合函数的各个函数的导数的乘积表示。将计算图的思路应用于神经网络,把构成神经网络的层作为一个类进行实现。首先,实现对应于激活函数的 ReLU 层和 Sigmoid 层。
神经网络的训练目的是找到使损失函数的值尽可能小的参数。寻找最优参数的过程称为最优化(Optimization)。在梯度下降算法中,将参数的梯度(导数)作为线索,沿梯度方向更新参数,并不断重复这个步骤,直到找到最优参数,这个过程称为随机梯度下降(Stochastic Gradient Descent,SGD)。
卷积神经网络(Convolutional Neural Network,CNN)。CNN 可用于图像识别、语音识别等场合。CNN 中包含了新的卷积层(Convolution层)和池化层(Pooling层)。卷积层进行卷积运算,卷积运算相当于图像处理中的“滤波器运算”。卷积层有填充、步幅的概念。在进行卷积层的处理前,有时要向输入数据的四周填入固定的数据(比如0等),这称为填充(padding),填充在卷积运算中经常会用到。应用波器的位置间隔称为步幅(stride).
在神经网络的实现中,卷积运算也可以进行批处理,实现处理的高效化。池化是一种缩小高、宽方向上的空间的运算。
神经网络部分设计的理论知识比较多,也有比较多的概念与数学公式,更多的学习在于积累与实践,多思考归纳总结勤动手,常读常新,会有很多新的收获。