deep_learning_3.多层感知机的从零实现

单层感知机模型,给定输入x,权重w,和偏移b,感知机输出:

o = O(<w,x> + b ) O(i) = {1, if x>0; -1 otherwise}

感知机模型为二分类:-1或1

  • vs 回归 输出实数
  • vs Softmax回归 输出概率

单层感知机不能划分XOR数据(亦或),对于这一点,我们可以使用多层感知机模型。我们可以通过在网络中加入一个或多个隐藏层来克服线性模型的限制, 使其能处理更普遍的函数关系类型。 要做到这一点,最简单的方法是将许多全连接层堆叠在一起。 每一层都输出到上面的层,直到生成最后的输出。 我们可以把前L−1层看作表示,把最后一层看作线性预测器。

这种架构通常称为多层感知机(multilayer perceptron),通常缩写为MLP

多层感知机模型

h1 = O(W1*x + b1)

h2 = O(W2*h1 + b2)

h3 = O(W3*h2 + b3)

o = W4*h3 + b4

最后一层不需要激活函数,激活函数主要是用来避免层数的塌陷。

常用的激活函数:

  • ReLU函数,ReLU提供了一种非常简单的非线性变换。

ReLU(x) = max(x,0)

  • sigmoid函数,sigmoid函数将输入变换为区间(0, 1)上的输出

Sigmoid(x) = $\frac{1}{1+exp(-x)}$

  • tanh函数

tanh(x) = $\frac{1-exp(-2x)}{1+exp(-2x)}$

1
2
3
4
5
6
7

import torch
from torch import nn
from d2l import torch as d2l

batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)

多层感知机从零实现

1.初始化模型参数

1
2
3
4
5
6
7
8
9
10
num_inputs, num_outputs, num_hiddens = 784, 10, 256

W1 = nn.Parameter(torch.randn(
num_inputs, num_hiddens, requires_grad=True) * 0.01)
b1 = nn.Parameter(torch.zeros(num_hiddens, requires_grad=True))
W2 = nn.Parameter(torch.randn(
num_hiddens, num_outputs, requires_grad=True) * 0.01)
b2 = nn.Parameter(torch.zeros(num_outputs, requires_grad=True))

params = [W1, b1, W2, b2]

2.激活函数

1
2
3
def relu(X):
a = torch.zeros_like(X)
return torch.max(X, a)

3.模型

1
2
3
4
def net(X):
X = X.reshape((-1, num_inputs))
H = relu(X@W1 + b1) # 这里“@”代表矩阵乘法
return (H@W2 + b2)

4.损失函数

1
loss = nn.CrossEntropyLoss(reduction='none')

5.训练

1
2
3
num_epochs, lr = 10, 0.1
updater = torch.optim.SGD(params, lr=lr)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, updater)

1
d2l.predict_ch3(net, test_iter)

多层感知机的简介实现

1
2
3
import torch
from torch import nn
from d2l import torch as d2l
1
2
3
4
5
6
7
8
9
10
11
添加了2个全连接层(之前我们只添加了1个全连接层)。 第一层是隐藏层,它包含256个隐藏单元,并使用了ReLU激活函数。 第二层是输出层
net = nn.Sequential(nn.Flatten(),
nn.Linear(784, 256),
nn.ReLU(),
nn.Linear(256, 10))

def init_weights(m):
if type(m) == nn.Linear:
nn.init.normal_(m.weight, std=0.01)

net.apply(init_weights);
1
2
3
4
5
6
batch_size, lr, num_epochs = 256, 0.1, 10
loss = nn.CrossEntropyLoss(reduction='none')
trainer = torch.optim.SGD(net.parameters(), lr=lr)

train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)

总结

多层感知机使用隐藏层和激活函数来得到非线形模型

常用的激活函数是Sigmoid,Tanh,ReLU(没有想法的时候,通常用ReLU)

使用Softmax来处理多类分类

超参数为隐藏层数,和各个隐藏层大小

对于设置隐藏层数大小,没有科学的方法解释,只能全凭手感

Q&A

  1. epoch是什么?和batch_size有什么不同?

一次epoch是指将所有数据训练一次,所有数据迭代一次不够的,实际训练中,要反复多次才能收敛。batch_size则是在一次训练中把所有数据分成几批进行模型的训练,因为模型的训练是把数据加载到内存中处理的,没办法一次性把所有数据加载到内存中处理的

  1. 隐藏层的层数怎么设置?

输入维数比较多的时候,比如128维的输入你要把它压缩到10维的空间的话,最好是慢慢的把它压缩,比如先到64,再到32,再到16等,最后到你的输出。

还有一种做法是,先压缩再扩张再压缩,这样做会避免模型的overfitting

  1. 神经网络中的一层是包括了线形函数和激活函数的
  2. SVM替换了多层感知机吗?

SVM用起来更简单,不用调那么多超参数,有很漂亮的数学解释,在实用性都差不多的情况下,学术界会更倾向于有数学解释的模型

  1. 请问神经网络要增加隐藏层的层数,而不是神经元的个数?

增加神经元的个数,学习起来很难,浅显解释就是不能一口吃一个胖子,先学习一点,每一层可以慢慢训练

  1. 不同任务下的激活函数是不是都不一样?也是通过实验来确认的吗?

一般都差不多,激活函数远远没有选择隐藏层的大小这些来的重要,可以尽量用ReLU

  1. 模型深度和宽度哪个更影响性能,怎么根据输入空间选择最优的深度或者宽度?

没有最优,哪有最优哈哈哈,慢慢尝试,比如说128到2,首先不要隐藏层,第二次加一个隐藏层,比如试下16,32,64,第三次可以再试下加两个隐藏层。这些就是老中医要自己试手感


觉得不错的话,给点打赏吧 ୧(๑•̀⌄•́๑)૭



wechat pay



alipay

deep_learning_3.多层感知机的从零实现
http://yuting0907.github.io/2022/07/31/deep-learning-3-多层感知机的从零实现/
作者
Echo Yu
发布于
2022年7月31日
许可协议