Colab - Tensorflow & Keras Get Started: 005 Keras Fine Tune Pre-Trained Models GTSRB
1. 源由
鉴于在《Jammy@Jetson Orin - Tensorflow & Keras Get Started: Transfer Learning & Fine Tuning》章节中,谈到神经网络训练资源(内存、GPU/CPU、时间)开销是非常大的,从一些示例运行的角度就能看出。
虽然已经都是示例代码,但是在Jetson Orin Nano的板子上仍然由于资源问题,无法顺利执行。比如:德国交通标志识别基准(GTSRB)这个示例,从Colab的运行资源显示情况看,GPU内存需要8.1GB,而Jetson Orin Nano的板子最高只有8GB(笔者手上的就是8GB的板子)。
-
如果有性能强大、资源充足的计算机或者Jetson 16GB系列的板子,那可以试试。但是笔者这里没有,因此只能另辟捷径。
-
不过互联网时代的学习,更多的是需要自主能动性。虽然,我们的这个Jetson Orin Nano的板子无法执行,Google的Colab IDE还是能够帮助我们解决这个问题。
鉴于以上关于训练学习资源、性能的问题,我们针对无人机系统设计的角度做了一些调整:《Ardupilot & OpenIPC & 基于WFB-NG构架分析和数据链路思考》,详见:6.3 GPU运算能力。
2. Colab介绍
Google Colab是一个托管的Jupyter Notebook服务,无需设置即可使用,并提供免费访问计算资源,包括GPU和TPU。Colab特别适用于机器学习、数据科学和教育领域。
注:有兴趣的朋友,可以去上面的链接详细了解。从我们的角度,有这样的一个学习平台,就节省了购买GPU的钱,可以继续我们学习算法的学习。
另外,Colab免费额度是定量的。因此,如果需要使用到Colab服务的朋友可以查阅相关付费资料:
以上是付费&免费的问题,但是作为学习,16GB以下的算法基本上还是可以覆盖到的。唯一大家可能需要注意的是,DEMO验证完成后,尽快与GPU/TPU资源断开连接,如果不断开Colab会封禁账号1天,如果多次封禁,那就不太好了。毕竟资源还是大家共享的。
3. 微调训练模型 - GTSRB
德国交通标志识别基准(GTSRB)是一个众所周知的分类数据集,包含来自43个类别的德国交通标志。整个数据集(训练和测试)包含超过50,000张图像。仅训练集就包含超过39,000张图像。
接下来演示如何利用预训练模型,经过小数据集样本微调训练模型。
3.1 准备
3.1.1 加载数据集
从网络上下载预先准备好的小数据样本集,并解压到当前目录下:
3.1.2 配置训练参数
这里使用Python的dataclasses
模块方便地创建两个类来配置数据和训练参数。
注:我们指定了LAYERS_FINE_TUNE = 8
,这是一个微调配置参数,表示我们想要微调VGG-16模型的最后八层。
3.1.3 建立训练和验证数据集
使用预先准备小训练数据集:每个类别包含28张图像,验证数据集每个类别包含12张图像。
在这里使用image_dataset_from_directory()函数读取。这是Keras中非常方便的一个用于创建图像数据集的实用工具。
数据集结构如下所示,每个类别的图像都包含在一个单独的类别子文件夹中。
main_directory/
├──> class_a/
│ ├──> a_image_1.png
│ └──> a_image_2.png
└──> class_b/
├──> b_image_1.png
└──> b_image_2.png
函数API只有一个必需参数,即数据集的顶层文件夹,但有几个可选参数可用于配置数据集。
注:尽管我们对其中一些参数使用了默认值,还是强调其中的一些。其中之一是如何指定标签编码的选项。在这里,我们决定使用整数编码,这是默认值(label_mode=‘int’),而不是一位有效编码。
映射数字顺序
训练和验证数据集中的类名具有一个非数字序列的字母数字。这些类名由数字组成,但它们不是按数字顺序排序。因此,我们需要在测试数据集中提供相同的映射。
检视下样本
3.1.4 加载测试数据集
虽然使用image_dataset_from_directory()
函数很容易创建训练和验证数据集。然而,由于测试数据集的图像和标签分别存储在文件系统上,需要编写一些自定义代码来读取和加载这些数据。
为了创建测试数据集,需要在内存中加载图像和标签,并将它们组合起来创建一个tf.data.Dataset
测试数据集,以下四个步骤来创建测试数据集:
- 从csv文件中检索类标签,将其存储在内存中作为Python列表。
- 构建图像文件路径的列表,将其存储在内存中作为Python列表。
- 将图像路径和相关标签组合在一个
tf.data.Dataset
对象中。 - 使用数据集对象的map方法加载和预处理数据集中的图像。
- Step1:从csv文件中(Test.csv)加载测试数据集,主要是类别信息
- Step2:对测试数据样本类别进行数字顺序映射编号
- Step3:获取测试数据样本图像文件位置信息
- Step4:将图像和标签组合起来创建测试数据集
- Step5:加载并预处理图像
- Step6:展示测试数据集部分样本
3.2 建模
3.2.1 加载VGG-16算法模型
为了配置模型进行微调,将加载模型的卷积基础部分,使用从ImageNet数据集中学习到的权重。这些权重作为微调模型以适应我们数据集的起点。
由于需要重新定义分类器,将加载模型而不包括分类器(include_top=False),这样我们就可以为数据集指定自己的分类器。
有关Keras中可用的VGG-16模型的更多信息,请参阅文档链接:Keras VGG-16模型API。
3.2.2 冻结卷积基础中的初始层
现在我们已经加载了卷积基础部分,需要锁定初始层,使得只有最后几层TrainingConfig.LAYERS_FINE_TUNE = 8
可训练。
有两种方法可以指定模型中可训练(可调整)的层:
- 可以首先将整个卷积基础部分设置为可训练,将trainable标志设置为True。然后遍历初始层,并将它们设置为不可训练,将每个层的相同标志(trainable)设置为False。
- 可以通过将trainable标志设置为False来冻结整个卷积基础部分,然后遍历最后几层并将trainable标志设置为True。
下面的代码单元中使用了第一种方法。首先将整个卷积基础部分设置为“可训练”,将trainable属性设置为True。
3.2.3 重新定义分类器
因为我们打算训练并使用模型来对交通标志进行分类(43个类别),所以我们需要添加自己的分类层。
在这个例子中,我们选择使用
- 一个包含128个节点的单个全连接的密集层
- 然后是一个包含43个节点的softmax输出层,每个节点对应一个类别中的43个类。
- 密集层的数量和每层的节点数量是一种设计选择,但输出层中的节点数量必须与数据集中的类别数量相匹配。
- 由于我们使用的数据集很小(每个类别40个样本),模型容易过拟合,所以我们还在分类器中添加了一个dropout层。
整个模型如下所示组装:
3.2.4 编译并训练模型
对于独热编码的标签,适当的损失函数将是CategoricalCrossentropy
。由于我们在模型输出中包含了一个Softmax层,我们指定from_logits=False
。这是默认设置,但明确指定是一个好的习惯。或者,从模型中删除Softmax层,并将from_logits=True
设置为损失函数将在内部应用Softmax函数。结果应该是相同的。
3.2.5 绘制训练成果
3.3 预测
样本预测分类vs真实分类对比代码:
3.3.1 验证集准确率
- 验证集,91.085%
- 验证样本
3.3.2 测试机准确率
- 测试集,91.742%
- 测试样本
4. 总结
微调预训练模型是一种强大的技术,允许将模型重新用于自定义数据集。
Keras捆绑了许多预训练的分类模型,可以方便地将模型加载到内存中,并为微调进行配置。
让我们总结微调预训练模型所需的关键步骤:
- 在微调预训练模型时,我们只加载模型的卷积基础部分,它使用ImageNet权重进行初始化
- “冻结”卷积基础的前几层,但允许最后几层进行训练(“微调”)
注:这些步骤通过模型的可训练属性来完成,以切换哪些层是可训练的,哪些是不可训练的。需要微调的层数是需要进行实验的。若能结合业务专业逻辑进行合理解释将会事半功倍。
- 分类器需要根据数据集重新定义,并使用随机权重进行初始化
通过上述这种微调训练方式,使得模型初始状态处于有利的位置。在进行持续学习,使其能够适应新数据集并比从头开始训练模型更快地学习,同时,节省更多的资源。
这种方法还允许将模型重新用于新数据集,而无需像从头开始训练模型那样需要更多的数据。
测试代码:005_Keras-Fine-Tuning-Pre-Trained-Models