-
什么是激活函数?激活函数有什么作用呢?
激活函数是神经网络中的一种非线性转换函数,它将神经元的输入信号转换为输出信号。在神经网络的每一层中,激活函数都会对输入信号进行处理,以便引入非线性特性,从而使神经网络能够学习和表示更加复杂的函数关系。
可以看见下图是一个神经元,神经元的输入是n个不同的特征,每个特征占有一定的权重值,然后计算W1*X1+W2*X2+......+Wn*Xn,但是所得的结果是线性结果。如果遇到复杂的非线性关系,是不是就需要激活函数了。
所以激活函数主要的作用有以下两点:
- 引入非线性:激活函数能够解决神经网络的线性叠加问题,通过引入非线性,使得神经网络能够学习非线性关系,从而提高其表示能力。
- 激活神经元:激活函数能够控制神经元的激活状态,将输入信号转化为输出信号,从而传递到网络的下一层。(类似于脑神经元,当我们大脑受到比较小的刺激信号,可能没什么反应,也就是输出0,但是当我们大脑受到比较大的刺激信号,达到某种阈值以后,就会激活,刺激信号往下传递,输出1)
具体过程如下图:
附上一个小demo,给一些散乱的点,进行非线性拟合:
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt
# 生成训练数据
x_train = np.linspace(-2 * np.pi, 2 * np.pi, 100).reshape(-1, 1)
y_train = np.sin(x_train)
# 转换为 PyTorch 的 Tensor
x_train_tensor = torch.from_numpy(x_train).float()
y_train_tensor = torch.from_numpy(y_train).float()
# 定义更复杂的神经网络模型
class ComplexNet(nn.Module):
def __init__(self):
super(ComplexNet, self).__init__()
self.fc1 = nn.Linear(1, 20)
self.fc2 = nn.Linear(20, 20)
self.fc3 = nn.Linear(20, 1)
def forward(self, x):
# 激活函数relu
x = torch.relu(self.fc1(x))
x = torch.relu(self.fc2(x))
x = self.fc3(x)
return x
model = ComplexNet()
# 定义优化器和损失函数,并调整学习率
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 增加训练迭代次数
losses = []
for epoch in range(5000):
optimizer.zero_grad()
output = model(x_train_tensor)
loss = criterion(output, y_train_tensor)
loss.backward()
optimizer.step()
losses.append(loss.item())
# 可视化曲线拟合效果
x_test = np.linspace(-3 * np.pi, 3 * np.pi, 200).reshape(-1, 1)
x_test_tensor = torch.from_numpy(x_test).float()
y_pred = model(x_test_tensor).detach().numpy()
plt.figure()
plt.scatter(x_train, y_train, c='b', label='Actual')
plt.plot(x_test, y_pred, c='r', label='Predicted')
plt.legend()
plt.show()
print("finish!")
运行结果如下,可以看到这是一个非线性拟合,多亏了激活函数:
-
什么是损失函数?
其实损失函数上一节课已经介绍过了,在这里再进行一个复习。损失函数(Loss Function)是用来衡量模型预测结果与真实数值之间的差异的函数。在神经网络的训练过程中,我们通过不断调整模型的参数,使得损失函数的数值逐渐减小,以达到使模型的预测结果更加接近真实数值的目的。
损失函数常用的有两种:均方误差(MSE)和交叉熵损失(Cross Entropy Loss)
- 均方误差(MSE):常用于回归问题,计算预测值与真实值之间的平方差的均值。在pytorch中调用MSELoss()函数即可。
- 交叉熵损失(Cross Entropy Loss):常用于分类问题,特别是多分类问题,衡量两个概率分布之间的差异。
-
梯度下降算法
梯度下降算法是一种常用的优化算法,用于最小化函数的数值。在机器学习和深度学习中,梯度下降算法通常被用来更新模型参数,以使损失函数的数值逐渐减小,从而使模型的预测结果更加接近真实数值。
举一个最常见的例子:一个人站在山顶,想要快速下山,那什么决策是最好的呢,当然是每次选的都是最陡的路,一直执行这个决策,循环多次,总能到达山脚。而梯度就是衡量这个坡是否陡峭。
梯度是一个数学上的概念,指的是多元函数在某一点的变化率或斜率。对于一个具有多个自变量的函数,其梯度由各个自变量的偏导数组成,用向量表示。
上面已经解决了下山的方向,那我们是否还得考虑每次下山所迈步伐的大小。如果步子太大了,就存在来回波动的可能性,久久不能到达最低点;如果步子太小了,下山速度太慢,也是久久不能到达最低点,所以我们要确定一个合适的步长。
大步长的优点:
- 快速收敛: 使用较大的步长可以使算法更快地收敛到最优解,特别是在初始阶段能够快速朝着最优解的方向前进。
- 提高泛化能力: 有时候,通过使用较大的步长,模型更容易跳出局部最优解,从而提高泛化能力,尤其是在损失函数具有多个局部最优解的情况下。
大步长的缺点:
- 不稳定性: 较大的步长可能导致在参数空间中来回摆动,甚至可能导致算法无法收敛或发散。
- 风险: 过大的步长可能导致算法“跳过”最优解,甚至在参数空间内反复震荡而无法收敛。
小步长的优点:
- 稳定性: 使用较小的步长可以使得算法更加稳定,避免发散或者来回震荡。
- 精确度: 较小的步长可以使得算法更加精确地逼近最优解,特别是接近最优解时能够更细致地搜索最优参数。
小步长的缺点:
- 收敛慢: 使用较小的步长可能导致算法收敛速度较慢,特别是在初始阶段需要更多的迭代次数才能接近最优解。
- 陷入局部最优解: 过小的步长可能会使得算法难以跳出局部最优解,从而影响模型的泛化能力。
在下山的方向和步伐大小已经确定的情况下,我们现在考虑怎么实现梯度下降算法。
θ=θ'−α∗∇J(θ)
J是关于θ的函数,当前点处于θ',我们要想走到山底,我们就得沿着梯度的反方向-∇J(θ),按照一定的步长下降α,最终达到最低点θ。
当谈到梯度下降算法时,通常会提到三种主要的变种:批量梯度下降(Batch Gradient Descent)、随机梯度下降(Stochastic Gradient Descent)和小批量梯度下降(Mini-Batch Gradient Descent)。
-
批量梯度下降 (Batch Gradient Descent):
- 批量梯度下降是最基本的梯度下降算法。在每一次迭代中,它使用整个训练数据集来计算目标函数的梯度,然后更新模型的参数。
- 优点是收敛稳定,能够保证在合理步长下收敛到局部最优解或全局最优解。然而,由于需要在整个数据集上进行计算,对于大规模数据集来说计算成本较高。
-
随机梯度下降 (Stochastic Gradient Descent):
- 随机梯度下降与批量梯度下降的区别在于,它在每次迭代中仅使用单个样本来计算梯度并更新参数。因此,它的更新是更加频繁的,且计算开销较小。
- 虽然随机梯度下降有助于跳出局部最优解,并且在大规模数据集上更为高效,但由于梯度估计的高方差性,使得其不太稳定,需要精心调整学习率。
-
小批量梯度下降 (Mini-Batch Gradient Descent):
- 小批量梯度下降结合了批量梯度下降和随机梯度下降的优点。它在每次迭代中使用一个小批量的样本来计算梯度并更新参数。
- 这种方法在实践中得到了广泛应用,因为它兼顾了收敛速度和计算效率,尤其对于中等规模的数据集表现良好。
总的来说,这三种梯度下降算法各有优劣,选择哪种取决于数据集的规模、计算资源和对收敛速度的要求。
梯度下降的实现代码:
# 执行梯度下降算法
losses = [] # 创建一个空列表用于存储每次迭代的损失值
for i in range(num_iterations): # 进行指定次数的迭代训练
y_pred = linear_function(w, b, x_train) # 使用当前的参数 w 和 b 对输入数据 x_train 进行预测
loss = mean_squared_error(y_train, y_pred) # 计算预测值与实际值之间的均方误差损失
losses.append(loss) # 将本次迭代的损失值添加到列表中,用于后续可视化或分析
dw, db = compute_gradients(x_train, y_train, y_pred) # 计算损失函数关于参数 w 和 b 的梯度
w -= learning_rate * dw # 根据梯度下降算法更新参数 w
b -= learning_rate * db # 根据梯度下降算法更新参数 b
但是后续pytorch中封装好了一些优化器供我们使用,例如下图:
我们正在使用PyTorch中的Adam优化器,Adam是一种有效的梯度下降优化算法,结合了动量方法和自适应学习率。它能够在训练过程中自适应地调整学习率,并且通常能够更快地收敛到较好的解。
-
net.parameters()
: 这部分将神经网络模型net
的所有参数传递给优化器,以便优化器可以更新这些参数。这确保了优化器将对神经网络模型中的所有可训练参数进行优化。 -
lr=0.0002
: 这部分指定了学习率(learning rate)为0.0002,学习率决定了在每次参数更新时的步长大小,它是梯度下降算法中非常重要的超参数之一。在Adam优化器中,学习率是动态调整的,但初始的学习率仍然起着关键作用。
下面是一个使用均分误差求损失函数的线性模型,可以运行一下代码。
import numpy as np
import matplotlib.pyplot as plt
# 目标函数
def linear_function(w, b, x):
return w * x + b
# 均方误差损失函数
def mean_squared_error(y_true, y_pred):
return np.mean((y_true - y_pred) ** 2)
# 计算梯度
def compute_gradients(x, y_true, y_pred):
dw = np.mean((y_pred - y_true) * x)
db = np.mean(y_pred - y_true)
return dw, db
# 初始化参数
w = 0.5
b = 2.0
learning_rate = 0.05
num_iterations = 100
# 生成训练数据
x_train = np.random.rand(100)
y_train = 2.5 * x_train + 1.5 + np.random.randn(100) * 0.2
# 执行梯度下降算法
losses = []
for i in range(num_iterations):
y_pred = linear_function(w, b, x_train)
loss = mean_squared_error(y_train, y_pred)
losses.append(loss)
dw, db = compute_gradients(x_train, y_train, y_pred)
w -= learning_rate * dw
b -= learning_rate * db
# 绘制损失函数随迭代次数的变化
plt.plot(range(num_iterations), losses)
plt.xlabel('Iterations')
plt.ylabel('Loss')
plt.title('Training Loss over Iterations')
plt.show()
# 绘制训练数据和拟合结果的散点图
plt.scatter(x_train, y_train, label='Training Data')
plt.plot(x_train, linear_function(w, b, x_train), color='red', label='Fitted Line')
plt.xlabel('X')
plt.ylabel('Y')
plt.title('Fitted Linear Model')
plt.legend()
plt.show()
print("finish!")
运行结果如下:(左图是线性模型拟合,右图是损失函数收敛过程)
-
过拟合?欠拟合?如果造成这两种现象的?解决方案是什么?
1、什么是过拟合?
一家运动鞋公司,设计了一款新的运动鞋,设计师是按照他自己的脚来设计的,所以对他的脚来说无比贴合,然后他心里就会想这个鞋子的模型也太过于完美了,肯定可以大卖一把。但是对于其他一些高脚被、宽脚掌、扁平足的人很不友好!换个人可能这双鞋就不行了,也可以说这双鞋的适应力很差,在设计的时候感觉无比完美,但是拿出来实用的时候,好像显得不那么好了。这种就叫过度拟合,拟合的太完美了,反而不适应于正常的数据。
用官方一点的解释就是:过拟合是指机器学习模型过度适应训练数据,以致于在面对新数据时表现不佳的现象。具体而言,过拟合表现为模型在训练数据上表现良好,但在未曾见过的数据上表现糟糕。这种现象通常发生在模型过于复杂或者训练数据太少的情况下。
2、什么是欠拟合?
就是设计师在设计鞋的时候,可能谁的脚型他都不参考了,他大概设计出一双鞋,这个鞋可能都是圆形的......就会导致这个模型看起来很差。
用官方一点的解释就是:欠拟合是指机器学习模型无法很好地适应训练数据的特征和规律,导致在训练数据和新数据上都表现不佳的现象。具体而言,欠拟合表示模型不能很好地捕捉数据背后的复杂关系和模式,通常表现为在训练集和测试集上都呈现较高的误差。