欢迎光临
我们一直在努力

深度学习的基本概念及简单神经网络的实现

1. 深度学习简介

在这里插入图片描述

深度学习作为机器学习的一个分支,专注于使用多层神经网络(深度神经网络)来建模和解决问题。
人脑中有很多相互连接的神经元,当大脑处理信息时,这些神经元之间通过电信号和化学物质相互作用,在大脑的不同区域之间传递信息。神经网络使用人工神经元模仿这种生物现象,这些人工神经元由称为节点的软件模块构成,使用数值计算来进行通信和传递信息。

在这里插入图片描述
适合处理非结构化数据,如图像、音频、文本等

依赖大量数据和计算资源,训练时间较长

模型复杂,通常被视为“黑箱”,解释性较差

2. 深度学习的特点

  • 使用多层神经网络,能够自动提取数据的多层次特征
  • 适合处理非结构化数据,如图像、音频、文本等
  • 依赖大量数据和计算资源,训练时间较长
  • 模型复杂,通常被视为“黑箱”,解释性较差
    媒体和娱乐:从网上购物到流媒体服务,跟踪用户活动及开发个性化推荐也应用到了深度学习

客户服务:聊天机器人、虚拟助手和拨入式客户服务门户网站利用语音识别等工具

医疗卫生:通过图像识别应用和深度学习技术,医学影像专家可以利用数字化的医疗记录和医学影像数据来支持和改进医学诊断过程,提供更精确和高效的医疗服务

工业自动化:在工厂和仓库中,深度学习应用可以自动检测人或物体何时处于机器的安全距离之外,或协助质量控制及预测性维护

自动驾驶汽车:汽车行业研究员使用深度学习来训练汽车检测停车标志、红绿灯、人行横道和行人等对象

航空航天和军事:深度学习技术可以用来在监控的大片地理区域中检测物体,从远处识别需要关注的区域,并为部队验证安全或不安全区域

执法:语音识别、计算机视觉和自然语言处理(NLP)有助于分析大量数据,从而节省时间和资源

3. 深度学习应用场景

  • 金融服务:预测分析可推荐股票的算法交易,评估贷款审批的业务风险,检测欺诈行为,并帮助管理信贷和投资组合
  • 媒体和娱乐:从网上购物到流媒体服务,跟踪用户活动及开发个性化推荐也应用到了深度学习
  • 客户服务:聊天机器人、虚拟助手和拨入式客户服务门户网站利用语音识别等工具
  • 医疗卫生:通过图像识别应用和深度学习技术,医学影像专家可以利用数字化的医疗记录和医学影像数据来支持和改进医学诊断过程,提供更精确和高效的医疗服务
  • 工业自动化:在工厂和仓库中,深度学习应用可以自动检测人或物体何时处于机器的安全距离之外,或协助质量控制及预测性维护
  • 自动驾驶汽车:汽车行业研究员使用深度学习来训练汽车检测停车标志、红绿灯、人行横道和行人等对象
  • 航空航天和军事:深度学习技术可以用来在监控的大片地理区域中检测物体,从远处识别需要关注的区域,并为部队验证安全或不安全区域
  • 执法:语音识别、计算机视觉和自然语言处理(NLP)有助于分析大量数据,从而节省时间和资源
    神经元从树突接收其它神经元细胞发出的电化学刺激脉冲,这些脉冲叠加后,一旦强度达到临界值,这个神经元就会产生动作电位,沿着轴突发送电信号

轴突将刺激传到末端的突触,电信号触发突触上面的电压敏感蛋白,把一个内含神经递质的小泡(突触小体)推到突触的膜上,从而释放出突触小体中的神经递质。这些化学物质会扩散到其它神经元的树突或轴突上

基本概念和结构

人工神经网络(Artificial Neural Network,ANN)简称 神经网络(NN),是一种模仿生物神经网络结构和功能的计算模型。大多数情况下人工神经网络能在外界信息的基础上改变内部结构,是一种自适应系统(adaptive system),通俗地讲就是具备学习功能

在这里插入图片描述
人工神经网络中的神经元,一般可以对多个输入进行加权求和,再经过特定的“激活函数”转换后输出

在这里插入图片描述
最左边的一列神经元都表示输入,称为 输入层

最右边一列表示网络的输出,称为 输出层

输入层与输出层之间的层统称为 中间层(隐藏层)

相邻层的神经元相互连接(图中下一层每个神经元都与上一层所有神经元连接,称为 全连接),每个连接都会有一个 权重

神经元中的信息逐层传递(一般称为 前向传播forward),上一层神经元的输出作为下一层神经元的输入

4. 激活函数

2.1 激活函数的作用
激活函数是连接感知机和神经网络的桥梁,在神经网络中起着至关重要的作用

如果没有激活函数,整个神经网络就等效于单层线性变换,不论如何加深层数,总是存在与之等效的“无隐藏层的神经网络”。激活函数必须是非线性函数,也正是激活函数的存在为神经网络引入了非线性,使得神经网络能够学习和表示复杂的非线性关系

2.2 阶跃(Binary step)函数

之前的感知机中,式(2.2)表示的 hx 就是最简单的激活函数,它可以为输入设置一个“阈值”;一旦超过这个阈值,就切换输出(0或者1)。这种函数被称为“阶跃函数”。

f(x)={0,x<01,x≥0,f′(x)=0f(x) = \\begin{cases} 0, & x < 0 \\\\ 1, & x \\ge 0 \\end{cases}, \\quad f'(x) = 0f(x)={0,1,x<0x0,f(x)=0

在这里插入图片描述

阶跃函数的导数恒为0。

阶跃函数可以用代码实现如下:

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

这里的x只能取一个数值(浮点数),如果我们希望直接传入Numpy数组进行批量化的操作,可以改进如下:

def step_function(x):
return np.array(x > 0, dtype=int) # True为1 False为0

2.3 Sigmoid函数

f(x)=11+e−xf(x) = \\frac{1}{1 + e^{-x}}f(x)=1+ex1

f′(x)=11+e−x(1−11+e−x)=f(x)(1−f(x))f'(x) = \\frac{1}{1+e^{-x}} \\left(1 – \\frac{1}{1+e^{-x}}\\right) = f(x)(1 – f(x))f(x)=1+ex1(11+ex1)=f(x)(1f(x))

在这里插入图片描述

Sigmoid(也叫Logistic逻辑斯蒂函数)是平滑的、可微的,能将任意输入映射到区间(0,1)。常用于二分类的输出层。但因其涉及指数运算,计算量相对较高

Sigmoid的输入在[-6,6]之外时,其输出值变化很小,可能导致信息丢失

Sigmoid的输出并非以0为中心,其输出值均>0,导致后续层的输入始终为正,可能影响后续梯度更新方向

Sigmoid的导数范围为(0,0.25),梯度较小。当输入在[-6,6]之外时,导数接近0,此时网络参数的更新将会极其缓慢。使用Sigmoid作为激活函数,可能出现梯度消失(在逐层反向传播时,梯度会呈指数级衰减)。所以Sigmoid函数一般用于输出层或者深度较浅的神经网络隐藏层

Sigmoid函数可以用代码实现如下:

def sigmoid(x):
return 1 / (1 + np.exp(x))

2.4 Tanh函数
f(x)=1−e−2×1+e−2xf(x) = \\frac{1 – e^{-2x}}{1 + e^{-2x}}f(x)=1+e2x1e2x

f′(x)=1−(1−e−2×1+e−2x)2=1−f2(x)f'(x) = 1 – \\left(\\frac{1 – e^{-2x}}{1 + e^{-2x}}\\right)^2 = 1 – f^2(x)f(x)=1(1+e2x1e2x)2=1f2(x)

在这里插入图片描述

Tanh(双曲正切)将输入映射到区间(-1,1)。其关于原点中心对称。常用在隐藏层

输入在[-3,3]之外时,Tanh的输出值变化很小,此时其导数接近0

Tanh的输出以0为中心,且其梯度相较于Sigmoid更大,收敛速度相对更快。但同样也存在梯度消失现象

2.5 ReLU函数
f(x)=max⁡(0,x)={0,x≤0x,x>0f(x) = \\max(0, x) = \\begin{cases} 0, & x \\le 0 \\\\ x, & x > 0 \\end{cases}f(x)=max(0,x)={0,x,x0x>0

f′(x)={0,x≤01,x>0f'(x) = \\begin{cases} 0, & x \\le 0 \\\\ 1, & x > 0 \\end{cases}f(x)={0,1,x0x>0
注意:x=0时ReLU函数不可导,此时我们默认使用左侧的函数

在这里插入图片描述

ReLU(Rectified Linear Unit,修正线性单元)会将小于0的输入转换为0,大于等于0的输入则保持不变。ReLU定义简单,计算量小。常用于隐藏层

ReLU作为激活函数不存在梯度消失。当输入小于0时,ReLU的输出为0,这意味着在神经网络中,ReLU激活的节点只有部分是“活跃”的,这种稀疏性有助于减少计算量和提高模型的效率

当神经元的输入持续为负数时,ReLU的输出始终为0。这意味着神经元可能永远不会被激活,从而导致“神经元死亡”问题。这会影响模型的学习能力,特别是如果大量的神经元都变成了“死神经元”。为解决此问题,可使用Leaky ReLU来代替ReLU作为激活函数。Leaky ReLU f(x)=αx,x≤0 x,x>0,其中α是一个很小的常数在负数区域引入一个小的斜率来解决“神经元死亡”问题

ReLU函数可以用代码实现如下:

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

2.6 Softmax函数

yk=exk∑i=1nexi,k=1,…,ny_k = \\frac{e^{x_k}}{\\sum_{i=1}^{n} e^{x_i}}, \\quad k = 1, \\ldots, nyk=i=1nexiexk,k=1,,n

∂yk∂xi={yk(1−yi),k=i−ykyi,k≠i\\frac{\\partial y_k}{\\partial x_i} = \\begin{cases} y_k(1 – y_i), & k = i \\\\ -y_k y_i, & k \\ne i \\end{cases}xiyk={yk(1yi),ykyi,k=ik=i

Softmax将一个任意的实数向量转换为一个概率分布,确保输出值的总和为1,是二分类激活函数Sigmoid在多分类上的推广。Softmax常用于多分类问题的输出层,用来表示类别的预测概率

Softmax会放大输入中较大的值,使得最大输入值对应的输出概率较大,其他较小的值会被压缩。即在类别之间起到了一定的区分作用

Softmax函数可以用代码实现如下:
考虑到x较大时,指数函数的值会非常大,容易溢出,可以改进为:

本代码所用 API 说明

  • np.max(x):取数组最大值,用于“溢出对策”——先减去最大值再算指数,避免 exp 上溢。
  • np.exp(x) / np.sum(…):同前,配合溢出对策实现数值稳定的 Softmax。

def softmax(x):
# 注意,这里的x是一维的情况
x = x np.max(x) # 溢出对策
return np.exp(x) / np.sum(np.exp(x))

考虑到x为二维数组(矩阵)的情况,可以进一步写为:

本代码所用 API 说明

  • x.ndim:NumPy 数组的维数属性,用于判断输入是单行(1D)还是批量(2D)。
  • x.T:数组转置,用于批量数据按列(样本维)计算。
  • np.max(x, axis=0) / np.sum(…, axis=0):沿指定轴(0 轴,即每个特征列)取最大值/求和。
  • np.exp:逐元素指数。整体实现可处理批量输入的、带溢出对策的 Softmax。

def softmax(X): # 这里X 可能是 [[1,2,3]] 也可能是 [[1,2,3],[4,5,6]]
if X.ndim == 1:
X = X.reshape(1,1)
X = X np.max(X, axis=1, keepdims=True)
return np.exp(X) / np.sum(np.exp(X),axis=1,keepdims=True)

或者

def softmax(x):
if x.ndim == 2:
# 保持 [N,D],按行操作 axis=1
max_val = np.max(x, axis=1, keepdims=True) # (N,1)
x = x max_val
sum_exp = np.sum(np.exp(x), axis=1, keepdims=True) # (N,1)
return np.exp(x) / sum_exp
# 一维情况
x = x np.max(x)
return np.exp(x) / np.sum(np.exp(x))

2.7 如何选择激活函数

隐藏层

首选ReLU ,如果效果不好可尝试Leaky ReLU等

Sigmoid在隐藏层易导致梯度消失,应尽量避免

Tanh的输出均值为0,对中心化数据更友好,但仍可能引发梯度消失,仅适用于浅层网络

输出层

二分类选择Sigmoid

多分类选择Softmax

回归默认选择Identity

3. 神经网络的简单实现

深度神经网络由多个层(layer)组成,通常将其称之为 模型(Model)。整个模型接受原始 输入(特征),生成 输出(预测),并包含一些 参数。而在模型内部,每个单独的层都会接受一些输入(由前一层提供),生成输出(到下一层的输入),并包含一组参数;层层向下传递,就可以得到最终的输出值

神经网络中的参数,就是每一层的权重和偏置

3.1 三层神经网络

我们这里以一个三层神经网络为例,实现从输入到输出的处理计算,这个过程就是 前向传播(forward)
在这里插入图片描述
简单起见,我们的输入层(第0层)有2个神经元;第1个隐藏层(第1层)有3个神经元;第2个隐藏层(第2层)有2个神经元;输出层(第3层)有2个神经元

3.2 各层之间的信号传递

上面只是三层网络的示意图,实际上每层还应该有偏置,各输入信号加权总和还要经过激活函数的处理。接下来逐层进行分析,考察信号在各层之间传递的过程

输入层(第0层)→ 第1层
在这里插入图片描述

权重和神经元的上标(1)表示网络层号。而下标对于神经元来说,就是这一层内的“索引号”;对于权重来说则包含两个数字,分别代表前一层和后一层神经元的索引号。所以,w21(1) 就表示这是第1层的权重(输入层到第1层),并且是从第2个输入节点到第1层第1个节点。偏置的下标只有1个,因为前一层的偏置节点只有一个

所以,可以利用式(2.4)(2.5)得到:

a1(1)=w11(1)x1+w21(1)x2+b1(1)a_1^{(1)} = w_{11}^{(1)} x_1 + w_{21}^{(1)} x_2 + b_1^{(1)}a1(1)=w11(1)x1+w21(1)x2+b1(1)

z1(1)=h(a1(1))z_1^{(1)} = h\\left(a_1^{(1)}\\right)z1(1)=h(a1(1))

同样,对于第1层的第2个、第3个神经元,有:

a2(1)=w12(1)x1+w22(1)x2+b2(1)a_2^{(1)} = w_{12}^{(1)} x_1 + w_{22}^{(1)} x_2 + b_2^{(1)}a2(1)=w12(1)x1+w22(1)x2+b2(1)

a3(1)=w13(1)x1+w23(1)x2+b3(1)a_3^{(1)} = w_{13}^{(1)} x_1 + w_{23}^{(1)} x_2 + b_3^{(1)}a3(1)=w13(1)x1+w23(1)x2+b3(1)

我们可以直接写成矩阵乘法的形式:

A(1)=XW(1)+B(1)\\mathbf{A}^{(1)} = \\mathbf{X}\\mathbf{W}^{(1)} + \\mathbf{B}^{(1)}A(1)=XW(1)+B(1)

其中,

A(1)=(a1(1)a2(1)a3(1)),X=(x1x2),B(1)=(b1(1)b2(1)b3(1)),W(1)=(w11(1)w12(1)w13(1)w21(1)w22(1)w23(1))\\mathbf{A}^{(1)} = \\begin{pmatrix} a_1^{(1)} & a_2^{(1)} & a_3^{(1)} \\end{pmatrix}, \\mathbf{X} = \\begin{pmatrix} x_1 & x_2 \\end{pmatrix}, \\mathbf{B}^{(1)} = \\begin{pmatrix} b_1^{(1)} & b_2^{(1)} & b_3^{(1)} \\end{pmatrix}, \\mathbf{W}^{(1)} = \\begin{pmatrix} w_{11}^{(1)} & w_{12}^{(1)} & w_{13}^{(1)} \\\\ w_{21}^{(1)} & w_{22}^{(1)} & w_{23}^{(1)} \\end{pmatrix}A(1)=(a1(1)a2(1)a3(1)),X=(x1x2),B(1)=(b1(1)b2(1)b3(1)),W(1)=(w11(1)w21(1)w12(1)w22(1)w13(1)w23(1))

可以看到,由于有2个输入节点、3个第1层节点,所以全连接层的权重W就应该是一个2×3的矩阵。这样,我们就可以很容易地利用Numpy中的矩阵乘法计算出输出信号值了

第1层 → 第2层

第1层到第2层的处理类似,权重参数应该是一个3×2的矩阵

在这里插入图片描述

第2层 → 输出层(第3层)

第2层到输出层的处理也类似,权重参数为2×2的矩阵;不过输出层的激活函数一般与隐藏层是不同的,这里用 σ() 表示

在这里插入图片描述

接下来我们用代码来实现一下简单的神经网络实现

import numpy as np

def sigmoid(x): #x是ndarray
return 1 / (1 + np.exp(x))

# 函数一,init_network
def init_network():
network = {}
# W1 W2 W2
network['W1'] = np.array([[0.1,0.2,0.3],[0.4,0.5,0.6]]) #2 X 3
network['W2'] = np.array([[0.6,0.1],[0.5,0.4],[0.2,0.3]])
network['W3'] = np.array([[0.6,0.7],[0.8,0.9]])
# b1,b2,b3
network['b1'] = np.array([0.1,0.1,0.1])
network['b2'] = np.array([0.2,0.3])
network['b3'] = np.array([0.5,0.6])
# 参数返回
return network

# 函数二,前向传播 forward
def forward(X): # 需要传入数据X,X是(n,2)
network = init_network()
W1,W2,W3 = network['W1'],network['W2'],network['W3']
b1,b2,b3 = network['b1'],network['b2'],network['b3']
# 前向传播
A1 = X @ W1 + b1
Z1 = sigmoid(A1)

A2 = Z1 @ W2 + b2
Z2 = sigmoid(A2)

A3 = Z2 @ W3 + b3
Y = A3
return Y

#测试
X = np.array([[1.0,2.0],[3.0,4.0],[5.0,6.0]]) # n * 2
Y = forward(X)
print(Y)

init_network():对参数进行初始化,每一个权重参数都是一个矩阵(二维),每一个偏置参数则是一个数组(一维)

forward():前向传播,将输入信号转换为输出信号的处理操作

这里的激活函数,隐藏层用sigmoid,输出层用identity(恒等函数)

赞(0)
未经允许不得转载:171主机测评 » 深度学习的基本概念及简单神经网络的实现
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址