AnyMath 文档
Notebook

使用卷积神经网络进行图像分类

在这个项目中,我们正在训练一个卷积神经网络来对几个类的图像进行分类。 在输出端,我们得到一个训练有素的算法,该算法将图像作为输入,并返回它可能属于的类的预测。

让我们准备环境

我们将安装必要的软件包并配置环境以显示静态图表。 如果库出现问题,请运行命令 EngeePkg.purge(),这将从您的系统中消除除系统软件包之外的所有软件包,并允许您安装必要的软件包而不会出现兼容性问题。

In [ ]:
# 安装必要的软件包
Pkg.add(["Flux", "BSON", "ImageTransformations"])
gr();

训练数据位于"训练数据"目录中的几个文件夹中。 文件夹名称从文件系统中读取并成为类名。 我们还指出了分类示例(带有未知标签)的位置。

In [ ]:
DATA_DIR = "$(@__DIR__)/训练数据";
UNKNOWN_DIR = "$(@__DIR__)/未知";

模型训练和验证

在这个项目中,我们将从头开始训练以下类型的卷积模型:

default_neuralnet_architecture.svg

在脚本中 train.jl 进行的功能进行收集:

  1. 上传图片从类文件夹,调整大小为128x128,规范化
  2. 计算类的不平衡(多少叉,多少汤匙)
  3. 数据划分为列车/测试(分层,75%/25%)
  4. *模型组装—-卷积网络与BatchNorm和Dropout
  5. 平衡批次-所以在每个屠夫有两个类平等
  6. *增强—-通过反射和突出显示使数据集中的样本加倍
  7. 学习周期-前进传球,损失计算,后退传球,体重更新
  8. 质量评估-准确性,精度,召回测试
  9. 提前停止-停止,如果没有改善8个时代
  10. 保存最佳模型
In [ ]:
include("$(@__DIR__)/_scripts/train.jl")
model, classes = train_model(DATA_DIR; epochs=25, batch_size=16, lr=0.0005, test_split=0.25);
批量大小:16,学习率:0.0005
测试样品的百分比:25.0%
Найдено классов: 2: ["叉子,叉子", "勺子"]

===类分布===

总图像:335(128×128)
  叉:189幅图像(56.4%)
  勺子:146图像(43.6%)

===数据分离===
  培训:252(75.2%)
  测试结果:83(24.8%)
型号参数:607810

===培训===
  历元1/25,火车损失:1.3937,火车Acc:44.4%,测试Acc:44.6%★(精度/按类召回:叉子:65.2%/31.9%,勺子:46.7%/77.8%)
  Epoch2/25,列车损耗:1.3289,列车Acc:48.0%,测试Acc:42.2%(精度/按类召回:叉子:75.0%/12.8%,勺子:45.3%/94.4%)
  Epoch3/25,火车损失:1.3427,火车Acc:66.3%,测试Acc:61.4%★(精度/按类召回:叉子:63.8%/78.7%,勺子:60.0%/41.7%)
  Epoch4/25,列车损失:1.1816,列车Acc:57.1%,测试Acc:49.4%(精度/按类召回:叉子:72.7%/17.0%,勺子:45.8%/91.7%)
  Epoch5/25,火车损失:1.1303,火车Acc:79.0%,测试Acc:75.9%★(精度/按类召回:叉子:71.7%/80.9%,勺子:70.0%/58.3%)
  Epoch6/25,列车损耗:1.0433,列车Acc:73.4%,测试Acc:68.7%(精度/按类召回:叉子:77.8%/74.5%,勺子:68.4%/72.2%)
  Epoch7/25,列车损耗:0.9447,列车Acc:78.2%,测试Acc:67.5%(精度/按类召回:叉子:78.0%/68.1%,勺子:64.3%/75.0%)
  Epoch8/25,火车损失:0.9592,火车Acc:79.4%,测试Acc:73.5%(精度/按类召回:叉子:90.6%/61.7%,勺子:64.7%/91.7%)
  Epoch9/25,列车损耗:1.0558,列车Acc:84.1%,测试Acc:75.9%(精度/按类召回:叉:93.8%/63.8%,勺子:66.7%/94.4%)
  Epoch10/25,列车损耗:0.8999,列车Acc:81.3%,测试Acc:67.5%(精度/按类召回:叉子:78.9%/63.8%,勺子:62.2%/77.8%)
  Epoch11/25,火车损失:0.97,火车Acc:86.5%,测试Acc:75.9%(精度/按类召回:叉:78.3%/76.6%,勺子:70.3%/72.2%)
  Epoch12/25,列车损耗:0.8364,列车Acc:89.3%,测试Acc:75.9%(精度/按类召回:叉子:82.9%/72.3%,勺子:69.0%/80.6%)
  Epoch13/25,列车损耗:0.7675,列车Acc:79.4%,测试Acc:66.3%(精度/按类召回:叉子:67.7%/89.4%,勺子:76.2%/44.4%)

   13个epoch后提前关机(8个epoch无改善)

最佳加载模型(测试Acc:75.9%)

===结果===
  测试精度更高:75.9%
  列车/测试精度:78.2%/72.3%
  ✓没有再培训(5.9%差距)
培训完成! 🚀
模型保存在model中。布森

训练后,我们将转换模型的行为方式。 该脚本执行以下步骤:

  1. *加载模型、元数据和未知图像—-从BSON文件中提取训练集每个类中的网络架构、权重、类名和示例数,并将模型切换到评估模式。 扫描指定的文件夹,每个图像缩小到128×128的大小,归一化到范围[-1,1]并转换为张量格式W×H×C

  2. 每个图像的分类-张量馈送到模型的输入,输出logits通过softmax转换为概率,确定具有最大概率和相应置信度的类,并按类进行分组

  3. 按置信度和统计输出排序-在每个类中,图像从最自信的预测到最不自信的预测进行排序。 预测图像的数量,总数的百分比,平均值,最大和最小置信度

  4. 偏倚分析-每个类的预测百分比与该类在训练集中的百分比的比较,指标输出

In [ ]:
include("$(@__DIR__)/_scripts/visualize.jl")
results = classify_and_visualize(UNKNOWN_DIR);
===训练集的统计===
  叉子:189张图片
  勺子:146图像

===分类结果===
  叉子,叉子:
    数量:5(50.0%)
    平均置信度:0.902
    最大/最小置信度:1.0/0.752
  勺子:
    数量:5(50.0%)
    平均置信度:0.626
    最大/最小置信度:0.692/0.578

===偏见分析===
  分叉:50.0%预测vs56.4%训练✓
  勺子:50.0%预测vs43.6%训练✓

我们将对"未知"文件夹中的所有图像进行分类,并为每个类输出最多10个图像。

In [ ]:
include("$(@__DIR__)/_scripts/simple_mosaic.jl")
plot(create_simple_mosaic(UNKNOWN_DIR))
Out[0]:
No description has been provided for this image

以下脚本允许您重新打开已训练的模型,预测未标记示例目录中所有文件的类,并将结果输出到表中。

In [ ]:
include("$(@__DIR__)/_scripts/predict_to_csv.jl")
predict_to_csv(UNKNOWN_DIR, confidence_threshold=0.6, output_csv="$(@__DIR__)/predictions.csv")
处理文件:10
  叉子:5
  勺子:4
  未知:1

保存在/user/_retrain_resnet/predictions中。csv档案源
Out[0]:
10×5 DataFrame
RowФайлПредсказанный_классУверенностьВероятность_вилкаВероятность_ложка
StringStringFloat32Float32Float32
100000495.jpgвилка0.9997570.9997570.000242674
200000496.pngвилка0.9958160.9958160.00418395
300000494.jpgвилка0.9363420.9363420.0636576
400000497.jpgвилка0.8243740.8243740.175625
500000498.jpgвилка0.7522250.7522250.247775
600000194.jpgложка0.6923430.3076570.692343
700000193.pngложка0.620940.379060.62094
800000196.jpgложка0.6184810.3815190.618481
900000195.jpgложка0.6182840.3817160.618284
1000000192.jpgнеизвестно0.5779280.4220720.577928

结论

该项目为一个简单的任务奠定了基础:将图像排列在多个文件夹中,并训练一个分类器,该分类器将允许您将具有未知对象的第二个文件夹中的图像分

示例中呈现的结果是使用经过数十次学习过程迭代的神经网络获得的。 为了得到一个好的分类算法,你需要改变超参数,研究数据集,改变训练的持续时间,神经网络的拓扑结构(更多层,打开或关闭批量归一化等。),批次或优化器的大小,消除过早关闭的障碍,或简单地改变随机数发生器的设置。