BP神经网络的手写体识别 Python3

1 BP公式的推导

  1. 神经网络的模型
    在这里插入图片描述

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

3.2 Mnist数据集

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 读取图片数据,并归一化

  • 训练采用灰度图片,读取图片的数据,转化为灰度数据,放入到神经网络中
  • 根据图片所在文件夹的顺序,对图片添加分类
def select_label(count):
    label = []
    for i in range(10):
        if i == count:
            label.append(1)
        else:
            label.append(0)
    return label
    pass

在这里插入图片描述

  • 返回一维的图像灰度矩阵与标签矩阵
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] / 255)

    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):
    data = pd.DataFrame(mat)
    data.to_excel(dst_path)
    pass


def read_excel2matrix(url):
    sheet = pd.read_excel(url)
    return np.mat(sheet)[:, 1:]  # 去掉第一列,为次序列
    pass


if __name__ == '__main__':
    # matrix = np.mat([[images_test1, images_test2], [3, 4]])
    # save_matrix2excel(matrix, "test.xlsx")
    data = read_excel2matrix("test.xlsx")
    print(data)
    pass

6.2 读取参数后进行预测

  • 自定义文件结构

在这里插入图片描述

  • 工具类
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, row_size, col_size):
    url = file + "/images_test" + str(count) + "/" + str(num) + ".jpg"

    # print("url: ", url)
    src_image = cv2.imread(url)
    new_image = cv2.resize(src_image, (row_size, col_size))  # 缺省,双线性插值
    # 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, row_size, col_size):
    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, row_size, col_size)
            data_set.append(data_row)
            label_set.append(label_row)
    return data_set, label_set
    pass


if __name__ == '__main__':
    data_row, label_row = get_array_image("images", 0, 0)
    print(data_row)
    pass

  • 测试函数
from neuron import neuron
import numpy as np
import excel_util
import data_util


# 进行预测
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 main():
    # 读取excel中的数据
    hidden_one_layer_w = excel_util.read_excel2matrix("excel_param/hidden_one_layer_w.xlsx")
    hidden_one_layer_b = excel_util.read_excel2matrix("excel_param/hidden_one_layer_b.xlsx")
    output_layer_w = excel_util.read_excel2matrix("excel_param/output_layer_w.xlsx")
    output_layer_b = excel_util.read_excel2matrix("excel_param/output_layer_b.xlsx")

    # 输出矩阵的维数
    print(hidden_one_layer_w.shape)
    print(hidden_one_layer_b.shape)
    print(output_layer_w.shape)
    print(output_layer_b.shape)

    # 定义网络参数

    hidden_one_layer = neuron(hidden_one_layer_w.shape[0], hidden_one_layer_w.shape[1], False, 0.01)
    output_layer = neuron(hidden_one_layer_w.shape[1], output_layer_w.shape[1], True, 0.01)

    hidden_one_layer.w = hidden_one_layer_w
    hidden_one_layer.b = hidden_one_layer_b
    output_layer.w = output_layer_w
    output_layer.b = output_layer_b

    # 设置测试图片的范围
    file_num = 10
    test_num_start = 0
    test_num_end = 200
    data_set_test, label_set_test = data_util.get_data_label("predict_images", file_num, test_num_start, test_num_end, 30, 30)
    rate = predict_test(data_set_test, label_set_test, [hidden_one_layer, output_layer])
    print("预测的正确率为: ", rate * 100, "%")
    pass


if __name__ == '__main__':
    main()
    pass

6.3 误差

在这里插入图片描述

6.4 预测结果

在这里插入图片描述

在这里插入图片描述

  • 17
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
BP神经网络是一种常用的神经网络模型,它可以用于手写体识别任务。在Python中,可以使用各种深度学习框架(如TensorFlow、Keras、PyTorch等)实现BP神经网络手写体识别任务通常需要对输入的图像进行预处理,将其转化为适合BP神经网络输入的格式。常用的预处理方法包括灰度化、二值化、调整图像大小等。 BP神经网络模型一般由输入层、隐藏层和输出层组成,其中隐藏层的神经元数量和层数需要根据具体任务进行调整。训练BP神经网络通常需要进行反向传播算法,在优化损失函数的过程中不断更新模型参数。 下面是一个使用Keras实现手写体识别BP神经网络的示例代码: ``` from keras.datasets import mnist from keras.models import Sequential from keras.layers import Dense, Dropout from keras.optimizers import RMSprop # 加载MNIST数据集 (x_train, y_train), (x_test, y_test) = mnist.load_data() # 预处理数据集 x_train = x_train.reshape(60000, 784) x_test = x_test.reshape(10000, 784) x_train = x_train.astype('float32') x_test = x_test.astype('float32') x_train /= 255 x_test /= 255 # 将标签转化为one-hot编码 num_classes = 10 y_train = keras.utils.to_categorical(y_train, num_classes) y_test = keras.utils.to_categorical(y_test, num_classes) # 构建BP神经网络模型 model = Sequential() model.add(Dense(512, activation='relu', input_shape=(784,))) model.add(Dropout(0.2)) model.add(Dense(512, activation='relu')) model.add(Dropout(0.2)) model.add(Dense(num_classes, activation='softmax')) model.summary() # 编译模型 model.compile(loss='categorical_crossentropy', optimizer=RMSprop(), metrics=['accuracy']) # 训练模型 batch_size = 128 epochs = 20 history = model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, verbose=1, validation_data=(x_test, y_test)) # 评估模型性能 score = model.evaluate(x_test, y_test, verbose=0) print('Test loss:', score) print('Test accuracy:', score) ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值