深度学习:感知机
感知机常用于二分类问题,找一个超平面将线性可分的数据集进行分类。本文将从单层感知机的原理开始探讨,再到多层感知机原理以及多层感知机的实现。
### 1、感知机
#### 1.1、感知机定义
感知机(Perceptron)由Frank Rosenblatt于1957年提出,是一种广泛使用的线性分类器。感知器可谓是最简单的人工神经网络,只有一个神经元。感知机是对生物神经元的简单数学模拟,有与生物神经元对应的部件,如权重(突触)、偏置(阈值)及激活函数(细胞体),输出为+1或-1。
#### 如图(1)所示。

### 2、多层感知机
在实际应用中,单层的感知机往往难以满足复杂问题的需求。因此,多层感知机被引入,以处理更复杂的非线性分类任务。
#### 2.1、多层感知机原理
多层感知机(Multi-layer Perceptron)是一种深度神经网络模型,它由多个层次组成,每个层次包括一个输入层、一个或多个隐藏层以及输出层。在每一层中,输入层的数据通过权重和偏置进行处理后传递到下一个隐藏层,直到最终输出层产生预测结果。
多层感知机的结构可以表示为:
\[ y = f(w^T x + b) \]
其中,
- \(w\) 表示所有权重
- \(x\) 表示输入数据
- \(b\) 表示偏置(阈值)
- \(f\) 是激活函数,用于处理线性组合后的结果
#### 2.2、多层感知机的实现
实现多层感知机需要解决几个关键问题:
1. **训练算法**:如何优化权重和偏置以使模型在给定数据上的表现达到最优。这个问题通常通过梯度下降法来解决。
2. **激活函数选择**:常见的激活函数有sigmoid、tanh和ReLU,每种都有其适用场景。
3. **隐藏层层数与神经元数量的选择**:过多的层数或神经元可能导致过拟合;太少则可能无法捕捉数据中的复杂模式。
通过以上步骤,可以构建并训练多层感知机模型来解决各种分类问题。
### 图1:感知机
#### 感知器是一种简单的两类线性分类模型,其分类准则为:
\[
y^=sgn(wTx+b).\tag{1}
\]
其中 \(\text{sgn}\) 函数的定义为:
\[
\text{sgn}(x)=
\begin{cases}
1 & \text{if} \, x>0\\
-1 & \text{otherwise}.
\end{cases}
.\tag{2}
\]
#### 损失函数
感知机模型属于二分类线性分类模型,属于判别模型和非概率模型。简单来说,就是找到一个超平面,把线性可分数据集分到超平面两侧。
那么如何定义感知机的损失函数?首先,我们需要明白损失函数用来衡量预测值与真实值之间的误差。引入到本文中,就是衡量分类错误的数据点与超平面的距离,因为对于分类错误的数据集我们才需要调整 \(w\) 和 \(b\) 参数,改变超平面的方向来重新分类数据点。
因此根据点到直线的距离公式,我们可以得出:
对于点 \((x_i, y_i)\) 到超平面 \(wx+b=0\) 的距离如下所示:
\[
d = |wx_i + b| / ||w||.
.\tag{3}
\]
### (3)中的 \(|\textbf{w}|\) 是 \(\textbf{w}\) 的 L2 范数。为了方便求导,我们需要把(3)中的绝对值去掉。
由于上述距离是表达错误分类数据点到超平面的距离,因此可得:
\[
\begin{cases}
wx_i + b < 0 & \text{if} \, y_i=1\\
wx_i + b > 0 & \text{if} \, y_i=-1.
\end{cases}
.\tag{4}
\]
因此 \(|wx_i+b| = -y_i(wx_i+b)\),又因为 \(\frac{1}{||\textbf{w}||}\) 是一个常数,不影响最终的导数,因此式子(3)可化为:
\[
d = -y_i(wx_i + b).
.\tag{5}
\]
由(5)可知,可用如下表达式来描述错误分类数据点的损失函数:
\[
l(\textbf{w}, \textbf{b}; x, y) = \sum_{x_i \in M} -y_i(wx_i + b).
.\tag{6}
\]
其中 \(M\) 是包含所有错误分类数据点的集合。
#### 参数更新
由(6)可知,损失函数对于 \(\textbf{w}\) 和 \(\textbf{b}\) 的导数分别为:
\[
\frac{\partial l}{\partial w} = \sum_{x_i \in M} -y_i x_i
.\tag{7}
\]
\[
\frac{\partial l}{\partial b} = \sum_{x_i \in M} -y_i.
.\tag{8}
\]
因此参数 \(\textbf{w}\) 和 \(\textbf{b}\) 的更新可以用如下式子表达:
\[
\textbf{w} \leftarrow \textbf{w} + \eta y_i x_i
.\tag{9}
\]
\[
\textbf{b} \leftarrow b + \eta y_i.
.\tag{10}
\]
#### 分类错误的判断条件
对于 \(N\) 个数据点,我们可以用下式来作为分类错误的判断条件:
\[
y_i(wx_i + b) \leq 0 \quad \forall i \in \{1, \cdots, N\}.
.\tag{11}
\]
#### 感知机中参数更新的过程
感知机中参数更新的整个过程可以描述为:
1. 初始化权重和偏置:首先需要对权重向量 \(w\) 和偏置项 \(b_w, b_b\) 进行初始化。
2. 对数据点进行分类:逐一选取数据点 \((x_i, y_i)\) 进行分类,其中 \(x_i\) 是输入特征,\(y_i\) 是对应的输出类别(1 或 0)。
3. 更新权重和偏置:如果当前分类是错误的,则根据错误的类别更新权重向量 \(w\) 和偏置项 \(b_b\)。具体来说,对于每一对正例 \((x_i, y_i) = (1,1)\) 和负例 \((x_j, y_j) = (0,1)\),计算误差项:
\[e_{ij} = 2(y_i - y_j)(x_i^T w + b_b)\]
然后更新权重和偏置项:
\[\Delta w = e_{ij}(x_i^T + b_w)\]
\[\Delta b_w = e_{ij}\]
其中,\( \Delta w \) 和 \( \Delta b_w \) 分别表示权重向量和偏置项的增量。如果分类是正确的,则跳过当前数据点。
4. 重复步骤2至3:直到所有数据点都被处理完毕或达到最大迭代次数 \(TTT\)。此时,更新完成,返回到第2步继续进行下一个数据点的分类。
图2给出了感知机参数学习的更新过程,其中红色实心点表示正例,蓝色空心点表示负例。黑色箭头表示当前权重向量的方向,红色虚线箭头则表示权重的更新方向。
总结:简单描述感知机训练过程包括初始化、数据点分类和参数更新三个步骤。在每个迭代中,通过计算误差项并相应地调整权重向量和偏置项来纠正错误分类。这个过程会一直重复直到没有新的错误出现或达到最大迭代次数为止。
图2:感知机参数更新的过程
1.4、单层感知机的不足
尽管单层感知机可以实现两个类别的分类,但是由于感知机是线性的,因此也只能对线性可分的数据集进行分类。实际情况中,我们需要处理的数据集常常是非线性,例如:
如果我们试图预测一个人是否会偿还贷款。我们可以认为,在其他条件不变的情况下,收入较高的人比收入较低的人更有可能偿还贷款。然而,虽然收入与还款概率存在单调性,但它们不是线性相关的。
收⼊从0增加到5万元,可能带来更大的还款可能性。但是,因为单层感知机只能产生线性分割面,因此无法拟合XOR函数。
### 2.1 XOR函数
通过观察(图3),我们可以发现,无论如何分割面,都无法有效地把两种数据集分开。这意味着单层感知机在处理非线性问题时存在局限。
### 2.2 多层感知机
为了解决这个问题,我们提出了一种多层感知机的结构。具体来说:
1. **两层感知机**:
- 我们使用蓝色和黄色标识的两个感知机分别对数据集进行分类。
- 其中一个感知机的结果将作为另一个感知机的输入。
2. **三层感知机**:
- 这种结构进一步提高了模型的复杂度,使得它可以更有效地处理非线性问题。
通过这种方式,我们可以利用多层感知机来拟合和分类非线性的函数。
1. 图4:多层感知机拟合XOR函数
由上图可知,多层感知机(MLP,Multilayer Perceptron)可以实现将非线性可分的数据集进行划分。
2. 2.1、多层感知机的定义
多层感知机(MLP)也叫人工神经网络(ANN),除了输入输出层外,它中间可以有多个隐藏层。最简单的MLP只含一个隐藏层,即三层的结构,如下图:
- 输入层:接收原始数据。
- 隐藏层:包含若干个神经元,负责处理特征和进行抽象表示。
- 输出层:将经过隐藏层处理的信息输出到结果。
3. 特性与优点
多层感知机具有许多特性,包括但不限于:
- 强大分类能力:可以用于解决复杂的非线性问题。
- 可扩展性强:通过添加更多层来提高复杂度和泛化能力。
- 灵活性高:可以根据任务需求调整结构和参数。
- 能处理大量数据:高效的计算能力,适合大规模学习。
4. 适用场景
多层感知机广泛应用于:
- 图像识别
- 自然语言处理
- 模式分类与回归分析
- 神经网络深度学习的基础
5. 基本操作
在Python中,使用scikit-learn库可以轻松实现MLP模型。基本步骤包括:
1. 安装和导入所需的库。
2. 准备数据集,并将其拆分为训练集和测试集。
3. 实例化MLP模型,设定参数(如层数、神经元个数等)。
4. 训练模型:使用训练集进行训练,调整超参数优化性能。
5. 预测与评估:应用模型对测试集进行预测,并计算准确率和损失等指标。
6. 模型选择
对于不同的任务和数据集,需要选择合适的MLP结构和参数。通常可以通过交叉验证、网格搜索等方法来优化模型性能。
如何确定适合的层数和神经元数量?可以参考文献中的经验法则,或者使用专门的工具如PyTorch等进行实验。
7. 模型改进
在多层感知机中,可以通过增加隐藏层或调整权重与偏置来提高模型性能。对于深度学习来说,引入Dropout、Batch Normalization等技术可以有效解决过拟合问题。
其他改进措施包括:
- 使用正则化方法(如L1/L2正则)
- 集成多种网络结构(stacked networks)
- 模型融合与数据增强
- 自监督学习
8. 结论
多层感知机是一种强大的机器学习技术,具有广泛的应用领域。通过适当的训练和模型选择策略,可以实现复杂任务的高效解决。
图5:多层感知机
其中,隐藏层层数以及每一层感知机的数量都是超参数。
对于单分类的多层感知机,其公式形式如下:
输入 \(x \in \mathbb{R}^n\)
隐藏层 \(h\) 的参数 \(W_1 \in \mathbb{R}^{m \times n}\), \(b_1 \in \mathbb{R}^m\)
输出层 \(o\) 的参数 \(W_2 \in \mathbb{R}^{k \times m}\), \(b_k \in \mathbb{R}\)
\(h = \sigma(W_1x + b_1)\)
\(o = W_2^T h + b_2\)
\(y = \text{softmax}(o)\)
对于多分类的多层感知机,其公式形式如下:
输入 \(x \in \mathbb{R}^n\)
隐藏层 \(h\) 的参数 \(W_1 \in \mathbb{R}^{m \times n}\), \(b_1 \in \mathbb{R}^m\)
输出层 \(o\) 的参数 \(W_2 \in \mathbb{R}^{k \times m}\), \(b_k \in \mathbb{R}\)
\(h = \sigma(W_1x + b_1)\)
\(o = W_2^T h + b_2\)
\(y = \text{softmax}(o)\)
为了实现一个多层感知机模型,我们将使用PyTorch库来构建和训练模型。在本节中,我们首先将从零开始构造一个多层感知机来预测之前softmax回归中的Fashion-MNIST数据集。
### 3.1 读取数据集
首先,我们需要加载并准备数据集。为此,我们将使用定义好的`load_data_fashion_mnist`函数:
```python
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)
```
### 3.2 初始化参数
接下来,我们需要初始化多层感知机的权重和偏置。我们可以将这些变量视为超参数,并使用2的若干次幂来选择隐藏单元的数量。
```python
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]
```
### 3.3 激活函数
在这里,我们选择使用ReLU激活函数。
```python
def relu(X):
a = torch.zeros_like(X)
return torch.max(X, a)
```
### 3.4 定义模型
为了构建我们的多层感知机,我们需要将每个二维图像转换为一个长度为`num_inputs`的向量。我们只需几行代码就可以实现这个过程:
```python
def net(X):
X = X.reshape((-1, num_inputs))
H = relu(X@W1 + b1) # 这里“@”代表矩阵乘法
return (H@W2 + b2)
```
### 3.5 损失函数
我们直接使用内置的交叉熵损失函数。
```python
loss = nn.CrossEntropyLoss(reduction='none')
def cross_entropy(y_hat, y):
return -torch.log(y_hat[range(len(y_hat)), y])
loss = cross_entropy
```
### 3.6 训练模型
为了训练我们的多层感知机,我们将使用PyTorch的内置函数`train_ch3`。我们将迭代周期数设置为10,并将学习率设置为0.1。
```python
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)
```
通过这些步骤,我们可以成功地实现一个多层感知机模型并应用于Fashion-MNIST数据集。
在第3.7节中,我们使用已训练好的模型进行图像类别的预测。
```python
d2l.predict_ch3(net, test_iter)
```
这段代码首先定义了一个函数`predict_ch3`,它接受一个神经网络模型和一个测试迭代器作为参数。然后调用该函数对给定的模型执行预测,并将结果打印出来。
总结
本文首先介绍了感知机的基本原理,随后探讨了它无法拟合非线性函数的原因。接着提出了多层感知机模型,并详细分析了其在复杂非线性函数拟合方面的优势。
最后,我们从零开始实现了一个简单的多层感知机模型,展示了该模型的构建过程和功能。
参考资料
1. 动动手学深度学习 Release2.0.0-beta0
2. 神经网络与深度学习_邱锡鹏
3. 单层感知机的原理推导