《深度学习入门》|| 第三章 神经网络——学习笔记

本文介绍了感知机和神经网络的区别与联系,包括激活函数如sigmoid和阶跃函数的实现,以及ReLU函数的作用。通过代码示例展示了多层神经网络的构建过程,包括前向传播的实现。此外,还讨论了输出层的设计,如恒等函数和softmax函数在分类问题和回归问题中的应用。最后,文章以MNIST手写数字识别为例,展示了神经网络的推理处理和批处理在提高识别效率上的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

3.1 感知机与神经网络的

略。

3.2激活函数

感知机——“阶跃函数”:以阈值为界,一旦超过阈值,就切换输出。

感知机与神经网络的主要区别是激活函数其他方面基本一致。

3.2.1 sigmoid 函数

神经网络常用函数,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存失败,源站可能有防盗链机制,建议将图片保存下来直接上传下上传(iAn72bgbjrJS-1689934058878)(C:\Users\Lin_Yu\AppData\Roaming\Typora\typora-user-images\image-20230721012127563.png)(C:\Users\Lin_Yu\AppData\Roaming\Typora\typora-user-images\image-20230721012127563.png)]

3.2.2 阶跃函数的实现

def step_function(x):
    if x > 0:
        return 1
    else:
        return 0
#改成能接收numpy数组的:
def step_function(x):
    y = x > 0 #y等于一个bool数组
    return y.astype(np.int)

#直观来说,以下x,y画图:
x = np.arange(-5.0, 5.0, 0.1) #生成[-0.5,0.5]以0.1为单位的数组
y = strp_function(x)

得:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CRmncu73-1689934058879)(C:\Users\Lin_Yu\AppData\Roaming\Typora\typora-user-images\image-20230721013437023.png)]

如图,以0为界,输出0切换为1(反之),值呈阶梯式变化,故称为阶跃函数

3.2.4 sigmoid 函数的实现

def sigmoid(x):
    return 1 / (1 + np.exp(-x))
#x 为数组亦可(numpy的广播功能)

#直观来说,以下x,y画图:
x = np.arange(-5.0, 5.0, 0.1) #生成[-0.5,0.5]以0.1为单位的数组
y = sigmoid(x)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b1Z7zQxc-1689934058879)(C:\Users\Lin_Yu\AppData\Roaming\Typora\typora-user-images\image-20230721014057356.png)]

3.3.5 二者的比较

对比图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6NPMVZk4-1689934058879)(C:\Users\Lin_Yu\AppData\Roaming\Typora\typora-user-images\image-20230721014218277.png)]

故可知:

  1. (不同点)神经网络中流动的是实数值信号,感知机是二元信号
  2. (相同点)宏观来说,输出形状相似。
  3. (相同点)无论信号多大/小,输出信号都在0~1。

3.2.6 非线性函数

阶跃函数和sigmoid函数都是非线性函数。

神经网络的激活函数必须使用非线性函数,否则无法发挥多层网络带来的优势。

3.2.7 ReLU 函数

现如今使用的函数。

输入大于0时,输出该值,输入小于等于0时,输出0.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tfb7yrgq-1689934058880)(C:\Users\Lin_Yu\AppData\Roaming\Typora\typora-user-images\image-20230721015252991.png)]

def relu(x):
    return np.maximum(0, x)

3.3 多维数组运算

3.3.1 多维数组

维数可以通过np.dim()获得。

3.3.2 矩阵乘法

np.dot()来进行数组乘积,eg.np.dot(A,B)

[tips:dot()中,前列数 = 后行数]

3.3.3 神经网络的内积

下面通过numpy矩阵来实现神经网络,来实现下图神经网络(省略偏置和激活函数,只有权重)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MmqyW4KO-1689934058880)(C:\Users\Lin_Yu\AppData\Roaming\Typora\typora-user-images\image-20230721150000486.png)]

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

X = np.array([1, 2])
x.shape ---> (2,)

W = np.array([[1, 3, 5],[2, 4, 6]])
print(W) --->[[1 3 5]
              [2 4 6]]
W.shape --->(2, 3)

Y = np.dot(X, W)
print(Y) --->[5 11 17]

如图,可以一次性计算出Y的元素,即使Y中有成百上千个元素,避免了使用(例如使用for)麻烦。

3.4 3层神经网络的实现

基于以上,我们可以代码实现下图神经网络。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-REMfQU6P-1689934058880)(C:\Users\Lin_Yu\AppData\Roaming\Typora\typora-user-images\image-20230721150805762.png)]

3.4.1 符号确认

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PcBT247E-1689934058881)(C:\Users\Lin_Yu\AppData\Roaming\Typora\typora-user-images\image-20230721150929846.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QUVPOoDL-1689934058881)(C:\Users\Lin_Yu\AppData\Roaming\Typora\typora-user-images\image-20230721151122615.png)]

3.4.2 各层间的信号传递的实现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8fmyHDq0-1689934058881)(C:\Users\Lin_Yu\AppData\Roaming\Typora\typora-user-images\image-20230721151325730.png)]

以下数学式来表示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bsgTWU0b-1689934058882)(C:\Users\Lin_Yu\AppData\Roaming\Typora\typora-user-images\image-20230721151406542.png)]

如果使用矩阵乘法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4ob3p8J8-1689934058882)(C:\Users\Lin_Yu\AppData\Roaming\Typora\typora-user-images\image-20230721151514569.png)]

接下来我们用代码来实现(3.9)

X = np.array([1.0, 0.5])
W1 = np.array([[0.1, 0.3, 0.5],[0.2, 0.4, 0.6]])
B1 = np.array([0.1, 0.2, 0.3])

print(W1.shape) --->(2, 3)
print(X.shape) --->(2,)
print(B1.shape) --->(3,)

A1 = np.dot(X, W1) + B1

接下来观察第一层中激活函数的计算过程。如下图,隐藏层的加权和(加权信号和偏置的总和)用a表示,被激活函数转换后的信号用z表示,h()表示激活函数,这里,我们使用sigmoid 函数来实现。

Z1 = sigmoid(A1)

print(A1) --->[0.3, 0.7, 1.1]
print(Z1) --->[0.57444252, 0.66818777, 0.75026011]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mSBcRSvW-1689934058883)(C:\Users\Lin_Yu\AppData\Roaming\Typora\typora-user-images\image-20230721152733869.png)]

接下来实现第1层到第2层的信号传递(如下图)

W2 = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
B2 = np.array([0.1, 0.2])
'''
print(Z1.shape) --->(3,)
print(W1.shape) --->(3, 2)
print(B1.shape) --->(2,)
'''
A2 = np.dot(Z1, W2) + B2
Z2 = sigmoid(A2)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6P7B3aPZ-1689934058883)(C:\Users\Lin_Yu\AppData\Roaming\Typora\typora-user-images\image-20230721153225454.png)]

最后是第2层到输出层的信号传递。

def identity_function(x):
    return x

W3 = np.array([[0.1, 0.3],[0.2, 0.4]])
B3 = np.array([0.1, 0.2])

A3 = np.dot(Z2, W3) + B3
Y = identity_function(A3) #或者 Y = A3

这里定义的identity_function()函数(也称“恒等函数”),并将其作为输出层的激活函数。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D8l7sn47-1689934058884)(C:\Users\Lin_Yu\AppData\Roaming\Typora\typora-user-images\image-20230721153733705.png)]

3.4.3 代码实现小结

def init_network():# 权重、偏置初始化
    network = {}# 字典保存每层的权重和偏置
    network['W1'] = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
    network['b1'] = np.array([0.1, 0.2, 0.3])
    network['W2'] = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
    network['b2'] = np.array([0.1, 0.2])
    network['W3'] = np.array([[0.1, 0.3],[0.2, 0.4]])
    network['b3'] = np.array([0.1, 0.2])
    
    return network

def forward(network, x): # 封装了输入输出信号的处理过程
    W1, W2, W3 = network['W1'],network['W2'],network['W3']
    b1, b2, b3 = network['b1'],network['b2'],network['b3']
    
    a1 = np.dot(x, W1) + b1
    z1 = sigmoid(a1)
    a2 = np.dot(z1, W2) + b2
    z2 = sigmoid(a2)
    a3 = np.dot(z2, W3) + b3
    y = identity_function(a3)
    
    return y

def identity_function(x):
    return x

network = init_network()
x = np.array([1.0, 0.5])
y = forword(network, x)
print(y)

3.5 输出层的设计

神经网络可以用在 分类问题回归问题,不过需要根据情况改变输出层的激活函数。

一般来说,回归问题用恒等函数,分类问题用softmax函数。

3.5.1 恒等函数和softmax函数

恒等函数会将输入按原样输出,不加任何改动地直接输出。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vEPCQ5x4-1689934058884)(C:\Users\Lin_Yu\AppData\Roaming\Typora\typora-user-images\image-20230721155519942.png)]

softmax函数可以使用下式表示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TW9B6n5Z-1689934058884)(C:\Users\Lin_Yu\AppData\Roaming\Typora\typora-user-images\image-20230721155556169.png)]

(exp(X)是表示e的x次方的指数函数)

以下图可以看出,输出输出层的各个神经元都受到所有输入信号的影响。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gjCzzphJ-1689934058885)(C:\Users\Lin_Yu\AppData\Roaming\Typora\typora-user-images\image-20230721155726483.png)]

现在来实现softmax函数:

a = np.array([0.3, 2.9, 4.0])

exp_a = np.exp(a)
sum_exp_a = np.sum(exp_a)
y = exp_a /sum_exp_a
#-----上式是按照公式来实现的,故不需要解释------
#-----接下来我们进行封装------
def softmax(a):
    exp_a = np.exp(a)
	sum_exp_a = np.sum(exp_a)
	y = exp_a /sum_exp_a
    
    return y

3.5.2 实现softmax函数的注意事项

上面的函数虽然正确描述了公式,但在计算机运算时存在溢出问题,即由于其中的指数函数运算。可能会返回一个代表无穷大的inf。

即可进行公式改进,改进后代码实现:

def softmax(a):
    c = np.max(a)
    exp_a = np.exp(a - c) #溢出对策
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a
    
    return y

3.5.3 softmax 函数 的特征

使用softmax()函数,可以按如下方式计算神经网络的输出:

a = np.array([0.3, 2.9, 4.0])
y = softmax(a)
print(y) ---> [ 0.01821127 0.24519181 0.73659691]
np.sum(y) ---> 1.0

如上,softmax函数总是输出0.0~1.0之间的实数,并且输出值的总和是1。

输出值的总和是1,是softmax函数的重要性质。正因如此,我们才可以把softmax函数的输出解释为“概率”。

如上,可以看出y[2]的概率最大(这里需要注意数组是从“0”开始)。

一般来说,神经网络只把输出值最大的神经元对应的类别作为识别结果。并且,即使使用softmax函数,输出值的最大神经元的位置也不会变。因此,在进行分类时,输出层的softmax函数可以省略。在实际问题中由于指数函数的运算量,一般输出层的softmax函数会被省略。

3.5.4 输出层的神经元数量

根据解决的问题来决定。

3.6 手写数字识别

假设学习已经全部完成,我们使用学习到的参数,先实现神经网络的“推理处理”,也称为神经网络的前向传播(forward propagation)

3.6.1 MNIST 数据集

这里使用MNIST手写数字图像集。该数据集是由0~9的数字图像构成的,训练图片有6万张,测试图片有1万张。

本书提供Python脚本mnist.py,使用其中的load_mnist()函数,就可以按如下方式读入数据。

import sys, os
sys.path.append(os.pardir) #为了导入父目录中的文件而进行的设定
from dataset.mnist import load_mnist

(x_train, t_train) (x_test, t_test) = load_mnist(flatten=True,normalize=False)

print(x_train.shape) #(60000, 784)
print(t_train.shape) # (60000,)
print(x_test.shape) # (10000, 784)
print(t_test.shape) # (10000,)

load_mnist 以(训练图像,训练标签),(测试图像,测试标签)的形式返回读入的数据.

可设置参数如下:

  1. normalize设置是否将输入图像正规化为0.01.0的值,如果False,则输入图像的像素保持原来的0255
  2. flatten 设置是否展开输入图像(变成一维数组),如果False,输入图像为1×28×28的三维数组;如果True,则输入图像保存为784个元素构成的一维数组。
  3. one_hot_label 设置是否将标签保存为one—hot,此表示是仅正确解标签为1,其余皆为0的数组。当False,只是像7、2这样的简单保存正确解标签。为True,则保存为one-hot。

接下来我们尝试显示 MNIST图像,同时也确认一下数据。图像显示使用PIL模块。下述代码会让第一张训练图像显示出来:

import sys, os
sys.path.append(os.pardir)
import numpy as np
from dataset.mnist import load_mnist
from PIL import Image

def img_show(img):
    pil_img = Image.fromarray(np.uint8(img))#把numpy数组的图像数据转换为PIL用的数据对象
    pil_img.show()
    
(x_train, t_train),(x_test, t_test) = load_mnist(flatten=True,
                                                 normalize=False)
img = x_train[0]
label = t_train[0]
print(label) --->5

print(img.shape) ---> (784,)
img = img.reshape(28, 28) #把图像的形状变成原来的尺寸
print(img.shape) ---> (28, 28)

img_show(img)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G2RsIk0w-1689934058885)(C:\Users\Lin_Yu\AppData\Roaming\Typora\typora-user-images\image-20230721171315754.png)]

3.6.2 神经网络的推理处理

下面对这个数据集实现神经网络的推理处理。

神经网络的输入层有784个(源于图像大小28*28=784)神经元,输出层有10个(源于0~9,10个数字类型)神经元。此外,这个神经网络有2个隐藏层,第1个隐藏层有50个神经元,第2个隐藏层有100个神经元,这个50和100可以设置为任何值。

先定义三个函数:

def get_data():
    (x_train, t_train),(x_test, t_test) = load_mnist(normalize=True,flatten=True, one_hot_label=False)
    return x_test, t_test

def init_network():# 会读入保存在pickle文件sample_weight.pkl中的学习到的权重参数
    with open("sample_weight.pkl",'rb') as f:
        network = pickle.load(f)   
    return network

def predict(network, x):
    W1, W2, W3 = network['W1'], network['W2'], network['W3']
    b1, b2, b3 = network['b1'], network['b2'], network['b3']
    a1 = np.dot(x, W1) + b1
    z1 = sigmoid(a1)
    a2 = np.dot(z1, W2) + b2
    z2 = sigmoid(a2)
    a3 = np.dot(z2, W3) + b3
    y = sigmoid(a3)
    return y

然后评价它的识别精度,即能在多大程度上正确分类。

x, t = get_data() #获得数据集
network = init_network() #生成网络

accuracy_cnt = 0
for i in range(len(X)): #逐一取出保存在x中的图像数据
    y = predict(network,x[i]) #分类
    p = np.argmax(y) #获得概率最高的元素的索引  np.argmax(x)函数取出数组中最大值的索引,将获取被赋给参数x的数组中的最大值元素的索引。
    if p == t[i]:# 比较神经网络所预测答案和正确解的标签
        accuracy_cnt +=1
print("Accuracy:" + str(float(accuracy_cnt) / len(x)))# 回答正确的概率作为识别精度

执行完上述代码后,会显示“Accuracy:0.9352”。这表示有93.52%数据被正确分类了。

3.6.3 批处理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ddPcKiFq-1689934058885)(C:\Users\Lin_Yu\AppData\Roaming\Typora\typora-user-images\image-20230721175440352.png)]

可以发现对应维度的元素个数是一致

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tHecCLgt-1689934058886)(C:\Users\Lin_Yu\AppData\Roaming\Typora\typora-user-images\image-20230721175558648.png)]

如上输入100 × 784 输出100 × 10,这表示100张图像的结果被一次性输出了。比如x[0]和y[0]中保存了第0张图像及其推理结果。

这样打包式的输入数据称为

x, t = get_data() 
network = init_network() 

batch_size = 100 ##批数量
accuracy_cnt = 0

for i in range(0, len(X), batch_size): 
    x_batch = x[i:i+batch_size]#通过x[i:i+batch_size]从输入数据中抽取批数据
    y_batch = predict(network,x_batch) 
    p = np.argmax(y_batch,axis=1)# axis=1 沿着一维方向
    accuracy_cnt += np.sum(p == t[i:i+batch_size])

print("Accuracy:" + str(float(accuracy_cnt) / len(x)))# 回答正确的概率作为识别精度
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值