24.8.2学习笔记

以下搭建了一个MNIST手写数字识别的神经网络:

先有个基本轮廓

# 导入所需库
from keras.datasets import mnist  # 导入MNIST数据集模块
from tensorflow.keras.utils import to_categorical  # 导入 one-hot 编码工具
from keras import models, layers, regularizers  # 导入Keras模型、层和正则化模块
from tensorflow.keras.optimizers import RMSprop  # 导入RMSprop优化器
import matplotlib.pyplot as plt  # 导入绘图库

# 加载MNIST数据集
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
# mnist.load_data() 加载 MNIST 数据集,返回两个元组,分别包含训练集和测试集的图像和标签

# 数据预处理
# 将训练图像从(60000, 28, 28)的形状重塑为(60000, 784),并转换为浮点类型
train_images = train_images.reshape((60000, 28 * 28)).astype('float32')
# reshape() 用于改变数组的形状
# astype('float32') 将数据类型转换为32位浮点数

# 将测试图像从(10000, 28, 28)的形状重塑为(10000, 784),并转换为浮点类型
test_images = test_images.reshape((10000, 28 * 28)).astype('float32')

# 将训练标签转换为one-hot编码格式
train_labels = to_categorical(train_labels)
# to_categorical() 将整数标签转换为one-hot编码形式

# 将测试标签转换为one-hot编码格式
test_labels = to_categorical(test_labels)

# 构建神经网络模型
network = models.Sequential()
# Sequential() 是一种线性堆叠模型,可以一层一层地添加层

# 添加第一个全连接层
network.add(layers.Dense(units=128, activation='relu', input_shape=(28*28,),
                         kernel_regularizer=regularizers.l1(0.0001)))
# layers.Dense() 是一个全连接层
# units=128 表示该层有128个神经元
# activation='relu' 表示激活函数为ReLU
# input_shape=(28*28,) 表示输入数据的形状为784维
# kernel_regularizer=regularizers.l1(0.0001) 表示使用L1正则化来惩罚大权重值,减少过拟合

# 添加Dropout层,用于减少过拟合
network.add(layers.Dropout(0.01))
# layers.Dropout() 层在训练过程中随机关闭一定比例的输入单元,比例为0.01,以防止过拟合

# 添加第二个全连接层
network.add(layers.Dense(units=32, activation='relu', kernel_regularizer=regularizers.l1(0.0001)))
# 同上,但神经元数量为32

# 再次添加Dropout层
network.add(layers.Dropout(0.01))

# 添加输出层
network.add(layers.Dense(units=10, activation='softmax'))
# 输出层有10个神经元,对应MNIST数据集中的10个类别
# activation='softmax' 用于多分类问题,将输出转换为概率分布

# 编译步骤
# 使用RMSprop优化器,损失函数为categorical_crossentropy,评估指标为accuracy
network.compile(optimizer=RMSprop(lr=0.001), loss='categorical_crossentropy', metrics=['accuracy'])
# compile() 用于配置学习过程
# optimizer=RMSprop(lr=0.001) 使用RMSprop优化器,学习率为0.001
# loss='categorical_crossentropy' 使用交叉熵损失函数
# metrics=['accuracy'] 记录准确率作为评估指标

# 训练网络
# 使用fit函数训练模型,epochs表示训练多少轮,batch_size表示每次训练的数据量
network.fit(train_images, train_labels, epochs=20, batch_size=128, verbose=2)
# fit() 用于训练模型
# train_images 和 train_labels 分别是训练图像和标签
# epochs=20 表示模型会遍历整个训练集20次
# batch_size=128 表示每次更新权重时使用128个样本
# verbose=2 控制训练过程的输出信息,2表示每轮输出进度条

# 在测试集上测试模型性能
# 使用evaluate函数计算测试集上的损失和准确率
test_loss, test_accuracy = network.evaluate(test_images, test_labels)
# evaluate() 用于评估模型在给定数据集上的表现
# test_images 和 test_labels 是测试图像和标签
# 返回值是损失和准确率

print("test_loss:", test_loss, "    test_accuracy:", test_accuracy)
# 打印测试集上的损失和准确率

 Dropout是一种常用的正则化技术,它通过在训练过程中随机“丢弃”(即设置为0)一部分神经元的输出来防止过拟合。

当然可以!下面我会用通俗易懂的例子来解释三种正则化技术:权重衰减(L2正则化)、L1正则化和Dropout。

1. 权重衰减(L2正则化)

例子:假设你是一位园艺师,你的任务是设计一个花园,让花园里的植物既美观又健康。但是你注意到有些植物长得太高,遮挡了其他植物的阳光,导致整个花园看起来不协调。为了保持花园的整体美观,你决定修剪那些长得太高的植物,让它们不至于遮挡其他植物。

类比

  • 花园:模型
  • 植物:权重(模型中的参数)
  • 长得太高的植物:较大的权重值
  • 修剪植物:对较大的权重值施加惩罚

解释

  • 权重衰减(L2正则化):通过在损失函数中加入权重平方的和的一个系数,来惩罚较大的权重值。这就像修剪那些长得太高的植物一样,使模型整体更加平衡,避免某些权重过大而导致模型对训练数据的过分拟合。

2. L1正则化

例子:想象你是一位图书管理员,你的任务是整理图书馆中的书籍。你注意到有些书很少有人借阅,占用了很多空间。为了提高图书馆的空间利用率,你决定将这些不常借阅的书籍移除,只保留那些经常有人借阅的书籍。

类比

  • 图书馆:模型
  • 书籍:权重(模型中的参数)
  • 不常借阅的书籍较小或接近0的权重值
  • 移除书籍:使较小的权重值变为0

解释

  • L1正则化:通过在损失函数中加入权重绝对值的和的一个系数,来惩罚较大的权重值。这会导致一些较小的权重值变为0,从而简化模型,只保留那些最重要的特征。这就像图书管理员移除不常借阅的书籍一样,让模型更加简洁,只关注最重要的特征。

3. Dropout

例子:假设你是一位教练,你的任务是训练一支足球队。你注意到球员们在比赛中过于依赖某些明星球员,导致球队的整体协作能力下降。为了提高球队的整体实力,你在训练中采取一种策略,即每次训练时随机挑选一部分球员不上场,让其他球员有机会展现自己的能力。

类比

  • 足球队:神经网络
  • 球员:神经元
  • 不上场的球员:被设置为0的神经元输出
  • 随机挑选球员不上场:随机丢弃一部分神经元的输出

解释

  • Dropout:在训练过程中随机“丢弃”(即设置为0)一部分神经元的输出。这就像教练随机挑选球员不上场一样,迫使模型中的神经元学会独立工作,而不是依赖于其他特定的神经元。这样可以提高模型的鲁棒性和泛化能力,减少过拟合。

主要区别总结

  1. 权重惩罚方式

    • L1正则化使用权重的绝对值之和来惩罚较大的权重值。
    • L2正则化使用权重的平方和来惩罚较大的权重值。
  2. 特征选择

    • L1正则化倾向于产生稀疏解,即部分权重值为0,这有助于特征选择
    • L2正则化倾向于使所有权重值都非零,但值较小,有助于模型稳定性和泛化能力。
  3. 适用场景

    • L1正则化适用于特征数量很大,需要进行特征选择的情况。
    • L2正则化适用于特征数量适中,可能存在多重共线性的情况。

optimizer=RMSprop(lr=0.001) 这一行代码是在配置神经网络模型的训练过程时指定使用的优化算法及其相关参数。在这里,我们使用的是 RMSprop 优化器,并设置了学习率为 0.001。

下面是对这一行代码的详细解释:

  • optimizer: 这是 compile() 方法中的一个参数,用来指定模型训练过程中使用的优化器。优化器负责更新模型的权重以最小化损失函数。

  • RMSprop: 这是一种流行的梯度下降优化算法,它通过动态调整学习率来加速收敛速度。RMSprop 的主要思想是使用指数加权平均数来平滑梯度的平方,从而对梯度进行归一化。这有助于解决梯度消失或梯度爆炸的问题。

  • lr=0.001: 这是 RMSprop 优化器的一个参数,代表学习率(learning rate)。学习率决定了模型权重更新的步长。较小的学习率会导致训练过程较慢,但如果设置得过大,则可能导致训练过程不稳定,甚至无法收敛到最优解。这里设置的学习率为 0.001,这是一个常见的初始选择。

 

network.fit(train_images, train_labels, epochs=20, batch_size=128, verbose=2) 这个部分是可以修改的。

  1. epochs:表示训练的轮数。如果您觉得模型训练不够充分或过拟合,可以增加或减少轮数。例如,如果希望更充分地训练,可以将其设置为 30 或 50;如果担心过拟合,可能尝试降低到 10 或 15 。

  2. batch_size:控制每次训练时使用的数据量。较小的批大小可能导致训练更不稳定,但可能有助于模型更好地泛化;较大的批大小通常可以加快训练速度。您可以尝试将其修改为 64 、256 等不同的值。

  3. verbose:控制训练过程中的输出信息详细程度。除了 2 (显示每个 epoch 的训练进度),还可以设置为 0 (不显示输出)、1 (显示每个 epoch 的损失和准确率)。

 

梯度下降优化算法是一种非常基础也非常重要的机器学习和深度学习中的优化方法。下面我将以通俗易懂的方式解释梯度下降算法。

梯度下降的直观理解

想象一下,你站在一座山的山顶上,你的目标是下山到达山脚下的最低点。但是,你不能直接看到整个山脉的地形,只能感觉到脚下地面的倾斜情况。你的策略是每次都朝着最陡峭的下坡方向走一小步,直到你认为自己已经到达了最低点。

这个过程可以类比为梯度下降算法的工作原理。在这个类比中:

  • 山顶:初始状态,即模型刚开始时的权重。
  • 下山的方向:梯度方向,即权重更新的方向。
  • 最陡峭的下坡方向:梯度指向的方向,即损失函数下降最快的方向。
  • 一小步:学习率,即每次更新权重的步长。

梯度下降的工作流程

  1. 初始化

    • 开始时,模型的权重被随机初始化。
  2. 计算梯度

    • 梯度是损失函数相对于模型权重的导数。简单来说,它告诉我们如果改变权重,损失函数将如何变化。
    • 我们计算损失函数关于每个权重的梯度。

4.重复

         1.重复步骤2和3,直到达到某个停止条件,比如达到预定的最大迭代次数或者梯度足够小。

  • 梯度是损失函数相对于模型权重的导数。简单来说,它告诉我们如果改变权重,损失函数将如何变化。
  • 我们计算损失函数关于每个权重的梯度。使梯度下降,也就是(梯度)导数变为0,也就是损失函数的最小值

α 是学习率,它决定了我们沿着梯度方向移动的步长。如果 α 很大,我们就会在每次更新时迈出很大的一步;如果 α 很小,我们就会迈出很小的一步。

∇L是梯度,它指示我们应该朝哪个方向移动。如果我们想要最小化损失函数,我们应该沿着梯度的反方向移动,因为梯度总是指向损失函数增加的方向。(联想U型函数的图像的右半部分)

更新权重的过程就是按照梯度的反方向移动一定的步长(由学习率决定)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值