lesson 1 fast.ai 图像分类

Fast.ai Lesson 1 图像分类 上篇

大家好,我叫南林笑笑生,因为在学习fast.ai这个深度学习框架的过程中觉得很好玩,希望能和更多志同道合的朋友一起讨论,但发现中文网上的资料不多,因此我把我学习的笔记在这里分享给大家。

简单介绍一下,fast.ai是一个基于PyTorch(如果你看到这里,想必你已经听说过天下第二的PyTorch了吧)的高级封装,类似于Keras和Tensorflow的关系,但远比Keras要方便和易上手的多的框架。

  • 当然,后两者的关系要紧密得多,tf.keras甚至可以和keras中的绝大多数api通用了。

易上手往往意味着难于不灵活和不便于部署,不过对fast.ai不需要太担心,需要灵活调整的部分完全可以交给PyTorch来做;部署上,训练好的模型可以直接用torch.onnx来把模型转换成各种你想要的格式。

除此外还有两个准备工作建议大家先完成(预计花费20分钟)。

  1. 使用谷歌搜索,不要再用百度了。不需要翻墙,只需要为你的Chrome浏览器安装一个谷歌访问助手即可。

    具体操作请百度,哦不,谷歌一下,这里就不炒冷饭了。

  2. 注册一个kaggle账号,这有两个目的,一个是尽可能地参加kaggle比赛,按照Jeremy的观点,如果在一个kaggle竞赛中你进入了前10%的名次,那么就真的弄明白你在做什么了。另一个目的是使用kaggle kernel,这是一个免费的GPU计算资源,使用Nvidia K80显卡,而且它下载许多国外的开源数据集速度非常快,这一点即使在国内自己搭梯子也没办法做到。

    注册需要临时搭个梯子,注册好账号,又有谷歌访问助手,就不再需要梯子,随时可以用了。


闲话不多说了,我们这就开始吧。深度学习的往往从图像入门,我们也不例外。

开始

首先,只需要下面两行代码(其实只要第二行的就可以了),即可完成fast.ai图像处理的模块以及很多相关的第三方库的引入。

1
2
from fastai import*
from fastai.vision import *

Jupyter格式子的使用技巧

一般我们都是在Jupyter Notebook中来调试深度学习的代码,如果看教程的你也是这样的话,有一些骚操作可以带来极大的便利。

  1. ?functione-name: 在类名/函数名前加?,然后shift + enter,可以看到相关文档。

    1
    ?ImageDataBunch
  2. ??functione-name: 在类名/函数名前加??,然后shift + enter,可以看到源代码。

    1
    ??ImageDataBunch
  3. doc(function-name): 显示函数的定义、docstring和指向文档的链接。

    1
    doc(ImageDataBunch)

训练过程过视化

Tensorboard是tensorflow用来可视化训练过程的一个很好用的工具,遗憾的是之前PyTorch一系一直不能使用它。不过最新版本的fast.ai已经支持使用Tensorboard了,这里需要添加下面一行代码:

1
from fastai.callbacks.tensorboard import LearnerTensorboardWriter

Jupyter魔法操作符

魔法操作符是可以在单元格上运行的函数,并将调用它们的行其余部分作为参数。可以通过在命令前放置’%’符号来调用它们。我把最有用的几个列在下面:

1
%matplotlib inline

眼熟吧,如果你用Jupyter跑过numpy和pandas的数据分析,你肯定使用过它了。此命令确保所有matplotlib绘图将被绘制在笔记本的输出单元格中,并在保存时保存在笔记本中(下次打开同一个ipynb时也会看到)。

1
2
%reload_ext autoreload
%autoreload 2

在执行新行之前重新加载所有模块。如果模块被编辑,则无需重新运行导入命令,模块将自动重新加载。

记住你总是在敲代码前在第一格把这三兄弟都复制进去就可以了。

1
2
3
%matplotlib inline
%reload_ext autoreload
%autoreload 2

关于数据

Oxford-IIIT Pet Dataset是一个宠物图片数据集,这个数据集由牛津大学出品,里面有12种猫和25种狗的图片。我们的模型需要学会区分这37个不同的类别。根据他们的论文,他们在2012年获得的最佳准确率为59.21%,使用的是一种专门用于宠物检测的复杂模型,宠物照片分别使用“图像”、“头部”和“身体”模型。让我们看看使用深度学习的效果吧。

fastai内置了一个获取机器学习常用数据集的函数,untar_data,它会自动下载解压数据。通过开头第二行的import,我们已经可以直接使用它了。我们可以使用URLs.PETS这个名字来直接获得这个数据集。

1
2
path = untar_data(URLs.PETS)
path

这里要说明一下,Fast.ai是国外的框架,所以下载的数据都是从国外下载,由于众所周知的原因,下载速度十分感人,因此需要自己搭个梯子。

别急,还有一个更方便的办法,就是使用前面提到的kaggle kernel。你可以点击下面这个链接(前提是你已经按我前面要求的注册好了kaggle账号,否则点进来了也没法使用)

lesson 1 fast.ai v3: What’s your pet

你可以对path直接使用如下语法:

1
2
3
4
5
# 类似在linux命令行中执行: ls path
path.ls()
# 等效于: path_anno = os.path.join(path, 'annotations')
path_anno = path/'annotations'
path_img = path/'images'

做分析前我们深入了解一下数据,我们总是需要很好地理解问题是什么,数据是什么样子的,然后才能找出解决的办法。查看数据意味着理解数据目录的结构、标签是什么以及一些示例图像是什么样子。

这里推荐使用linux的第三方工具tree,查看文件树形结构,使用前需要安装。在Jupyter Notebook里安装Linux工具可以使用如下办法:

1
2
3
import os
os.system("apt install tree")
os.system("tree")
1
2
3
4
5
6
7
8
9
10
fnames = get_image_files(path_img)
fnames[:5]
'''
显示如下:
[PosixPath('/tmp/.fastai/data/oxford-iiit-pet/images/shiba_inu_11.jpg'),
PosixPath('/tmp/.fastai/data/oxford-iiit-pet/images/pug_74.jpg'),
PosixPath('/tmp/.fastai/data/oxford-iiit-pet/images/Maine_Coon_2.jpg'),
PosixPath('/tmp/.fastai/data/oxford-iiit-pet/images/Bombay_107.jpg'),
PosixPath('/tmp/.fastai/data/oxford-iiit-pet/images/leonberger_13.jpg')]
'''
1
2
3
4
5
6
# 设置随机种子,不用担心前面没有import numpy和re,fast.ai已经代劳了
np.random.seed(2)
pat = re.compile(r'/([^/]+)_\d+.jpg$')
'''
简单解释一下,这个正则表达式能从比如'/tmp/.fastai/data/oxford-iiit-pet/images/leonberger_13.jpg'字符串中取出leonberger这个名字,作为后面的分类的类名
'''

GPU处理数据的速度十分快,同时从硬盘把数据送入到GPU的过程很慢,因此为了减少GPU无效的等待时间,PyTorch提供了dataloader。fast.ai则封装了dataloader,高度集成之后,只需要使用如下代码即可准备好数据了。

1
data = ImageDataBunch.from_name_re(path_img, fnames, pat, ds_tfms=get_transforms(), size=224, bs=16, num_workers=0).normalize(imagenet_stats)

预览一下三行三列的图片

1
data.show_batch(rows=3, figsize=(7,6))
1
2
3
4
5
6
7
print(data.classes)
len(data.classes),data.c
'''
输出:
['Abyssinian', 'Bengal', 'Birman', 'Bombay', 'British_Shorthair', 'Egyptian_Mau', 'Maine_Coon', 'Persian', 'Ragdoll', 'Russian_Blue', 'Siamese', 'Sphynx', 'american_bulldog', 'american_pit_bull_terrier', 'basset_hound', 'beagle', 'boxer', 'chihuahua', 'english_cocker_spaniel', 'english_setter', 'german_shorthaired', 'great_pyrenees', 'havanese', 'japanese_chin', 'keeshond', 'leonberger', 'miniature_pinscher', 'newfoundland', 'pomeranian', 'pug', 'saint_bernard', 'samoyed', 'scottish_terrier', 'shiba_inu', 'staffordshire_bull_terrier', 'wheaten_terrier', 'yorkshire_terrier']
(37, 37)
'''

好了,我们可以开始训练了。限于篇幅,我把接下来的部分放在下篇。