手动搭建神经网络应用于手写数字识别

import numpy as np
import scipy.special
import matplotlib.pyplot as plt
from PIL import Image

class neuralNetwork :

    # 用于神经网络初始化
    def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):
        # 输入层节点数
        self.inodes = inputnodes
        # 隐层节点数
        self.hnodes = hiddennodes
        # 输出层节点数
        self.onodes = outputnodes
        # 学习率
        self.lr = learningrate

        # 初始化输入层与隐层之间的权重
        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))

        # 激活函数(S函数)
        self.activation_function = lambda x: scipy.special.expit(x)
        # 逆激活函数
        self.iactivation_function = lambda y: scipy.special.logit(y)

    # 设置权重
    def setweights(self, wih, who):
        self.wih = wih
        self.who = who

    # 神经网络学习训练
    def train(self, inputs_list, targets_list):
        # 将输入数据转化成二维矩阵
        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_errors = 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_errors * hidden_outputs * (1.0 - hidden_outputs)), np.transpose(inputs))

    # 根据标签逆向生成图片
    def makeinput(self, outputs_list):
        # 将标记数据(输出层的输出)转化成二维矩阵
        final_outputs = np.array(outputs_list, ndmin=2).T
        # 计算输出层的输入
        final_inputs = self.iactivation_function(final_outputs)

        # 计算隐层的输出
        hidden_outputs = np.dot(self.who.T, final_inputs)
        # 处理下限使得下限为0
        hidden_outputs -= np.min(hidden_outputs)
        # 处理上限使得上限为1
        hidden_outputs /= np.max(hidden_outputs)
        hidden_outputs *= 0.98
        hidden_outputs += 0.01
        # 计算隐层的输入
        hidden_inputs = self.iactivation_function(hidden_outputs)
        # 计算输入层的数据
        inputs = np.dot(self.wih.T, hidden_inputs)
        inputs -= np.min(inputs)
        inputs /= np.max(inputs)
        inputs *= 255
        print(inputs)
        return inputs


    # 神经网络测试
    def test(self, inputs_list):
        # 将输入数据转化成二维矩阵
        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

# 训练神经网络
def train_neuralnetwork():
    # 初始化 784(28 * 28)个输入节点,100个隐层节点,10个输出节点(0~9)
    input_nodes = 784
    hidden_nodes = 200
    output_nodes = 10

    # 学习率0.3
    learning_rate = 0.1
    # 训练次数
    epochs = 5
    # 初始化神经网络实例
    n = neuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate)

    # 读取训练集
    training_data_file = open('mnist_dataset/mnist_train.csv', 'r')
    training_data_list = training_data_file.readlines()
    training_data_file.close()

    # 训练数据
    for e in range(epochs):
        for record in training_data_list:
            all_values = record.split(',')
            # 输入数据范围(0.01~1)
            inputs = np.asfarray(all_values[1:]) / 255.0 * 0.99 + 0.01
            # 标记数据(相应标记为0.99,其余0.01)
            targets = np.zeros(output_nodes) + 0.01
            targets[int(all_values[0])] = 0.99
            n.train(inputs, targets)

    np.savetxt('weights/who_60000.csv', n.who, delimiter=',')
    np.savetxt('weights/wih_60000.csv', n.wih, delimiter=',')

# 验证性能
def pre_acc():

    # 初始化 784(28 * 28)个输入节点,100个隐层节点,10个输出节点(0~9)
    input_nodes = 784
    hidden_nodes = 200
    output_nodes = 10

    # 学习率0.1
    learning_rate = 0.1

    # 初始化神经网络实例
    n = neuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate)

    # 读取测试数据
    test_data_file = open('mnist_dataset/mnist_test.csv', 'r')
    test_data_list = test_data_file.readlines()
    test_data_file.close()

    # 性能分析(正确率)
    wih = np.loadtxt(open('weights/wih_60000.csv'), delimiter=",", skiprows=0)
    who = np.loadtxt(open('weights/who_60000.csv'), delimiter=",", skiprows=0)
    n.setweights(wih, who)
    scorecard = []
    for record in test_data_list:
        # 读取测试集中的每个数据,进行预测
        test_data = record.split(',')
        correct_label = int(test_data[0])
        outputs = n.test(np.asfarray(test_data[1:]) / 255.0 * 0.99 + 0.01)
        # 找到每次预测结果中最大值的索引(即,预测的标签)
        pre_label = np.argmax(outputs)
        # 如果预测正确,则得1分,否则得0分
        if pre_label == correct_label:
            scorecard.append(1)
        else:
            scorecard.append(0)
    print(scorecard)
    # 计算正确率
    scorecard_array = np.asarray(scorecard)
    accuracy = scorecard_array.sum() / scorecard_array.size
    print(accuracy)

# 单个预测
def pre_one():
    # 初始化 784(28 * 28)个输入节点,100个隐层节点,10个输出节点(0~9)
    input_nodes = 784
    hidden_nodes = 200
    output_nodes = 10

    # 学习率0.1
    learning_rate = 0.1
    # 初始化神经网络实例
    n = neuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate)

    # 读取测试数据
    test_data_file = open('mnist_dataset/mnist_test_10.csv', 'r')
    test_data_list = test_data_file.readlines()
    test_data_file.close()

    # 打印测试数据标签
    test_data = test_data_list[0].split(',')
    print('原标签:', test_data[0])

    # 生成标签图片
    image_array = np.asfarray(test_data[1:]).reshape(28, 28)
    plt.imshow(image_array, cmap='Greys', interpolation='None')
    plt.show()

    # 利用神经网络预测
    wih = np.loadtxt(open('weights/wih_60000.csv'), delimiter=",", skiprows=0)
    who = np.loadtxt(open('weights/who_60000.csv'), delimiter=",", skiprows=0)
    n.setweights(wih, who)
    results = n.test(np.asfarray(test_data[1:]) / 255.0 * 0.99 + 0.01)
    pre_label = np.argmax(results)
    print('预测结果:', pre_label)
    print(results)

# 根据标签逆向生成图片
def pre_imakepic():
    # 初始化 784(28 * 28)个输入节点,100个隐层节点,10个输出节点(0~9)
    input_nodes = 784
    hidden_nodes = 200
    output_nodes = 10

    # 学习率0.1
    learning_rate = 0.1
    # 初始化神经网络实例
    n = neuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate)

    # 要制作的标签
    want_label = 0
    # 生成相应的输出层的输出数据
    label_data = np.zeros(output_nodes) + 0.01
    label_data[int(want_label)] = 0.99
    wih = np.loadtxt(open('weights/wih_60000.csv'), delimiter=",", skiprows=0)
    who = np.loadtxt(open('weights/who_60000.csv'), delimiter=",", skiprows=0)
    n.setweights(wih, who)
    res_inputs = n.makeinput(label_data)

    # 生成标签图片
    image_array = np.asfarray(res_inputs).reshape(28, 28)
    plt.imshow(image_array, cmap='Greys', interpolation='None')
    plt.show()

# 手写照片识别
def pre_pic():
    # 初始化 784(28 * 28)个输入节点,100个隐层节点,10个输出节点(0~9)
    input_nodes = 784
    hidden_nodes = 200
    output_nodes = 10

    # 学习率0.1
    learning_rate = 0.1
    # 初始化神经网络实例
    n = neuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate)

    # 读取带预测图片
    img = Image.open('picture/2.jpg').convert('L')
    newimg = img.resize((28, 28), Image.ADAPTIVE)
    # newimg.save('picture/2_resize.jpg')
    test_pic = np.array(newimg)

    # 利用神经网络预测
    wih = np.loadtxt(open('weights/wih_60000.csv'), delimiter=",", skiprows=0)
    who = np.loadtxt(open('weights/who_60000.csv'), delimiter=",", skiprows=0)
    n.setweights(wih, who)
    # 正常255表示白色,但mnist数据集255表示黑色,所以现实图片颜色应该翻转一下
    results = n.test(np.asfarray(255.0 - test_pic.flatten()) / 255.0 * 0.99 + 0.01)
    pre_label = np.argmax(results)
    print('预测结果:', pre_label)
    print(results)

if __name__ == "__main__":
    # train_neuralnetwork()
    pre_pic()
    # pre_imakepic()
    # pre_one()
    # pre_acc()

注:代码是对《Python神经网络编程》中代码的扩展。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章