2021-06-12

人工智能导论之神经网络基础知识总结规划

第一卷 基础概念

第一回 发展历史

“人工智能”这四字中最为突出的便是“智能”二字,何为之智能?就目前所发表的论文及文献中,这里我引用著名的图灵测试来做为定义标准。图灵测试:若有一台机器,其可与人类对话交流,但人类不能辨别出其机器身份,则可趁此机器具备智能。在当今的人工智能的理念中人工智能可以分为三个等级,即,弱人工智能,强人工智能以及超人工智能。比如我们现在大家都在用的手机电脑上的语音助手,他们可以说连弱人工智能的水准还未达到。
接下来我们可以玩一个由美国哲学家 John Searle 提出的有趣思维挑战——中文房间问题。
问题如下:话说有一个对中文一窍不通,只会英语的人被关在一个封闭的房间里。房间里有一本记录如何处理收到的汉语信息的英文手册。房外的人想房内输入中文问题,房间内的这个人变按照手册上的说明,找到何时的知识,将对应的中文字符组合成对问题的解答,并将答案数出。那么那个躲在房外的家伙看到自己输入的中文问题被解答了,他可能会认为房间内的人会中文,就像我们现在的聊天机器这样,可这是“智能”吗?
对人工智能的发展经历我们可以分为2007年前与至今这两个阶段。
1.从1956年的达特茅斯会议开始到2007年至今,人工智能发展可以说是时起时伏。
(1)1943-1956年诞生的控制论符号推理;
(2)1956-1974年出现的高潮时期,诞生了搜索式推理,自然语言处理,反向传播算法;
(3) 1974-1980年出现的寒冬低谷时期,运算能力的不够,复杂性指数级爆炸及没有常识的“中文房间”问题;
(4)1980-1987年出现了短暂的繁荣,期间出现了专家系统五代机神经网络;   
(5)1987-1993年的再入低谷,原因在于PC性能超过专用的AI硬件,五代机没有实用成果;
(6)1993-2006年的再次发展阶段,1997年深蓝贝叶斯网络,隐马尔代夫模型及信息论的发展;
2.2007年至今发生的突破,深度学习,视觉/翻译在比赛中超过人类,阿尔法围棋比赛的胜出等。
在目前看来人工智能是一个非常庞杂的概念。

第二回 神经网络的三个基本概念

2.1 通俗的理解三大概念

神经网络训练具备基本思想为:先“猜”一个结果,即预测结果A,看看这个预测的结果和事先标记好的训练集中的真是结果Y之间的差距,然后在调整方案,在预测一次,当然这一次就不是“猜”了,而是具有依据地向正确的方向靠近。通过这种形式反复进行多次,一直到预测结果和真是结果相差无几,就可以结束训练了。
在神经网络训练中,我们把“猜”叫做初始化,可以随机,也可以根据以前的经验给定初始值。所以“猜”也是要有技术含量的。
神经网络的三大概念是:反向传播,梯度下降,损失函数。这上概念是相连的,三个之中都相互设计。
我们可以通过几个例子来直观的理解说明一下这三个概念。
【例2.1】猜数
有甲乙两个人玩猜数的游戏,乙提前确定好一个数,由甲来才,数字的范围是[1,50]。
甲:我才5
乙:太下了
甲:50
乙:哎,太大了
甲:30
乙:小了
甲:…

可将这个游戏总结如下
(1)目的:猜到乙确定的数字
(2)初始化:甲猜5
(3)前向计算:甲每次猜的新数字。
(4)损失函数:乙根据甲猜的数来和自己确定的数做比较,得出了“大了”或“小了”的两种结论
(5)反向传播:乙告诉甲“小了”或:大了
(6)梯度下降:甲根据乙的反馈自行调整下一轮的猜测值。
这里的损失函数“太小了”“有卡大”,虽然很不精确,但是给出了两个信息。
方向:大了或小了
程度:“太”“有点儿”
【例2.2】黑盒子
假设有一个黑盒子,我们只能看到输入和输出的数值,看不到里面的计算过程,当输入1时,输出结果2.334,同时黑盒子有个信息显示:我需要输出值是4.然后试试输入2,结果输出5.332,比4大了很多。那么第一次输入的损失值是2.334-4=-1.666,而二次的损失值是5.332-4=1.332
这里的损失函数就是一个简单的减法,用实际值减去目标值。他可以给出两个信息:一是方向,是大了还是小了;二是差值。这样就给下一次输入提供了依据。
(1)目的:猜测一个输入值,使得黑盒子的输出是4
(2)初始化:输入1
(3)前向计算:黑盒子内部的数学逻辑
(4)损失函数:在输出端,用输出值减4
(5)方向传播:告诉猜数的人差值,包过正负号与值
(6)梯度下降:在输入端,根据正负号和值,确定下一次的猜测值,再次进行前向计算。

2.2 线性反向传播
2.21 正向计算
假设一个函数,
                   z=x*y                                                                 (2.2.1)

其中,
x=2w+3b (2.2.2)
y=2b+1 (2.2.3)
简单线性计算的计算过程图
计算过程可看上图
注意这里x,y,z是计算结果。w,b是变量
当w=3,b=4时,会得到x=18,y=9,z=162的结果
最终的z值,受到了前面很多因数的影响:变量w,变量b,计算式x,计算式y。常数是个定值,不考虑。

2.2.2反向传播求解w

1.求w的偏导
当z=162时如果想让z变小一些,例如目标是z=150,w应该如何变化呢?为了简化问题,暂时只考虑改变w的值,令b值固定为4.
如果想解决这个问题,可以在输入端不断尝试,把w变成4试试,再变成3.5试试…直到满意为止。那有没有个号的解决办法呢?
有,那便是反向传播。
从z开始一层一层向回看,关于变量w的偏导计算结果如下。
因为z=x*y,其中x=2w+3b,y=2b+1,所以

在这里插入图片描述 (2.2.4)
其中,
在这里插入图片描述
在这里插入图片描述
z的误差通过中间得x传递到w,我们如果直接用z的表达式计算对w的偏导数,那么会怎么样?
根据公式(2.2.1)至(2.2.3),可以得到
z=xy=(2w+3b)(2b+1)=4wb+2w+6b^2+3b (2.2.5)
对上式求w得偏导,
在这里插入图片描述(2.2.6)
不难发现,公式(2.2.4)和公式(2.2.6)的结果完全一致
2.求W的具体变化值
公式(2.2.4)和公式(2.2.6)的含义是:当w发生变化时,z的变化值是w的变化值是18部。目的的是z=150时,w需要变化多少?
既然,
在这里插入图片描述

在这里插入图片描述
所以,
w=w-0.667=2.3333
x=2w+3b=16.6666
z=x
y=16.6666*9=149.999
通过计算,很快就能将z值变成149.9994,与150的目标非常的接近,这就是偏导数的威力所在

2.2.3 反向传播求解b

1.求b的偏导
本例中,令w的值固定为3,变化b的值,目标还是让z=150.同上面的步骤一样,先求出b的偏导数。
但是我们在上面求解w时只经过了从z到x到w,
而求b的导数时要经过两条路。
(1)从z到x到b
(2)从z到y到b
从复合导数公式来看,这两者应该是相加的关系,所以有
在这里插入图片描述 (2.2.7)
其中,
在这里插入图片描述
不妨在验证一下链式求导的正确性。根据公式(2.2.5)有
z=x*y=(2w+3b)(2b+1)=4wb+2w+6b^2+3b
对上式求b的偏导
在这里插入图片描述 (2.2.8)
结果与公式(2.2.7)的链式法则一样。
2.求b的具体变化值
公式(2.2.7)和公式(2.2.8)的含义是:当b发生变化时,z的变化值是b的变化值得63倍。目的是让z=150,目前在初始状态时时162,所以,问题转化为z需要从162变到150时,b需要变化多少?
既然,
在这里插入图片描述
则有
在这里插入图片描述
所以,
在这里插入图片描述
这个结果与150很接近了,但是精度还不够。在迭代几次,应该可以近似等于150了,直到误差不大于0.0001时,就可以结束迭代了,对计算机来说,这些运算的执行速度很快。

2.2.4 同时求解w和b的变化值

同时改变w和b,使得最终结果为z=150.
已知
在这里插入图片描述
不妨假定误差的一半由w产生,另外一半由b产生,则有
在这里插入图片描述
在这里插入图片描述
其中,
在这里插入图片描述
我们可以用代码来演示查看。

# 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

def target_function(w,b):
    x = 2*w+3*b
    y=2*b+1
    z=x*y
    return x,y,z

def single_variable(w,b,t):
    print("\nsingle variable: b ----- ")
    error = 1e-5
    while(True):
        x,y,z = target_function(w,b)
        delta_z = z - t
        print("w=%f,b=%f,z=%f,delta_z=%f"%(w,b,z,delta_z))
        if abs(delta_z) < error:
            break
        delta_b = delta_z /63
        print("delta_b=%f"%delta_b)
        b = b - delta_b

    print("done!")
    print("final b=%f"%b)

def single_variable_new(w,b,t):
    print("\nsingle variable new: b ----- ")
    error = 1e-5
    while(True):
        x,y,z = target_function(w,b)
        delta_z = z - t
        print("w=%f,b=%f,z=%f,delta_z=%f"%(w,b,z,delta_z))
        if abs(delta_z) < error:
            break
        factor_b = 2*x+3*y
        delta_b = delta_z/factor_b
        print("factor_b=%f, delta_b=%f"%(factor_b, delta_b))
        b = b - delta_b

    print("done!")
    print("final b=%f"%b)


# this version has a bug
def double_variable(w,b,t):
    print("\ndouble variable: w, b -----")
    error = 1e-5
    while(True):
        x,y,z = target_function(w,b)
        delta_z = z - t
        print("w=%f,b=%f,z=%f,delta_z=%f"%(w,b,z,delta_z))
        if abs(delta_z) < error:
            break
        delta_b = delta_z/63/2
        delta_w = delta_z/18/2
        print("delta_b=%f, delta_w=%f"%(delta_b,delta_w))
        b = b - delta_b
        w = w - delta_w
    print("done!")
    print("final b=%f"%b)
    print("final w=%f"%w)

# this is correct version
def double_variable_new(w,b,t):
    print("\ndouble variable new: w, b -----")
    error = 1e-5
    while(True):
        x,y,z = target_function(w,b)
        delta_z = z - t
        print("w=%f,b=%f,z=%f,delta_z=%f"%(w,b,z,delta_z))
        if abs(delta_z) < error:
            break

        factor_b, factor_w = calculate_wb_factor(x,y)
        delta_b = delta_z/factor_b/2
        delta_w = delta_z/factor_w/2
        print("factor_b=%f, factor_w=%f, delta_b=%f, delta_w=%f"%(factor_b, factor_w, delta_b,delta_w))
        b = b - delta_b
        w = w - delta_w
    print("done!")
    print("final b=%f"%b)
    print("final w=%f"%w)

def calculate_wb_factor(x,y):
    factor_b = 2*x+3*y
    factor_w = 2*y
    return factor_b, factor_w

if __name__ == '__main__':
    w = 3
    b = 4
    t = 150
    single_variable(w,b,t)
    single_variable_new(w,b,t)
    double_variable(w,b,t)
    double_variable_new(w,b,t)

下面就是结果

w=3.000000,b=4.000000,z=162.000000,delta_z=12.000000
delta_b=0.190476
w=3.000000,b=3.809524,z=150.217687,delta_z=0.217687 
delta_b=0.003455
w=3.000000,b=3.806068,z=150.007970,delta_z=0.007970 
delta_b=0.000127
w=3.000000,b=3.805942,z=150.000294,delta_z=0.000294
delta_b=0.000005
w=3.000000,b=3.805937,z=150.000011,delta_z=0.000011
delta_b=0.000000
w=3.000000,b=3.805937,z=150.000000,delta_z=0.000000
done!
final b=3.805937

single variable new: b -----
w=3.000000,b=4.000000,z=162.000000,delta_z=12.000000
factor_b=63.000000, delta_b=0.190476
w=3.000000,b=3.809524,z=150.217687,delta_z=0.217687
factor_b=60.714286, delta_b=0.003585
w=3.000000,b=3.805938,z=150.000077,delta_z=0.000077
factor_b=60.671261, delta_b=0.000001
w=3.000000,b=3.805937,z=150.000000,delta_z=0.000000
done!
final b=3.805937

double variable: w, b -----
w=3.000000,b=4.000000,z=162.000000,delta_z=12.000000
delta_b=0.095238, delta_w=0.333333
w=2.666667,b=3.904762,z=150.181406,delta_z=0.181406
delta_b=0.001440, delta_w=0.005039
w=2.661628,b=3.903322,z=150.005526,delta_z=0.005526
delta_b=0.000044, delta_w=0.000154
w=2.661474,b=3.903278,z=150.000170,delta_z=0.000170
delta_b=0.000001, delta_w=0.000005
w=2.661469,b=3.903277,z=150.000005,delta_z=0.000005
done!
final b=3.903277
final w=2.661469

double variable new: w, b -----
w=3.000000,b=4.000000,z=162.000000,delta_z=12.000000
factor_b=63.000000, factor_w=18.000000, delta_b=0.095238, delta_w=0.333333
w=2.666667,b=3.904762,z=150.181406,delta_z=0.181406
factor_b=60.523810, factor_w=17.619048, delta_b=0.001499, delta_w=0.005148
w=2.661519,b=3.903263,z=150.000044,delta_z=0.000044
factor_b=60.485234, factor_w=17.613053, delta_b=0.000000, delta_w=0.000001
w=2.661517,b=3.903263,z=150.000000,delta_z=0.000000
done!
final b=3.903263
final w=2.661517
2.3 梯度下降
2.3.1 从自然现象中理解梯度下降

在自然界汇总,梯度下降的最好例子就是泉水流下山的过程(此处请忽略泉水流动的惯性)
(1)泉水受重力影响,会在当前位置,沿着最陡峭的方向流动,有时会形成瀑布——梯度下降
(2)泉水流下山的路径不是唯一的,在同一个地点,有可能有多个位置具有同样的陡峭程度,而造成了分流——可以得到多个解
(3)遇到坑洼地区,有可能形成湖泊,而终止下山过程——不能得到全局最优解,而是局部最优解。

2.3.2 梯度下降的数学理解

梯度下降的数学公式为
在这里插入图片描述
梯度下降的三要素为当前点,方向和步长。
“梯度下降”包含了如下两层含义。
(1)梯度:函数当前位置的最快上升点。
(2)下降:与导数相反的方向,亦即与上升相反的方向运动,就是下降。

2.3.3 单变量函数的梯度下降

假设一个单变量函数,
J(x)=x^2
目的是找到该函数的最小值,计算其微分,
在这里插入图片描述
假使初始位置为
在这里插入图片描述
假设学习率为
在这里插入图片描述
根据公式(2.3.1),进行迭代,
在这里插入图片描述 (2.3.2)
假设终止条件为J(x)<le-2,迭代过程如下图所示。

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 双变量的梯度下降

假设一个双变量函数,
在这里插入图片描述
目的是找到该函数的最小值,于是计算其微分,
在这里插入图片描述

假设初始位置为
在这里插入图片描述
假设学习率为
在这里插入图片描述
根据公式(2.3.1),迭代过程如下。
在这里插入图片描述
假设终止条件为J(x,y)<0.01迭代过程如表所示
迭代次数| x | y | J(x,y)|
1 |3 | 1 | 9.708073|
2 |2.4 | 0.909070 | 6.382415|
… |… |… | … |
15 |0.105553| 0.063481| 0.015166|
16 |0.084442| 0.050819| 0.009711|

迭代16次后,J(x,y)的值为0.009711,满足小于0.01的条件,停止迭代。
我们可以用三维图来解释。
代码如下:

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)

在这里插入图片描述

2.3.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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值