基于fastai和Google App Engine的简单网页图片分类器

学习Fastai的深度学习课程后自己找了些图片数据训练了一个卡比和胖丁的分类器,然后又鼓捣了一下Google App Engine,制作了一个简单的网页APP。

简述

做的东西是一个基于网页的图片分类APP,分类对象是卡比和胖丁,下面左边是卡比,右边是胖丁…二者还是很相似的。


整个过程大致分为三步,收集图片,训练模型,部署APP,在这篇博文记录一下整个过程,也会介绍一部分原理。

图片收集

先从Google Image直接搜索kirby和jigglypuff后再ctrl+shift+J呼出控制台,然后输入两行代码

urls = Array.from(document.querySelectorAll('.rg_di .rg_meta')).map(el=>JSON.parse(el.textContent).ou);
window.open('data:text/csv;charset=utf-8,' + escape(urls.join('\n')));

这样就会得到搜索到的图片的URL信息。接下来通过fastai library的download_images()函数来下载图片到本地。下载好图片后调用verify_images()函数来验证下载的图片是否破损。
到此得到了训练分类器使用的数据,但是这样的数据会发现有很多错标的或者无关的图片,毕竟是直接Google而来,并不是标准数据集,所以需要做一些人工的数据清理工作。比如在卡比的图片里就有好多星之卡比中的boss帝帝帝大王,需要人工把这类图片删除掉。
这样就得到了训练使用的数据集,再做一个Train/Valid的划分,最终训练集有284个样本,验证集有71个样本。

data.classes, data.c, len(data.train_ds), len(data.valid_ds)
>(['jigglypuff', 'kirby'], 2, 284, 71)

模型训练

模型的训练是这个小项目中的核心部分,我借助了Fastiai库,使用了resnet34架构进行了迁移学习。即用在ImageNet上训练出的resnet34模型参数作为初始权重,首先freeze掉conv层做一次训练,然后unfreeze卷积层做finetune。在这一过程中,用到了之前博客里介绍过的learning rate finder来确定学习率。
模型finetune过程的每个epoch数据如下:




模型最终在验证集上表现如下:




借助迁移学习的力量,仅用17秒和两百多张图片就可以训练出准确率在99%左右的模型。

网页app部署

这部分参考了fastai production部分的教程,教程链接在文末列出,部署过程不多赘述,这里记录几个遇到的问题

问题1 TypeError: transform() got multiple values for argument ‘tfms’

研究一番后发现这问题的原因是版本不匹配,老版本中的tfms在后续版本更名为ds_tfms,修改app/server.py,将tfms改成ds_tfms即可

问题2 _pickle.UnpicklingError: invalid load key, ‘\x0a’.

从网上查到这一报错信息说明pickle加载了空文件,而导致这一问题的原因是原本应该下载到models/下的.pth文件(训练出的模型)没有被正确下载。于是手动下载model.pth文件,并放置到正确的目录下便解决了问题。

参考资料:
[1] fastai深度学习课程Lesson2
[2] Google App Engine部署教程