52、神经网络训练:从评估到优化

神经网络训练:从评估到优化

1. 评估多层感知机(MLP)

在Python中,一旦实现了评估方法,评估大型神经网络和小型神经网络的难度是一样的,因为Python会帮我们完成所有工作。

MLP类的评估方法应接收一个64维向量作为输入,并返回一个10维向量作为输出。从输入到输出的过程是基于逐层计算激活值,从输入层一直到输出层。为了便于后续的反向传播,我们需要记录所有层的激活值。因此,我们将评估函数分为两步构建:
- 前馈(feedforward)方法 :用于计算所有层的激活值。输入层的激活值就是输入向量,要得到下一层的激活值,需要将当前层的激活值向量与权重矩阵相乘,加上下一层的偏置,然后将结果的每个坐标通过sigmoid函数。重复这个过程直到输出层。以下是代码实现:

class MLP():
    ...
    def feedforward(self,v):
        activations = [] 
        a = v
        activations.append(a) 
        for w,b in zip(self.weights, self.biases): 
            z = w @ a + b 
            a = [sigmoid(x) for x in z] 
            activations.append(a) 
        return activations
  • 评估(evaluate)方法 :运行前馈方法并提取最后一层的激活向量作为结果。代码如下:
class MLP():
    ...
    def evaluate(self,v):
        return np.array(self.feedforward(v)[-1])
2. 测试MLP的分类性能

使用合适大小的MLP,它现在可以接受一个数字图像的向量并输出结果。例如:

nn = MLP([64,16,10])
v = np.matrix.flatten(digits.images[0]) / 15.
nn.evaluate(v)

由于权重和偏置是随机初始化的,这些数字并不能很好地预测图像代表的数字。实际上,随机初始化的MLP只有10%的预测准确率,我们可以使用 test_digit_classify 函数来验证这一点:

test_digit_classify(nn.evaluate)
3. 使用梯度下降训练神经网络

训练神经网络意味着找到最佳的权重和偏置,使神经网络尽可能好地完成手头的任务。我们可以将训练过程看作一个最小化问题。

3.1 将训练构建为最小化问题

对于线性函数 ax + b 或逻辑函数 σ(ax + by + c) ,我们创建了一个成本函数来衡量这些函数与数据的匹配程度。对于MLP,它的行为可能取决于数百或数千个常量,包括所有层的权重和偏置。我们的神经网络有64、16和10个神经元的三层结构,总共有1210个常量需要调整。

我们可以将成本函数看作这些1210个值的函数,并使用梯度下降来最小化它。为了衡量神经网络输出向量与理想输出向量之间的误差,我们可以使用它们在10维空间中的距离的平方。

3.2 使用反向传播计算梯度

如果直接计算成本函数的1210个偏导数,计算量会非常大,因为每个偏导数都需要对成本函数进行两次评估。更好的方法是使用反向传播算法,它可以递归地计算所有偏导数,从输出层的权重和偏置开始,一直到第一层。

3.3 使用scikit-learn自动训练

我们可以使用scikit-learn库来自动完成成本计算、反向传播和梯度下降。具体步骤如下:
1. 准备数据 :将训练数据(数字图像的64维向量)放入一个NumPy数组中,并将对应的答案放入一个输出列表中。

x = np.array([np.matrix.flatten(img) for img in digits.images[:1000]]) / 15.0
y = digits.target[:1000]
  1. 初始化MLP :使用 MLPClassifier 类初始化一个MLP,并指定隐藏层的大小、激活函数、最大迭代次数等参数。
from sklearn.neural_network import MLPClassifier
mlp = MLPClassifier(hidden_layer_sizes=(16,), 
                    activation='logistic', 
                    max_iter=100, 
                    verbose=10, 
                    random_state=1,
                    learning_rate_init=.1) 
  1. 训练神经网络 :使用 fit 方法将输入数据和输出数据传递给MLP进行训练。
mlp.fit(x,y)
  1. 测试性能 :训练完成后,我们可以使用 _predict 方法对图像向量进行预测,并使用 test_digit_classify 函数测试其分类准确率。
def sklearn_trained_classify(v):
    return mlp._predict([v])[0]
test_digit_classify(sklearn_trained_classify)
4. 相关练习
  • 练习16.10 :使用显式循环重写前馈方法,而不是使用NumPy矩阵乘法,并确认结果与之前的实现完全匹配。
  • 练习16.11 :修改 test_digit_classify 函数,使其可以在测试集的自定义范围内工作,并测试训练后的MLP在训练集之后的500个示例上的表现。
def test_digit_classify(classifier,start=0,test_count=1000):
    correct = 0
    end = start + test_count 
    for img, target in zip(digits.images[start:end], 
digits.target[start:end]): 
        v = np.matrix.flatten(img) / 15
        output = classifier(v)
        answer = list(output).index(max(output))
        if answer == target:
            correct += 1
    return (correct/test_count)
  • 练习16.12 :使用平方距离成本函数,计算随机生成的MLP和scikit-learn训练的MLP在1000个训练示例上的成本。
def y_vec(digit):
    return np.array([1 if i == digit else 0 for i in range(0,10)])

def cost_one(classifier,x,i):
    return sum([(classifier(x)[j] - y_vec(i)[j])**2 for j in range(10)])

def total_cost(classifier):
    return sum([cost_one(classifier,x[j],y[j]) for j in range(1000)])/1000.
  • 练习16.13 :从 MLPClassifier 中提取权重和偏置,将它们插入到我们自己构建的MLP类中,并测试其在数字分类任务上的性能。
nn = MLP([64,16,10])
nn.weights = [w.T for w in mlp.coefs_] 
nn.biases = mlp.intercepts_
test_digit_classify(nn.evaluate,
                    start=1000,
                    test_count=500)
5. 总结

通过以上步骤,我们学习了如何评估MLP的性能,如何将训练过程构建为最小化问题,以及如何使用scikit-learn库自动训练神经网络。通过练习,我们可以进一步巩固所学知识,并深入理解神经网络的工作原理。

以下是一个简单的流程图,展示了神经网络训练的主要步骤:

graph TD;
    A[准备数据] --> B[初始化MLP];
    B --> C[训练神经网络];
    C --> D[测试性能];

通过这些步骤,我们可以不断优化神经网络的性能,使其在数字分类等任务上取得更好的效果。

神经网络训练:从评估到优化

6. 深入理解反向传播

虽然我们可以使用scikit - learn库自动完成训练,但了解反向传播的原理对于深入理解神经网络非常有帮助。反向传播的核心是递归地计算成本函数关于权重和偏置的偏导数。

在神经网络中,每个神经元的输出取决于前一层神经元的输出、权重和偏置。通过链式法则,我们可以从输出层开始,逐步计算每一层的偏导数。以下是反向传播的大致步骤:
1. 前向传播 :计算所有层的激活值,就像我们在 feedforward 方法中所做的那样。
2. 计算输出层的误差 :将神经网络的输出与理想输出进行比较,计算误差。
3. 反向传播误差 :从输出层开始,逐层计算误差的传播,更新每一层的权重和偏置。

下面是一个简化的反向传播过程的表格说明:
|步骤|操作|
| ---- | ---- |
|前向传播|计算各层激活值,记录中间结果|
|输出层误差计算|计算输出与理想输出的差异|
|反向传播误差|从输出层向输入层传播误差,更新权重和偏置|

7. 优化训练过程

在训练神经网络时,有几个关键因素会影响训练的效果和效率:
- 学习率 :学习率决定了在每次梯度下降步骤中权重和偏置更新的幅度。如果学习率过大,可能会导致训练过程不稳定,甚至无法收敛;如果学习率过小,训练速度会非常缓慢。
- 迭代次数 :迭代次数是指梯度下降算法执行的次数。如果迭代次数太少,神经网络可能无法充分学习数据的特征;如果迭代次数太多,可能会导致过拟合。
- 激活函数 :激活函数引入了非线性因素,使得神经网络能够学习复杂的模式。不同的激活函数具有不同的特性,例如sigmoid函数将输入映射到(0, 1)区间,ReLU函数则在输入大于0时直接输出输入值。

以下是一个不同学习率和迭代次数对训练效果影响的示例表格:
|学习率|迭代次数|训练准确率|
| ---- | ---- | ---- |
|0.01|50|80%|
|0.1|100|90%|
|1|20|不稳定|

8. 过拟合与欠拟合问题

在训练神经网络时,过拟合和欠拟合是两个常见的问题。
- 欠拟合 :当神经网络无法学习到数据的基本特征时,就会出现欠拟合。这可能是由于模型过于简单,或者训练数据不足导致的。解决欠拟合的方法包括增加模型的复杂度、增加训练数据等。
- 过拟合 :当神经网络在训练数据上表现良好,但在测试数据上表现不佳时,就会出现过拟合。这是因为模型过于复杂,学习了训练数据中的噪声和细节,而没有学习到数据的一般规律。解决过拟合的方法包括正则化、早停法等。

下面是一个简单的流程图,展示了过拟合和欠拟合的判断和解决方法:

graph TD;
    A[训练模型] --> B{训练集和测试集表现};
    B -->|训练集和测试集准确率都低| C[欠拟合];
    B -->|训练集准确率高,测试集准确率低| D[过拟合];
    C --> E[增加模型复杂度];
    C --> F[增加训练数据];
    D --> G[正则化];
    D --> H[早停法];
9. 拓展应用

神经网络在许多领域都有广泛的应用,除了数字分类,还包括图像识别、语音识别、自然语言处理等。在不同的应用场景中,需要根据具体的需求调整神经网络的结构和参数。

例如,在图像识别中,通常会使用卷积神经网络(CNN),它可以自动提取图像的特征。在自然语言处理中,循环神经网络(RNN)及其变体(如LSTM、GRU)可以处理序列数据。

10. 总结与展望

通过对多层感知机(MLP)的评估、训练和优化,我们深入了解了神经网络的工作原理和训练方法。从最初随机初始化的低准确率,到使用scikit - learn库训练后的高准确率,我们见证了神经网络的强大能力。

在未来的研究和应用中,我们可以进一步探索更复杂的神经网络结构,如深度卷积神经网络、生成对抗网络等。同时,我们也可以关注如何处理大规模数据、提高训练效率和模型的可解释性等问题。

通过不断地学习和实践,我们可以更好地利用神经网络解决各种实际问题,推动人工智能技术的发展。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值