大家好,我是Petter Guo
一位热爱探索
的全栈工程师
。在这里,我将用最接地气
的方式,带你玩转前端
、后端
到 DevOps
的硬核技术,解锁AI
,助你打通技术任督二脉,成为真正的全能玩家
!!
如果对你有帮助, 请点赞
+ 收藏
+关注
鼓励下, 学习公众号为 全栈派森
。
神经网络的原理
有关神经网络的核心概念,已经有单独的文章进行讲解,请参考神经网络核心概念解析进一步了解与学习
-
传统机器学习算法的局限性
- 特征工程的依赖性强
- 核心问题: 传统算法通常需要人工或半自动地从原始数据中提取、转换和选择有用的特征。这个过程称为特征工程。
- 对非结构化数据的处理能力有限
- 核心问题: 传统算法在处理图像、视频、音频、文本等非结构化数据时表现不佳。这些数据通常维度高且具有复杂的内部结构。
- 对大规模数据和高维数据的处理挑战
- 核心问题: 许多传统算法在面对海量数据时,训练速度会变得非常慢,甚至无法在合理时间内完成训练。同时,当特征维度非常高时("维度灾难"),模型的性能可能会下降,或者需要更复杂的降维技术。
- 模型复杂度与表达能力受限
- 核心问题: 传统算法通常基于相对简单的数学模型(如线性回归、决策树、简单核函数)。它们在捕捉数据中的复杂非线性关系和多层次抽象能力方面受到限制。
- ...
- 特征工程的依赖性强
-
神经网络的优势
- 强大的非线性建模能力和表达能力
- 优势: 神经网络通过多层非线性变换(激活函数)和大量的神经元及连接,能够学习和表示数据中极其复杂的非线性关系。它们可以近似任何复杂的函数。
- 自动特征学习(或特征提取)
- 优势: 这是神经网络最革命性的优势之一。它们能够从原始输入数据中自动学习和提取多层次、抽象的特征表示,而无需人工干预。例如,在图像识别中,CNN 可以自动学习从边缘、纹理到局部形状,再到物体部分的层次化特征。
- 端到端学习 (End-to-End Learning)
- 优势: 神经网络可以直接从原始输入(如图像像素、音频波形、原始文本)映射到最终输出(如分类标签、识别文本、预测值),而不需要复杂的手动预处理、特征提取和多个独立模型的组合。这简化了整个机器学习系统的构建和优化过程。
- 对非结构化数据的强大处理能力
- 优势: 神经网络在处理图像、视频、音频、自然语言文本等非结构化数据方面表现卓越。卷积神经网络(CNN)在计算机视觉领域、循环神经网络(RNN)和 Transformer 在自然语言处理和语音识别领域都取得了里程碑式的成就。
- ...
- 强大的非线性建模能力和表达能力
从感知器到单隐层网络
- 感知器是最基本的神经元

它可以接收输入, 并根据输入提供一个输出。

Sigmoid函数, 在神经网络中则称为激活函数, 用以类比人类神经系统中神经元的"激活"过程。
通过调整感知器的权重和偏置, 比如设置w1=20,w2=20,b=-10后,就成功的实现了新规则。
根据不同的数据输入,感知器适当的调整权重, 在不同的功能之间切换(也就是拟合),形成了一个简单的自适应系统,就说它拥有了**"感知"**事物的能力。
-
单神经元特征空间局限性
- 无法学习复杂的逻辑关系: 像 XOR 这种简单的非线性逻辑,单神经元都无法学习。这意味着它无法解决现实世界中许多稍微复杂一点的分类问题。
- 决策边界单一: 它的决策边界永远是一个简单的超平面。这限制了它对数据分布复杂性的建模能力。
- 对特征的线性组合敏感: 单神经元只能基于输入特征的线性组合来做出决策。如果特征之间的关系是高度非线性的,它就无能为力。
-
分层: 加入一个网络隐层
网络隐层就是把手工的特征工程工作丢给了神经网络, 网络第一层的权重和偏置自己去学,网络第二层的权重和偏置也是自己去学。 我们除了提供数据以及一些网络的初始参数之外, 剩下的事情全部让网络自己完成。

用Keras单隐层网络预测客户流失率
-
数据准备
- 在kaggle数据集中搜索 "bank-customer"
python
import numpy as np
import pandas as pd
df_bank = pd.read_csv("../input/bank-customer/BankCustomer.csv")
df_bank.head()

- 银行客户的分布情况
python
import matplotlib.pyplot as plt
import seaborn as sns
features = ['City', 'Gender', 'Age', 'Tenure', 'ProductsNo', 'HasCard', 'ActiveMember', 'Exited']
fig = plt.subplots(figsize=(15,15))
for i, j in enumerate(features):
plt.subplot(4, 2, i+1)
plt.subplots_adjust(hspace=1.0)
sns.countplot(x=j, data=df_bank)
plt.title("No. of costumers")

- 数据清洗
python
df_bank['Gender'].replace('Female', 0, inplace=True)
df_bank['Gender'].replace('Male', 1, inplace=True)
print("Gender unique values", df_bank['Gender'].unique())
d_city = pd.get_dummies(df_bank['City'], prefix='City')
df_bank = [df_bank, d_city]
df_bank = pd.concat(df_bank, axis=1)
y = df_bank['Exited']
X = df_bank.drop(['Name', 'Exited', 'City'], axis=1)
X.head()

- 拆分数据集
python
from sklearn.model_selection import train_test_split # 拆分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
- 尝试逻辑回归算法
python
from sklearn.linear_model import LogisticRegression # 逻辑回归模型
lr = LogisticRegression()
history = lr.fit(X_train, y_train)
print("逻辑回归预测准确率{:.2f}%".format(lr.score(X_test, y_test)*100))
# 逻辑回归预测准确率78.35%
- 单隐层神经网络的Keras实现
- 模型创建总结
python
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.utils import plot_model # 导入 plot_model
ann = Sequential() # 序贯模型创建
# 添加网络隐层 Dense: 层类型(全连接层) input_dim: 输入维度 unit: 输出维度 activation: 激活函数( 神经网络中使用 relu )
ann.add(Dense(units=12, input_dim=12, activation='relu'))
ann.add(Dense(units=24, activation='relu'))
ann.add(Dense(units=1, activation='sigmoid')) # 二分类问题输出层, Sigmoid是固定选择
ann.summary()

- 网络编译
python
# optimizer 优化器, loss 损失函数, metrics 评估指标
ann.compile(optimizer = 'adam', loss='binary_crossentropy', metrics=['acc'])
- 数据训练
python
# optimizer 优化器, loss 损失函数, metrics 评估指标
ann.compile(optimizer = 'adam', loss='binary_crossentropy', metrics=['acc'])

单隐层神经网络预测准确率: 78.90%
显然该结果是不尽人意的 。
- 分类报告

从单隐层神经网络到深度神经网络

浅层神经网络可以模拟任何函数,但是需要巨大的数据量去训练它。
深层神经网络解决了这个问题。相比浅层神经网络,深层神经网络可以用更少的数据量来学到更好的模型。
从网络拓扑结构或数学模型上来说, 深层神经网络里没有什么神奇的东西,正如费曼形容宇宙时说: "它并不复杂,只是很多而已"
- 梯度下降: 正向传播和反向传播
- 正向传播
(1). 从输入层开始,线性处理权重和偏置后,再经过一个激活函数处理得到中间隐层1的输出。
(2). 将隐层1的输出,作为隐层2的输入,继续线性处理权重和偏置,再经过一个激活函数处理得到隐层2的输出。
(3). 以此类推至隐层n。
(4). 通过输出处理得到输出层的分类输出(就是样本值, 也称为预测值)。
(5). 在输出层, 通过指定损失函数(不同类型的的问题对应不同的损失函数)得到一个损失值。
- 反向传播(BP算法)
反向传播就是反向计算偏微分, 信息会从神经网络的高层向底层反向传播, 并在这个过程中根据输出来调整权重。
反向传播的思路是拿到损失函数给出的值,从结果开始,顺藤摸瓜,逐步求导,偏微分逐步的发现每一个参数应该往哪个方向调整, 才能够减小损失。
-
深度神经网络中的一些可调超参数
- 优化器
- 激活函数
- 损失函数
- 评估指标
-
梯度下降优化器
梯度下降过程中,会有局部最低点出现, 也就是损失函数对于整个神经网络的参数来说并不总是凸函数, 而是非常复杂的函数。上面代码注释中有写(optimizer: 优化器)
关于神经网络优化,请参考神经网络优化进行了解与学习。
-
激活函数: 从Sigmoid到ReLU
激活: 可以将其简单理解成神经网络从线性变换到非线性变换的过程

Sigmoid函数是唯一的逻辑结构中的激活函数(单分类线性),适合神经网络的非线性激活函数ReLU,PReLU,eLU等。
- 损失函数的选择
- 二分类问题, 使用同样熟悉的二元交叉熵损失函数
python
ann.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
- 多分类问题,如果输出是one-hot编码,则用分类交叉熵损失函数
python
ann.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
用Keras深度神经网络预测客户流失率
- 模型编译
python
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.utils import plot_model # 导入 plot_model
ann = Sequential() # ANN 模型
ann.add(Dense(units=12,input_dim=12, activation='relu')) # 添加输入层
ann.add(Dense(units=24, activation='relu'))
ann.add(Dense(units=48, activation='relu'))
ann.add(Dense(units=96, activation='relu'))
ann.add(Dense(units=192, activation='relu'))
ann.add(Dense(units=1, activation = 'sigmoid')) # 添加输出层
ann.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['acc']) # 优化器, 损失函数, 评估指标
- 模型训练
python
# 训练集, 指定轮数, 批量大小, 验证集
history = ann.fit(X_train, y_train, epochs=30, batch_size=64, validation_data=(X_test, y_test))
- 训练数据

- 分类报告

- 结论
-
发现较深的神经网络训练效率要高于小型, 1-2轮之后,准确率迅速提升到0.79, 而单隐层网络需要好几轮才能达到这个准确率。
-
总体准确率对比有所提升, 而从F1分数上看,目前是较深神经网络反而不如单隐层网络, 从0.46下降到0.45。
深度神经网络的调试及性能优化
- 更换优化器 adam
python
ann.compile(optimizer='adam', loss='binary_crossentropy', metrics=['acc']) # 优化器, 损失函数, 评估指标
- 神经网络正则化: 添加Dropout层(只对训练集起作用)
直白理解: 为了让模型粗狂一点,不要过分追求完美。
原理: 在某一层之后添加Dropout层, 意思就是随机将该层的一部分神经元的输出特征丢掉(设为 0),相当于随机消灭一部分神经元。
python
ann = Sequential() # ANN 模型
ann.add(Dense(units=12,input_dim=12, activation='relu')) # 添加输入层
ann.add(Dense(units=24, activation='relu'))
ann.add(Dropout(0.5))
ann.add(Dense(units=48, activation='relu'))
ann.add(Dropout(0.5))
ann.add(Dense(units=96, activation='relu'))
ann.add(Dropout(0.5))
ann.add(Dense(units=192, activation='relu'))
ann.add(Dropout(0.5))
ann.add(Dense(units=1, activation = 'sigmoid')) # 添加输出层
ann.compile(optimizer='adam', loss='binary_crossentropy', metrics=['acc']) # 优化器, 损失函数, 评估指标
阅读到此, 欢迎交流 !!