导入依赖
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_circles
from sklearn.model_selection import train_test_split
数据准备
# factor 表示内外圆的衡量因子
# X 表示点集
# y 表示相同索引下点集中的点所在的圆
X, y = make_circles(2000, noise=0.03, factor=0.6)
inner = np.where(y==1)
outer = np.where(y==0)
# 将内外圆的圆心放到 (1,1)上
X += 1
# 绘图
plt.plot(X[inner, 0], X[inner, 1], 'bo')
plt.plot(X[outer, 0], X[outer, 1], 'ro')
plt.show()
分割数据
# 选取 80% 的数据用来训练
# 选取 20% 的数据用来测试
train_x, test_x, train_y, test_y = train_test_split(X, y, test_size=0.2)
定义阶跃函数
def sigmoid(x):
return 1 / (1 + np.exp(-x))
定义超参数
# 输入的自变量是 2D
# 输出的因变量是 1D
# 隐层节点数目
n_hidden = 50
# 完整训练集的训练次数
n_epochs = 1000
# 学习率
learning_rate = 1
初始化权重矩阵
# 自变量的维度为 train_x.shape[1] 2D
weights_hidden = np.random.normal(0.0, size=(train_x.shape[1], n_hidden))
# 因变量的维度为 1D
weight_output = np.random.normal(0.0, size=(n_hidden))
构建FNN
# 进行 n_epochs 轮训练
for _ in range(n_epochs):
# 每轮训练累加的误差
del_w_hidden = np.zeros(weights_hidden.shape)
del_w_output = np.zeros(weights_output.shape)
# 训练FNN
for x_, y_ in zip(train_x, train_y):
# 信息前向计算
hidden_input = np.dot(x_, weights_hidden)
hidden_output = sigmoid(hidden_input)
output = sigmoid(np.dot(hidden_output, weights_output))
# 误差后向传播
# 运算结果与期望结果的误差
error = y_ - output
# 输出层的误差
# output * (1 - output) 表示罚函数
# 某一个神经元计算得出的实际结果与期望结果偏差越大
# 该神经元需要纠正(惩罚)的程度就越大
output_error = error * output * (1 - output)
# 隐层的误差
# np.dot(output_error, weights_output)
# 表示将误差按权重传播
# output_error 由于只有一个输出节点
# 因此权重始终为 1
hidden_error = np.dot(output_error, weights_output) * hidden_output * (1 - hidden_output)
# 更新误差
# 权重的更新受两方面影响
# 自变量数据越大对因变量的影响就越大
# 神经元之间的权重越大对因变量的影响就越大
# hidden_output & x_[:, None]
# 表示自变量数据对误差的影响
del_w_output += output_error * hidden_output
del_w_hidden += hidden_error * x_[:, None]
# 更新权重
weights_hidden += learning_rate * del_w_hidden / train_x.shape[0]
weights_output += learning_rate * del_w_output / train_x.shape[0]
测试FNN
# res 记录预测结果
res = np.array([])
for x_, y_ in zip(test_x, test_y):
hidden_input = np.dot(x_, weights_hidden)
hidden_output = sigmoid(hidden_input)
output = sigmoid(np.dot(hidden_output, weights_output))
res = np.append(res, output)
# round 函数表示四舍五入
# 用来圆整结果
res = np.round(res)
# 记录预测结果与期望结果相同的索引
compare = np.where(res==test_y)
# 预期正确的数据占测试数据的比例
compare[0].shape[0] / test_y.shape[0]
# 0.96
参考书籍
《Python深度学习实战:75个有关神经网络建模、强化学习与迁移学习的解决方案》