04 第二章、使用Python进行DIY 2.4

时间:2024-06-03 08:14:52

第 2 章、使用Python进行DIY

2.4、使用Python制作神经网络

2.4.1、框架代码

  神经网络至少有三个函数:
  初始化函数——设定输入层节点、隐藏节点和输出层节点的数量。
  训练——学习给定训练集样本后,优化权重。
  查询——给定输入,从输出节点给出答案。
  框架代码如下:

# 框架代码
# neural network class definition

class neuralNetwork:

    # initialise the neural network
    def __init__():
        pass

    # train the neural network
    def train():
        pass

    # query the neural network
    def query():
        pass
 

2.4.2、初始化网络

  即如何初始化整个神经网络。
  填写之后代码如下:

# 框架代码
# neural network class definition

class neuralNetwork:

    # initialise the neural network
    # 初始化神经网络
    # inputnodes是输入层网络节点的个数
    # hiddennodes是中间层网络节点的个数
    # outputnodes是输出层网络节点的个数
    # learningrate是学习率
    def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):
        # set number of nodes in each input, hidden, output layer
        self.inodes = inputnodes
        self.hnodes = hiddennodes
        self.onodes = outputnodes
        # learning rate
        self.lr = learningrate
        pass

    # train the neural network
    def train():
        pass

    # query the neural network
    def query():
        pass


# number of input, hidden and output nodes
# 设置输入,隐藏和输出层节点的数量
input_nodes = 3
hidden_nodes = 3
output_nodes = 3

# learning rate is 0.3
# 设置学习率为0.3
learning_rate = 0.3

# create instance of neural network
# 创建一个神经网络的实例
n = neuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate)

2.4.3、权重——网络的核心

  因为对于一个如下的神经网络来说:
04 第二章、使用Python进行DIY 2.4
  有:X=W·IW是权重矩阵,I是输入矩阵,X是组合调节后的信号,即:
04 第二章、使用Python进行DIY 2.4
  所以有,输入层和隐藏层之间的链接权重矩阵Winput_hidden的大小是hidden_nodes乘以input_nodes
  同理,隐藏层和输出层之间的链接权重矩阵Whidden_output的大小是output_nodes乘以hidden_nodes

# 框架代码
# neural network class definition
import numpy

class neuralNetwork:

    # initialise the neural network
    # 初始化神经网络
    # inputnodes是输入层网络节点的个数
    # hiddennodes是中间层网络节点的个数
    # outputnodes是输出层网络节点的个数
    # learningrate是学习率
    def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):

        # set number of nodes in each input, hidden, output layer
        # 设置输入,隐藏和输出层节点的数量
        self.inodes = inputnodes
        self.hnodes = hiddennodes
        self.onodes = outputnodes

        # link weight matrices, wih an who
        # 链接权重矩阵
        # wih是输入层和隐藏层之间的链接权重矩阵W_input_hidden
        # who是输入层和隐藏层之间的链接权重矩阵W_hidden_output
        # weights inside the arrays are w_i_j, where link is from node i to node j in the next layer
        # 数组里的权重是wij,其中链接是从节点i到节点j的下一层
        # w11 w21
        # w12 w22
        # numpy.random.rand(X,Y)的意思是生成一个随机数组,数组大小为X*Y,内容为0~1之间
        # 书上之前说这个权重最好是-1~+1,但是他做了个减0.5的操作,就成了-0.5~+0.5
        # 我觉得此处在乘以2效果更好些
        self.wih = (numpy.random.rand(self.hnodes, self.inodes)-0.5)
        self.who = (numpy.random.rand(self.onodes, self.hnodes)-0.5)

        # learning rate
        # 设置学习率
        self.lr = learningrate
        pass

    # train the neural network
    def train():
        pass

    # query the neural network
    def query():
        pass

# number of input, hidden and output nodes
# 设置输入,隐藏和输出层节点的数量
input_nodes = 3
hidden_nodes = 3
output_nodes = 3

# learning rate is 0.3
# 设置学习率为0.3
learning_rate = 0.3

# create instance of neural network
# 创建一个神经网络的实例
n = neuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate)

2.4.4、可选项——较复杂的权重

  上一节在设置权重的时候是随机了一个-0.5~+0.5的数,但是第一章有说过,如果满足-1~+1中取值,并且在一个节点传入链接数量平方根倒数的大致范围内随机采样(见1.16)会更好。
  其实就是中心值为0,标准方差为1/√(节点数),的一个分布。
  用normal函数替代rand函数即可。
  改进后代码如下:

# 框架代码
# neural network class definition
import numpy

class neuralNetwork:

    # initialise the neural network
    # 初始化神经网络
    # inputnodes是输入层网络节点的个数
    # hiddennodes是中间层网络节点的个数
    # outputnodes是输出层网络节点的个数
    # learningrate是学习率
    def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):

        # set number of nodes in each input, hidden, output layer
        # 设置输入,隐藏和输出层节点的数量
        self.inodes = inputnodes
        self.hnodes = hiddennodes
        self.onodes = outputnodes

        # link weight matrices, wih an who
        # 链接权重矩阵
        # wih是输入层和隐藏层之间的链接权重矩阵W_input_hidden
        # who是输入层和隐藏层之间的链接权重矩阵W_hidden_output
        # weights inside the arrays are w_i_j,
        # where link is from node i to node j in the next layer
        # 数组里的权重是wij,其中链接是从节点i到节点j的下一层
        # w11 w21
        # w12 w22
        # numpy.random.normal(a,b,(X,Y))的意思是生成一个随机数组
        # 数组大小为X*Y,内容服从中心值为a,方差为b
        self.wih = numpy.random.normal(
            0.0, pow(self.inodes, -0.5), (self.hnodes, self.inodes))
        self.who = numpy.random.normal(
            0.0, pow(self.inodes, -0.5), (self.onodes, self.hnodes))

        # learning rate
        # 设置学习率
        self.lr = learningrate
        pass

    # train the neural network
    def train():
        pass

    # query the neural network
    def query():
        pass

# number of input, hidden and output nodes
# 设置输入,隐藏和输出层节点的数量
input_nodes = 3
hidden_nodes = 3
output_nodes = 3

# learning rate is 0.3
# 设置学习率为0.3
learning_rate = 0.3

# create instance of neural network
# 创建一个神经网络的实例
n = neuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate)

2.4.5、查询网络

  1、X=W·I公式转换成代码
    公式:X=W·IW是权重矩阵,I是输入矩阵,X是组合调节后的信号
    输入层到中间层的计算,代码:

hidden_inputs = numpy.dot(self.wih, inputs)

    中间层到输出层的计算,代码:

final_inputs = numpy.dot(self.who, hidden_outputs)

  2、sigmod函数转换成代码
    scipy.special这个模块中有sigmod函数的计算,自己就不用写逻辑了。
    声明代码:

# scipy.special for the sigmoid function expit()
import scipy.special

    使用sigmod函数的时候,将sigmod函数用lambda定义为一个内部的函数,不过我感觉这里最好还是使用def定义一个。
    还有,这里使用scipy.special.expit的时候报警告,说是没有这个函数,警告如下:

[pylint] E1101:Module 'scipy.special' has no 'expit' member

    但是,的确能使用,先放下吧。
    定义函数的代码:

# activation function is the sigmod function
self.activation_function = lambda x: scipy.special.expit(x)

    使用函数的代码:

# 计算隐藏层的输出
hidden_outputs = self.activation_function(hidden_inputs)
# 计算输出层的输出
final_outputs = self.activation_function(final_inputs)

  3、改进后的代码:

# 框架代码
# neural network class definition
import numpy
# scipy.special for the sigmoid function expit()
import scipy.special

class neuralNetwork:

    # initialise the neural network
    # 初始化神经网络
    # inputnodes是输入层网络节点的个数
    # hiddennodes是中间层网络节点的个数
    # outputnodes是输出层网络节点的个数
    # learningrate是学习率
    def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):

        # set number of nodes in each input, hidden, output layer
        # 设置输入,隐藏和输出层节点的数量
        self.inodes = inputnodes
        self.hnodes = hiddennodes
        self.onodes = outputnodes

        # link weight matrices, wih an who
        # 链接权重矩阵
        # wih是输入层和隐藏层之间的链接权重矩阵W_input_hidden
        # who是输入层和隐藏层之间的链接权重矩阵W_hidden_output
        # weights inside the arrays are w_i_j,
        # where link is from node i to node j in the next layer
        # 数组里的权重是wij,其中链接是从节点i到节点j的下一层
        # w11 w21
        # w12 w22
        # numpy.random.normal(a,b,(X,Y))的意思是生成一个随机数组
        # 数组大小为X*Y,内容服从中心值为a,方差为b
        self.wih = numpy.random.normal(
            0.0, pow(self.inodes, -0.5), (self.hnodes, self.inodes))
        self.who = numpy.random.normal(
            0.0, pow(self.inodes, -0.5), (self.onodes, self.hnodes))

        # learning rate
        # 设置学习率
        self.lr = learningrate
        # activation function is the sigmod function
        self.activation_function = lambda x: scipy.special.expit(x)
        pass

    # train the neural network
    def train():
        pass

    # query the neural network
    def query(self, inputs_list):
        # convert inputs list to 2d array
        inputs = numpy.array(inputs_list, ndmin=2).T
        # calculate signals into hidden layer
        # 计算隐藏层的输入
        # numpy.dot(X,Y)的意思是两个数组的点乘
        hidden_inputs = numpy.dot(self.wih, inputs)
        # calculate the signals emerging from hidden layer
        # 计算隐藏层的输出
        hidden_outputs = self.activation_function(hidden_inputs)
        # calculate signals into final output layer
        # 计算输出层的输入
        final_inputs = numpy.dot(self.who, hidden_outputs)
        # calculate the signals emerging from final output layer
        # 计算输出层的输出
        final_outputs = self.activation_function(final_inputs)
        pass

# number of input, hidden and output nodes
# 设置输入,隐藏和输出层节点的数量
input_nodes = 3
hidden_nodes = 3
output_nodes = 3

# learning rate is 0.3
# 设置学习率为0.3
learning_rate = 0.3

# create instance of neural network
# 创建一个神经网络的实例
n = neuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate)

2.4.6、迄今为止的代码

  改进上一节的一些小问题。
  1、query函数最后要返回结果,即return final_outputs,然后就可以删除最后的pass 了。
  2、随便加一个数据,进行测试,看看程序是不是能跑

print(n.query((1.0, 0.5, -1.5)))

  3、改到现在的代码:

# 框架代码
# neural network class definition
import numpy
# scipy.special for the sigmoid function expit()
import scipy.special

class neuralNetwork:

    # initialise the neural network
    # 初始化神经网络
    # inputnodes是输入层网络节点的个数
    # hiddennodes是中间层网络节点的个数
    # outputnodes是输出层网络节点的个数
    # learningrate是学习率
    def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):

        # set number of nodes in each input, hidden, output layer
        # 设置输入,隐藏和输出层节点的数量
        self.inodes = inputnodes
        self.hnodes = hiddennodes
        self.onodes = outputnodes

        # link weight matrices, wih an who
        # 链接权重矩阵
        # wih是输入层和隐藏层之间的链接权重矩阵W_input_hidden
        # who是输入层和隐藏层之间的链接权重矩阵W_hidden_output
        # weights inside the arrays are w_i_j,
        # where link is from node i to node j in the next layer
        # 数组里的权重是wij,其中链接是从节点i到节点j的下一层
        # w11 w21
        # w12 w22
        # numpy.random.normal(a,b,(X,Y))的意思是生成一个随机数组
        # 数组大小为X*Y,内容服从中心值为a,方差为b
        self.wih = numpy.random.normal(
            0.0, pow(self.inodes, -0.5), (self.hnodes, self.inodes))
        self.who = numpy.random.normal(
            0.0, pow(self.inodes, -0.5), (self.onodes, self.hnodes))

        # learning rate
        # 设置学习率
        self.lr = learningrate
        # activation function is the sigmod function
        self.activation_function = lambda x: scipy.special.expit(x)
        pass

    # train the neural network
    def train():
        pass

    # query the neural network
    def query(self, inputs_list):
        # convert inputs list to 2d array
        inputs = numpy.array(inputs_list, ndmin=2).T
        # calculate signals into hidden layer
        # 计算隐藏层的输入
        # numpy.dot(X,Y)的意思是两个数组的点乘
        hidden_inputs = numpy.dot(self.wih, inputs)
        # calculate the signals emerging from hidden layer
        # 计算隐藏层的输出
        hidden_outputs = self.activation_function(hidden_inputs)
        # calculate signals into final output layer
        # 计算输出层的输入
        final_inputs = numpy.dot(self.who, hidden_outputs)
        # calculate the signals emerging from final output layer
        # 计算输出层的输出
        final_outputs = self.activation_function(final_inputs)
        return final_outputs

# number of input, hidden and output nodes
# 设置输入,隐藏和输出层节点的数量
input_nodes = 3
hidden_nodes = 3
output_nodes = 3

# learning rate is 0.3
# 设置学习率为0.3
learning_rate = 0.3

# create instance of neural network
# 创建一个神经网络的实例
n = neuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate)
# 测试query函数
print(n.query((1.0, 0.5, -1.5)))

2.4.7、训练网络

  训练网络由两部分组成:
  第一部分:针对给定的训练样本计算输出。这和query中的没啥区别。
  第二部分:将计算得到的输出与所需要的输出进行对比,得到误差,指导网络的权重更新。
  1、定义函数。形参列表,需要两个外部值,一个是输入网络的数据,另一个是目标数据。

def train(self, inputs_list, targets_list):

  2、第一部分代码,和query中的一样,但是加了个target的初始化:

# vonvert inputs list to 2d array
inputs = numpy.array(inputs_list, ndmin=2).T
targets = numpy.array(targets_list, ndmin=2).T
# calculate signals into hidden layer
# 计算隐藏层的输入
# numpy.dot(X,Y)的意思是两个数组的点乘
hidden_inputs = numpy.dot(self.wih, inputs)
# calculate the signals emerging from hidden layer
# 计算隐藏层的输出
hidden_outputs = self.activation_function(hidden_inputs)
# calculate signals into final output layer
# 计算输出层的输入
final_inputs = numpy.dot(self.who, hidden_outputs)
# calculate the signals emerging from final output layer
# 计算输出层的输出
final_outputs = self.activation_function(final_inputs)

  3、第二部分,计算误差部分:
    输出层的误差就是目标输出值减去实际输出值,转换成代码:

output_error = targets-final_outputs

    隐藏层的误差公式前面说过,如下所示:
04 第二章、使用Python进行DIY 2.4
    所以,转换成代码如下:

hidden_error = numpy.dot(self.who.T, output_error)

  4、第二部分,更新权值部分:
    权值的增量公式为:
04 第二章、使用Python进行DIY 2.4
    所以,转换成代码如下:

# 更新隐藏层到输出层的权重
self.who += self.lr * numpy.dot((output_error*final_outputs*(1.0-final_outputs)),numpy.transpose(hidden_outputs))
# 更新输入层到隐藏层的权重
self.wih += self.lr * numpy.dot((hidden_error*hidden_outputs * (1.0-hidden_outputs)), numpy.transpose(inputs))

  5、目前的代码:
    见下一节,此处不赘述了。

2.4.8、完整的神经网络代码

# 框架代码
# neural network class definition
import numpy
# scipy.special for the sigmoid function expit()
import scipy.special

class neuralNetwork:

    # initialise the neural network
    # 初始化神经网络
    # inputnodes是输入层网络节点的个数
    # hiddennodes是中间层网络节点的个数
    # outputnodes是输出层网络节点的个数
    # learningrate是学习率
    def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):

        # set number of nodes in each input, hidden, output layer
        # 设置输入,隐藏和输出层节点的数量
        self.inodes = inputnodes
        self.hnodes = hiddennodes
        self.onodes = outputnodes

        # link weight matrices, wih an who
        # 链接权重矩阵
        # wih是输入层和隐藏层之间的链接权重矩阵W_input_hidden
        # who是输入层和隐藏层之间的链接权重矩阵W_hidden_output
        # weights inside the arrays are w_i_j, where link is from node i to node j in the next layer
        # 数组里的权重是wij,其中链接是从节点i到节点j的下一层
        # w11 w21
        # numpy.random.normal(a,b,(X,Y))的意思是生成一个随机数组,数组大小为X*Y,内容服从中心值为a,方差为b
        self.wih = numpy.random.normal(
            0.0, pow(self.inodes, -0.5), (self.hnodes, self.inodes))
        self.who = numpy.random.normal(
            0.0, pow(self.inodes, -0.5), (self.onodes, self.hnodes))

        # learning rate
        # 设置学习率
        self.lr = learningrate
        # activation function is the sigmod function
        self.activation_function = lambda x: scipy.special.expit(x)
        pass

    # train the neural network
    def train(self, inputs_list, targets_list):
        # vonvert inputs list to 2d array
        inputs = numpy.array(inputs_list, ndmin=2).T
        targets = numpy.array(targets_list, ndmin=2).T
        # calculate signals into hidden layer
        # 计算隐藏层的输入
        # numpy.dot(X,Y)的意思是两个数组的点乘
        hidden_inputs = numpy.dot(self.wih, inputs)
        # calculate the signals emerging from hidden layer
        # 计算隐藏层的输出
        hidden_outputs = self.activation_function(hidden_inputs)
        # calculate signals into final output layer
        # 计算输出层的输入
        final_inputs = numpy.dot(self.who, hidden_outputs)
        # calculate the signals emerging from final output layer
        # 计算输出层的输出
        final_outputs = self.activation_function(final_inputs)
        # output layer error is the (target-actual)
        # 计算输出层的误差
        output_error = targets-final_outputs
        # hidden layer error is the output_error, split by weight,recombined at hidden nodes
        # 计算隐藏层的误差
        hidden_error = numpy.dot(self.who.T, output_error)
        # update the weights for the links between the hidden and output layers
        # 更新隐藏层到输出层的权重
        # 下面行末尾加的反斜杠\的意思是编译的时候忽略换行符
        # 如果一行写不下,在代码末尾加上“\”即可
        # 另外,在括号() {} [] 中的代码不需要换行符“\”,直接换行即可达到同样的效果
        self.who += self.lr * \
            numpy.dot((output_error*final_outputs*(1.0-final_outputs)),
                      numpy.transpose(hidden_outputs))
        # update the weights for the links between the input and hidden layers
        # 更新输入层到隐藏层的权重
        self.wih += self.lr * \
            numpy.dot((hidden_error*hidden_outputs *
                       (1.0-hidden_outputs)), numpy.transpose(inputs))

    # query the neural network
    def query(self, inputs_list):
        # convert inputs list to 2d array
        inputs = numpy.array(inputs_list, ndmin=2).T
        # calculate signals into hidden layer
        # 计算隐藏层的输入
        # numpy.dot(X,Y)的意思是两个数组的点乘
        hidden_inputs = numpy.dot(self.wih, inputs)
        # calculate the signals emerging from hidden layer
        # 计算隐藏层的输出
        hidden_outputs = self.activation_function(hidden_inputs)
        # calculate signals into final output layer
        # 计算输出层的输入
        final_inputs = numpy.dot(self.who, hidden_outputs)
        # calculate the signals emerging from final output layer
        # 计算输出层的输出
        final_outputs = self.activation_function(final_inputs)
        return final_outputs

# number of input, hidden and output nodes
# 设置输入,隐藏和输出层节点的数量
input_nodes = 3
hidden_nodes = 3
output_nodes = 3

# learning rate is 0.3
# 设置学习率为0.3
learning_rate = 0.3

# create instance of neural network
# 创建一个神经网络的实例
n = neuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate)
# 测试query函数
print(n.query((1.0, 0.5, -1.5)))

另:一些说明
1、本博客仅用于学习交流,欢迎大家瞧瞧看看,为了方便大家学习。
2、如果原作者认为侵权,请及时联系我,我的qq是244509154,邮箱是[email protected],我会及时删除侵权文章。
3、我的文章大家如果觉得对您有帮助或者您喜欢,请您在转载的时候请注明来源,不管是我的还是其他原作者,我希望这些有用的文章的作者能被大家记住。
4、最后希望大家多多的交流,提高自己,从而对社会和自己创造更大的价值。