神经网络编程

神经网络编程

框架代码

神经网络类至少需要3个函数:

  • 初始化函数————设定输入层节点、隐藏层节点和输出层节点的数量、学习率、权重、激活函数
  • 训练————学习给定训练集样本后,优化权重
  • 查询————给定输入,从输出节点给出答案

权重

  • 在输入层与隐藏层之间的链接权重矩阵为\(W_{input-hidden}\),大小为hidden_nodes乘以input_nodes
  • 在隐藏层与输出层之间的链接权重矩阵为\(W_{hidden-output}\),大小为outpu_nodes乘以hidden_nodes

查询网络

  • 链接权重点乘输入层就可以得到隐藏层的输入信号\(X_{hidden}=W_{input-hidden}\cdot I\)
  • 为了获得从隐藏层节点处出现的信号,使用sigmoid激活函数\(O_{hidden}=sigmod(X_{hidden})\),sigmod函数:1/(1+exp(-x));exp(-x)就是e的-x次方
  • 同理链接权重点乘隐藏层可以得到输出层的输入信号\(X_{output}=W_{hidden-output}\cdot H\)
  • 通过将输出层的输入信号带入激活函数得到输出层的输出信号

训练网络

  • 针对给定的训练样本计算输出
  • 将计算得到的输出与所需的输出对比,使用差值来指导网络权重的更新
  • 通过隐藏层节点反向传播误差\(error_{hidden}=W^T_{hidden-output}\cdot error_{output}\) T代表需要转置权重
  • 更新节点j与其下一层节点k之间链接权重的矩阵表达式\(\Delta W_{j,k}+=\alpha*E_k*sigmoid(O_k)*(1-sigmoid(O_k))\cdot O_j\) > \(\alpha\)是学习率,sigmoid是激活函数,*是普通乘法,\(\cdot\) 是点乘矩阵点积
1
2
3
4
# 导入库
import numpy as np
from scipy.special import expit
import matplotlib.pyplot as plt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# 神经网络类
class neuralNetwork:
# 初始化神经网络
def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):
# 初始化输入层、隐藏层、输出层
self.inodes = inputnodes
self.hnodes = hiddennodes
self.onodes = outputnodes

# 初始化学习率
self.lr = learningrate

# 初始化权重参数(输入到隐藏,隐藏到输出)传播时,前面的为列,后面的为行,W表示权重
# 使用正态分布初始化权重(中心设定为0.0,与下一层节点相关用标准方差表达式,第三个参数是数组形状大小)normal(loc=0.0, scale=1.0, size=None)
self.wih = np.random.normal(0.0, pow(self.hnodes, -0.5),(self.hnodes, self.inodes))
self.who = np.random.normal(0.0, pow(self.onodes, -0.5),(self.onodes, self.hnodes))

# 激活函数,公式为:1 / 1 + e ** x
self.activation_function = lambda x: expit(x)


pass

# 训练神经网络
def train(self, inputs_list, targets_list):

# 转置 2D 数组的行和列
inputs = np.array(inputs_list, ndmin=2).T
targets = np.array(targets_list, ndmin=2).T
# 用点乘获取隐藏层输入信号
hidden_inputs = np.dot(self.wih, inputs)
# 通过激活函数获取隐藏层输出信号
hidden_outputs = self.activation_function(hidden_inputs)
# 用点乘获取输出层输入信号
final_inputs = np.dot(self.who, hidden_outputs)
# 用激活函数获取输出层的输出层信号
final_outputs = self.activation_function(final_inputs)

# 反向传播--计算误差
output_errors = targets - final_outputs
# 通过点乘权重获取隐藏层误差
hidden_error = np.dot(self.who.T, output_errors)
# 更新输出层和隐藏层的链接权重
self.who += self.lr * np.dot((output_errors * final_outputs * (1.0 - final_outputs)),np.transpose(hidden_outputs))
# 更新隐藏层和输入层的链接权重
self.wih += self.lr * np.dot((hidden_error * hidden_outputs * (1.0 - hidden_outputs)),np.transpose(inputs))
pass

# 查询神经网络
def query(self, inputs_list):

# 转置 2D 数组的行和列
inputs = np.array(inputs_list, ndmin=2).T
# 用点乘获取隐藏层输入信号
hidden_inputs = np.dot(self.wih, inputs)
# 通过激活函数获取隐藏层输出信号
hidden_outputs = self.activation_function(hidden_inputs)
# 用点乘获取输出层输入信号
final_inputs = np.dot(self.who, hidden_outputs)
# 用激活函数获取输出层的输出层信号
final_outputs = self.activation_function(final_inputs)
# 返回最终输出
return final_outputs
1
2
3
4
5
6
7
8
# 设置节点和学习率
input_nodes = 784
hidden_nodes = 200
output_nodes = 10
learning_rate = 0.1

# 创建一个神经网络对象
n = neuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate)
1
2
3
4
# 导入训练数据
training_data_file = open("../GPT神经网络学习/mnist_train.csv",'r')
training_data_list = training_data_file.readlines()
training_data_file.close()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 训练神经网络
# 设置训练次数,这里设置为5
epochs = 5
for e in range(epochs):
for record in training_data_list:
# 分割数据
all_values = record.split(',')
# 缩放数据
inputs = (np.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01
# 创建训练目标
targets = np.zeros(output_nodes) + 0.01
# 设置训练目标,就是数据的标签数据设置为答案
targets[int(all_values[0])] = 0.99
# 训练数据
n.train(inputs, targets)
pass
pass
1
2
3
4
# 导入测试数据
test_data_file = open("../GPT神经网络学习/mnist_test.csv",'r')
test_data_list = test_data_file.readlines()
test_data_file.close()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 测试神经网络
# 创建计分卡
scorecard = []

# 测试模型并计分
for record in test_data_list:
# 分割数据
all_values = record.split(',')
# 设置列表的第一列元素为答案
correct_label = int(all_values[0])
# 缩放数据
inputs = (np.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01
# 查询神经网络
outputs = n.query(inputs)
# 筛选输出的最大值
label = np.argmax(outputs)
# 添加到计分卡
if (label == correct_label):
# 列表最大值的下标如果等于列表第一列,那就是正确的
scorecard.append(1)
else:
# 否则就把0添加到计分卡
scorecard.append(0)
pass

pass

1
2
3
# 显示计分卡分数
scorecard_array = np.asarray(scorecard)
print("测试得分: ", scorecard_array.sum() / scorecard_array.size)
测试得分:  0.975

识别手写数字

1
2
3
4
# 打开下载的训练和测试集
training_data_file = open("../GPT神经网络学习/mnist_train.csv",'r')
training_data_list = training_data_file.readlines()
training_data_file.close()

imshow()函数绘制矩形数组

  • 将由逗号分隔,长的文本字符串值,拆分成单个值,在逗号处进行分割
  • 忽略第一个值,一般是标签,将剩余的值转换成28*28的矩阵
  • 绘制数组
1
2
3
all_values = training_data_list[0].split(',')
image_array = np.asfarray(all_values[1:]).reshape([28,28])
plt.imshow(image_array, cmap='Greys',interpolation='None')
<matplotlib.image.AxesImage at 0x1525b492b10>


png

准备MNIST训练数据

  • 将数据的范围缩小到0.01--0.99
  • 因为是训练识别数字,我们的输出层节点应该有10个,输入层为数据的节点784个,隐藏层不好设置,可以先默认为100个
1
2
3
4
5
6
7
8
# 缩放数据为 0.01 到 1.00之间
scaled_input = (np.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01
# print(scaled_input)

# 设置输出层节点,并设置数据标签为训练目标,也就是正确答案
onodes = 10
targets = np.zeros(onodes) + 0.01
targets[int(all_values[0])] = 0.99

训练神经网络

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 设置节点和学习率
input_nodes = 784
hidden_nodes = 100
output_nodes = 10
learning_rate = 0.3

# 创建一个神经网络对象
n = neuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate)

# 导入数据
training_data_file = open("../GPT神经网络学习/mnist_train.csv",'r')
training_data_list = training_data_file.readlines()
training_data_file.close()

# 训练神经网络
for record in training_data_list:
# 分割数据
all_values = record.split(',')
# 缩放数据
inputs = (np.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01
# 创建训练目标
targets = np.zeros(output_nodes) + 0.01
# 设置训练目标,就是数据的标签数据设置会答案
targets[int(all_values[0])] = 0.99
# 训练数据
n.train(inputs, targets)
pass

神经网络编程
http://example.com/2024/10/04/2024-10-04-神经网络编程/
作者
zqten
发布于
2024年10月4日
许可协议