首页 > 技术文章 > 学习Make your own neural network 记录(三)

ChrisInsistPy 2018-05-21 16:36 原文

通过之前两章的学习,基于input, hidden, output, 3层的神经网络,我们尝试来做一些人工智能的小项目。

前两章链接:

第一章 :https://www.cnblogs.com/ChrisInsistPy/p/9002880.html

第二章 :https://www.cnblogs.com/ChrisInsistPy/p/9056066.html 

 

神经网络在机器学习中有很多应用, 比如说,字符识别,字符识别对于人工智能来说是一项不小的挑战,尤其是在识别的过程中,会遇到很多意想不到的困难,比如清晰度,噪音等等。。。

有些时候,对于人类来说,去识别一个图案上的内容,偶尔也会引起分歧,比如说下面这张图,是4,还是9呢??

首先,我们知道图片都是由像素组成的,

在MNIST database => http://yann.lecun.com/exdb/mnist/ 可以下载到很多字符识别的成功数据,测试数据,以及一些training data。

我们下载一个100份的成功数据,先进行分析,下载下来的数据是保存为csv文件格式的,所以我们先读入python 数组中,然后再来分析。

 

def read():
    data_file = open('mnist_dataset/mnist_train_100.csv', 'r')
    data_list = data_file.readlines()
    data_file.close()
    print(data_list[0])

 

首先尝试着打印出第一份数据:

通过观察,发现这组input数据有很多0, 也就是说一会儿我们需要做一下转换,因为0会导致我们的整个weight没法继续更新,导致整个学习过程终止

通过MNIST描述,我们发现数组的第一位,也就是 ‘5‘ 是真实对应的图片数字,从数组下标1开始,后面读到的都是被扫描图片的像素,也就是字符显示的像素,我们通过matplotlib包,把这个像素打印出来,看看是否与结果一致:

def read():
    data_file = open('mnist_dataset/mnist_train_100.csv', 'r')
    data_list = data_file.readlines()
    data_file.close()

    all_values = data_list[0].split(',')
    image_array = numpy.asfarray(all_values[1:]).reshape((28, 28))
    plt.imshow(image_array, cmap='Greys', interpolation='None')
    plt.show()
    pass

 

打印出来的结果为:

通过人工识别,的确是数字5的可能性最大。这些成功数据,可以用来在我们的机器学习完成后,做结果验证。

 

--------------------------------------------------------------------------------------------------分割线------------------------------------------------------------------------------------------

upload 一部分代码,明天做解释:

if __name__ == '__main__':
    input_nodes = 784
    hidden_nodes = 100
    output_nodes = 10

    learning_rate = 0.3
    # create instance of neural network
    n = neuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate)

    # load data of mnist
    data_file = open('mnist_dataset/mnist_train_100.csv', 'r')
    data_list = data_file.readlines()
    data_file.close()

    # train the neural network

    # go through all records in the training data set
    for record in data_list:
        all_values = record.split(',')
        inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01
        targets = numpy.zeros(output_nodes) + 0.01
        targets[int(all_values[0])] = 0.99
        n.train(inputs, targets)
        pass

 

首先把从MNIST数据集下载的两个文件读入数组,第一组为100个训练data,剩下的一组为10组,验证结果datalist。所以在第一个循环中,我们先modify target数组,让target 的数组样式能跟我们需要的output进行对比,所以我们把target设置为真实值的value为0.99,其他为0.01。 在input中,我们同样把range 为0-255像素的input 缩小到理想的0.01-1之间,所以做了一些数学处理。然后传入train方法进行训练。 在for循环运行完毕后,我们初始化时随机的weight就根据100组正确数据 进行了modify。

 

根据https://blog.csdn.net/lz0499/article/details/80212695举出下面的例子,方便理解记忆:

让我们实际计算下一个简单的神经网络中权重(weight)是如何更新的。

下图是我们之前遇到的一个神经网络。但是这次我们添加了每一个隐藏层的输出结果。这些输出结果只是为了演示如何更新权重而设置的,实际中并不一定是这个值。


我们想更新隐藏层和输出之间的权重W1,1。W1,1当前的权重值为2.0.

让我们再一次写出误差斜率表达式:

我们一步一步开始计算:

l  第一部分tk-ok是误差e1=0.8

l  Sigmoid函数中的加权和为2.0*0.4+3.0*0.5=2.3

l  把2.3带入Sigmoid函数得到0.909.中间表达式为0.909*(1-0.909)=0.083

l  最后一部分Oj即使j=1的隐藏层输出,即为oj=0.4

把上述所有部分相乘,不要忘记前面的负号。我们将得到最后的结果为-0.0265。如果我们设置学习率为0.1,则我们需要改变权重W1,1 -(0.1*-0.0265)=0.002650大小,即W11=2.0+0.002650=2.00265。

这个改变值很小,但是经过上千次甚至上万次迭代之后,权重值将固定在某一个数值,表示的是神经网络已经训练好了

 

接下来:

    # Test after 100 dataSet runs
    test_data_file = open('mnist_dataset/mnist_test_10.csv', 'r')
    test_data_list = test_data_file.readlines()
    test_data_file.close()
    scorecard = []
    for record in test_data_list:
        all_values = record.split(',')
        correct_label = int(all_values[0])
        print(correct_label, "correct label")
        inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01
        outputs = n.query(inputs)
        label = numpy.argmax(outputs)
        print(label, "network's answer")
        print('------------------')
        if(label == correct_label):
            scorecard.append(1)
        else:
            scorecard.append(0)
    print(scorecard)

 

接下来用同样的方法,去验证我们训练的结果, 其中all_values[0]是我们之前提到的真实数据的正确值,而numpy.argmax()方法,可以得到每组输出output中的最大值,也就是整个程序根据像素分析出的output结果(对应的数组下标0-9便是结果), 然后把正确的结果计入scorecard value=1, 错误的记为0。

打印出scorecard的结果:

通过100组trainingdata的训练,现在数字识别能力已经达到百分之60的水准!!!也就是performance 达到了百分之60。

Tutorial的作者尝试了另一组实验,也就是用60000组真实数据去training, 然后用10000组真实数据去验证结果,最后得出的performance 高达95.3%。

还有一些优化的方法,比如去调试 learning rate去控制学习率,以及去多次循环training data让神经网络多次学习。

学习次数对结果的影响如图:

当然改变hidden layer的nodes数量也会对学习结果产生影响。

 

完整代码:

import numpy
import scipy.special
class neuralNetwork:
    def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):
        self.inodes = inputnodes
        self.hnodes = hiddennodes
        self.onodes = outputnodes

        self.lr = learningrate
        # generate the link weights between the range of -1 to +1
        self.wih = numpy.random.normal(0.0, pow(self.hnodes, -0.5), (self.hnodes, self.inodes))
        self.who = numpy.random.normal(0.0, pow(self.onodes, -0.5), (self.onodes, self.hnodes))
        self.activation_function = lambda x: scipy.special.expit(x)   # sigmoid
        pass


    # backpropagating result to modify weight
    # 通过output来反向修正weight的值,需要用到之前推倒的公式
    # targets_list is the real effective data, which used to compare with training outputs
    def train(self, inputs_list, targets_list):
        inputs = numpy.array(inputs_list, ndmin=2).T   # .T 是.transpose(), 矩阵转置,行变列,列变行
        targets = numpy.array(targets_list, ndmin=2).T
        hidden_inputs = numpy.dot(self.wih, inputs)  # 矩阵相乘 wih和inputs
        hidden_outputs = self.activation_function(hidden_inputs)
        final_inputs = numpy.dot(self.who, hidden_outputs)
        final_outputs = self.activation_function(final_inputs)

        output_errors = targets - final_outputs
        hidden_errors = numpy.dot(self.who.T, output_errors)
        # 反向推倒,去modify weight的矩阵
        self.who += self.lr * numpy.dot((output_errors * final_outputs * (1.0 - final_outputs))
                                        , numpy.transpose(hidden_outputs))
        self.wih += self.lr * numpy.dot((hidden_errors * hidden_outputs * (1.0 - hidden_outputs))
                                        , numpy.transpose(inputs))
        pass


    #takes input to a neural network and returns the network's output
    #输入input,return output
    def query(self, inputs_list):
        # Convert input list to 2d array
        inputs = numpy.array(inputs_list, ndmin=2).T
        hidden_inputs = numpy.dot(self.wih, inputs)
        hidden_outputs = self.activation_function(hidden_inputs)
        final_inputs = numpy.dot(self.who, hidden_outputs)
        final_outputs = self.activation_function(final_inputs)
        return final_outputs


# Test
if __name__ == '__main__':
    input_nodes = 784
    hidden_nodes = 100
    output_nodes = 10

    learning_rate = 0.2
    # create instance of neural network
    n = neuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate)

    # load data of mnist
    data_file = open('mnist_dataset/mnist_train_100.csv', 'r')
    data_list = data_file.readlines()
    data_file.close()

    # train the neural network

    # go through all records in the training data set
    for record in data_list:
        all_values = record.split(',')
        inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01
        targets = numpy.zeros(output_nodes) + 0.01
        targets[int(all_values[0])] = 0.99 # set the real number => value 0.99 in the output array
        n.train(inputs, targets)
        pass

    # Test after 100 dataSet runs
    test_data_file = open('mnist_dataset/mnist_test_10.csv', 'r')
    test_data_list = test_data_file.readlines()
    test_data_file.close()
    scorecard = []
    for record in test_data_list:
        all_values = record.split(',')
        correct_label = int(all_values[0])
        print(correct_label, "correct label")
        inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01
        outputs = n.query(inputs)
        label = numpy.argmax(outputs)
        print(label, "network's answer")
        print('------------------')
        if(label == correct_label):
            scorecard.append(1)
        else:
            scorecard.append(0)
    scorecard_array = numpy.asarray(scorecard)
    print("performance = ", scorecard_array.sum() / scorecard_array.size)

 

推荐阅读