【深度学习入门:基于 Python 的理论与实现】(2)

2.4 感知机的局限性

    感知机可以实现与门,与非门,或门三种逻辑电路,现在我们来考虑以下“异或门”(XOR gate)。

2.4.1 异或门

    异或门也称为逻辑异或电路。它仅当x1或x2任意一方为1时,才会输出1(“异或”时拒绝其他的意思)

​​​​   065e4fe0b4e4ef4b95797b2b2a4098b1.png

 

    实际上,前面介绍的感知机是实现不了异或门的。如果将或门进行图像化,就会发现1和0是可以利用一根直线分割出来的:

8b7043e102557d5214d175347e037361.png

 

    图中○表示0,△表示1。可当变成异或门的时候图就变成这样了:

754adf0a80d8c1b6393c5ff5cb48e782.png

 

    此时就无法利用一根直线去分割0和1了,这也是感知机的局限性。

2.4.2 线性与非线性

    异或门的图像无法用一条直线去分割0和1,但如果将“直线”这个限制去掉,就可以实现了:

eba044fd638a50b69e2aaa416cf06f10.png

 

    像上图中利用曲线分割0和1是感知机无法表示出来的。因此由曲线分割而成的空间称为非线性空间,由直线分割而成的空间称为线性空间。这两个术语都是在机器学习领域很常见的。

2.5 多层感知机

    虽然感知机无法表示异或门,但感知机可以通过“叠加层”来表示它。

2.5.1 已有门电路的组合

    异或门制作方法繁多,其中之一便是组合之前做好的与门与非门或门进行配置。这里与门,与非门,或门我们分别用AND,NAND,OR来表示:

55451f45dd58ff3bd355bf6aeaf7fa73.png

 

    与非门前端的〇表示反转输出的意思。将与门,与非门,或门带入到下图中即可实现异或门:

a3ea56088871b6252e23122785cd6385.png

 

    异或门——x1和x2是输入信号,s1和s2表示与非门和或门的输出,y表示输出信号。x1和x2是与非门和或门的输入,而与非门和或门的输出则是与门的输入。随后即可得出异或门的真值表:

a21b2a5f9f64d9dbc7fee2980d483fdc.png

 

2.5.2 异或门的实现

    下面尝试使用Python和之前定义的AND函数,NAND函数,OR函数来实现异或门:

#异或门
def XOR(x1,x2):
    s1 = NAND(x1,x2)  #与非门
    s2 = OR(x1,x2)  #或门
    y = AND(s1,s2)  #与门
    return y
print(XOR(0,0)) ###0
print(XOR(1,0)) ###1
print(XOR(0,1)) ###1
print(XOR(1,1)) ###0

 

    试着用感知机的表示方法(神经元)来表示异或门:

8031779cf28850207986b6a540d04f1f.png

 

 

    图中可以看出异或门是2层感知机,而与门,与非门,或门都是单层感知机。叠加了多层的感知机就是多层感知机

 

2.6 从与非门到计算机

    多层感知机可以实现比之前见到的电路更复杂的电路,因此只要一直堆叠感知机的层,理论上就可以实现几乎任何东西。就比如可以用多层感知机的与非门来实现计算机,因为计算机也是有输入有输出的东西,这很符合感知机的逻辑。

2.7 小结

    本章我们学习了感知机及其构造以及它的一些算法。这章是下章《神经网络》的基础,因此本章内容特别重要。

第三章 神经网络

3.1 从感知机到神经网络

  神经网路与感知机有许多共同点,这里,我们主要以二者的差异为中心来介绍神经网络的结构。

3.1.1 神经网络的例子

    下图就是用图来表示的神经网络。最左边的那一列称为“输入层”,最右边的那一列是“输出层”,中间的一列是“中间层”,又称“隐藏层”(与前二者不同,中间层的神经元是肉眼看不见的)。另外,为了方便基于Python进行实现神经网络,从输入层到输出层依次称为“第0层”“第1层”···“第n层”

7e070fe2224844419fdc08ac40828baf.png

 

    神经网络的形状类似于感知机,其连接方式也和感知机没有任何差异。

3.1.2 复习感知机

031a24fc10243cb4e02a17c22eb68f1e.png

 

上图感知机接收x1和x2两个输入信号,输出y。用数学公式来表示图中的感知机则是:

                                        

dacd49b3c36055d3991790e724a92247.png

 

    b称为偏置的参数,用于控制神经元被激活的容易程度;w1和w2表示各个信号的权重的参数,用于控制各个信号的重要性。如果将偏置也在图中表示出来则是:

efcd9f08ec7e86261e5b3d3866b3bdfe.png

 

 

    现在将上面的数学式进行简化,因此引入新函数h(x)。将上式改写成下面的两种式子:


9f501ec75a3d6afcbb9a7e0caf85d71d.png式1

 

9386196465e2bdc84f4bd72bb8d9f106.png式2

 

    式1中输入信号的总和会被函数h(x)转换,转换后的值就是输出值y。式2所表示的函数h(x)在输入超过0时则返回1,反之则返回0。因此上面三式做的都是相同的事情。

3.1.3 激活函数登场

    刚才的h(x)函数会将输入信号的总和转换成输出信号,这种函数一般称为“激活函数”(activation function),它是连接感知机和神经网络的桥梁。其作用在于决定如何来激活输入信号的总和

    现在进一步将式1改写:

49bf9f2c091306bf2be760ca7d2b3a37.png3式

 

    之前神经元都是用〇来表示的,如果在图中明确表示式3,则是:

3b3a1f2842e9d8639f50193bfce97828.png

 

    上图的神经元中明确显示出了激活函数的计算过程,即信号的加权总和为节点(与“神经元”的含义相同)a,然后节点a被激活函数h()转换成节点y作为输出值。上图简单表示之后则可以变成:

ca9dc976aedf58720addc401ef7ba36b.png

 

3.2 激活函数

    式2表示的激活函数以阈值为界,一旦输入超过阈值,机会切换输出。这样的函数称为“阶跃函数”。因此可以说感知机在众多激活函数中使用了阶跃函数。如果感知机使用其他激活函数,则就可以进入神经网络的世界了。接下来我们来介绍以下神经网络使用的激活函数。

3.2.1 sigmoid函数

    神经网络中常使用的一个激活函数,其表达式为:

7e50ffc45be96c3610ddddc29cfdd5d0.png式4

 

    式4中的exp(-x)表示e-x的意思。Sigmoid函数看上去很复杂,实际上它跟普通函数一样,只要给输入,就会输出某个值。如h(1.0)=0.731···,h(2.0)=0.880···。

3.2.2 阶跃函数的实现

45f38a23e0cdd1c4589213f6e8a354e8.png式2

 

这里我们试着用Python画出阶跃函数的图。阶跃函数如式2所示,>0则输出1,≤0则输出0:

def step_function(x1)
    if x1 > 0:
        return 1
    else:
        return 0

 

    这个实现的很简单,到那时参数x只接受实数(浮点数),不能接受NumPy数组。因此为了便于后面的操作,我们将它改为支持NumPy数组的实现:

#阶跃函数
def step_function(x1):
    y = np.array(x1)  #将参数x1转为数组
    y = y>0  #判断元素>或<=0
    return y.astype(int)  #利用numpy中的astype()方法将布尔值转为int(True=1,False=0)
print(step_function(np.array([-1,2,0]))) ###[0 1 1]

 

 

    上图其中astype()类型转换方法是NumPy中专属的“技巧”。

3.2.3 阶跃函数的图形

    绘出图形需要用到matplotlib库。

#阶跃函数
def step_function(x1):
    y = np.array(x1)
    y = y>0
    return y.astype(int)
print(step_function(np.array([-1,2,0])))
x1 = np.arange(-5,5,0.1)   #生成一个-5到5,步数为0.1的数组
y1 = step_function(x1)     #将数组x传入函数中
plt.plot(x1,y1,linestyle='dashed',label='y=step_function')
plt.ylim(-0.1,1.1)
plt.show()

 

    运行结果:

8107f814c49c9fe8c3c8b0e75010ea9b.png

 

 

    通过图像我们可以看出阶跃函数的输出值从0 切换到1(或者从1到0)呈阶梯式变化,这也是它名字的由来。

3.2.4 sigmoid函数的实现

8d6983ecda8098514e73c590ea3a60a7.png式4

 

    用Python可以这样实现sigmoid函数:

def sigmoid(x2):
    return 1/(1+np.exp(-x2))
print(sigmoid(np.array([-1,1,2]))) ###[0.26894142 0.73105858 0.88079708]

 

    下面我们把sigmoid函数画出来。代码中我们可以看到和刚才的阶跃函数几乎是一样的,唯一不同之处在于输出y:

#sigmoid函数
def sigmoid(x2):
    return 1/(1+np.exp(-x2))
x2 = np.arange(-5,5,0.1)
y2 = sigmoid(x2)
plt.plot(x2,y2,label='y=sigmoid')
plt.ylim(-0.1,1.1)
plt.legend()
plt.show()

 

    运行结果:

996f067c3fad4a05ed51ac1b61ec45aa.png

 

3.2.5 sigmoid函数和阶跃函数的比较

    阶跃函数与sigmoid函数的图形对比:

506cbba6cb9f3e7f3d48ff7279607b27.png

 

    二者之间sigmoid函数要相对阶跃函数更加平滑一点,这对神经网络的学习具有重要意义。正因为阶跃函数只能返回0或1,而sigmoid函数可以返回0.731···,0.880···等实数,可以得出结论感知机中神经元之间流动的是0或1的二元信号,而神经网络中流动的是连续的实数值信号

    Sigmoid函数和阶跃函数共同性质之处在于二者的结构均为“输入小时输出接近或为0,随着输入增大,输出会向1靠近或变成1”。无论输入的值有多大/小,输出的值都会在0-1之间。

3.2.6 非线性函数

    Sigmoid函数和阶跃函数还有其他的共同点,就是二者均为非线性函数,因二者的图都不是一条笔直的线。线性函数是一条笔直线的函数,反之即是非线性函数。

    神经网络的激活函数必须使用非线性函数。因为线性函数无论加多少层神经网络都会变成没有意义的。为了理解,这里请思考一下下面的例子:我们把线性函数h(x)=cx作为激活函数,把y(x)=h(h(h(x)))的运算对应3层神经网络。这个运算会进行y(x)=c·c·c·x的乘法运算,但是同样的处理可以由y(x)=ax(a=c3)这一次乘法运算来表示。如本例所示,使用线性函数时,无法发挥多层网络带来的优势,因此为了发挥叠加层所带来的优势,激活函数必须使用非线性函数

3.2.7 ReLU函数

    sigmoid函数在神经网络的发展史上很早就开始使用了,但最近则主要是ReLU(Rectified Linear Unit)函数。

    ReLU函数在输入>0时会直接输出该值;输入<=0时则输出0:

2e35cd9e57da6b7ee2fab194287d8375.png

 

    ReLU函数的时间也很简单:

def ReLU(x3):
    return np.maximum(0,x3)  #实现>0直接输出数值,<=0则输出0
print(ReLU(np.array([-1,-2,3,6])))  ###[0 0 3 6]

 

    运行结果:

dc5d452412f3e8e7e12673747a9e37c6.png

 

 

3.3 多维数组的运算

如果掌握了NumPy多维数组的运算,就可以高效地实现神经网络,因此本章将介绍NumPy多维数组的运算。

3.3.1 多维数组

多维数组就是“数字的集合”,排成一列及以上的都是多维数组。接下来就用NumPy生成一个多维数组:

import numpy as np
a = np.array([1,2,3,4,5])
print(a)  ###[1 2 3 4 5]
print(np.ndim(a))  #输出数组的维度  ###1
print(a.shape)     #输出数组是几行几列的  ###(5,)
print(a.shape[0])   ###5

 

 

   这里需要注意.shape()输出的结果是元组(tuple)类型,这是为了与多维数组结果的一致性。接下来生成一个二维数组:

b = np.array([[1,2],
              [3,4],
              [5,6]])
print(b)  ###[[1 2] [3 4] [5 6]]
print(np.ndim(b))  ###2
print(b.shape)  ###(3,2)

 

 

    这里生成了一个3×2的数组b。3×2表示第一个维度有3个元素,第二个维度有2个元素。另外,第一个维度对应第0维,第二个维度对应第1维(Python的索引从0开始)。二维数组也成为矩阵(matrix),数组的横向称为行(row),纵向称为列(column)

3.3.2 矩阵乘法

    NumPy中矩阵的乘法与线性代数中的矩阵乘法相同,都是如下图表示的那样:

ae639efc73adac1ca43dd449442de507.png


 

 

    接下来我们用Python来实现以下上面的运算:

A = np.array([[1,2],[3,4]])
B = np.array([[9,8],[7,6]])
print(A.shape)  ###(2,2)
print(B.shape)  ###(2,2)
print(np.dot(A,B))  ###[[23 20] [55 48]]

 

 

    这里的乘积用的是NumPy中的np.dot()函数计算的。np.dot()接收到两个参数之后并返回数组的乘积,这里要注意的是np.dot(A,B)的结果和np.dot(B,A)的结果是不一样的,也就是说np.dot()函数有顺序性。

    除此之外,其他形状的矩阵也可以用这个方法进行计算:

A0 = np.array([[1,2,3],[4,5,6]])
B0 = np.array([[9,8],[7,6],[5,4]])
print(A0.shape)  ###(2,3)
print(B0.shape)  ###(3,2)
print(np.dot(A0,B0))  ###[[38 32] [101 86]]

 

 

    这里需要注意乘积的两个矩阵需满足“行=对方的列,列=对方的行”。如上面的例子,矩阵A是一个2×3的矩阵,B是3×2的矩阵。A的行=B的列A的列=B的行,所以才可以进行乘积的运算。如果这两个值不相等,就会报错。其背后的逻辑是这样的:

e2d1982cff1efcae887d0736a463e5d8.png

 

    就算是多维数组对一维数组进行乘积,也会遵循上图的原则:

c = np.array([[1,2],[3,4],[5,6]])
d = np.array([1,2])
print(np.dot(c,d))  ###[5 11 17]

 

 

3.3.3 神经网络的内积

    下面我们将使用NumPy矩阵来实现神经网络。我们以下图中的简单神经网络为对象。这个神经网络省略了偏置和激活函数,只有权重。

9188ccf5acfa38cff5bbf7ed21955ff1.png

 

    实现该神经网络时需要注意X,W,Y的形状。特别是X和W的对应维度的元素格式是否一致。

X0 = np.array([1,2])
print(X0.shape)  ###(2,)
print(X0)  ###[1 2]
W0 = np.array([[1,2,3],[4,5,6]])
print(W0.shape)  ###(2,3)
print(W0)  ###[[1 2 3] [4 5 6]]
Y0 = np.dot(X0,W0)
print(Y0)  ###[9 12 15]

 

 

    如上所示,使用np.dot(多维数组的点积)可以一次性计算出Y的结果,不管Y有多大。如果不使用np.dot(),就必须单独计算Y的每一个元素,因此通过矩阵的乘积一次性完成计算的技巧在实现层面上是非常重要的。

3.4 3层神经网络的实现

    接下来我们以下图的3层神经网络为对象,来实现从输入到输出的书里。代码方面巧妙地使用NumPy的多维数组:

6d531755d0c2a2a487e86e1b0d94402d.png

 

    图中从左到右分别是输入层(第0层)有两个神经元,第1个隐藏层(第1层)有三个神经元,第2个隐藏层(第2层)有两个神经元,输出层(第3层)有两个神经元。

3.4.1 符号确认

    本节的重点是神经网络的运算可以作为矩阵运算打包进行。因为神经网络各层的运算时通过矩阵的乘法运算打包进行的,因此即便忘了具体符号的规则也不影响后面的内容。

    在介绍神经网络中的处理之前,我们先从定义符号开始。

c561cebc7140271a5ce4cd7b27ce316e.png

 

 

    上图中凸显了从输入层x2到后一层神经元a1(1)的权重以及符号的意思。图中我们可以明白权重的右下角时按照“后一层的索引号,前一层的索引号”的顺序排列的。

3.4.2 各层间信号传递的实现

    现在先看一下从输入层到第一层的第一个神经元的信号传递过程:

58922a2238387ccea4775422bcc313b8.png

 

 

    上图中增加了表示偏置的神经元“1”.为了确认前面的内容,现在用数学式表示a1(1):

1b5d229df19ad2bf0769ae82b922f4fc.png式5

 

    如果使用矩阵的乘法运算,则可以将第一层的加权和表示成下面的式:

c59547367d194573f92fea0bcf996fe8.png式6

 

    其中

A(1)=(a1(1),a2(1),a3(1))

X=(x1,x2)

B(1)=(b1(1),b2(1),b3(1))

ff83f6a4bb8e787a908b292ac35e7893.png

 

    下面用NumPy多维数组来实现式6,这里将输入信号,权重,偏置设置成任意值:

X = np.array([4,5])
B = np.array([6,7,8])
W = np.array([[9,10,11],[12,13,14]])
print(X.shape)  ###(2,)
print(B.shape)  ###(3,)
print(np.dot(X,W)+B  ###[102 112 122]

 

 

    如果将这个运算过程用图来表示的话就是下面这个样子:

43c95f19af27200668152c1a9446d536.png

 

    如图所示,隐藏层的加权和(加权信号和偏置的总和)用a表示,被激活函数转换后用z表示。这里的激活函数使用sigmoid函数。用Python实现就是下面这个样子:

X = np.array([4,5])
B = np.array([6,7,8])
W = np.array([[9,10,11],[12,13,14]])
A = np.dpt(X,W)+B
def sigmoid(A):
    return 1/(1+np.exp(A))
Z = sigmoid(np.array([-1,1,2])
print(A)  ###[102 112 122]
print(Z)  ###[0.73105858 0.26894142 0.11920292]

 

 

    这样第一层的输出Z就变成了第二层的输入。接着第三层的实现与之前一模一样:

8d6c45055de69c35ef01664aa24e4d8f.png

 

    最后第二层的输出变成了 第三层的输入。输出层的实现与之前基本相同,就是激活函数和之前的隐藏层有所不同:

def identity_function(x):  #可有可无,仅为了与一二层的格式保持一致
    return x
W3 = np.array([[1,2],[3,4]])
B3 = np.array([5,6])
A3 = np.dot(Z2,W2)+B3
Y = identity_function(A3)  #或者Y=A3

 

    这里为了与前几层的格式保持一致,所以定义了一个identity_function()函数(“恒等函数”)。第2层到输出层的图像表示是这样的:

9284b4cf71d96884e3d537d06ad36656.png

 

    输出层的激活函数不同于隐藏层,用σ()表示(σ读作sigma)。

    输出层的激活函数(下章细讲)要根据求解问题的性质决定。一般地,回归问题可以使用恒等函数,二元分类问题可以使用sigmoid函数,多元分类问题可以使用softmax函数

3.4.3 代码实现小结

    至此,我们已经介绍完了三层神经网络的实现,现在我们将之前的代码进行整理。这里,按照神经网络的实现惯例,将权重记为W1,其他的都用小写字母表示:

import numpy as np
class Nueral_Networks:
    #对权重和偏置进行初始化
    def __init__(self):
        self.network = {}  #将权重和偏置存入network字典中
        self.network['W1'] = np.array([[0.1,0.3,0.5],[0.2,0.4,0.6]])
        self.network['W2'] = np.array([[0.1,0.4],[0.2,0.5],[0.3,0.6]])
        self.network['W3'] = np.array([[0.1,0.3],[0.2,0.4]])
        self.network['b1'] = np.array([0.1,0.2,0.3])
        self.network['b2'] = np.array([0.1,0.2])
        self.network['b3'] = np.array([0.1,0.2])

    #将输入信号转为输出信号
    def forward(self,x):
        W1,W2,W3 = self.network['W1'],self.network['W2'],self.network['W3']
        b1,b2,b3 = self.network['b1'],self.network['b2'],self.network['b3']
        a1 = np.dot(x,W1)+b1
        z1 = 1/(1+np.exp(-a1))  #用sigmoid函数运算出self.z1
        a2 = np.dot(z1,W2)+b2
        z2 = 1/(1+np.exp(-a2))  #用sigmoid函数运算出self.z2
        self.a3 = np.dot(z2,W3)+b3

    #输出层(输出y)
    def identity_function(self):
        y = self.a3
        print(y)
x = Nueral_Networks()
x.forward(np.array([1,0.5]))
x.identity_function()  ###[0.31682708 0.69627909]

 

 

    这里我们通过巧妙地运用NumPy多维数组实现了神经网络前向(forward)处理。以后的学习中将会学习到后向。 

 

 

### 回答1: 深度学习是一种机器学习技术,可以通过模拟人类大脑的神经网络结构来实现智能决策和预测。Python是一种广泛使用的编程语言,也是深度学习中使用最多的语言之一。 如果你想入门深度学习并使用Python进行实现,可以参考一些经典的教材和资源,例如《Python深度学习》(Francois Chollet著)、《深度学习入门:基于Python理论实现》(斋藤康毅著)等。这些教材通常会介绍深度学习的基础理论Python的基本语法和深度学习框架(如TensorFlow、Keras等)的使用方法,同时也会提供一些实例代码和练习题帮助你快速上手。 此外,你也可以通过在线课程和MOOC平台学习深度学习Python编程。例如,Coursera、Udacity和edX等平台都提供了相关课程,可以根据自己的需求和兴趣进行选择。 ### 回答2: 深度学习入门:基于Python理论实现,是一本介绍深度学习的较为全面的教程。本书主要介绍了人工神经网络,包括基于反向传播算法的多层感知器、卷积神经网络、循环神经网络等基本模型以及它们的实现方法,同时还介绍了一些高级话题,如深度强化学习、生成模型等等。 在本书中,作者通过大量的编程实例来演示深度学习的应用。这些实例包括用深度学习算法进行手写数字识别、图像分类、语音识别和自然语言处理等任务。由于Python是目前流行的机器学习工具之一,因此这本书的实现过程都使用了Python编程语言。 具体来说,本书的主要内容包括人工神经网络基础知识、多层感知器模型、卷积神经网络模型、循环神经网络模型、生成模型、 强化学习、深度学习框架等方面,同时还包括很多深度学习的应用案例。作者采用了基础理论、数学公式、实例程序和实验数据等不同形式的阐释方法,使读者既能够理解深度学习的基本原理,也能够掌握它的实现方法。 此外,本书还提供了大量的参考文献和网上资源,使读者可以进一步深入学习和研究深度学习。在阅读本书的同时,读者可以根据作者提供的代码和数据,通过实际操作来进一步巩固理论知识和应用技能。 总之,深度学习入门:基于Python理论实现是一本非常实用的深度学习教材,可以帮助初学者更好地了解深度学习的基本概念和方法,提高实际应用的技能。 ### 回答3: 深度学习是一种人工智能技术,可用于训练计算机识别和理解大量数据。《深度学习入门:基于Python理论实现》这本书是入门者学习深度学习的必读之书。以下是本书的内容概述。 本书的第一部分介绍了深度学习的基础概念和理论,包括神经网络、反向传播算法、损失函数等。介绍了基本的深度学习模型,如前馈神经网络、卷积神经网络和循环神经网络。此外,还介绍了优化算法和正则化技术。 在第二部分中,作者使用Python编程语言实现了各种深度学习模型,使用的是许多广泛使用的深度学习框架,如TensorFlow和PyTorch。学习者获得从头开始编写深度学习算法的经验,同时实际应用中必备的PyTorch和TensorFlow经验。 在第三部分中,本书涵盖了几个应用案例,包括图像分类、语音识别和自然语言处理。幸运的是,这些案例通过代码演示展示,确保即使您没有实际应用经验也能操作成功。 总的来说,《深度学习入门:基于Python理论实现》是一本适合想要学习深度学习的初学者的绝佳书籍。其提供了深度学习的基本理论和核心技术,同时应用Python编程语言演示了实现技术。由此学习者可以建立深度学习专业的技术栈和能力,在人工智能领域有更广阔的发展空间。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值