垃圾分类模型想上maixpy(3)

简介: 1-5对比Params与模型文件实际体积。结果:模型实际大小与Params大小是可以对上的,参数应该是以float32存储。我把“字节”与“位”搞混了,应该是一个字节为8位。

垃圾分类模型想上maixpy(2):https://developer.aliyun.com/article/1407163

1-5

对比Params与模型文件实际体积

结果:模型实际大小与Params大小是可以对上的,参数应该是以float32存储。我把“字节”与“位”搞混了,应该是一个字节为8位。疑惑:为什么nncase量化后,模型文件体积还是没有显著减小?例如tfilte文件大小为436KB,量化后的kmodel大小仍有380KB。但从float32到uint8,大小理应变为四分之一。

看tensorflow的视频,卷积层参数量如何计算。

结果:P a r a m = C o u t ∗ ( W ∗ H ∗ C i n + 1 ) 。输出特征图的通道数决定过滤器的个数,输入特征图的通道数决定每个过滤器的通道数。

链接:https://blog.csdn.net/m0_63238256/article/details/128619369

重新训练mobilenet_v2。


发现:使用batch_size=128和使用batch_size=32时每个step的耗时差不多,于是整体使用batch_size=128时准确率上升更快。然而训练准确率达到92%时,测试准确率却只有70%。


使用batch_size=32时,也出现了过拟合。训练5个epoch时准确率从78%到了81%,但是测试准确率却突然从73%掉到了58%。再训练5个epoch后训练准确率为84%,测试准确率又回到了74%。


问题:过拟合真的是噩梦。


发现2:转换为kmodel后的体积发生了变化。tflite是8.47MB没有变,上次kmodel是8.44MB,这次kmodel是6.31MB。使用Netron依然打不开模型,板子上也依然加载不了。


问题2:据chatGPT和mainxpy群里的“小老鼠”所说,转换模型时的WARN: Conv2D_19 Fallback to float conv2d due to weights divergence没有关系。那导致加载模型时ValueError的原因是什么呢?


发现3:因为使用的cifar10数据集,图片分辨率为(32, 32),所以网络中出现了(1, 1)分辨率的图片被(3, 3)卷积核卷积的情况,可能是它导致了问题。

改用图片分辨率为(224, 224)的数据集训练mobilenet_v2 。


进度:卡在了调整数据集中图片大小这一步,找了个猫狗数据集,数据集中图片的分辨率是不固定的。虽然opencv的resize操作可以调整图片大小,但是我不知道怎么把这个操作插入到tensorflow训练模型的流水线中去。


贪图一些API的方便,却又不熟悉这些API的使用。


解决方案:继续学习tensorflow课程视频,了解对自己数据集的处理流程

1-8

miblenet_v2在horse-or-human数据集上训练失败

发现:层 tf.keras.layers.BatchNormalization() 似乎会导致问题,多次使用该层容易导致像是过拟合的现象。

下面是五层卷积的简单模型,插入了三层BatchNormalization,产生的训练数据:

Epoch 1/5
16/16 [=====] - 7s 345ms/step - loss: 2.6593 - acc: 0.7812 - val_loss: 0.6854 - val_acc: 0.7617
Epoch 2/5
16/16 [=====] - 5s 305ms/step - loss: 0.0719 - acc: 0.9793 - val_loss: 0.7076 - val_acc: 0.4570
Epoch 3/5
16/16 [=====] - 5s 320ms/step - loss: 0.3488 - acc: 0.8887 - val_loss: 0.6957 - val_acc: 0.4688
Epoch 4/5
16/16 [=====] - 5s 321ms/step - loss: 0.0114 - acc: 0.9980 - val_loss: 0.6909 - val_acc: 0.5000
Epoch 5/5
16/16 [=====] - 6s 373ms/step - loss: 0.2425 - acc: 0.9503 - val_loss: 0.8048 - val_acc: 0.5000

使用mobilenet_v2时,现象类似,train_acc可以在90%以上,val_acc恒为50%整。

令人不解的是,当我使用训练集数据进行评估,acc是在50%附近浮动,那为何训练时会显示那么高的准确率?

model.evaluate(train_generator)
129/129 [==============================] - 10s 77ms/step - loss: 0.8571 - acc: 0.4869

删除mobilenet_v2中的所有BatchNormalization层,模型却无法收敛了,train_acc在50%附件徘徊。


使用的mobilenet_v2模型代码来自MobileNet V2 网络结构的原理与 Tensorflow2.0 实现 。


想法:换个数据集会不会不一样?毕竟mobilenet_v2之前在mnist数据集上是可以正常训练的。


猜测:1、我的mobilenet_v2代码有问题,与官方的不同;2、数据集不合适。


方案:1、调用 model.summary() 查看keras中官方mobienet_v2的模型结构,与它对齐;2、改用自己的4分类垃圾数据集训练。

1-9

对齐mobilenet_v2模型结构

步骤1:先试试keras中的mobilenet_v2能不能正常训练;


结果:train_acc正常上升。(补充:这步疏忽了,没有测试val_acc,后面发现是有问题)


步骤2:对比两个模型的结构,以及训练时准确率;


发现:相对官方模型的train_acc随epoch稳定上升,我的模型train_acc显得不稳定。仔细对比模型结构,发现我模型尾部多了个卷积层。

# 例 - 调用keras官方mobilenet_v2
tf.keras.applications.mobilenet_v2.MobileNetV2(input_shape=(224,224,3), weights=None, classes=4)

在原来CSDN找到的代码中,该卷积层与Reshape层搭配,发挥全连接层的作用。因为nncase-v0.2.0不支持Reshape层(Reshape算子是支持的,但是Reshape层会产生不被支持的Shape算子),我就把Reshape删了,补了全连接层Dense,但是我没有把那个卷积层删掉。于是,相当于多了一层。


# 原代码中的用法

# 原代码中的用法
x = tf.keras.layers.GlobalAveragePooling2D()(x)
x = tf.keras.layers.Reshape((1,1,1280))(x)
x = tf.keras.layers.Conv2D(classes, (1,1), padding='same')(x)
x = tf.keras.layers.Reshape((classes,))(x)
x = tf.keras.layers.Activation('softmax')(x)
# 正确修改方式
x = tf.keras.layers.GlobalAveragePooling2D(keepdims=True)(x)
x = tf.keras.layers.Flatten()(x)
x = tf.keras.layers.Dense(classes)(x)
x = tf.keras.layers.Activation('softmax')(x)

改成上述“正确修改方式“后,训练效果与官方模型接近。

进一步训练mobilenet_v2模型,尝试转换和上板

突发:Colab的GPU限额了,正在摸索阿里的天池实验室。

原来的代码与天池实验室默认环境不兼容,但此时发现我的Colab解封了,哈哈。

问题:发现官方的模型也不能正常训练;训练时train_acc可以上升,但我将训练集作为验证集得到的val_acc在25%左右。

Epoch 1/2  64/64 - 53s 820ms/step - loss: 1.5922 - acc: 0.3819 - val_loss: 1.4714 - val_acc: 0.2489
Epoch 2/2  64/64 - 53s 834ms/step - loss: 1.5034 - acc: 0.3931 - val_loss: 1.4462 - val_acc: 0.2489

分析:是模型的问题,还是训练过程的问题?

  • 要说模型,但之前mobilenet_v2模型在mnist和cifar-10数据集上都可以正常预测;
  • 要说训练过程,但之前该流程在horse-or-human上训练也可以正常预测。

怎么组合起来就不行了呢?

发现:只要换成下面注释调的那几行代码,模型训练就由 ”正常“ 变为 ”val_acc恒为50%“。

from tensorflow.keras.optimizers import RMSprop
# model = tf.keras.applications.mobilenet_v2.MobileNetV2(input_shape=(150,150,3), weights=None, classes=2)
model.compile(
    loss='binary_crossentropy',
    # loss='categorical_crossentropy',
              optimizer=RMSprop(lr=0.001),
              metrics=['acc'])
from tensorflow.keras.preprocessing.image import ImageDataGenerator
train_datagen = ImageDataGenerator(rescale=1/255)
train_generator = train_datagen.flow_from_directory(
    'horse-or-human',
    target_size=(150,150),
    batch_size=32,
    class_mode='binary'
    # class_mode='categorical'
)
validation_datagen = ImageDataGenerator(rescale=1/255)
validation_generator = validation_datagen.flow_from_directory(
    'validation-horse-or-human',
    target_size=(150,150),
    batch_size=32,
    class_mode='binary'
    # class_mode='categorical'
)
history = model.fit(
    train_generator,
    steps_per_epoch=16,  # 控制单个epoch的大小,以batch为单位。
    epochs=5,
    verbose=1,
    validation_data=validation_generator
)

发现2:令人疑惑的情况越来越多了,在tensorflow官方手写数字识别的例子(数据集已被我换成cifar-10)中,换上我的mobilenet_v2时val_acc正常,调用的官方mobilenet_v2模型却val_acc=10%。


参见我的notebook:mobilenet_v2尝试-mnist 。


感觉Colab的环境不太稳定,容易突然卡住或者变慢;而且有时会提示配额上限。


也许我还是需要在自己的电脑上搭建个tensorflow环境。

1-10

给我的电脑安装tensorflow的GPU环境

(不用)查看某个已安装包的信息

pip show <包名>

查看电脑的CUDA版本,在命令行输入

nvidia-smi

tensorflow-gpu需要搭配cuda和cudnn使用。


我的CUDA版本:11.7


官方链接:tensorflow-gpu的版本关系


计划版本搭配:python3.7,tensorflow_gpu-2.6.0,cudnn8.2.1,对应的CUDA应该是11.2。


包管理工具:使用conda install


结果:安装成功,很顺利。


解决conda install时CondaSSLError的问题。


参考:[报错解决]CondaSSLError


在参考博客的评论区看到说环境变量的问题,我想起来我以前为了在命令行窗口运行非anaconda的python,把一些环境变量删掉了,后来忘记补上。一股脑补上一些环境变量后,重启终端窗口,就好了。

D:\anaconda
D:\anaconda\Scripts
D:\anaconda\Library\bin
D:\anaconda\Library\mingw-w64\bin

将cifar-10数据集用ImageDataGenerator加载,训练mobilenet_v2 。


怀疑:ImageDataGenerator的使用流程可能存在导致问题;


理由:


我之前直接用API调cifar-10数据集,是可以正常训练mobilenet_v2模型的。


换到ImageDataGenerator从文件夹加载图片后,就出现 “训练时train_acc上涨,val_acc不变;在训练集上的评估acc像没训练” 的情况。


下一步:何必用ImageDataGenerator?我可以自己写代码从文件夹读图片,读成images+labels的形式,与正确训练的条件对齐。


重写数据加载部分代码,训练mobilenet_v2 。


结果:在cifar-10上训练成功,在horse-or-human和我的GarbageForMaixHub上训练失败。


越来越疑惑,是谁的问题?模型?数据集?

1-11

尝试mobilenet_v2模型从训练到板上推理的流程能否走通,暂不考虑模型准确性

问题:转kmodel时报错:Fatal: KPU allocator cannot allocate more memory. ;搜索问题发现,可能是KPU限制特征图大小不能超过2MB。但我最大的一层特征图尺寸为(1, 112, 112, 96),大小是 1 , 204 , 224 1,204,2241,204,224 ,1MB多一点而已。


尝试:将训练时输入尺寸减半,从(224,224)到(112,112)


结果:转换得到了kmodel,大小为2.25MB


问题:E (4139792902) SYSCALL: Out of memory 。烧录后,加载模型会卡住没反应,打开串口终端就报这个错误。


可能方案:换更小的固件,参见:使用mind+运行口罩识别模型显示内存不足(已解决)


分析:应该是板子是的main.py文件里有加载模型的操作,加载我刚刚烧录的模型,就会导致Out of memory


查看内存大小,参见:内存管理 - Sipeed Wiki

import gc
print(gc.mem_free() / 1024) # stack mem
import Maix
print(Maix.utils.heap_free() / 1024) # heap mem
'''
我的
502.9687
2532.0
官方示例
352.0937
4640.0
'''

内存好像是偏小,可以换个小固件、或者减小模型输入图片尺寸试试。


换固件:maixpy_v0.6.2_84_g8fcd84a58_openmv_kmodel_v4_with_ide_support.bin,再查看内存大小为[502.9687, 3912.0]


再减小模型输入尺寸 :从(112, 112)到(96, 96)。96应该是当前模型结构能用的最小输入尺寸了,再小就会出现(2, 2)的特征图被(3, 3)的卷积核处理的情况,这在k210上会导致加载失败(上次mobilenet_v2在cifar-10上训练的模型就是加载时报错)。


结果:模型加载成功。

import sensor, lcd, image
import KPU as kpu
# 测试板子是否响应
print('\nboard start...')
# 载入模型
model_addr = 0x300000
print('load model...')
task = kpu.load(model_addr)
print('hello, world')
''' 终端输出
board start...
load model...
hello, world
'''

下一步:测试模型能否产生预测输出

相关实践学习
部署Stable Diffusion玩转AI绘画(GPU云服务器)
本实验通过在ECS上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。
相关文章
|
6月前
|
vr&ar
垃圾分类模型想上maixpy(2)
1-1 关于模型部署,MaixPy文档的这一部分中可能有些有用的参考:部署模型到 Maix-I(M1) K210 系列开发板 - Sipeed Wiki 。 实际用数字图片进行测试时,手写数字识别的模型无法产生正确的输出。
165 1
【yolo训练数据集】标注好的垃圾分类数据集共享
【yolo训练数据集】标注好的垃圾分类数据集共享
2025 117
【yolo训练数据集】标注好的垃圾分类数据集共享
|
1月前
|
机器学习/深度学习 算法
五、分类模型
五、分类模型
21 0
点分类模型实战
点分类模型实战
|
4月前
|
机器学习/深度学习 自然语言处理 算法
什么是数据集的分类?
【7月更文挑战第10天】什么是数据集的分类?
486 1
|
6月前
|
IDE TensorFlow 开发工具
垃圾分类模型想上maixpy(1)
maixpy笔记 Something 上下拉。应该就是强制高、低电平,可以避免不确定的状态。 模型区没有文件系统,模型之间烧录在指定地址。
122 0
|
机器学习/深度学习 数据可视化 计算机视觉
使用深度学习进行图像类别分类
使用预训练卷积神经网络 (CNN) 作为特征提取器来训练图像类别分类器。
133 0
分类问题的判别
分类问题的判别 自用
53 0
|
数据挖掘
非监督分类
非监督分类
330 0
|
机器学习/深度学习 算法 数据挖掘
监督分类
监督分类,又称训练分类法,用被确认类别的样本像元去识别其他未知类别像元的过程。它就是在分类之前通过目视判读和野外调查,对遥感图像上某些样区中影像地物的类别属性有了先验知识,对每一种类别选取一定数量的训练样本,计算机计算每种训练样区的统计或其他信息,同时用这些种子类别对判决函数进行训练,使其符合于对各种子类别分类的要求,随后用训练好的判决函数去对其他待分数据进行分类。使每个像元和训练样本作比较,按不同的规则将其划分到和其最相似的样本类,以此完成对整个图像的分类。
250 0