2021-06-13

神经网络的基本内容

2.2 非线性反向传播

2.2.1 提出问题

在上面的线性例子中,我们可以发现,误差一次性地传递给了初始值 w w w b b b,即,只经过一步,直接修改 w w w b b b 的值,就能做到误差校正。因为从它的计算图看,无论中间计算过程有多么复杂,它都是线性的,所以可以一次传到底。缺点是这种线性的组合最多只能解决线性问题,不能解决更复杂的问题。这个我们在神经网络基本原理中已经阐述过了,需要有激活函数连接两个线性单元。

下面我们看一个非线性的例子,如图2-8所示。

图2-8 非线性的反向传播

其中 1 < x < = 10 , 0 < y < 2.15 1<x<=10,0<y<2.15 1<x<=10,0<y<2.15。假设有5个人分别代表 x , a , b , c , y x,a,b,c,y x,a,b,c,y

正向过程
  1. 第1个人,输入层,随机输入第一个 x x x 值, x x x 的取值范围 ( 1 , 10 ] (1,10] (1,10],假设第一个数是 2 2 2
  2. 第2个人,第一层网络计算,接收第1个人传入 x x x 的值,计算: a = x 2 a=x^2 a=x2
  3. 第3个人,第二层网络计算,接收第2个人传入 a a a 的值,计算: b = ln ⁡ ( a ) b=\ln (a) b=ln(a)
  4. 第4个人,第三层网络计算,接收第3个人传入 b b b 的值,计算: c = b c=\sqrt{b} c=b
  5. 第5个人,输出层,接收第4个人传入 c c c 的值
反向过程
  1. 第5个人,计算 y y y c c c 的差值: Δ c = c − y \Delta c = c - y Δc=cy,传回给第4个人
  2. 第4个人,接收第5个人传回 Δ c \Delta c Δc,计算 Δ b = Δ c ⋅ 2 b \Delta b = \Delta c \cdot 2\sqrt{b} Δb=Δc2b
  3. 第3个人,接收第4个人传回 Δ b \Delta b Δb,计算 Δ a = Δ b ⋅ a \Delta a = \Delta b \cdot a Δa=Δba
  4. 第2个人,接收第3个人传回 Δ a \Delta a Δa,计算 Δ x = Δ 2 x \Delta x = \frac{\Delta}{2x} Δx=2xΔ
  5. 第1个人,接收第2个人传回 Δ x \Delta x Δx,更新 x ← x − Δ x x \leftarrow x - \Delta x xxΔx,回到第1步

提出问题:假设我们想最后得到 c = 2.13 c=2.13 c=2.13 的值, x x x 应该是多少?(误差小于 0.001 0.001 0.001 即可)

2.2.2 数学解析解

c = b = ln ⁡ ( a ) = ln ⁡ ( x 2 ) = 2.13 c=\sqrt{b}=\sqrt{\ln(a)}=\sqrt{\ln(x^2)}=2.13 c=b =ln(a) =ln(x2) =2.13
x = 9.6653 x = 9.6653 x=9.6653

2.2.3 梯度迭代解

d a d x = d ( x 2 ) d x = 2 x = Δ a Δ x (1) \frac{da}{dx}=\frac{d(x^2)}{dx}=2x=\frac{\Delta a}{\Delta x} \tag{1} dxda=dxd(x2)=2x=ΔxΔa(1)
d b d a = d ( ln ⁡ a ) d a = 1 a = Δ b Δ a (2) \frac{db}{da} =\frac{d(\ln{a})}{da} =\frac{1}{a} = \frac{\Delta b}{\Delta a} \tag{2} dadb=dad(lna)=a1=ΔaΔb(2)
d c d b = d ( b ) d b = 1 2 b = Δ c Δ b (3) \frac{dc}{db}=\frac{d(\sqrt{b})}{db}=\frac{1}{2\sqrt{b}}=\frac{\Delta c}{\Delta b} \tag{3} dbdc=dbd(b )=2b 1=ΔbΔc(3)
因此得到如下一组公式,可以把最后一层 Δ c \Delta c Δc 的误差一直反向传播给最前面的 Δ x \Delta x Δx,从而更新 x x x 值:
Δ c = c − y (4) \Delta c = c - y \tag{4} Δc=cy(4)
Δ b = Δ c ⋅ 2 b (根据式3) \Delta b = \Delta c \cdot 2\sqrt{b} \tag{根据式3} Δb=Δc2b (3)
Δ a = Δ b ⋅ a (根据式2) \Delta a = \Delta b \cdot a \tag{根据式2} Δa=Δba(2)
Δ x = Δ a / 2 x (根据式1) \Delta x = \Delta a / 2x \tag{根据式1} Δx=Δa/2x(1)

我们给定初始值 x = 2 x=2 x=2 Δ x = 0 \Delta x=0 Δx=0,依次计算结果如表2-2。

表2-2 正向与反向的迭代计算

方向公式迭代1迭代2迭代3迭代4迭代5
正向 x = x − Δ x x=x-\Delta x x=xΔx24.2437.3449.2959.665
正向 a = x 2 a=x^2 a=x2418.00553.93486.40493.233
正向 b = ln ⁡ ( a ) b=\ln(a) b=ln(a)1.3862.8913.9884.4594.535
正向 c = b c=\sqrt{b} c=b 1.1771.7001.9972.1122.129
标签值y2.132.132.132.132.13
反向 Δ c = c − y \Delta c = c - y Δc=cy-0.953-0.430-0.133-0.018
反向 Δ b = Δ c ⋅ 2 b \Delta b = \Delta c \cdot 2\sqrt{b} Δb=Δc2b -2.243-1.462-0.531-0.078
反向 Δ a = Δ b ⋅ a \Delta a = \Delta b \cdot a Δa=Δba-8.973-26.317-28.662-6.698
反向 Δ x = Δ a / 2 x \Delta x = \Delta a / 2x Δx=Δa/2x-2.243-3.101-1.951-0.360

表2-2,先看“迭代-1”列,从上到下是一个完整的正向+反向的过程,最后一行是 − 2.243 -2.243 2.243,回到“迭代-2”列的第一行, 2 − ( − 2.243 ) = 4.243 2-(-2.243)=4.243 2(2.243)=4.243,然后继续向下。到第5轮时,正向计算得到的 c = 2.129 c=2.129 c=2.129,非常接近 2.13 2.13 2.13 了,迭代结束。

运行示例代码可以得到如下结果:

how to play: 1) input x, 2) calculate c, 3) input target number but not faraway from c
input x as initial number(1.2,10), you can try 1.3:
2
c=1.177410
input y as target number(0.5,2), you can try 1.8:
2.13
forward...
x=2.000000,a=4.000000,b=1.386294,c=1.177410
backward...
delta_c=-0.952590, delta_b=-2.243178, delta_a=-8.972712, delta_x=-2.243178
......
forward...
x=9.655706,a=93.232666,b=4.535098,c=2.129577
backward...
done!

为节省篇幅只列出了第一步和最后一步(第5步)的结果,第一步时c=1.177410,最后一步时c=2.129577,停止迭代。

代码位置

代码如下

# Copyright (c) Microsoft. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for full license information.

import numpy as np
import matplotlib.pyplot as plt

def draw_fun(X,Y):
    x = np.linspace(1.2,10)
    a = x*x
    b = np.log(a)
    c = np.sqrt(b)
    plt.plot(x,c)

    plt.plot(X,Y,'x')

    d = 1/(x*np.sqrt(np.log(x**2)))
    plt.plot(x,d)
    plt.show()


def forward(x):
    a = x*x
    b = np.log(a)
    c = np.sqrt(b)
    return a,b,c

def backward(x,a,b,c,y):
    loss = c - y
    delta_c = loss
    delta_b = delta_c * 2 * np.sqrt(b)
    delta_a = delta_b * a
    delta_x = delta_a / 2 / x
    return loss, delta_x, delta_a, delta_b, delta_c

def update(x, delta_x):
    x = x - delta_x
    if x < 1:
        x = 1.1
    return x

if __name__ == '__main__':
    print("how to play: 1) input x, 2) calculate c, 3) input target number but not faraway from c")
    print("input x as initial number(1.2,10), you can try 1.3:")
    line = input()
    x = float(line)
    
    a,b,c = forward(x)
    print("c=%f" %c)
    print("input y as target number(0.5,2), you can try 1.8:")
    line = input()
    y = float(line)

    error = 1e-3

    X,Y = [],[]

    for i in range(20):
        # forward
        print("forward...")
        a,b,c = forward(x)
        print("x=%f,a=%f,b=%f,c=%f" %(x,a,b,c))
        X.append(x)
        Y.append(c)
        # backward
        print("backward...")
        loss, delta_x, delta_a, delta_b, delta_c = backward(x,a,b,c,y)
        if abs(loss) < error:
            print("done!")
            break
        # update x
        x = update(x, delta_x)
        print("delta_c=%f, delta_b=%f, delta_a=%f, delta_x=%f\n" %(delta_c, delta_b, delta_a, delta_x))

    
    draw_fun(X,Y)

代码结果如下
x=0.480000, y=0.230400
x=0.192000, y=0.036864
x=0.076800, y=0.005898
x=0.030720, y=0.000944

2.3 梯度下降

2.3.1 从自然现象中理解梯度下降

在大多数文章中,都以“一个人被困在山上,需要迅速下到谷底”来举例,这个人会“寻找当前所处位置最陡峭的地方向下走”。这个例子中忽略了安全因素,这个人不可能沿着最陡峭的方向走,要考虑坡度。

在自然界中,梯度下降的最好例子,就是泉水下山的过程:

  1. 水受重力影响,会在当前位置,沿着最陡峭的方向流动,有时会形成瀑布(梯度下降);
  2. 水流下山的路径不是唯一的,在同一个地点,有可能有多个位置具有同样的陡峭程度,而造成了分流(可以得到多个解);
  3. 遇到坑洼地区,有可能形成湖泊,而终止下山过程(不能得到全局最优解,而是局部最优解)。

2.3.2 梯度下降的数学理解

梯度下降的数学公式:

θ n + 1 = θ n − η ⋅ ∇ J ( θ ) (1) \theta_{n+1} = \theta_{n} - \eta \cdot \nabla J(\theta) \tag{1} θn+1=θnηJ(θ)(1)

其中:

  • θ n + 1 \theta_{n+1} θn+1:下一个值;
  • θ n \theta_n θn:当前值;
  • − - :减号,梯度的反向;
  • η \eta η:学习率或步长,控制每一步走的距离,不要太快以免错过了最佳景点,不要太慢以免时间太长;
  • ∇ \nabla :梯度,函数当前位置的最快上升点;
  • J ( θ ) J(\theta) J(θ):函数。
梯度下降的三要素
  1. 当前点;
  2. 方向;
  3. 步长。
为什么说是“梯度下降”?

“梯度下降”包含了两层含义:

  1. 梯度:函数当前位置的最快上升点;
  2. 下降:与导数相反的方向,用数学语言描述就是那个减号。

亦即与上升相反的方向运动,就是下降。

图2-9 梯度下降的步骤

图2-9解释了在函数极值点的两侧做梯度下降的计算过程,梯度下降的目的就是使得x值向极值点逼近。

2.3.3 单变量函数的梯度下降

假设一个单变量函数:

J ( x ) = x 2 J(x) = x ^2 J(x)=x2

我们的目的是找到该函数的最小值,于是计算其微分:

J ′ ( x ) = 2 x J'(x) = 2x J(x)=2x

假设初始位置为:

x 0 = 1.2 x_0=1.2 x0=1.2

假设学习率:

η = 0.3 \eta = 0.3 η=0.3

根据公式(1),迭代公式:

x n + 1 = x n − η ⋅ ∇ J ( x ) = x n − η ⋅ 2 x x_{n+1} = x_{n} - \eta \cdot \nabla J(x)= x_{n} - \eta \cdot 2x xn+1=xnηJ(x)=xnη2x

假设终止条件为 J ( x ) < 0.01 J(x)<0.01 J(x)<0.01,迭代过程是:

x=0.480000, y=0.230400
x=0.192000, y=0.036864
x=0.076800, y=0.005898
x=0.030720, y=0.000944
# Copyright (c) Microsoft. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for full license information.

import numpy as np
import matplotlib.pyplot as plt

def target_function(x):
    y = x*x
    return y

def derivative_function(x):
    return 2*x

def draw_function():
    x = np.linspace(-1.2,1.2)
    y = target_function(x)
    plt.plot(x,y)

def draw_gd(X):
    Y = []
    for i in range(len(X)):
        Y.append(target_function(X[i]))
    
    plt.plot(X,Y)

if __name__ == '__main__':
    x = 1.2
    eta = 0.3
    error = 1e-3
    X = []
    X.append(x)
    y = target_function(x)
    while y > error:
        x = x - eta * derivative_function(x)
        X.append(x)
        y = target_function(x)
        print("x=%f, y=%f" %(x,y))


    draw_function()
    draw_gd(X)
    plt.show()

代码结果如下
在这里插入图片描述

2.3.4 双变量的梯度下降

假设一个双变量函数:

J ( x , y ) = x 2 + sin ⁡ 2 ( y ) J(x,y) = x^2 + \sin^2(y) J(x,y)=x2+sin2(y)

我们的目的是找到该函数的最小值,于是计算其微分:

∂ J ( x , y ) ∂ x = 2 x {\partial{J(x,y)} \over \partial{x}} = 2x xJ(x,y)=2x
∂ J ( x , y ) ∂ y = 2 sin ⁡ y cos ⁡ y {\partial{J(x,y)} \over \partial{y}} = 2 \sin y \cos y yJ(x,y)=2sinycosy

假设初始位置为:

( x 0 , y 0 ) = ( 3 , 1 ) (x_0,y_0)=(3,1) (x0,y0)=(3,1)

假设学习率:

η = 0.1 \eta = 0.1 η=0.1

根据公式(1),迭代过程是的计算公式:
( x n + 1 , y n + 1 ) = ( x n , y n ) − η ⋅ ∇ J ( x , y ) (x_{n+1},y_{n+1}) = (x_n,y_n) - \eta \cdot \nabla J(x,y) (xn+1,yn+1)=(xn,yn)ηJ(x,y)
= ( x n , y n ) − η ⋅ ( 2 x , 2 ⋅ sin ⁡ y ⋅ cos ⁡ y ) (1) = (x_n,y_n) - \eta \cdot (2x,2 \cdot \sin y \cdot \cos y) \tag{1} =(xn,yn)η(2x,2sinycosy)(1)

根据公式(1),假设终止条件为 J ( x , y ) < 0.01 J(x,y)<0.01 J(x,y)<0.01,迭代过程如表2-3所示。

表2-3 双变量梯度下降的迭代过程

迭代次数xyJ(x,y)
1319.708073
22.40.9090706.382415
150.1055530.0634810.015166
160.0844420.0508190.009711

迭代16次后, J ( x , y ) J(x,y) J(x,y) 的值为 0.009711 0.009711 0.009711,满足小于 0.01 0.01 0.01 的条件,停止迭代。

上面的过程如表2-4所示,由于是双变量,所以需要用三维图来解释。请注意看两张图中间那条隐隐的黑色线,表示梯度下降的过程,从红色的高地一直沿着坡度向下走,直到蓝色的洼地。

表2-4 在三维空间内的梯度下降过程

1# Copyright (c) Microsoft. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for full license information.

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

def target_function(x,y):
    J = x**2 + np.sin(y)**2
    return J

def derivative_function(theta):
    x = theta[0]
    y = theta[1]
    return np.array([2*x,2*np.sin(y)*np.cos(y)])

def show_3d_surface(x, y, z):
    fig = plt.figure()
    ax = Axes3D(fig)
 
    u = np.linspace(-3, 3, 100)
    v = np.linspace(-3, 3, 100)
    X, Y = np.meshgrid(u, v)
    R = np.zeros((len(u), len(v)))
    for i in range(len(u)):
        for j in range(len(v)):
            R[i, j] = X[i, j]**2 + np.sin(Y[i, j])**2

    ax.plot_surface(X, Y, R, cmap='rainbow')
    plt.plot(x,y,z,c='black')
    plt.show()

if __name__ == '__main__':
    theta = np.array([3,1])
    eta = 0.1
    error = 1e-2

    X = []
    Y = []
    Z = []
    for i in range(100):
        print(theta)
        x=theta[0]
        y=theta[1]
        z=target_function(x,y)
        X.append(x)
        Y.append(y)
        Z.append(z)
        print("%d: x=%f, y=%f, z=%f" %(i,x,y,z))
        d_theta = derivative_function(theta)
        print("    ",d_theta)
        theta = theta - eta * d_theta
        if z < error:
            break
    show_3d_surface(X,Y,Z)

|观察角度1|观察角度2|
|-在这里插入图片描述
-|--
|
|||

2.3.5 学习率η的选择

在公式表达时,学习率被表示为 η \eta η。在代码里,我们把学习率定义为learning_rate,或者eta。针对上面的例子,试验不同的学习率对迭代情况的影响,如表2-5所示。

表2-5 不同学习率对迭代情况的影响

# Copyright (c) Microsoft. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for full license information.

import numpy as np
import matplotlib.pyplot as plt

def targetFunction(x):
    y = (x-1)**2 + 0.1
    return y

def derivativeFun(x):
    y = 2*(x-1)
    return y

def create_sample():
    x = np.linspace(-1,3,num=100)
    y = targetFunction(x)
    return x,y

def draw_base():
    x,y=create_sample()
    plt.plot(x,y,'.')
    plt.show()
    return x,y
   
def gd(eta):
    x = -0.8
    a = np.zeros((2,10))
    for i in range(10):
        a[0,i] = x
        a[1,i] = targetFunction(x)
        dx = derivativeFun(x)
        x = x - eta*dx
    
    plt.plot(a[0,:],a[1,:],'x')
    plt.plot(a[0,:],a[1,:])
    plt.title("eta=%f" %eta)
    plt.show()

if __name__ == '__main__':

    eta = [1.1,1.,0.8,0.6,0.4,0.2,0.1]

    for e in eta:
        X,Y=create_sample()
        plt.plot(X,Y,'.')
        #plt.show()
        gd(e)

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【1】项目代码完整且功能都验证ok,确保稳定可靠运行后才上传。欢迎下载使用!在使用过程中,如有问题或建议,请及时私信沟通,帮助解答。 【2】项目主要针对各个计算机相关专业,包括计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网等领域的在校学生、专业教师或企业员工使用。 【3】项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 【4】如果基础还行,或热爱钻研,可基于此项目进行二次开发,DIY其他不同功能,欢迎交流学习。 【注意】 项目下载解压后,项目名字和项目路径不要用中文,否则可能会出现解析不了的错误,建议解压重命名为英文名字后再运行!有问题私信沟通,祝顺利! 基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip基于C语言实现智能决策的人机跳棋对战系统源码+报告+详细说明.zip
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值