概念解析
1.特征&&标签
1)特征(Feature)是描述数据的输入变量。它是从原始数据中提取出来的用于描述数据的属性。
例如,如果我们要预测西瓜是否是好瓜,那么西瓜的颜色、瓜蒂的形状、敲击的声音等就是特征。
2)标签(Label)是我们对应输入变量的目标值或类别。即当特征经过我们的模型后,我们希望它能输出的结果。
数据集的标签通常需要人工手动创建。例如,如果我们要训练一个图像分类模型,我们需要为每个图像打上相应的标签,例如“猫”、“狗”或“汽车”。即例如当我们向模型输送一张猫的图片,我们希望它的输出结果是“猫”这个分类。
总结一下:
特征是描述数据的输入变量,用来表征标签的特性。
标签是我们希望的的输出值,也就是目标变量。
2.模型的鲁棒性
模型的鲁棒性是指模型对于输入数据中的噪声、异常值或不完整信息的变化具有一定的稳定性。在现实世界中,数据往往包含噪声、缺失值或不完整的特征,因此构建具有鲁棒性的模型对于实际应用至关重要。一般来讲,我们可以通过以下的方式来增强模型的鲁棒性:
1)数据预处理:
-
清洗数据:去除异常值、处理缺失值,确保数据质量。
-
特征工程:选择合适的特征、进行特征变换,提高模型对数据变化的适应能力。
2)正则化:
-
在训练模型时,使用正则化技术(如L1正则化、L2正则化)来限制模型参数的大小,减少过拟合,提高鲁棒性。
3)集成学习:
-
使用集成方法(如随机森林、梯度提升树)来组合多个模型,减少单个模型的过拟合风险,提高鲁棒性。
4)模型选择:
-
选择鲁棒性较好的模型,例如决策树、支持向量机(SVM)等。
5)对抗训练:
-
针对对抗样本攻击,使用对抗训练方法来提高模型的鲁棒性。
6)增强数据集:
-
通过数据增强技术(如旋转、平移、缩放等)生成更多样本,增加模型的泛化能力。
7)跨领域训练:
-
在不同领域的数据上进行训练,提高模型的泛化能力
3.过拟合和欠拟合
1)过拟合:
-
定义:在统计学中,过拟合是指相较有限的数据而言,模型参数过多或者结构过于复杂,且过于紧密或精确地匹配特定数据集,以致于无法良好地拟合其他数据或预测未来的观察结果的现象。
-
过拟合的直观表现是:模型在训练集上表现良好,但在测试集上表现不佳,泛化性能差。
-
原因:在模型参数拟合过程中,由于训练数据包含抽样误差,复杂的模型可能会将这些抽样误差也进行拟合,导致过拟合;影响:过拟合模型在验证集或测试集上的损失函数值很大,无法泛化到新的数据,因此无法准确预测未来的观察结果。
-
解决方法: 减少特征数量:人工选择保留哪些特征,或使用模型选择算法。 实行正则化:保留所有特征,但减小参数的值或数量级,以限制模型的复杂度。
2)欠拟合:
-
定义:欠拟合是指模型不能在训练集上获得足够低的误差。换句话说,当模型过于简单时,它在训练集上表现很差,无法很好地学习到数据背后的规律。欠拟合的模型通常无法很好地泛化到测试集或未知数据上。
-
原因:
-
模型复杂度低:模型过于简单,无法捕捉数据中的复杂关系。
-
训练数据不足:如果训练样本数量有限,模型可能无法充分学习数据的特点。
-
特征不足:模型没有足够的输入特征来描述数据。
-
-
解决:
-
增加网络复杂度:增加模型的层数或神经元数量,使其能够更好地拟合数据。
-
增加特征:在模型中添加更多有意义的特征,以提高模型的表现。
-
数据集增强:通过旋转、缩放、裁剪等方式增加训练数据的多样性,改善模型的泛化能力。
-
4.模型训练的大致过程
每个批次的训练数据送入模型后,通过前向传播输出预测值,然后损失函数会计算出预测值和真实值之间的差异值,即损失值。接着通过反向传播来更新参数,降低真实值与预测值之间的损失,从而使模型生成的预测值更接近真实值,达到学习的目的。
5.前向传播
-
前向传播是数据从输入层到输出层在神经网络中的正向传递过程。
-
在训练神经网络时,输入数据被送入网络的输入层,然后通过隐藏层逐层传递,每一层的神经元会对输入的数据进行加权求和、激活函数处理等操作,最终产生输出。
-
前向传播的目的是根据当前网络的参数(权重和偏置),对输入数据进行处理,从而得到预测结果。
总而言之,前向传播其实就是一个名词解释,解释了数据在神经网络中的正向传递,最终得到预测值的过程。
6.反向传播
在介绍方向传播之前,我们先回忆一下,在求复合函数的导数时,我们用到了链式法则。
我们用以下例子进行引入,如下图所示,输入层有两个神经元x1,x2,隐含层有两个神经元h1,h2,最终输出只有一个神经元y,各个神经元之间全连接。
为了将问题具体化,我们先给各个变量赋值:令x1=1,x2=0.5,再令w1,w2,w3,w4,w5,w6的真实值分别为1,2,3,4.0.5,0.6。根据我们所给的值,可以算出y的真实值t=4。
现在我们来模拟一个反向传播的过程。一般我们已知的条件只有x1=1,x2=0.5,以及对应的目标t=4,即(样本,标签)。我们并不知道w1,w2,w3,w4,w5,w6的 真实值,我们需要随机为他们初始化值,假设我们的随机化结果是w1=0.5,w2=1.5,w3=2.3,w4=3,w5=1,w6=1,
因为我们这里选择的损失函数是E=1/2(t-y_pred)^2,我们要分别算出E对w1,w2,w3,w4,w5的偏导数(注意要使用链式法则哦,在链式法则中,E是y的函数,y是h1,h2的函数,而y是w5,w6的函数,h1,h2是w1,w2,w3,w4的函数)再根据诸如以下公式对w1,w2,w3,w4,w5,w6的值进行更新。(这个公式就是我们后面要介绍的梯度下降算法)
这样子,我们就完成了一次梯度下降法,我们使用得到的这6个参数的新的值再来预测一次网络输出值,得出的值y_pred 再代入损失函数E=1/2(t-y_pred)^2中计算,发现该值减少了,说明我们的模型预测稍微准确了一点。因此,只要重复这个步骤,不断更新网络参数我们就能学到更准确的模型了。
7.损失函数
损失函数(Loss Function)用于度量模型的预测值与真实值之间的差异程度。它是一个非负实值函数,损失函数越小,模型的鲁棒性就越好。
常见的损失函数:
均方误差损失函数(MSE):是回归任务中最常用的损失函数之一,MSE计算的是一个批量的预测值和真实值差值的平方和的均值。
交叉熵损失函数(Cross Entropy Loss)常用于分类问题中,特别是在使用sigmoid或softmax激活函数时。其用于衡量两个概率分布之间的相似性。
8.梯度下降和学习率
1)定义:梯度下降法是用来对损失函数进行优化的工具。通俗地说,它帮助我们寻找一个「极小值点」,从而让函数的值尽可能地小。我们可以将之类比为在山上寻找最低点的过程。想象一下你站在一个山坡上,你的目标是找到山坡上的最低点。梯度下降法就是帮你找到这个最低点的方法。
梯度下降法要求我们沿着梯度的反方向,以一定的步长(学习率)更新参数的值,使得损失函数逐渐减小。
2)为什么要沿着梯度下降的方向前进?
我们遇到的情况有以下情况:
导数为负(梯度为负),要想找到函数的最小值所对应的自变量的值(曲线最低点对应x的值)怎么走?答案是水平向右,随着x增大,导数的绝对值是减小的,即梯度下降。
导数为正(梯度为正),要想找到函数的自变量的值(曲线最低点对应x的值)怎么走?此时随着x减小,导数(梯度)的绝对值是减小的,即梯度下降。
即无论是哪种情况,要想找到函数的极小值,都是要沿着梯度下降的方向前进。
让我具体来介绍在上述“反向传播”知识点处提到的公式:
学习率的定义
学习率(Learning Rate)是深度学习中的一个超参数,它决定了在训练过程中模型参数更新的步幅大小。简单来说,学习率控制了模型参数在每次更新时的调整幅度。具体而言,学习率决定了模型参数在每一步更新中的变化量。
注:超参数是指在训练模型之前人工设定的配置选项或参数。这些超参数决定了模型的结构、训练过程的行为以及优化算法的行为,而不是模型的内部权重值。
学习率的作用
学习率的大小直接影响以下两个方面:
-
训练速度:较大的学习率会导致模型参数快速收敛,但可能会使训练过程不稳定。相反,较小的学习率会使训练速度变慢,但更稳定。
-
收敛性能:合适的学习率能够使模型在合理的时间内收敛到局部最优值,避免陷入局部最优解或震荡。
在深度学习中,我们通常采用以下方法来设置和调整学习率:
-
初始学习率设置:首先,我们需要设置一个初始学习率。这个初始学习率应该让损失尽可能快地降低。通常,初始学习率的范围在 10^-6到 1.0 之间。
-
学习率衰减:训练过程中,我们可以按照一定的时间表(学习率schedule)降低学习率,或者根据实际训练情况自适应地调整学习率。还有一些自适应算法(如Adam、Adagrad等)可以根据模型的训练情况自动调整学习率。
9.常见的梯度算法
1.批量梯度下降(Batch Gradient Descent):
它在每一次迭代中使用整个训练数据集来计算梯度,并更新模型参数。虽然计算梯度的效率较低,但是可以得到全局最优解。批量梯度下降的缺点是可能陷入局部最优解,同时对内存要求较高。
2.随机梯度下降(Stochastic Gradient Descent):
随机梯度下降是批量梯度下降的一种改进方法,它在每一次迭代中随机选择一个样本来计算梯度,并更新模型参数。虽然计算梯度的效率较高,但是由于参数更新的方向波动较大,因此收敛过程不稳定。随机梯度下降通常用于大规模数据集和在线学习。
3.小批量梯度下降(Mini-batch Gradient Descent):
小批量梯度下降是批量梯度下降和随机梯度下降的结合,每次迭代使用一个小批量的样本来计算梯度,并更新模型参数。这种方法在计算效率和收敛稳定性之间取得了平衡,是实际应用中最常用的梯度下降算法之一。
4.Adam优化算法:
Adam(Adaptive Moment Estimation)是一种自适应学习率的优化算法,结合了动量梯度下降和自适应学习率的优点。它通过计算梯度的一阶矩估计和二阶矩估计来自适应地调整学习率,从而在不同维度上具有不同的学习率。Adam算法在实践中表现良好,被广泛应用于深度学习中。
5.RMSProp优化算法:
RMSProp(Root Mean Square Propagation)是一种自适应学习率的优化算法,它在Adam算法之前提出,通过计算梯度的平方的移动平均来调整学习率,从而加速收敛过程。RMSProp算法通常用于优化神经网络的训练。
6.Adagrad优化算法:
Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,它通过将学习率分别应用于每个参数的梯度的平方来调整学习率,从而使得稀疏梯度的参数得到更大的更新,稠密梯度的参数得到较小的更新。Adagrad算法通常用于处理稀疏数据集和非凸优化问题。
对于这几个常见的梯度下降算法的详细分析后面我再通过其他文章给出。
10.激活函数
激活函数(Activation Function)是添加到人工神经网络中的函数,旨在帮助网络学习数据中的复杂模式。类似于人类大脑中基于神经元的模型,激活函数最终决定了是否传递信号以及要发射给下一个神经元的内容。在神经网络中,一个节点的激活函数定义了该节点在给定的输入或输入集合下的输出。
常见的激活函数如下所示:
Sigmoid函数:
-
输出范围:(0, 1)
-
优点:可以表示概率,用于二分类问题
-
缺点:容易产生梯度消失问题
Tanh函数
-
输出范围:(-1, 1)
-
优点:均值为0,收敛速度较快
-
缺点:也容易产生梯度消失问题
ReLU函数:
-
优点:解决了梯度消失问题,在正区间保持梯度不衰减
-
缺点:在负区间存在神经元死亡问题
对于激活函数的更加详细的分析,我将在后面的文章给出。
10.监督问题和非监督问题
监督学习和无监督学习都是模型训练的方法。
1)监督学习方式从过去的数据中学习,并将学习的结果应用到当前的数据中,以预测未来的事件。
2) 无监督学习的特点是:
没有明确的目的:与监督学习不同,无监督学习没有预先定义的目标。我们无法提前知道结果是什么。
不需要给数据打标签:在无监督学习中,我们不需要为数据样本打上标签,因此不需要人工标注。
无法量化效果:由于缺乏明确目标,无监督学习的效果很难量化。
其理念是先让计算机与大量变化的数据接触,并允许它从这些数据中学习,以提供以前未知的见解,并识别隐藏的模式。因此,无监督学习算法不一定有明确的结果,被用于在没有标签的数据中发现潜在结构。
11.回归和分类
回归和分类本质上都是为了基于特征,分析其内容,最后预测其值或者判别其类型。
他们之间的区别是分类问题输出的是物体所属的类别,回归问题输出的是物体的值。 具体来讲:分类的目的是为了寻找决策边界,即分类算法得到是一个决策面,用于对数据集中的数据进行分类。回归的目的是为了找到最优拟合,通过回归算法得到是一个最优拟合线,这个线条可以最好的接近数据集中的各个点。
在机器学习中常见的回归算法有:
-
线性回归: 将输入特征与输出之间的关系表示为一条直线,并找到最佳拟合这条直线的参数。
-
多项式回归:将输入特征的多项式组合作为模型,适用于非线性关系的数据。
-
支持向量回归(SVR):基于支持向量机的思想,适用于非线性问题。
-
神经网络回归:使用深度神经网络来建模输入和输出之间的复杂关系。
在机器学习中常见的分类算法有:
逻辑回归(Logistic Regression):用于二分类问题,预测概率。
线性回归代码示例
# 定义输入数据和目标数据
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
# 初始化权重 w
w = 1.0
# 定义前向传播函数
def forward(x):
return x * w
# 定义损失函数
def cost(xs, ys):
cost = 0
for x, y in zip(xs, ys):
y_pred = forward(x)
cost += (y_pred - y) ** 2
return cost / len(xs)
# 定义梯度计算函数
def gradient(xs, ys):
grad = 0
for x, y in zip(xs, ys):
grad += 2 * x * (x * w - y)
return grad / len(xs)
# 打印初始预测值
print('Predict (before training)', 4, forward(4))
# 训练模型
for epoch in range(100):
cost_val = cost(x_data, y_data)
grad_val = gradient(x_data, y_data)
w -= 0.01 * grad_val
print('Epoch:', epoch, 'w=', w, 'loss=', cost_val)
# 打印训练后的预测值
print('Predict (after training)', 4, forward(4))
代码分析
这段代码是一个简单的线性回归示例,用于拟合一组数据点。
数据集:
-
x_data
是输入特征的列表,包含了[1.0, 2.0, 3.0]
。 -
y_data
是对应的目标值(标签)的列表,包含了[2.0, 4.0, 6.0]
。
模型+损失函数
forward(x)函数定义了一个简单的线性模型y=wx,其中 w是权重,这个模型假设输入和输出之间存在线性关系。
cost(xs, ys) 函数计算了模型预测值与实际值之间的均方误差(MSE)。即对于每个数据点,计算预测值与实际值之差的平方,然后求平均。
其代码如下:
# 定义前向传播函数
def forward(x):
return x * w
# 定义损失函数
def cost(xs, ys):
cost = 0
for x, y in zip(xs, ys):
y_pred = forward(x)
cost += (y_pred - y) ** 2
return cost / len(xs)
对于每个输入 x 和对应的输出 y,首先通过 forward(x) 计算预测值 y_pred。 然后计算 (y_pred - y) ** 2,即预测值与实际值之间的平方差。 然后将所有样本的平方差相加,并除以样本数量 len(xs),得到平均损失。 最终,cost 函数返回的是平均损失。
梯度下降
我们在这使用gradient(xs, ys)
函数计算损失函数关于权重 w
的梯度。
他的代码思路是:对于每一组传入的(样本,标签),我们通过计算 (y_pred - y) * x
,并将其累加在grad变量中,最后并除以样本数量 len(xs)
,便可得到关于参数 w
的梯度。
//定义
def gradient(xs, ys):
//用于存储梯度的累积值
grad = 0
//遍历输入数据和目标数据的对应元素
for x, y in zip(xs, ys):
grad += 2 * x * (x * w - y)
return grad / len(xs)
现在我具体来讲一下为什么这里将2 * x * (x * w - y)作为梯度。
梯度便是损失函数的导数,我们前面的损失函数是(y_pred - y) ** 2,则其导数 2 * x * (x * w - y)便是梯度了。
训练过程:
-
通过多次迭代(100 次),不断更新权重
w
,使损失函数最小化。 -
每次迭代都会计算损失值和梯度,并根据梯度更新权重。
# 训练模型
for epoch in range(100):
cost_val = cost(x_data, y_data)
grad_val = gradient(x_data, y_data)
w -= 0.01 * grad_val
print('Epoch:', epoch, 'w=', w, 'loss=', cost_val)
输出结果:
-
在训练之前,模型对输入值 4 的预测是
4.0
。 -
训练后,模型的权重
w
被调整,使得预测更接近实际值,根据我们所给的数据,w的值应为2。
w值更新图
损失函数曲线图
matplotlib 介绍
1.matplotlib
是一个用于绘制图表和图形的 Python 库。它提供了许多功能,可以创建各种类型的图表,包括折线图、散点图、柱状图、饼图等 我们可以在同一个图中创建多个子图,以便同时显示多个图表。matplotlib还 提供了灵活的布局选项,以便我们可以自由排列子图。
2.pyplot 是 matplotlib 库的一部分,旨在使绘图工作更像 MATLAB。每个 pyplot 函数都会对图形进行一些更改,例如创建图形、在图形中创建绘图区域、在绘图区域中绘制线条、为图表添加标签等。它还可以打开图形并充当图形的 GUI 管理器。
3.代码模板要想使用 matplotlib ,我们需要通过以下命令进行安装。
pip install matplotlib
再在项目中将其导入:
import matplotlib.pyplot as plt
import numpy as np
然后就可以绘制基本图形了,基本的绘图步骤如下:
-
创建图形: 使用
plt.figure()
创建一个空的图形,或者使用plt.subplots()
创建一个包含单个坐标轴的图形,或者创建一个具有多个子图的图形。 -
绘制数据: 使用不同的绘图函数(如
plt.plot()
、plt.scatter()
、plt.bar()
等)在坐标轴上绘制数据。 -
设置标签和标题: 使用 plt.xlabel()
、
plt.ylabel()和
plt.title()` 设置坐标轴标签和图表标题。 -
显示图形: 使用
plt.show()
显示绘制的图形。
代码模板
我们以损失函数为纵轴,epochs为横轴为例进行分析。
首先导入用户绘图的 matplotlib库,然后定义两个数组epochs,和loss_values分别用于记录迭代次数和损失函数值,然后再每一轮的迭代中将对应的值进行统计。
-
记录迭代次数:
epochs.append(epoch)
-
记录损失函数值:
loss_values.append(cost_val)
再使用下面的函数对其进行绘画。
-
plt.plot(epochs, loss_values, label='Loss')
:绘制损失函数值随迭代次数变化的曲线。 -
plt.xlabel('Epoch')
:设置 x 轴标签为“迭代次数”。 -
plt.ylabel('Loss')
:设置 y 轴标签为“损失函数值”。 -
plt.title('Loss Curve')
:设置图表标题为“损失函数变化图”。 -
plt.grid(True)
:显示网格线。 -
plt.show()
:显示图表。
import matplotlib.pyplot as plt
# ... (您之前提供的代码)
# 训练模型
epochs = []
loss_values = []
for epoch in range(100):
cost_val = cost(x_data, y_data)
grad_val = gradient(x_data, y_data)
w -= 0.01 * grad_val
epochs.append(epoch)
loss_values.append(cost_val)
# 打印训练后的预测值
print('Predict (after training)', 4, forward(4))
# 绘制损失函数变化图
plt.plot(epochs, loss_values, label='Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Loss Curve')
plt.grid(True)
plt.show()