神经网络Deep Learning

《Python神经网络编程》读书笔记

2018-10-20  本文已影响706人  7155e3de5658

第一章 神经网络如何工作

1.8 矩阵乘法大有用途

neutral networks中 X = W * input 的大致样子:

1.10 学习来自多个节点的权重

输出误差和误差的分配:

1.12 反向传播误差到更多层中

如果神经网络有多个层,那么我们就从最终的输出层往回工作。

对于隐藏层的结点,我们没有目标值(所希望的输出值)。我们只有最终输出节点的目标值,那么我们如何找到隐藏层结点的目标值呢?

观察上图可以看到,隐藏层的第一个结点有两个节点,分别指向输出层的1,2. 此时我们有两个输出节点的误差,我们在这里就重组这两个链接的误差,形成隐藏层结点的误差。

E(hidden, 1) = E(output, 1) * (w11 / w11 + w21) + E(output, 2) * (w12 / w12 + w22)

1.13 利用矩阵乘法进行反向传播误差

隐藏层误差的矩阵计算:

其中前一个矩阵,每一列的分母都是相同的,代表分给下一层同一个结点的权重之和。即 (W11 + W21 + W31 + W41 ....)

这些分数的分母是一种归一化因子,如果忽略这个因子,矩阵乘法会非常好辨认:

此时前一个矩阵等于 Whidden_output 的转置

Whidden_output = [
w11 w21 w31 ...
w12 w22 w32 ...
w13 w23 w33 ...
]

如果我们要进一步思考这个问题,那么我们可以观察到,即使反馈的 误差过大或过小,在下一轮的学习迭代中,网络也可以自行纠正。重要的 是,由于链接权重的强度给出了共享误差的最好指示,因此反馈的误差应 该遵循链接权重的强度。

1.14 我们实际上如何更新权重

1.14.1 误差函数的选择

我们在这里有几个误差函数的选择。

  1. 误差 = 目标值 - 实际值

如果我们观察所有节点的误差值和,如果为0,我们会认为得到了很好的训练。但是实际上是正负误差抵消。

  1. 误差 = | 目标值 - 实际值 |

为了纠正1中的错误,我们采用差的绝对值。但是斜率在最小值附近不是连续的,这使得梯度下降方法无法很好地发挥作用 (The reason this isn’t popular is because the slope isn’t continuous near the minimum )。由于这个误差函数,我们会在V型山谷附近来回跳动。

在这种情况下,即使接近了最小值,斜率也不会变的很小,因此我们的步长也不会变小,有超调的风险 (The slope doesn’t get smaller closer to the minimum, so our steps don’t get smaller, which means they risk overshooting. )

  1. 误差 = (目标值 - 真实值)^ 2

我们选择第三种误差函数的,原因有以下几点:

1.14.2 误差对权重变化的推导

使用Python进行DIY

2.4 使用Python制作神经网络

2.4.4 较复杂的权重

有些人比较喜欢较复杂的方法来随机初始化权重。即使用正态分布采样权重,其中平均值为0标准方差为传入链接数目的开方(1/√(number of incoming links)。

numpy代码如下:

self.weighti2h = (np.random.normal(0.0, pow(self.hnodes, -0.5), (self.hnodes, self.inodes)))
self.weighth2o = (np.random.normal(0.0, pow(self.onodes, -0.5), (self.onodes, self.hnodes)))

疑问:number of incoming links的数目对于 weight of input to hidden应该是input nodes?为何书上为hnodes?

myNeutralNetworks类完整代码

实际代码不长,其中包括了我在写代码过程中的一些注释,可以帮助看的清楚一点。

import numpy as np
import scipy.special

class neutralNetworks:

    def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):
        self.inodes = inputnodes
        self.hnodes = hiddennodes
        self.onodes = outputnodes

        self.lr = learningrate

        '''
        权重矩阵的大小为 hiddennodes * inputnodes
        例如:

        W1,1 W2,1 W3,1 ...
        W1,2 W2,2 W3,2 ...
        W1,3 W2,3 W3,3 ...

        numpy 中的 random.rand() 函数在这里生成大小为x*y的,数值在0~1之间的数组。

        self.weighti2h = (np.random.rand(self.hnodes, self.inodes) - 0.5)
        self.weighth2o = (np.random.rand(self.onodes, self.hnodes) - 0.5)

        有些人喜欢用正态分布采样权重,其中平均值为0,方差为1/√传入链接数目
        采用 numpy 中的 random.normal()可以实现。
        其中0.0是正态分布的中心,pow(self.hnodes, -0.5)表示结点数目的0.5次方。

        '''
        self.weighti2h = (np.random.normal(0.0, pow(self.hnodes, -0.5), (self.hnodes, self.inodes)))
        self.weighth2o = (np.random.normal(0.0, pow(self.onodes, -0.5), (self.onodes, self.hnodes)))

        '''
        定义激活函数
        '''
        self.activation_function = lambda x: scipy.special.expit(x)

        pass

    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.weighti2h, inputs)
        hidden_outputs = self.activation_function(hidden_inputs)

        final_inputs = np.dot(self.weighth2o, hidden_outputs)
        final_outputs = self.activation_function(final_inputs)

        output_errors = targets - final_outputs

        '''
        output_errors = 
        [
            1,
            2,
            3,
            4
        ]

        weighth2o = 
        [
            W1,1 W2,1 W3,1 ...
            W1,2 W2,2 W3,2 ...
        ]

        weighth2o.T = 
        [
            W1,1 W1,2 W1,3 ...
            W2,1 W2,2 W2,3 ...
            W3,1 W3,1 W3,3 ...
        ]

        hidden_error = dot(wieghth2o.T, output_errors) = 
        [
            W1,1*ERROR1 + W1,2*ERROR2 + W1,3*ERROR3 + ...,
            W2,1*ERROR1 + W2,2*ERROR2 + W2,3*ERROR3 + ...,
            ...
        ]
        '''
        hidden_errors = np.dot(self.weighth2o.T, output_errors)
        self.weighth2o += self.lr * np.dot((output_errors * final_outputs * (1.0 - final_outputs)), np.transpose(hidden_outputs))
        self.weighti2h += self.lr * np.dot((hidden_errors * hidden_outputs * (1.0 - hidden_outputs)), np.transpose(inputs))
        
        pass
    
    # 给定输出,从输出节点获得答案
    def query(self, inputs_list):
        '''
        convert inputs list to 2d array

        ndmin means minimum dimensions:

        >>> np.array([1, 2, 3], ndmin=2)
        array([[1, 2, 3]])

        >>> np.array([1.0, 0.5, -1.5], ndmin=2).T
        array([[ 1. ],
              [ 0.5],
              [-1.5]])
        '''
        inputs = np.array(inputs_list, ndmin=2).T

        hidden_inputs = np.dot(self.weighti2h, inputs)
        hidden_outputs = self.activation_function(hidden_inputs)

        final_inputs = np.dot(self.weighth2o, hidden_outputs)
        final_outputs = self.activation_function(final_inputs)

        return final_outputs

在jupyter notebook中测试myNeutralNetwork类

1. 数据读入

data_file = open("mnist_train_100.csv", "r")
data_list = data_file.readlines()
data_file.close()

2. 数据示例

3. matplotlib展示第count个数字

def showNumber(count):
    all_values = data_list[count].split(",")
    # Return an array converted to a float type.
    # 在这里将文本字符串转换为实数
    image_array = np.asfarray(all_values[1:]).reshape((28, 28))
    plt.imshow(image_array, cmap='Greys', interpolation='None')

4. 数据缩放

将数据缩放到0.01 ~ 1.0的范围。

将0.01作为范围最低点是为了避免输入的0值造成权重更新失败。

将0 ~ 255范围内的值除以255,得到0 ~ 1;随后将输入值乘以0.99,将他们范围变成0.0 ~ 0.99;接下来加上0.01,将输入值编程0.01 ~ 1.00。

scaled_input = (np.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01

5. 每个节点的目标矩阵

all_values[0]为数字的标记。

targets = np.zeros(output_nodes) + 0.01
targets[int(all_values[0])] = 0.99

训练的完整代码

from myNeutralNetworks import neutralNetworks 

input_nodes = 784
hidden_nodes = 100
output_nodes = 10

learning_rate = 0.1

n = neutralNetworks(input_nodes, hidden_nodes, output_nodes, learning_rate)

path_train_file = "mnist_train.csv"
path_test_file = "mnist_test.csv"

train_file = open(path_train_file, "r")
test_file = open(path_test_file, "r")

train_data_list = train_file.readlines()
test_data_list = test_file.readlines()

train_file.close()
test_file.close()

print(len(train_data_list), len(test_data_list))

epoch = 5
for e in range(epoch):
    for record in train_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)
        
    count = 0
    for data in test_data_list:
        label = data[0]
        image = (np.asfarray(data.split(",")[1:]) / 255.0 * 0.99 ) + 0.01
        # find the index of highest value
        res = np.argmax(n.query(image))
        if int(label) == res:
            count += 1

    print("test accuracy is ", count/10000)

输出:

test accuracy is 0.952
test accuracy is 0.9616
test accuracy is 0.9665
test accuracy is 0.9662
test accuracy is 0.9681

上一篇 下一篇

猜你喜欢

热点阅读