zoukankan      html  css  js  c++  java
  • 构建一个简单的神经网络

    1. 模型阐述

    假设我们有下面的一组数据

    输入1输入2输入3输出
    0 0 1 0
    1 1 1 1
    1 0 1 1
    0 1 1 0

    对于上面的表格,我们可以找出其中的一个规律是:

    输入的第一列和输出相同

    那对于输入有3列,每列有0和1两个值,那可能的排列有(2^3=8)种,但是此处只有4种,那么在有限的数据情况下,我们应该怎么预测其他结果呢?
    这个时候神经网络就大显身手了!

    如下图:输入1,2,3作为输入变量x1,x2,x3.输出作为o

    将输入x1,x2,x3乘上相应的权重,然后做累加之后作为sigmoid单元的输入。sigmoid的输出定义为o。

    sigmoid函数:

    ,它有一个很有用的特征,就是它的导数很容易用它的输出来表示:,后面将会用到这个特征。

    定义一个误差:

     

    w=(w1,w2,w3),td和od分为训练样例的输出和定义模型的输出。

    接下来的工作就是在w的假设空间(三维空间)中寻找一个最佳复合训练样例的w,即使得上面定义的误差最小。


    标准梯度下降算法:

    1、初始化网络权重w1,w2,w3为小的随机值。

    2、在遇到终止条件之前:

      2.1、初始化每个Δwi为0

      2.2、对于每个训练样例<x,t>,做:

        把x输入到此单元中,计算输出o

        对于每个权值调整Δwi,做:

          Δwi = Δwi+η*o*(1-o)(t-o)*xi

      2.3、对于每个权值wi,做:

        wi = wi+Δwi 


     随机梯度下降,寻找最佳w。算法如下:

    1、初始化网络权重w1,w2,w3为小的随机值。

    2、在遇到终止条件之前:

      对于训练样例中的每个<x,t>,比如上面的模型中的四个样例,做:

      2.1、把x输入网络,计算网络的输出o

      2.2、对于网络的输出单元计算它的误差,δ=o(1-o)(t-o)。t为训练样例给出的目标输出值。

      2.3、更新每个权值。wi <— wi+Δwi; Δwi = η*δ*xi。 η是学习速率,是一个比较小的值。


    算法说明:

    ,求这个误差项的最小值。它是一个关于变量w1,w2,w3的一个函数。为了确定一个使E最小化的权向量,梯度下降搜索从一个任意的初始权向量开始,然后以很小的步伐反复修改这个向量。每一步都沿误差曲面产生最陡峭下降的方向修改权向量。继续这个过程直到得到全局的最小误差点。

    如何获取最陡峭的方向?

    计算E相对向量w各个分量的导数,得到该点的梯度为最陡峭的方向。

    确定最陡峭的方向为梯度,那么梯度下降的训练法则是:

    写成分量的形式为:

    接着就是求:

    标准的梯度下降算法的对所有的样例汇总的误差。如图所示:

    带入上面的Δwi得出:

    , 与上面的标准梯度下降算法中的一致。

    下面说明随机梯度下降算法:


     随机梯度下降的权值是通过考查每个训练样例来更新的,它可以以任意的程度接近标准梯度下降,只有学习速率η足够小。

    因为随机梯度是对单个的样例来更新权值。定义一个类似的误差函数:

    ,其中td和od是训练样例d的目标输出值和单元输出值。随机梯度下降迭代计算训练样例D中的每个训练样例d,在每次迭代过程中按照关于的梯度来改变权值。

    下面来计算针对单个样例的

    推导出:

    。与上面的随机梯度下降算法一致。

    下面基于标准梯度下降算法的代码实现如下:

    from numpy import exp, array, random, dot
    
    class NeuralNetwork():
        def __init__(self):
            # Seed the random number generator, so it generates the same numbers
            # every time the program runs.
            random.seed(1)
    
            # We model a single neuron, with 3 input connections and 1 output connection.
            # We assign random weights to a 3 x 1 matrix, with values in the range -1 to 1
            # and mean 0.
            self.synaptic_weights = 2 * random.random((3, 1)) - 1
            self.sigmoid_derivative = self.__sigmoid_derivative
    
        # The Sigmoid function, which describes an S shaped curve.
        # We pass the weighted sum of the inputs through this function to
        # normalise them between 0 and 1.
        def __sigmoid(self, x):
            return 1 / (1 + exp(-x))
    
    
    
        # The derivative of the Sigmoid function.
        # This is the gradient of the Sigmoid curve.
        # It indicates how confident we are about the existing weight.
        def __sigmoid_derivative(self, x):
            return x * (1 - x)
    
        # We train the neural network through a process of trial and error.
        # Adjusting the synaptic weights each time.
        def train(self, training_set_inputs, training_set_outputs, number_of_training_iterations):
            for iteration in range(number_of_training_iterations):
                # Pass the training set through our neural network (a single neuron).
                output = self.think(training_set_inputs)
    
                # Calculate the error (The difference between the desired output
                # and the predicted output).
                error = training_set_outputs - output
    
                # Multiply the error by the input and again by the gradient of the Sigmoid curve.
                # This means less confident weights are adjusted more.
                # This means inputs, which are zero, do not cause changes to the weights.
                adjustment = dot(training_set_inputs.T, error * self.__sigmoid_derivative(output))
    
                # Adjust the weights.
                self.synaptic_weights += adjustment
    
        # The neural network thinks.
        def think(self, inputs):
            # Pass inputs through our neural network (our single neuron).
            return self.__sigmoid(dot(inputs, self.synaptic_weights))
    #Intialise a single neuron neural network.
    neural_network = NeuralNetwork()
    
    print("Random starting synaptic weights: ")
    print(neural_network.synaptic_weights)
    
    # The training set. We have 4 examples, each consisting of 3 input values
    # and 1 output value.
    training_set_inputs = array([[0, 0, 1], [1, 1, 1], [1, 0, 1], [0, 1, 1]])
    training_set_outputs = array([[0, 1, 1, 0]]).T
    
    # Train the neural network using a training set.
    # Do it 10,000 times and make small adjustments each time.
    neural_network.train(training_set_inputs, training_set_outputs, 10000)
    
    print("New synaptic weights after training: ")
    print(neural_network.synaptic_weights)
    
    # Test the neural network with a new situation.
    print("Considering new situation [1, 0, 0] -> ?: ")
    print(neural_network.think(array([1, 0, 0])))

     输出结果:

    Random starting synaptic weights:
    [[-0.16595599]
    [ 0.44064899]
    [-0.99977125]]
    New synaptic weights after training:
    [[ 9.67299303]
    [-0.2078435 ]
    [-4.62963669]]
    Considering new situation [1, 0, 0] -> ?:
    [ 0.99993704]

    下面是在上面的代码改动为随机梯度下降算法:

    '''
    Created on 2017年2月22日
    
    @author: LBX
    '''
    
    from numpy import exp, array, random, dot
    
    class NeuralNetwork():
        
        def __init__(self):
            random.seed(1)
            
            #初始化权值 0-1
            self.synaptic_weights = 2*random.random((3,1))-1
            self.sigmoid_derivative = self.__sigmoid_derivative
            
        def __sigmoid(self, x):
            return 1/(1+exp(-x))
        
        def __sigmoid_derivative(self,x):
            return x*(1-x)
        
        def train(self, training_set_inputs, training_set_outputs, number_of_training_iterations):
            for iteration in range(number_of_training_iterations):
                for i in range(training_set_inputs.shape[0]):
                    output = self.think(training_set_inputs[i])
                    
                    error = training_set_outputs[i][0]-output
                    
                    for j in range(self.synaptic_weights.size):
                        adjustment = (training_set_inputs[i]) * (error*self.__sigmoid_derivative(output))
                    
                        self.synaptic_weights[j] += adjustment[j]
            
        def think(self, inputs):
            return self.__sigmoid(dot(inputs, self.synaptic_weights))
    
    neural_network = NeuralNetwork()
    
    print("Random starting synaptic weights: ")
    print(neural_network.synaptic_weights)
    
    training_set_inputs = array([[0,0,1],[1,1,1],[1,0,1],[0,1,1]])  #4*3
    training_set_outputs = array([[0,1,1,0]]).T
    neural_network.train(training_set_inputs, training_set_outputs, 10000)
    
    
    print("New synaptic weights after training: ")
    print(neural_network.synaptic_weights)
    
    # Test the neural network with a new situation.
    print("Considering new situation [1, 0, 0] -> ?: ")
    print(neural_network.think(array([1, 0, 0])))

    输出结果:

    Random starting synaptic weights:
    [[-0.16595599]
    [ 0.44064899]
    [-0.99977125]]
    New synaptic weights after training:
    [[ 9.67299303]
    [-0.2078435 ]
    [-4.62963669]]
    Considering new situation [1, 0, 0] -> ?:
    [ 0.99993704]

    参考

    1、《机器学习》

    2、http://www.jianshu.com/p/15db29e72719

  • 相关阅读:
    力学,结构动力NewMark法软组织模拟
    力学,非线性形变
    力学,线性形变
    波动方程水面模拟(简版)
    FFT海面(简版)
    测地极坐标参数化纹理贴图
    参数化离散指数映射纹理贴图
    Gridview中各个事件的操作以及FindControl
    CSS样式
    博客声明(博客大多均非原创文章,只用于记录)
  • 原文地址:https://www.cnblogs.com/ming-zi/p/6428890.html
Copyright © 2011-2022 走看看