机器学习之监督学习(三)神经网络
0. 文章传送
机器学习之监督学习(一)线性回归、多项式回归、算法优化[巨详细笔记]
机器学习之监督学习(二)二元逻辑回归
机器学习之实战篇——预测二手房房价(线性回归)
机器学习实战篇——肿瘤良性/恶性分类器(二元逻辑回归)
1. 深度学习 Deep Learning
神经网络是深度学习算法的基础。在监督学习板块中,前面我们学习了线性回归模型和逻辑回归模型,这些被称为传统机器学习模型。何为深度学习?和传统机器学习模型相比又有什么优势?
深度学习是机器学习的一个子领域,它主要通过使用深层神经网络(即具有多个隐含层的神经网络)来学习和提取数据中的复杂模式和特征。
深度学习的关键特点
多层结构:深度学习模型通常由多个层级组成,包括输入层、多个隐含层和输出层。每一层都可以提取不同级别的特征。
非线性激活函数:通过使用非线性激活函数(如ReLU、Sigmoid、Tanh等),深度学习模型能够学习复杂的非线性关系。
自动特征学习:深度学习能够自动从原始数据中提取特征,减少了对人工特征工程的需求。
大数据处理:深度学习在大规模数据集上表现优异,能够从中学习出有用的信息和模式。
端到端学习:深度学习模型可以直接从原始输入学习到最终输出,无需中间的特征处理步骤。
迁移学习能力:已经在一个任务上训练的深度学习模型可以被迁移到其他相关任务上,充分利用已有的知识。
深度学习VS传统机器学习
- 复杂数据表示
图像处理:深度学习能够自动从原始像素中提取特征,识别复杂模式,如图像分类和目标检测,而传统机器学习依赖手动特征提取,难以处理高维度和复杂结构。
自然语言处理:深度学习模型(如循环神经网络、Transformer)能够处理序列数据,捕捉上下文信息,适用于机器翻译和文本生成等任务。 - 大规模数据处理
大数据应用:深度学习在处理大规模数据集(如图像、视频和文本)时表现突出,能够利用数据的复杂性和多样性进行学习,而传统方法在数据量庞大时可能面临过拟合等问题。 - 多模态学习
结合多种数据类型:深度学习能够同时处理图像、文本和音频等多种信息,适用于多模态任务,如图像描述生成和视频分析,而传统机器学习通常不具备这种能力。 - 生成模型
内容生成:深度学习能够生成新的数据样本,如GANs生成高度逼真的图像或音频,传统机器学习方法在这方面的能力相对有限。 - 实时处理与反馈
快速决策:深度学习在实时应用(如自动驾驶、实时语音识别)中,能够处理大量数据并迅速做出决策,而传统模型可能无法满足实时性要求。 - 复杂的非线性关系建模
高维非线性映射:深度学习能够有效地捕捉复杂的非线性关系,适用于高度复杂的应用场景,而传统机器学习方法如线性回归、决策树在处理这些问题时会受到限制。 - 迁移学习
知识迁移:深度学习允许模型在一个任务上训练后迁移到另一个相关任务,利用已有知识优化新任务的学习,而传统机器学习往往需要从头开始训练。
2. 生物神经网络 Biological Neural Network
神经网络可以分为生物神经网络和人工神经网络:
(1)生物神经网络,指的是生物脑内的神经元、突触等构成的神经网络,可以使生物体产生意识,并协助生物体思考、行动和管理各机体活动。
(2)人工神经网络,是目前热门的深度学习的研究基础。目前对人工神经网络的定义多种多样,采用TKohonen1988年在NeuralNetworks 创刊号上给出的定义,即:“人工神经网络是由具有适应性的简单单元组成的广泛并行互连的网络,它能够模拟生物神经系统对真实世界物体所做出的交互反应”(Kohonen,1988)
先回顾一下高中生物所学的神经元:
回忆生物神经元的结构,细胞体作为神经元的主体,由细胞体向外延伸的多个突起神经纤维称为树突,树突作为细胞体的输入端,轴突为细胞体向外延伸最长的突起,末端由很多细的分支被称为神经末梢,每一条神经末梢相当于细胞体的输出端。每个神经元通过轴突的神经末梢与其他神经元的细胞体或树突相连接,这种连接称为突触。
细胞体的细胞膜在正常状态下形成内负外正的膜电位,当神经元突触与上千个其他神经元连接时,接受不同输入对神经元点位的影响也不用(视为不同输入具有权重),当膜电位升高到一个阈值时,就会产生一个脉冲。突触也可以分为兴奋性和抑制性两种,兴奋性的突触可能引起下一个神经元兴奋,抑制性的突出会抑制下一个神经元的兴奋。
前面所说的逻辑回归模型可视为最简单的神经网络结构(单个神经元模型),输入的各个特征相当于神经元树突接收的各个信号,不同特征乘以不同权重相当于不同输入对神经元具有不同影响,最后将线性组合的结果通过激活函数(逻辑回归中用的是sigmoid函数)作用后输出。
引入激活函数的原因是引入非线性,如果神经网络中没有激活函数(只使用线性激活函数),那无论层次结构多复杂,总体来看还是一个线性回归模型。
单个神经元的数学表达式:
z = ∑ i = 1 d w i x i + b = w ⃗ ⋅ x ⃗ + b a = f ( z ) z=\sum_{i=1}^{d}{w_ix_i}+b=\vec{w}\cdot\vec{x}+b\\a=f(z) z=i=1∑dwixi+b=w⋅x+ba=f(z)
3. 神经网络模型基本结构
了解了单个神经元的基本功能后,我们开始探讨由多个神经元构成的神经网络结构的基本组成。
假设我们想要制作一个模型判断服装产品是否能畅销,考虑的特征有价格、运费、营销力度和制作材料。
对于一件产品,输入层(input layer)输入这四个特征。进一步考虑,价格和运费联系到客户可购买能力,营销力度联系到客户对产品了解程度,材料和价格涉及到客户对产品质量感知,用这三个新特征构造一个隐层(hidden layer),下图中黄色箭头指示了哪些特征输入相应的隐层神经元。隐层的三个神经元接收输入后,进行线性运算,激活后输出,三个输出数值再传入最后一个神经元(即输出层 output layer),输出最终结果,用来预测服装畅销的概率。在这个案例中,我们通过对初级特征的提炼总结构造了一层新特征,提升了模型的复杂性,有利于更充分挖掘原始特征,取得更好的预测效果。
这种引入了隐层的神经网络,也称为多层感知机(multiple perception)。值得注意的是在上图中,由于我们人为地对原始特征进行了一定归纳,每个隐层神经元都只与特点的部分输入特征连接。但事实上神经网络具备自主提炼特征的能力,一般神经网络结构都采用全连接的形式,全连接层(Dense layer)是神经网络中的一种基本层类型,它的特点是每个神经元(节点)与前一层的所有神经元都有连接。可以认为在层层递进过程中,神经元逐渐学习到越来越复杂的特征表示,很难定义每一层神经元具体表示什么特征(比较抽象),举人脸识别的案例来说:
图片转化为像素向量输入(卷积)神经网络,经过三层隐层后输出,可以看到第一层学习到了图像的边缘/线条特征,第二层用边缘特征组合出更复杂的几何图形结构,表示人的眼睛、鼻子等区域,第三层几乎提炼出了整个面部结构,然后模型输出人脸对应某人的概率,实现人脸识别。这个过程体现了深度学习的核心优势:自动特征提取。相比传统的计算机视觉方法需要手动设计特征提取器,深度学习模型能够自动学习到从低级到高级的特征层次结构。
在讲解了几个案例后,相信大家已经领会到了神经网络的魅力,接下来从数学上进行定量描述。
下面定义:
n
[
i
]
:
第
i
层神经元数量
x
⃗
:
输入特征向量
a
⃗
[
i
]
:
第
i
层输出向量
z
j
[
i
]
:
第
i
层第
j
个神经元线性组合值
a
j
[
i
]
:
第
i
层第
j
个神经元输出值
W
[
i
]
:
第
i
层权重矩阵
w
⃗
j
[
i
]
:
第
i
层第
j
个神经元权重向量
b
⃗
[
i
]
:
第
i
层偏置向量
b
j
[
i
]
:
第
i
层第
j
个神经元偏置值
y
⃗
:输出目标向量
n^{[i]}:第i层神经元数量\\ \vec{x}:输入特征向量\\ \vec{a}^{[i]}:第i层输出向量\\ z_j^{[i]}:第i层第j个神经元线性组合值\\ a_j^{[i]}:第i层第j个神经元输出值\\ W^{[i]}:第i层权重矩阵\\ \vec{w}_{j}^{[i]}:第i层第j个神经元权重向量 \\ \vec{b}^{[i]}:第i层偏置向量\\ b^{[i]}_j:第i层第j个神经元偏置值\\ \vec{y}:输出目标向量\\
n[i]:第i层神经元数量x:输入特征向量a[i]:第i层输出向量zj[i]:第i层第j个神经元线性组合值aj[i]:第i层第j个神经元输出值W[i]:第i层权重矩阵wj[i]:第i层第j个神经元权重向量b[i]:第i层偏置向量bj[i]:第i层第j个神经元偏置值y:输出目标向量
对于第i层第j个神经元,其数学表达式为:
输入向量
:
i
n
p
u
t
⃗
[
i
]
=
a
⃗
[
i
−
1
]
(
i
n
p
u
t
⃗
[
1
]
=
x
⃗
)
输入向量 :\vec{input}^{[i]}=\vec{a}^{[i-1]}(\vec{input}^{[1]}=\vec{x})
输入向量:input[i]=a[i−1](input[1]=x)
线性组合:
z
j
[
i
]
=
w
⃗
j
[
i
]
⋅
i
n
p
u
t
⃗
[
i
]
+
b
j
[
i
]
线性组合:z_j^{[i]}=\vec{w}_{j}^{[i]}\cdot\vec{input}^{[i]}+ b^{[i]}_j
线性组合:zj[i]=wj[i]⋅input[i]+bj[i]
激活(激活函数
g
):
a
j
[
i
]
=
g
(
z
j
[
i
]
)
激活(激活函数g):a_j^{[i]}=g(z_j^{[i]})
激活(激活函数g):aj[i]=g(zj[i])
如上图的神经网络,有一个输入层,输入特征数量为4,有两个隐层,第一隐层有5个神经元,第二隐藏有3个神经元;还有一个输出层,包含一个神经元。
Q1 这个神经网络总共包含多少参数(包含权重和偏置)?我们来进行简单计算:
第一层(不考虑输入层)输入向量长度为4,每一个神经元参数包含长度为4的权重向量和一个偏置值,共5*(4+1)=25个参数,由此可总结规律:第i层有
n
i
n_i
ni个神经元,上一层有
n
i
−
1
n_{i-1}
ni−1个神经元(或输出),则该层参数数量计算公式为
n
i
∗
(
n
i
−
1
+
1
)
n_i*(n_{i-1}+1)
ni∗(ni−1+1)
由于四层大小分别为4、5、3、1,参数总数为
5
×
(
4
+
1
)
+
3
×
(
5
+
1
)
+
1
×
(
3
+
1
)
=
25
+
18
+
4
=
47
5×(4+1)+3×(5+1)+1×(3+1)=25+18+4=47
5×(4+1)+3×(5+1)+1×(3+1)=25+18+4=47
Q2 从前往后写出每个神经元的数学表达式:
了解了神经网络中符号表示和单个神经元的数学表达式后,我们不难写出这个神经网络中所有神经元的数学表达式,初步入门的读者可以自行练习,熟悉神经网络这个前向传播(forward propagation)的过程。
注意:当输入多个数据时,输入神经网络的为特征矩阵
模块一:TensorFlow搭建神经网络
在前面的线性回归、逻辑回归中,我们都自己编写了实现代码,在神经网络中,由于模型结构比较复杂(特别是后面说的反向传播梯度下降),个人觉得编写代码难度很高。因此个人建议把神经网络模型的基本数学原理了解清楚后,推荐借助python强大的机器学习库例如TensorFlow、pytorch来构建神经网络。
这里主要先介绍TensorFlow。TensorFlow 是一个开源的机器学习框架,由 Google Brain 团队开发。它被广泛用于深度学习、神经网络和其他机器学习任务。
TensorFlow 的核心数据结构是张量,可以看作是多维数组。所有的数据在 TensorFlow 中都是以张量的形式表示的,支持标量、向量、矩阵和更高维的数据结构。TensorFlow 使用计算图来表示计算过程。计算图由节点(操作)和边(数据流)组成,便于进行并行计算和优化。
Keras 是一个高级神经网络 API,旨在简化深度学习模型的构建和训练过程。它提供了简洁且易于使用的接口,使得用户可以快速构建和实验各种神经网络架构。 从 TensorFlow 2.x 开始,Keras 被作为 TensorFlow 的官方高层 API 集成。这意味着用户可以直接通过 TensorFlow 使用 Keras,享受两者的优势。如遇到两个模块不兼容的情况,解决方案参照传送门。在机器学习入门阶段,经常会遇到numpy、pandas、matplotlib、scipy、scikit-learn、TensorFlow等等这些数据分析、机器学习基本模块不兼容的情况,建议这时候重新创建新的虚拟环境,按照上面教程推荐的顺序和版本去安装各个库,使无后患之忧。有时在jupyter notebook中遇到不兼容错误,重启pycharm后可能会解决问题。
下面代码演示用TensorFlow搭建上图的神经网络:
第一步:导入tensorflow和相应模块
import tensorflow as tf
from tensorflow.keras.layers import Normalization,Input,Dense#(Input:输入层,Dense:全连接层,Normalization:标准化层)
from tensorflow.keras.models import Sequential #Sequential:联系各层,构造完整的神经网络
from tensorflow.keras.activations import sigmoid,relu,linear #激活函数:sigmoid、relu、linear
from tensorflow.keras.losses import BinaryCrossentropy,MeanSquaredError #损失函数,二元交叉熵损失函数、平均平方损失函数
第二步:可先用Normalizatoin模块对输入特征矩阵标准化
Norm_l=Normalization()
Norm_l.adapt(X)
Xn=Norm_l(X)
第三步:使用Sequential搭建神经网络模型
model=Sequential(
[
Input(shape=(4,)), #标明输入每一个特征向量的长度,即特征数
Dense(units=5,activation='sigmoid',name='1'), #第一层,5个神经元,使用sigmoid激活函数
Dense(units=3,activation='sigmoid',name='L2'), #第二层,3个神经元,使用sigmoid激活函数
Dense(units=1,activation='sigmoid',name='L_out') #输出层,1个神经元,使用sigmoid激活函数
]
)
第四步:查看模型结构
model.summary()
Model: "model1"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
L1 (Dense) (None, 5) 25
L2 (Dense) (None, 3) 18
L_out (Dense) (None, 1) 4
=================================================================
Total params: 47
Trainable params: 47
Non-trainable params: 0
第五步:编译模型,指定损失函数
#分类模型:二元交叉熵损失函数
model.compile(loss=BinaryCrossentropy())
#回归模型:平均平方损失函数
model.compile(loss=MeanSquaredError())
第六步:拟合数据,开始训练
model.fit(Xn,y,epochs=100) #epochs:迭代次数
第七步:应用模型进行预测,返回值是numpy对象,在分类问题中返回的是预测概率向量,需要通过设置阈值后转换为预测类别向量
y_pred=model.predict(X_pred)
查看训练后每层的参数:
layer_1=model.get_layer(name='L1')
w_1,b_1=layer_1.get_weights()
print(f'第一层参数w:{w_1},b:{b_1}')
在机器学习实战篇——肿瘤良性/恶性分类器(二元逻辑回归)中,我们使用逻辑回归模型取得了准确率高于95%的预测效果,而读者可以尝试使用神经网络模型训练,准确率可以达到100%,足见神经网络模型的强大。
4. 反向传播梯度下降 Back Propagation Gradient Descent
上面我们已经学习了如何使用tensorflow搭建神经网络,可以看到不需要对内部原理有多少认识,就足以搭建出一个强大的机器学习模型。我们不满足于此,希望了解神经网络模型是如何发挥魔力的。其具体训练机制是什么?学习了线性回归模型和逻辑回归模型后,我们能直接猜出答案:使用梯度下降算法迭代训练各个参数。但问题是,神经网络模型结构相当复杂,定义了代价函数后,计算偏导异常困难。在神经网络模型中,计算偏导的策略是反向传播(Back Propagation),为什么叫"反向"呢,因为梯度的计算是从网络的输出层开始,逐层向输入层传播,与数据的前向传播方向相反。反向传播依赖于微积分中的链式法则。这允许我们将复杂的复合函数的导数分解为更简单的部分。由于这部分涉及比较复杂的数学运算,如果我们的学习目标并非是从0手撕神经网络,那不必过分纠结,可以只了解其主要思想。
关于损失函数,在机器学习系列前两篇文章中已有详细解读,这里不再赘述,回归问题中通常采用平均平方损失函数,二元分类问题中通常采用二元交叉熵损失函数(对数损失函数)。梯度下降每一次迭代过程中都需要计算代价函数对各个参数的偏导,并更新各个参数。
关于反向传播的具体细节,参照笔者的两张图片笔记,可以算是最容易理解的推导版本: