Python BP神经网络实现手写体识别
Posted 今晚看星星
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python BP神经网络实现手写体识别相关的知识,希望对你有一定的参考价值。
文章目录
1 BP公式的推导
- 神经网络的模型
1.1 激活函数
1.1.1 Sigmod
函数导数
- 注意:Sigmod函数与矩阵相乘的时候是对应位置相乘,对应于
numpy.mutiply()
1.2 损失函数
1.3 前向传播
- N为神经网络的输出
1.3 计算误差反向传播
- 矩阵求导时,系数矩阵为导数时,要对其进行求逆
1.3.1 误差为方差时,输出层误差的计算
1.3.2 误差为方差时,隐层层误差的计算
1.4 调整参数
- 其中误差的计算,E对输出Z的偏导即为误差
2 神经网络设计
- 根据BP公式设计神经网络
import numpy as np
class neuron():
def __init__(self, input_len, output_len, is_output_layer, learning_rate): # 构造函数,随机生成网络中的权值与偏置
self.RANDOM_INT = 10
self.is_output_layer = is_output_layer
self.w = np.random.randint(-self.RANDOM_INT, self.RANDOM_INT, (input_len, output_len)).astype(np.float64) / 10
self.b = np.random.randint(-self.RANDOM_INT, self.RANDOM_INT, (1, output_len)).astype(np.float64) / 10
self.output = 0
self.error = 0
self.learning_rate = learning_rate
self.input_data = 0
def active_function(self, input_z):
return 1 / (1 + np.exp(-input_z))
def forward_propagation(self, input_data):
self.input_data = input_data
self.output = self.active_function(np.dot(self.input_data, self.w).astype(np.float64) - self.b)
return self.output
def get_output(self, input_data):
return self.active_function(np.dot(input_data, self.w).astype(np.float64) - self.b)
pass
def back_propagation(self, error, next_w):
if self.is_output_layer:
# 是输出层, sigmod函数与矩阵点成, 采用方差形式的误差
self.error = np.multiply((error - self.output), np.multiply(self.output, 1 - self.output))
return self.error
else:
# 该层不是输出层,则从下一层的误差中,计算本层的误差
self.error = np.multiply(np.multiply(self.output, 1 - self.output), np.dot(error, np.transpose(next_w)))
return self.error
pass
def adjust_param(self, error):
delta_w = np.dot(np.transpose(self.input_data), error)
delta_b = error
self.w = self.w + self.learning_rate * delta_w
self.b = self.b - self.learning_rate * delta_b
pass
3 使用OpenCV 分割图片
3.1 整张图片资源
- 对图片进行分割
import cv2
import os
def cut_image(src_image, dst_src, row_size, col_size):
img_1 = cv2.imread(src_image)
img = cv2.cvtColor(img_1, cv2.COLOR_BGR2GRAY)
row_num = img.shape[0] // row_size
col_num = img.shape[1] // col_size
print(row_num, col_num)
# 保存到不同的文件夹
file_name = 0
file_count = 0
for i in range(row_num):
offset_row = i * row_size
if i % 5 == 0 and i != 0:
file_name += 1
file_count = 0
path = dst_src + "\\\\" + str(file_name)
if not os.path.exists(path):
os.makedirs(path)
for j in range(col_num):
offset_col = j * col_size
filepath = path + "\\\\" + str(file_count) + ".jpg"
file_count += 1
im = img[offset_row:offset_row + row_size - 1, offset_col:offset_col + col_size - 1]
'''
function: cv2.imwrite('F:/images',image,[int(cv2.IMWRITE_JPEG_QUALITY),5])
- 三个参数分别对应保存的路径及文件名、图像矩阵、指定格式
- (对于JPEG,其表示的是图像的质量,用0-100的整数表示,默认为95。
- 注意,cv2.IMWRITE_JPEG_QUALITY类型为Long,必须转换成int;对于PNG,第三个参数表示的是压缩级别。
- cv2.IMWRITE_PNG_COMPRESSION,
- 从0到9,压缩级别越高,图像尺寸越小。这个是可选参数)
'''
cv2.imwrite(filepath, im, [int(cv2.IMWRITE_JPEG_QUALITY), 95])
if __name__ == '__main__':
cut_image("test.png", "images_data", 20, 20) # 块大小为20 * images_test2
pass
分开的图片资源
import cv2
import os
def cut_image(image_src, row_size, column_size, output_src):
image = cv2.imread(image_src)
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 转化为2值灰度图像
row_num = image.shape[0] // row_size # 图像的行数 = 图像行像素 / 子图行像素
col_num = image.shape[1] // column_size # 图像的列数 = 图像列像素 / 子图列像素
print("图像的行数为: ", row_num, "图像的列数为: ", col_num)
file_num = 0
for i in range(row_num):
offset_row = i * row_size # 图像的宽度
path = output_src
if not os.path.exists(path):
os.makedirs(path)
for j in range(col_num):
offset_col = j * column_size
file_path = path + "\\\\" + str(file_num) + ".jpg"
file_num += 1
'''
按照像素的位置取出图像
'''
im = image[offset_row: offset_row + row_size - 1, offset_col: offset_col + column_size - 1]
# 转化为灰度值, 进行保存
'''
function: cv2.imwrite(F:/images',image,[int(cv2.IMWRITE_JPEG_QUALITY),5])
- 三个参数分别对应保存的路径及文件名、图像矩阵、指定格式
- (对于JPEG,其表示的是图像的质量,用0-100的整数表示,默认为95。
- 注意,cv2.IMWRITE_JPEG_QUALITY类型为Long,必须转换成int;对于PNG,第三个参数表示的是压缩级别。
- cv2.IMWRITE_PNG_COMPRESSION,
- 从0到9,压缩级别越高,图像尺寸越小。这个是可选参数)
'''
cv2.imwrite(file_path, im, [int(cv2.IMWRITE_JPEG_QUALITY), 95]) #
if __name__ == '__main__':
cut_image("mnist_test0.jpg", 28, 28, "images/images_test0")
cut_image("mnist_test1.jpg", 28, 28, "images/images_test1")
cut_image("mnist_test2.jpg", 28, 28, "images/images_test2")
cut_image("mnist_test3.jpg", 28, 28, "images/images_test3")
cut_image("mnist_test4.jpg", 28, 28, "images/images_test4")
cut_image("mnist_test5.jpg", 28, 28, "images/images_test5")
cut_image("mnist_test6.jpg", 28, 28, "images/images_test6")
cut_image("mnist_test7.jpg", 28, 28, "images/images_test7")
cut_image("mnist_test8.jpg", 28, 28, "images/images_test8")
cut_image("mnist_test9.jpg", 28, 28, "images/images_test9")
4 进行训练
4.1 读取图片数据,并归一化
-
训练采用灰度图片,读取图片的数据,转化为灰度数据,放入到神经网络中
-
根据图片所在文件夹的顺序,对图片添加分类
-
返回一维的图像灰度矩阵与标签矩阵
import cv2
def select_label(count):
label = []
for i in range(10):
if i == count:
label.append(1)
else:
label.append(0)
return label
pass
def get_array_image(file, count, num):
url = file + "/images_train" + str(count) + "/" + str(num) + ".jpg"
# print("url: ", url)
# images_test1. 读入图片数据
src_image = cv2.imread(url)
new_image = cv2.resize(src_image, (30, 30)) # 缺省,双线性插值
# 3. 转化为灰度图
gray_image = cv2.cvtColor(new_image, cv2.COLOR_BGR2GRAY)
data_list = []
for i in range(len(gray_image)):
data_list.extend(gray_image[i])
label_list = select_label(count)
return data_list, label_list
pass
def get_data_label(file_name, file_num, num_start, num_end):
data_set = []
label_set = []
# 读取多个文件夹
for i in range(file_num):
for j in range(num_start, num_end):
data_row, label_row = get_array_image(file_name, i, j)
data_set.append(data_row)
label_set.append(label_row)
return data_set, label_set
pass
if __name__ == '__main__':
# data, la = get_data_label("train_images", 10, images_test0, 10)
data_row, label_row = get_array_image("train_set_images_cut/train_images/images", 0, 0)
print(data_row)
# print(data)
pass
5.2 对神经网络进行训练,训练好的参数放入Excel文件中
import numpy as np
from neuron import neuron
import data_util
import excel_util
import data_util2
# 激活函数
def sigmoid(value):
return 1 / (1 + np.exp(-value))
pass
def get_e(data_test, label, neurons):
data_set_len = len(data_test)
tmp = 0
for i in range(data_set_len):
# images_test1. 前向传播的输出
output = np.mat(data_test[i]).astype(np.float64)
for neuron_item in neurons:
output = neuron_item.get_output(output)
# images_test2. 计算误差
tmp += np.multiply((output - label[i]), (output - label[i]).T) # .T 为matrix的转置
return tmp / data_set_len
pass
# 进行预测
def predict_test(data_test, label_test, neurons):
right_cnt = 0
# 测试的个数
test_set_len = len(data_test)
# 对数据集的每一个输入进行测试
for i in range(test_set_len):
# # 传播
output = np.mat(data_test[i]).astype(np.float64)
for neuron_item in neurons:
output = neuron_item.get_output(output)
predict_class = 1000
for row in range(output.shape[0]):
for col in range(output.shape[1]):
if output[row, col] >= 0.5:
predict_class = col
break
label_class = 1000
for index in range(len(label_test[i])):
if label_test[i][index] == 1:
label_class = index
break
print("第", i + 1, "次预测:predict: ", output, ", \\n真实: ", label_test[i])
print("第", i + 1, "次预测:predict: ", predict_class, ", \\n真实: ", label_class)
if predict_class == label_class != 1000:
right_cnt += 1
return right_cnt / test_set_len
def plot_e(a_list):
import matplotlib.pyplot as plt
x = np.arange(1, len(a_list) + 1)
y = np.array(a_list) # 转化为向量
print("最后误差:", y[-1])
# 绘制
plt.plot(x, y)
plt.xlabel("practiseTime")
plt.ylabel("variance")
plt.show()
pass
def main():
# 设置训练图片的范围
file_num = 10
train_num_start = 0
train_num_end = 300
data_set, label_set = data_util2.get_data_label("train_set_images_cut/train_images/images", file_num, train_num_start, train_num_end)
# images_test1. 设置神经网络的参数
input_len = len(data_set[0])
hidden_one_len = 50
output_len = len(label_set[0])
# 构建三层神经网络
hidden_one_layer = neuron(input_len, hidden_one_len, False, 0.01)
output_layer = neuron(hidden_one_len, output_len, True, 0.01)
# 进行一定次数的训练
a_list = []
for num in range(150):
for j in range(len(data_set)):
# 进行训练
# images_test1. 前向传播
hidden_one_output = hidden_one_layer.forward_propagation(np.mat(data_set[j]).astype(np.float64))
output_one_later = output_layer.forward_propagation(hidden_one_output)
# images_test2. 计算误差
error_2 = output_layer.back_propagation(label_set[j], 1)
error_1 = hidden_one_layer.back_propagation(error_2, output_layer.w)
# 3. 反向传播
output_layer.adjust_param(error_2)
hidden_one_layer.adjust_param(error_1)
# 计算方差误差,为数组中绝对值的和
e = get_e(data_set, label_set, [hidden_one_layer, output_layer])
e_value = 0
for row in range(len(e)):
for col in range(len(e[0])):
e_value = e_value + e[row, col]
a_list.append(abs(e_value))
# 保存数据到txt文件
excel_util.save_matrix2excel(hidden_one_layer.w, "excel_param/hidden_one_layer_w1.xlsx")
excel_util.save_matrix2excel(hidden_one_layer.b, "excel_param/hidden_one_layer_b1.xlsx")
excel_util.save_matrix2excel(output_layer.w, "excel_param/output_layer_w1.xlsx")
excel_util.save_matrix2excel(output_layer.b, "excel_param/output_layer_b1.xlsx")
# 绘制方差的图像
plot_e(a_list)
# 设置测试图片的范围
test_num_start = 100
test_num_end = 120
data_set_test, label_set_test = data_util2.get_data_label("train_set_images_cut/train_images/images", file_num, test_num_start, test_num_end)
rate = predict_test(data_set_test, label_set_test, [hidden_one_layer, output_layer])
print("预测的正确率为: ", rate * 100, "%")
pass
if __name__ == '__main__':
main()
6 进行预测
- 读取Excel文件中网络的参数进行预测
6.1 存取excel工具
import pandas as pd
import numpy as np
def save_matrix2excel(mat, dst_path):<以上是关于Python BP神经网络实现手写体识别的主要内容,如果未能解决你的问题,请参考以下文章