多层感知机的基本知识
我们将以多层感知机(multilayer perceptron,MLP)为例,介绍多层神经网络的概念。
隐藏层
下图展示了一个多层感知机的神经网络图,它含有一个隐藏层,该层中有5个隐藏单元。
表达公式
激活函数
以上问题在于全连接层只是对数据做仿射变换(affine transformation),而多个仿射变换的叠加仍然是一个仿射变换。所以需要一个非线性函数来进行变换,打破这种仿射变换,然后输出再作为下一个全连接层的输入。这个非线性函数被称为激活函数(activation function)。
下面我们介绍几个常用的激活函数:
ReLU函数
ReLU(rectified linear unit)函数提供了一个简单的非线性变换。给定元素,该函数定义为
由上述可得,ReLU函数只保留正数元素,并将负数元素清零。下面我们把ReLU函数画出来。先定义一个绘图函数xyplot。
注:d2lzh1981为一个包名,先封装好然后可以直接调用;具体代码在下面Github页面上:https://github.com/d2l-ai/d2l-zh/tree/master/d2lzh
%matplotlib inline import torch import numpy as np import matplotlib.pyplot as plt import sys sys.path.append("/home/input") #文件夹路径 import d2lzh1981 as d2l def xyplot(x_vals, y_vals, name): # d2l.set_figsize(figsize=(5, 2.5)) plt.plot(x_vals.detach().numpy(), y_vals.detach().numpy()) plt.xlabel('x') plt.ylabel(name + '(x)') x = torch.arange(-8.0, 8.0, 0.1, requires_grad=True) y = x.relu() xyplot(x, y, 'relu')
y.sum().backward() xyplot(x, x.grad, 'grad of relu')
Sigmoid函数
sigmoid函数将元素的值变换到0和1之间:
y = x.sigmoid() xyplot(x, y, 'sigmoid')
对sigmoid函数求导,其导数为:
tanh(双曲正切)函数可以将元素的值变换到-1和1之间:
当输入接近0时,tanh函数接近线性变换。tanh函数在坐标系的原点上对称。
y = x.tanh() xyplot(x, y, 'tanh')
tanh的导数为:
x.grad.zero_() y.sum().backward() xyplot(x, x.grad, 'grad of tanh')
激活函数的选择
ReLu函数是一个通用的激活函数,一般都用ReLu。但是,ReLU函数只能在隐藏层中使用。用于分类器时,sigmoid函数及其组合通常效果更好。由于梯度消失问题,有时要避免使用sigmoid和tanh函数。
多层感知机
多层感知机含有至少一个隐藏层的由全连接层组成的神经网络,且每个隐藏层的输出通过激活函数进行变换。
多层感知机从零开始的实现
import torch import numpy as np import sys sys.path.append("/home/input") #文件夹路径 import d2lzh1981 as d2l #获取数据集 batch_size = 256 train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size,root='/home/input/FashionMNIST2065') #自定义模型参数 num_inputs, num_outputs, num_hiddens = 784, 10, 256 W1 = torch.tensor(np.random.normal(0, 0.01, (num_inputs, num_hiddens)), dtype=torch.float) b1 = torch.zeros(num_hiddens, dtype=torch.float) W2 = torch.tensor(np.random.normal(0, 0.01, (num_hiddens, num_outputs)), dtype=torch.float) b2 = torch.zeros(num_outputs, dtype=torch.float) params = [W1, b1, W2, b2] for param in params: param.requires_grad_(requires_grad=True) #定义激活函数 def relu(X): return torch.max(input=X, other=torch.tensor(0.0)) #定义网络 def net(X): X = X.view((-1, num_inputs)) H = relu(torch.matmul(X, W1) + b1) return torch.matmul(H, W2) + b2 #定义损失函数 loss = torch.nn.CrossEntropyLoss() #训练 num_epochs, lr = 5, 100.0 def train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, params=None, lr=None, optimizer=None): for epoch in range(num_epochs): train_l_sum, train_acc_sum, n = 0.0, 0.0, 0 for X, y in train_iter: y_hat = net(X) l = loss(y_hat, y).sum() # 梯度清零 if optimizer is not None: optimizer.zero_grad() elif params is not None and params[0].grad is not None: for param in params: param.grad.data.zero_() l.backward() if optimizer is None: d2l.sgd(params, lr, batch_size) else: optimizer.step() # “softmax回归的简洁实现”一节将用到 train_l_sum += l.item() train_acc_sum += (y_hat.argmax(dim=1) == y).sum().item() n += y.shape[0] test_acc = evaluate_accuracy(test_iter, net) print('epoch %d, loss %.4f, train acc %.3f, test acc %.3f' % (epoch + 1, train_l_sum / n, train_acc_sum / n, test_acc)) d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, params, lr)
多层感知机pytorch简洁实现
import torch from torch import nn from torch.nn import init import numpy as np import sys sys.path.append("/home/input") import d2lzh1981 as d2l num_inputs, num_outputs, num_hiddens = 784, 10, 256 net = nn.Sequential( d2l.FlattenLayer(), nn.Linear(num_inputs, num_hiddens), nn.ReLU(), nn.Linear(num_hiddens, num_outputs), ) for params in net.parameters(): init.normal_(params, mean=0, std=0.01) num_inputs, num_outputs, num_hiddens = 784, 10, 256 net = nn.Sequential( d2l.FlattenLayer(), nn.Linear(num_inputs, num_hiddens), nn.ReLU(), nn.Linear(num_hiddens, num_outputs), ) for params in net.parameters(): init.normal_(params, mean=0, std=0.01)
参考文献
[1]《动手深度学习》李沐
[2]伯禹教育课程