前言
提醒:
文章内容为方便作者自己后日复习与查阅而进行的书写与发布,其中引用内容都会使用链接表明出处(如有侵权问题,请及时联系)。
其中内容多为一次书写,缺少检查与订正,如有问题或其他拓展及意见建议,欢迎评论区讨论交流。
分类与回归算法
机器学习中的分类与回归算法是两种主要的监督学习任务,它们分别用于解决不同类型的问题。以下是这两种算法的总结:
分类算法:
分类算法用于将数据分成不同的类别,适用于输出为离散标签的问题。常见的分类算法包括:
- 逻辑回归:使用逻辑函数来估计概率,用于二分类问题,也可以扩展到多分类问题。
- 支持向量机(SVM):通过找到最优的决策边界来最大化样本的分类准确率,适用于高维数据。
- 决策树:通过树结构来进行决策,每个节点代表一个特征的选择,叶子节点代表分类结果。
- 随机森林:由多个决策树组成的集成学习方法,通过投票来决定最终分类结果。
- 梯度提升决策树(GBDT):通过构建和结合多个弱学习器来形成强学习器,适用于分类和回归问题。
- 朴素贝叶斯:基于贝叶斯定理,假设特征之间相互独立,适用于文本分类等场景。
- K近邻(KNN):根据样本之间的距离进行分类,适用于小规模数据集。
- 神经网络:通过多层感知机学习数据的复杂模式,适用于图像、语音等复杂分类问题。
回归算法:
回归算法用于预测连续数值输出,适用于输出为连续变量的问题。常见的回归算法包括:
- 线性回归:通过拟合一条直线来预测目标变量的值,是最简单的回归方法。
- 岭回归:线性回归的扩展,通过引入L2正则化项来防止过拟合。
- Lasso回归:线性回归的另一种扩展,通过引入L1正则化项来进行特征选择。
- 弹性网回归:结合了岭回归和Lasso回归,同时引入L1和L2正则化项。
- 决策树回归:使用决策树结构来进行回归预测,适用于非线性关系。
- 随机森林回归:由多个决策树组成的集成学习方法,通过平均来决定最终回归结果。
- 梯度提升决策树回归(GBDT回归):通过构建和结合多个弱学习器来形成强学习器,适用于回归问题。
- 支持向量回归(SVR):支持向量机在回归问题上的应用,通过找到最优的决策边界来最大化样本的回归准确率。
- 神经网络回归:通过多层感知机学习数据的复杂模式,适用于复杂的回归问题。
分类与回归算法的比较:
- 输出类型:分类算法输出离散标签,回归算法输出连续数值。
- 评估指标:分类算法常用准确率、召回率、F1分数等指标,回归算法常用均方误差(MSE)、均方根误差(RMSE)等指标。
- 问题类型:分类算法适用于类别预测问题,如垃圾邮件检测;回归算法适用于数值预测问题,如房价预测。 在实际应用中,选择分类还是回归算法取决于问题的性质和需求。有时,可以将回归问题转化为分类问题,或者将分类问题转化为回归问题,具体取决于问题的特点和目标。
神经网络
B站大佬视频
从零设计并训练一个神经网络,你就能真正理解它了
原理分析
神经网络分类算法讲解
一、神经网络的基本结构与数学公式
神经网络主要由神经元组成。一个神经元的计算过程可以表示为:
- 加权求和:
z = w 1 x 1 + w 2 x 2 + . . . + w n x n + b = ∑ i = 1 n w i x i + b z = w_1x_1 + w_2x_2 + ... + w_nx_n + b = \sum\limits_{i=1}^n w_ix_i + b z=w1x1+w2x2+...+wnxn+b=i=1∑nwixi+b
其中, x i x_i xi 是输入数据, w i w_i wi 是对应的权重, b b b 是偏置项。 - 激活函数:
a = σ ( z ) a = \sigma(z) a=σ(z)
这里的 a a a 是神经元的输出, σ \sigma σ 是激活函数。常用激活函数包括 Sigmoid 和 ReLU 等。以 Sigmoid 为例:
σ ( z ) = 1 1 + e − z \sigma(z) = \frac{1}{1 + e^{-z}} σ(z)=1+e−z1
它将加权和 z z z 映射到区间 (0, 1),适用于二分类问题。
二、分类算法中的前向传播
以三层神经网络(输入层、隐藏层、输出层)为例: - 输入层到隐藏层:
a j ( 1 ) = σ ( ∑ i = 1 n w j i ( 1 ) x i + b j ( 1 ) ) a^{(1)}_j = \sigma\left(\sum\limits_{i=1}^n w^{(1)}_{ji}x_i + b^{(1)}_j\right) aj(1)=σ(i=1∑nwji(1)xi+bj(1))
其中, w j i ( 1 ) w^{(1)}_{ji} wji(1) 是输入层到隐藏层的权重, b j ( 1 ) b^{(1)}_j bj(1) 是隐藏层的偏置项。 - 隐藏层到输出层:
a k ( 2 ) = σ ( ∑ j = 1 m w k j ( 2 ) a j ( 1 ) + b k ( 2 ) ) a^{(2)}_k = \sigma\left(\sum\limits_{j=1}^m w^{(2)}_{kj}a^{(1)}_j + b^{(2)}_k\right) ak(2)=σ(j=1∑mwkj(2)aj(1)+bk(2))
对于多分类问题,输出层常用 Softmax 函数:
a k ( 2 ) = e z k ( 2 ) ∑ p = 1 p e z p ( 2 ) a^{(2)}_k = \frac{e^{z^{(2)}_k}}{\sum\limits_{p=1}^p e^{z^{(2)}_p}} ak(2)=p=1∑pezp(2)ezk(2)
其中, z k ( 2 ) z^{(2)}_k zk(2) 是输出层的加权和。Softmax 函数将输出转换为类别概率。
三、分类算法中的训练过程(基于反向传播和梯度下降) - 损失函数:
- 二分类问题的交叉熵损失:
H ( p , q ) = − [ y log ( q ) + ( 1 − y ) log ( 1 − q ) ] H(p, q) = -[y \log(q) + (1 - y) \log(1 - q)] H(p,q)=−[ylog(q)+(1−y)log(1−q)] - 多分类问题的交叉熵损失:
H ( p , q ) = − ∑ k = 1 p y k log ( q k ) H(p, q) = -\sum\limits_{k=1}^p y_k \log(q_k) H(p,q)=−k=1∑pyklog(qk)
- 二分类问题的交叉熵损失:
- 反向传播:
- 输出层误差梯度:
δ k ( 2 ) = a k ( 2 ) − y k \delta^{(2)}_k = a^{(2)}_k - y_k δk(2)=ak(2)−yk - 隐藏层误差梯度:
δ j ( 1 ) = σ ′ ( z j ( 1 ) ) ∑ k = 1 p w k j ( 2 ) δ k ( 2 ) \delta^{(1)}_j = \sigma'(z^{(1)}_j) \sum\limits_{k=1}^p w^{(2)}_{kj} \delta^{(2)}_k δj(1)=σ′(zj(1))k=1∑pwkj(2)δk(2)
- 输出层误差梯度:
- 梯度下降:
- 权重更新:
w j i ( ℓ ) = w j i ( ℓ ) − η ⋅ δ j ( ℓ ) ⋅ a i ( ℓ − 1 ) w^{(\ell)}_{ji} = w^{(\ell)}_{ji} - \eta \cdot \delta^{(\ell)}_j \cdot a^{(\ell-1)}_i wji(ℓ)=wji(ℓ)−η⋅δj(ℓ)⋅ai(ℓ−1) - 偏置更新:
b j ( ℓ ) = b j ( ℓ ) − η ⋅ δ j ( ℓ ) b^{(\ell)}_j = b^{(\ell)}_j - \eta \cdot \delta^{(\ell)}_j bj(ℓ)=bj(ℓ)−η⋅δj(ℓ)
通过迭代训练,使损失函数减小,得到有效分类模型。
优势补充:
- 权重更新:
- 非线性拟合能力:自动学习复杂特征映射,适用于高维、非线性数据。
- 自动特征学习:减少人工特征工程,提高泛化能力。
- 泛化能力:通过正则化(如 L2 正则化)防止过拟合。L2 正则化公式:
正则化项 = λ ⋅ ∑ w w 2 \text{正则化项} = \lambda \cdot \sum_{w} w^2 正则化项=λ⋅w∑w2
其中, λ \lambda λ 为正则化系数, w w w 为权重参数。
反向传播数学原理
-
损失函数:
假设损失函数为 C C C,例如均方误差损失:
C = 1 2 ∑ k ( y k − a k ( 2 ) ) 2 C = \frac{1}{2}\sum_{k}(y_k - a^{(2)}_k)^2 C=21k∑(yk−ak(2))2
其中, y y y 是真实标签, a ( 2 ) a^{(2)} a(2) 是模型的预测结果。 -
输出层误差:
计算输出层的误差 δ k ( 2 ) \delta^{(2)}_k δk(2):
δ k ( 2 ) = ∂ C ∂ z k ( 2 ) = ( a k ( 2 ) − y k ) ⋅ σ ′ ( z k ( 2 ) ) \delta^{(2)}_k = \frac{\partial C}{\partial z^{(2)}_k} = (a^{(2)}_k - y_k) \cdot \sigma'(z^{(2)}_k) δk(2)=∂zk(2)∂C=(ak(2)−yk)⋅σ′(zk(2))
其中, σ ′ ( z ) = σ ( z ) ⋅ ( 1 − σ ( z ) ) \sigma'(z) = \sigma(z) \cdot (1 - \sigma(z)) σ′(z)=σ(z)⋅(1−σ(z)) 是 Sigmoid 激活函数的导数。 -
隐藏层误差:
将误差从输出层传回到隐藏层,计算隐藏层的误差 δ j ( 1 ) \delta^{(1)}_j δj(1):
δ j ( 1 ) = ∑ k δ k ( 2 ) ⋅ w k j ( 2 ) ⋅ σ ′ ( z j ( 1 ) ) \delta^{(1)}_j = \sum_{k} \delta^{(2)}_k \cdot w^{(2)}_{kj} \cdot \sigma'(z^{(1)}_j) δj(1)=k∑δk(2)⋅wkj(2)⋅σ′(zj(1))
其中, z j ( 1 ) z^{(1)}_j zj(1) 是隐藏层第 j j j 个神经元的加权和, σ ′ \sigma' σ′ 是激活函数的导数。 -
梯度计算:
计算损失函数对权重和偏置的梯度:- 输出层权重和偏置:
∂ C ∂ w k j ( 2 ) = δ k ( 2 ) ⋅ a j ( 1 ) \frac{\partial C}{\partial w^{(2)}_{kj}} = \delta^{(2)}_k \cdot a^{(1)}_j ∂wkj(2)∂C=δk(2)⋅aj(1)
∂ C ∂ b k ( 2 ) = δ k ( 2 ) \frac{\partial C}{\partial b^{(2)}_k} = \delta^{(2)}_k ∂bk(2)∂C=δk(2) - 隐藏层权重和偏置:
∂ C ∂ w i j ( 1 ) = δ j ( 1 ) ⋅ x i \frac{\partial C}{\partial w^{(1)}_{ij}} = \delta^{(1)}_j \cdot x_i ∂wij(1)∂C=δj(1)⋅xi
∂ C ∂ b j ( 1 ) = δ j ( 1 ) \frac{\partial C}{\partial b^{(1)}_j} = \delta^{(1)}_j ∂bj(1)∂C=δj(1)
- 输出层权重和偏置:
-
参数更新:
使用梯度下降更新参数:- 输出层权重和偏置:
w k j ( 2 ) = w k j ( 2 ) − η ⋅ δ k ( 2 ) ⋅ a j ( 1 ) w^{(2)}_{kj} = w^{(2)}_{kj} - \eta \cdot \delta^{(2)}_k \cdot a^{(1)}_j wkj(2)=wkj(2)−η⋅δk(2)⋅aj(1)
b k ( 2 ) = b k ( 2 ) − η ⋅ δ k ( 2 ) b^{(2)}_k = b^{(2)}_k - \eta \cdot \delta^{(2)}_k bk(2)=bk(2)−η⋅δk(2) - 隐藏层权重和偏置:
w i j ( 1 ) = w i j ( 1 ) − η ⋅ δ j ( 1 ) ⋅ x i w^{(1)}_{ij} = w^{(1)}_{ij} - \eta \cdot \delta^{(1)}_j \cdot x_i wij(1)=wij(1)−η⋅δj(1)⋅xi
b j ( 1 ) = b j ( 1 ) − η ⋅ δ j ( 1 ) b^{(1)}_j = b^{(1)}_j - \eta \cdot \delta^{(1)}_j bj(1)=bj(1)−η⋅δj(1)
其中, η \eta η 是学习率。
- 输出层权重和偏置:
-
链式法则:
整个反向传播过程实际上是链式法则的运用,通过层层传递误差来计算梯度:
∂ C ∂ w = ∂ C ∂ a ⋅ ∂ a ∂ z ⋅ ∂ z ∂ w \frac{\partial C}{\partial w} = \frac{\partial C}{\partial a} \cdot \frac{\partial a}{\partial z} \cdot \frac{\partial z}{\partial w} ∂w∂C=∂a∂C⋅∂z∂a⋅∂w∂z -
实际应用中的优化:
- 梯度消失和梯度爆炸:通过使用合适的激活函数(如 ReLU)、更好的权重初始化方法(如 He 初始化)和梯度校正算法(如 Adam)来解决。
- 批处理和批标准化:通过批处理和批标准化减小内部协变量偏移,使梯度下降更加稳定。
通过这些步骤,反向传播算法能够有效地优化神经网络的权重和偏置,使得模型在训练数据上达到更好的拟合效果。
代码实现
手动实现
代码解释:
神经网络结构
输入层:2个神经元(特征)
隐藏层:3个神经元,使用Sigmoid激活函数
输出层:1个神经元,使用Sigmoid激活函数
示例问题
使用神经网络分类以下两个类别的数据:
类别0:点集 {(0,0), (0,1)}
类别1:点集 {(1,0), (1,1)}
import numpy as np
# 激活函数和其导数
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def sigmoid_derivative(x):
return x * (1 - x)
# 初始化权重和偏置
input_size = 2
hidden_size = 3
output_size = 1
np.random.seed(0)
weights_input_hidden = np.random.uniform(size=(input_size, hidden_size))
bias_hidden = np.random.uniform(size=(1, hidden_size))
weights_hidden_output = np.random.uniform(size=(hidden_size, output_size))
bias_output = np.random.uniform(size=(1, output_size))
# 训练数据
X = np.array([[0,0], [0,1], [1,0], [1,1]])
y = np.array([[0], [0], [1], [1]])
# 学习率
learning_rate = 0.1
# 训练神经网络
for epoch in range(10000):
# 前向传播
hidden_input = np.dot(X, weights_input_hidden) + bias_hidden
hidden_output = sigmoid(hidden_input)
final_input = np.dot(hidden_output, weights_hidden_output) + bias_output
final_output = sigmoid(final_input)
# 计算损失
loss = y - final_output
# 反向传播
d_output = loss * sigmoid_derivative(final_output)
error_hidden_layer = d_output.dot(weights_hidden_output.T)
d_hidden_layer = error_hidden_layer * sigmoid_derivative(hidden_output)
# 更新权重和偏置
weights_hidden_output += hidden_output.T.dot(d_output) * learning_rate
bias_output += np.sum(d_output, axis=0, keepdims=True) * learning_rate
weights_input_hidden += X.T.dot(d_hidden_layer) * learning_rate
bias_hidden += np.sum(d_hidden_layer, axis=0, keepdims=True) * learning_rate
# 测试神经网络
print("测试结果:")
for i in range(len(X)):
hidden_input = np.dot(X[i], weights_input_hidden) + bias_hidden
hidden_output = sigmoid(hidden_input)
final_input = np.dot(hidden_output, weights_hidden_output) + bias_output
final_output = sigmoid(final_input)
print(f"输入:{X[i]},预测输出:{final_output}, 真实输出:{y[i]}")
运行结果:
python函数库实现
使用Tensorflow,使用GPU训练,配置可参见:
【深度学习】TensorFlow(cuda版)安装以及对应第三方库安装流程
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.optimizers import Adam
# 定义模型
model = Sequential([
Dense(units=3, activation='sigmoid', input_shape=(2,)), # 隐藏层
Dense(units=1, activation='sigmoid') # 输出层
])
# 编译模型
model.compile(optimizer=Adam(learning_rate=0.1), loss='binary_crossentropy', metrics=['accuracy'])
# 训练数据
X = np.array([[0,0], [0,1], [1,0], [1,1]])
y = np.array([[0], [0], [1], [1]])
# 训练模型
model.fit(X, y, epochs=10000, verbose=0)
# 测试模型
print("测试结果:")
predictions = model.predict(X)
for i in range(len(X)):
print(f"输入:{X[i]},预测输出:{predictions[i].round()}, 真实输出:{y[i]}")
运行结果: