本节介绍几种典型的神经网络,包括感知器、误差反向传播(BP)神经网络和径向基函数(RBF)神经网络。
感知器分单层与多层,是具有学习能力的神经网络;也是最简单的前馈网络,主要用于模式分类。
单层感知器是一个具有单层处理单元的神经网络,如下图所示,感知器的输出为$y=f\left(\sum_{j=1}^{n} w_{j} u_{j}-\theta\right)$,式中$f$为阶跃函数。
学习算法:
随机给出一组初始链接权值$w_j(0),(j=1,2,\ldots,n)$;
输入一组样本$X_{\mathrm{p}}=\left(x_{\mathrm{p} 1}, x_{\mathrm{p} 2}, \ldots, x_{\mathrm{p} n}\right)$和希望输出$d_p(p=1,2,\ldots,L)$
$d_{p}=\left\{\begin{array}{ll}1, & X_{p} \in A \\ 0 & X_{p} \in B \end{array}\right.$
计算感知器的输出$y_p$
权值调整:$w_{j}(k+1)=w_{j}(k)+\eta\left[d_{p}-y_{p}(k)\right] x_{p j}$
若$y_p(k)=d_p$,学习结束,否则返回 3。
可见学习结束后,网络将样本模式以连接权和阈值的形式分布记忆(存储)于网络中。
特性:
二维平面上的两类模式
如下表:
$u_1$ | $u_2$ | $y$ |
---|---|---|
0 | 0 | 0 |
1 | 0 | 0 |
0 | 1 | 0 |
1 | 1 | 1 |
用下图所示的二输入/单输出单层感知器,其输入输出描述为:
显然这四组样本可分为两类,因而是线性可分集合,此直线方程可用下式表示:
三维空间两类模式
如下表:
$u_1$ | $u_2$ | $u_3$ | $y$ |
---|---|---|---|
0 | 0 | 0 | 0 |
1 | 0 | 0 | 0 |
1 | 1 | 0 | 0 |
0 | 1 | 0 | 0 |
0 | 0 | 1 | 1 |
1 | 0 | 1 | 1 |
0 | 1 | 1 | 1 |
1 | 1 | 1 | 1 |
用下图(a)所示三输入/单输出单层感知器,其输入输出描述:
对这$8$组样本可以找到一个平面,将其分为两类,该平面方程为:
同理对于维数$n>3$的高维空降上的线性可分集合,一定可找到一超平面,将输入模式分为两类。由$n$输入/单输出的单层感知器实现。
但对于 线性不可分集合,单层感知器则无能为力,如下图所示的 异或问题 就是如此。因为对于该图找不到可以将其分为红、蓝两类的一条直线。对于这类问题,单层感知器不会收敛。
import numpy as np
import matplotlib.pyplot as plt
class Perceptron:
def __init__(self, learning_rate=0.01, n_iterations=1000):
self.learning_rate = learning_rate # 学习率
self.n_iterations = n_iterations # 迭代次数
self.weights = None # 权重
self.bias = None # 偏置
def fit(self, X, y):
n_samples, n_features = X.shape
# 初始化权重和偏置
self.weights = np.zeros(n_features) # 初始化权重
self.bias = 0 # 初始化偏置
# 梯度下降
for _ in range(self.n_iterations):
for idx, x_i in enumerate(X):
linear_output = np.dot(x_i, self.weights) + self.bias # 计算线性输出
y_predicted = self.activation(linear_output) # 计算预测值
# 更新权重和偏置
update = self.learning_rate * (y[idx] - y_predicted) # 计算更新值
self.weights += update * x_i # 更新权重
self.bias += update # 更新偏置
def predict(self, X):
linear_output = np.dot(X, self.weights) + self.bias # 计算线性输出
y_predicted = self.activation(linear_output) # 计算预测值
return y_predicted
def activation(self, x):
return np.where(x >= 0, 1, -1) # 激活函数
def visualize(self, X, y):
# 可视化数据
fig = plt.figure() # 创建一个新的图形
ax = fig.add_subplot(1, 1, 1) # 添加一个子图
plt.scatter(X[:, 0], X[:, 1], marker='o', c=y) # 绘制散点图
x0_1 = np.amin(X[:, 0]) # 获取X的最小值
x0_2 = np.amax(X[:, 0]) # 获取X的最大值
x1_1 = (-self.weights[0] * x0_1 - self.bias) / self.weights[1] # 计算x1_1
x1_2 = (-self.weights[0] * x0_2 - self.bias) / self.weights[1] # 计算x1_2
ax.plot([x0_1, x0_2], [x1_1, x1_2], 'k') # 绘制直线
ymin = np.amin(X[:, 1]) # 获取Y的最小值
ymax = np.amax(X[:, 1]) # 获取Y的最大值
ax.set_ylim([ymin - 3, ymax + 3]) # 设置Y轴的范围
plt.show() # 显示图形
# 添加数据
X = np.array([[2, 3], [1, 2], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10], [10, 11]])
y = np.array([-1, -1, -1, -1, -1, 1, 1, 1, 1, 1])
# 创建感知器对象
perceptron = Perceptron()
# 训练模型
perceptron.fit(X, y)
# 可视化模型
perceptron.visualize(X, y)
分类结果: