如何用 Python 和 fast.ai 做图像深度迁移学习?

简介: 本文带你认识一个优秀的新深度学习框架,了解深度学习中最重要的3件事。框架看到这个题目,你可能会疑惑:老师,你不是讲过如何用深度学习做图像分类了吗?迁移学习好像也讲过了啊!说得对!我要感谢你对我专栏的持续关注。
img_5f718a6d2b7b4c396c40304feb71e27e.jpe

本文带你认识一个优秀的新深度学习框架,了解深度学习中最重要的3件事。

框架

看到这个题目,你可能会疑惑:

老师,你不是讲过如何用深度学习做图像分类了吗?迁移学习好像也讲过了啊!

说得对!我要感谢你对我专栏的持续关注。我确实讲过深度学习做图像分类,以及迁移学习这两项内容。

写这篇文章,是因为最近因为科研的关系,发现了 fast.ai 这款框架。我希望把它介绍给你。

你可能会不解,之前介绍过的 TuriCreate, Tensorflow, tflearn 和 Keras 好像都挺好用的啊!

我想问问,你在实际的科研工作里,用过哪一个呢?

大多数的读者,只怕基本上都没真正用它们跑过实际的任务。

为什么呢?

因为对普通用户(例如我经常提到的“文科生”),这些框架要么用起来很简单,但是功能不够强大;要么功能很强大,但是不够易用。

例如苹果的 TuriCreate ,我给你演示过,直接零基础上手都没问题。但当你希望对模型进行构造调整的时候,马上就会发现困难重重。因为其专长在于快速产生模型,并且部署到苹果移动设备,因此文档里面底层细节的介绍是有欠缺的。而且有些模型,非苹果平台目前还不能兼容。

img_bb6ea5642e4a451687140f67566050ce.jpe

至于某著名框架,直到推出3年后,在各方压力下,不得已才把好用的 Eager Execution 作为主要使用模式。其间充分体现了那种技术人员独有的傲慢和固执。另外,就连程序员和数据科学家们都把吐槽“看不懂”它的官方文档当作了家常便饭。这些轶事,由于公开发布会招致口水仗,所以我只写在了知识星球专属语雀团队《发现了一套非常棒的(该框架名称)视频教程》一文中。感兴趣的话,不妨去看看。

原本我认为, Keras 已经是把功能和易用性做到了最佳平衡了。直到我看到了 Jeremy Howard,也就是 fast.ai 创始人提出的评判标准——如果一个深度学习框架需要写个教程给你,那它的易用性还不够好。

我看了之后,可以用感动来形容。

Jeremy 说这话,不是为了夸自己——因为他甚至做了个 MOOC 出来。他自己评价,说目前 fast.ai 的易用性依然不算成功。但在我看来, fast.ai 是目前把易用性和功能都做到了极致的深度学习框架。

它的门槛极低。如同 TuriCreate 一样,你可以很轻易用几句话写个图片分类模型出来,人人都能立即上手。

它的天花板又很高。因为它只是个包裹了 Pytorch 的代码库。

你可能也听说了,在过去的一年里,Pytorch 在学术界大放异彩,就是因为它的门槛对于科研人员来说,已经足够友好了。如果你有需求,可以非常方便地通过代码的修改和复用,敏捷构造自己的深度学习模型。

这种积木式的组合方式,使得许多新论文中的模型,可以第一时间被复现验证。如果你在这个过程中有了自己的灵感和心得,可以马上实践。

且慢,fast.ai 的作者不是已经做了自己的 MOOC 了吗?那写这篇文章,岂不是多此一举?

不是的。

首先,作者每年迭代一个 MOOC 的版本,因为 MOOC 一共包括三门课程,分别是:

但现在你能看到的深度学习基础课,还是去年录的。今年10月,伴随着 Pytorch 1.0 的推出, fast.ai 做了一次显著的大版本(1.0)更新。如果你去看去年的课程,会发现和目前的 fast.ai 代码有很多区别。在完成同一个功能时,你愿意再跑去学旧的过时内容吗?特别是,如果搞混了,还很容易出错。

可是,想看到这个版本课程的免费视频,你至少得等到明年1月。因为目前正式学员们也才刚刚开课。

img_25e91cf80982d267ce8a0daaaa5b043a.jpe

而且,那视频,也是英文的。

正因如此,我觉得有必要给你讲讲,如何用最新的 fast.ai 1.0 版本,来完成图像深度迁移学习。

数据

Jeremy 在 MOOC 中提到,如果你打算让机器通过数据来学习,你需要提供3样东西给它,分别是:

  • 数据(Data)
  • 模型结构(Architecture)
  • 损失度量(Loss Metrics)

模型结构,是根据你的具体问题走的。例如说,你需要让机器做图片分类,那么就需要使用卷积神经网络(Convolutional Neural Network)来表征图片上的像素信息构成的特征。如果你需要做自然语言处理,那么就可以使用循环神经网络(Recurrent Neural Network)来捕捉文本或者字符的顺序关联信息。

损失衡量,是指你提供一个标准,衡量机器对某项任务的处理水平。例如说对于分类效果如何,你可以使用交叉熵(Binary Cross Entropy)来评判。这样,机器会尝试最小化损失结果,从而让分类表现越来越好。

至于数据,因为我们这里的任务是做分类。因此需要有标注的训练数据。

我已经把本文需要用到的数据放到了这个 github 项目上。

img_dd655fbf7c615744e6c47634511474e2.jpe

打开其中的 imgs 文件夹,你会看见3个子文件夹,分别对应训练(train),验证(valid)和测试(test)。

打开 train 文件夹看看。

你没猜错,我们用的图片还是哆啦A梦(doraemon)和瓦力(walle)。

img_1f9133148c6b917afd3c94ab5bc0d07e.jpe

因为这样不仅可以保持教程的一惯性,而且也可以保证结果对比的公平。

打开哆啦A梦的目录看看:

img_e0cab07439f46d2f8a4adf1841832234.jpe

展示其中第一个文件内容。

img_6d295bd780aa37e0f687ce591b86f4fa.jpe

好熟悉,是不是?

你可以浏览一下其他的哆啦A梦照片,然后别忘了去瓦力的文件夹里面扫上一眼。

img_253beb44a02b57c4c557a3a85cca3ac1.jpe

这就是我们的数据集了。

环境

为了运行深度学习代码,你需要一个 GPU 。但是你不需要去买一个,租就好了。最方便的租用方法,就是云平台。

fast.ai 官方,给出了以下5种云计算平台使用选项:

其中,我推荐你使用的,是 Google Compute Platform 。原因很简单,首先它成本低,每小时只需要 0.38 美元。更重要的是,如果你是新用户, Google 会先送给你300美金,1年内有效。算算看,这够你运行多久深度学习?

img_713e83a6aeee7a24cb7c17bb7ad458c4.jpe

原先,fast.ai 上面的设置 Google Compute Platform 教程写得很简略。于是我写了个一步步的教程,请使用这个链接访问。

img_2056fc1e0e50d4d20991d3c617db70c9.jpe

不过,我发现 fast.ai 的迭代速度简直惊人,短短几天时间,新的教程就出来了,而且详尽许多。因此你也可以点击这里查看官方的教程。其中如果有跳步,你可以回看我的教程,作为补充。

因此,Google Compute Platform 中间步骤,咱们就不赘述了。当你的终端里面出现这样的提示的时候,就证明一切准备工作都就绪了。

img_c876e73f8738063b9755df2aac5d1e54.jpe

下面,你需要下载刚刚在 github 上面的代码和数据集。

git clone https://github.com/wshuyi/demo-image-classification-fastai.git
img_7aec53e7252a73ac967a709eec1a0ad1.jpe

之后,就可以呼叫 jupyter 出场了。

jupyter lab
img_c02fb43a5a0100ac72dd735662a4f1d7.jpe

注意因为你是在 Google Compute Platform 云端执行 jupyter ,因此浏览器不会自动弹出。

你需要打开 Firefox 或者 Chrome,在其中输入这个链接http://localhost:8080/lab?)。

img_8fc18a73dc35a7aa0de65b48917ab0bc.jpe

打开左侧边栏里面的 demo.ipynb

img_970469979afbee530ee5a47b60f49b84.jpe

本教程全部的代码都在这里了。当然,你如果比较心急,可以选择执行Run->Run All Cells,查看全部运行结果。

img_822e80b2b91bd0e0cc6b6f8c2bf87c0f.jpe

但是,跟之前一样,我还是建议你跟着教程的说明,一步步执行它们。以便更加深刻体会每一条语句的含义。

载入

我们先要载入数据。第一步是从 fast.ai 读入一些相关的功能模块。

from fastai import *
from fastai.vision import *
from fastai.core import *

接着,我们需要设置数据所在文件夹的位置,为 imgs 目录。

img_d04924c0c6fbcf229fa9506abffaa1e3.jpe

执行:

path = Path('imgs')

下面,我们让 fast.ai 帮我们载入全部的数据。这时我们调用 ImageDataBunch 类的 from_folder 函数,结果存储到 data 中:

data = ImageDataBunch.from_folder(path, test='test', ds_tfms=get_transforms(), size=224)

注意这里,我们不仅读入了数据,还顺手做了2件事:

  • 我们进行了数据增强(augmentation),也就是对数据进行了翻转、拉伸、旋转,弄出了很多“新”训练数据。这样做的目的,是因为数据越多,越不容易出现过拟合(over-fitting),也就是模型死记硬背,蒙混考试,却没有抓住真正的规律。
  • 我们把图片大小进行了统一,设置成了 224 x 224 ,这样做的原因,是我们需要使用迁移学习,要用到预训练模型。预训练模型是在这样大小的图片上面训练出来的,因此保持大小一致,效果更好。

下面,检查一下数据载入是否正常:

data.show_batch(rows=3, figsize=(10,10))
img_d1bf126730de7333ac9b4de981d3cbd9.jpe

没问题。图片和标记都是正确的。

训练

用下面这一条语句,我们把“数据”、“模型结构”和“损失度量”三样信息,一起喂给机器。

learn = ConvLearner(data, models.resnet34, metrics=accuracy)

数据就不说了,模型我们采用的是 resnet34 这样一个预训练模型作为基础架构。至于损失度量,我们用的是准确率(accuracy)。

你可能会纳闷,这就完了?不对呀!

没有告诉模型类别有几个啊,没有指定任务迁移之后接续的几个层次的数量、大小、激活函数……

对,不需要。

因为 fast.ai 根据你输入的上述“数据”、“模型结构”和“损失度量”信息,自动帮你把这些闲七杂八的事情默默搞定了。

下面,你需要用一条指令来训练它:

learn.fit_one_cycle(1)

注意,这里我们要求 fast.ai 使用 one cycle policy 。如果你对细节感兴趣,可以点击这个链接了解具体内容。

img_a54d5aecf9ea11f4a771037625fa251c.jpe

5秒钟之后,训练结束。

验证集准确率是,100%。

注意,你“拿来”的这个 resnet34 模型当初做训练的时候,可从来没有见识过哆啦A梦或者瓦力。

看了100多张形态各异,包含各种背景噪声的图片,它居然就能 100% 准确分辨了。

之前我们讲过机器学习的可解释性很重要。没错,fast.ai 也帮我们考虑到了这点。

preds,y = learn.get_preds()
interp = ClassificationInterpretation(data, preds, y, loss_class=nn.CrossEntropyLoss)

执行上面这两行语句,不会有什么输出。但是你手里有了个解释工具。

我们来看看,机器判断得最不好的9张图片都有哪些?

interp.plot_top_losses(9, figsize=(10,10))
img_9c3e801e7ec5d8b165d774f3acd79e15.jpe

因为准确率已经 100% 了,所以单看数值,你根本无法了解机器判断不同照片的时候,遇到了哪些问题。但是这个解释器却可以立即让你明白,哪些图片,机器处理起来,底气(信心)最为不足。

我们还能让解释器做个混淆矩阵出来:

interp.plot_confusion_matrix()
img_eab2cc3e364fae4fa47d14b24d7dd09d.jpe

不过这个混淆矩阵好像没有什么意思。反正全都判断对了。

评估

我们的模型,是不是已经完美了?

不好说。

因为我们刚才展示的,只是验证集的结果。这个验证集,机器在迭代模型参数的时候每一回都拿来尝试。所以要检验最为真实的效能,我们需要让机器看从来没有看到过的图片。

你可以到 test 目录下面,看看都有什么。

img_5590089341cd16dc58ee1da62929f77c.jpe

注意这里一共6张图片,3张哆啦A梦的,3张瓦力的。

这次,我们还会使用刚才用过的 get_preds 函数。不过区别是,我们把 is_test 标记设置为 True,这样机器就不会再去验证集里面取数据了,而是看测试集的。

preds,y = learn.get_preds(is_test=True)

注意目录下面看到的文件顺序,是依据名称排列的。但是 fast.ai 读取数据的时候,其实是做了随机洗牌(randomized shuffling)。我们得看看实际测试集里面的文件顺序。

data.test_dl.dl.dataset.ds.x
img_5d82d76dd6f0dbe84100f21a468eb011.jpe

好了,我们自己心里有数了。下面就看看机器能不能都判断正确了。

preds
img_232309c5fb9e9226559d4d116cd53d0c.jpe

这都啥玩意儿啊?

别着急,这是模型预测时候,根据两个不同的分类,分别给出的倾向数值。数值越大,倾向程度越高。

左侧一列,是哆啦A梦;右侧一列,是瓦力。

我们用 np.argmax 函数,把它简化一些。

np.argmax(preds, axis=1)
img_9285d13b7ed1a58b88217f85fb8e6034.jpe

这样一来,看着就清爽多了。

我们来检查一下啊:瓦力,瓦力,哆啦A梦,哆啦A梦,哆啦A梦,哆啦A梦……

不对呀!

最后这一张,walle.113.jpg,不应该判断成瓦力吗?

打开看看。

img_e4a4a985b9d7b7bb86dcfa5d023c07aa.jpe

哦,难怪。另一个机器人也出现在图片中,圆头圆脑的,确实跟哆啦A梦有相似之处。

要不,就这样了?

微调

那哪儿行?!

我们做任务,要讲究精益求精啊。

遇到错误不要紧,我们尝试改进模型。

用的方法,叫做微调(fine-tuning)。

我们刚刚,不过是移花接木,用了 resnet34 的身体,换上了一个我们自定义的头部层次,用来做哆啦A梦和瓦力的分辨。

img_d00824159fab150bce9f7aa11ccf05dd.jpe

这个训练结果,其实已经很好了。但是既然锁定了“身体”部分的全部参数,只训练头部,依然会遇到判断失误。那我们自然想到的,就应该是连同“身体”,一起调整训练了。

但是这谈何容易?

你调整得动作轻微,那么效果不会明显;如果你调整过了劲儿,“身体”部分的预训练模型通过海量数据积累的参数经验,就会被破坏掉。

两难啊,两难!

好在,聪明的研究者提出了一个巧妙的解决之道。这非常符合我们不只一次提及的“第一性原理”,那就是返回到事情的本源,问出一句:

谁说调整的速度,要全模型都一致?!

深度卷积神经网络,是一个典型的层次模型。

模型靠近输入的地方,捕获的是底层的特征。例如边缘形状等。

模型靠近输出的地方,捕获的是高层特征,例如某种物体的形貌。

对于底层特征,我们相信哆啦A梦、瓦力和原先训练的那些自然界事物,有很多相似之处,因此应该少调整。

反之,原先模型用于捕获猫、狗、兔子的那些特征部分,我们是用不上的,因此越靠近输出位置的层次,我们就应该多调整。

这种不同力度的调整,是通过学习速率(learning rate)来达成的。具体到我们的这种区分,专用名词叫做“歧视性学习速率”(discriminative learning rate)。

你可能想放弃了,这么难!我不玩儿了!

且慢,看看 fast.ai 怎么实现“歧视性学习速率”。

learn.unfreeze()
learn.fit_one_cycle(3, slice(1e-5,3e-4))

对,只需在这里指定一下,底层和上层,选择什么不同的起始速率。搞定。

没错,就是这么不讲道理地智能化

img_6516512e383954122e78ffb70235a416.jpe

这次,训练了3个循环(cycle)。

注意,虽然准确率没有变化(一直是100%,也不可能提升了),但是损失数值,不论是训练集,还是验证集上的,都在减小。

这证明模型在努力地学东西。

你可能会担心:这样会不会导致过拟合啊?

看看就知道了,训练集上的损失数值,一直高于验证集,这就意味着,没有过拟合发生的征兆。

好了,拿着这个微调优化过后的模型,我们再来试试测试集吧。

首先我们强迫症似地看看测试集文件顺序有没有变化:

data.test_dl.dl.dataset.ds.x
img_acb596717a6c051063771e694c3bbf43.jpe

既然没有变,我们就放心了。

下面我们执行预测:

preds,y = learn.get_preds(is_test=True)

然后,观察结果:

np.argmax(preds, axis=1)
img_e67ea53abf669da1749a377061f31a0d.png

如你所见,这次全部判断正确。

可见,我们的微调,是真实有用的。

小结

本文为你介绍了如何用 fast.ai 1.0 框架进行图像深度迁移学习。可以看到, fast.ai 不仅简洁、功能强大,而且足够智能化。所有可以帮用户做的事情,它全都替你代劳。作为研究者,你只需要关注“数据”、“模型结构”和“损失度量”这3个关键问题,以改进学习效果。

我希望你不要满足于把代码跑下来。用你获得的300美金,换上自己的数据跑一跑,看看能否获得足够满意的结果。

祝(深度)学习愉快!

喜欢请点赞和打赏。还可以微信关注和置顶我的公众号“玉树芝兰”(nkwangshuyi)

如果你对 Python 与数据科学感兴趣,不妨阅读我的系列教程索引贴《如何高效入门数据科学?》,里面还有更多的有趣问题及解法。

目录
相关文章
|
5天前
|
机器学习/深度学习 数据采集 人工智能
AI赋能教育:深度学习在个性化学习系统中的应用
【10月更文挑战第26天】随着人工智能的发展,深度学习技术正逐步应用于教育领域,特别是个性化学习系统中。通过分析学生的学习数据,深度学习模型能够精准预测学生的学习表现,并为其推荐合适的学习资源和规划学习路径,从而提供更加高效、有趣和个性化的学习体验。
38 9
|
1天前
|
机器学习/深度学习 人工智能 自然语言处理
探索AI驱动的个性化学习平台构建###
【10月更文挑战第29天】 本文将深入探讨如何利用人工智能技术,特别是机器学习与大数据分析,构建一个能够提供高度个性化学习体验的在线平台。我们将分析当前在线教育的挑战,提出通过智能算法实现内容定制、学习路径优化及实时反馈机制的技术方案,以期为不同背景和需求的学习者创造更加高效、互动的学习环境。 ###
13 3
|
1月前
|
存储 JSON API
Python| 如何使用 DALL·E 和 OpenAI API 生成图像(1)
Python| 如何使用 DALL·E 和 OpenAI API 生成图像(1)
36 7
Python| 如何使用 DALL·E 和 OpenAI API 生成图像(1)
|
18天前
|
机器学习/深度学习 人工智能 Cloud Native
在AI师傅(AI-Shifu.com)学习通义灵码的旅程
在这个数字化时代,编程技能愈发重要。通过AI师傅平台,我接触并学习了阿里云推出的通义灵码。从初识到深入学习,我系统掌握了云计算基础、云原生技术、数据库管理和大数据与人工智能等方面的知识。通过实践项目,我不仅巩固了理论,还提升了实际操作能力。通义灵码的易用性和强大功能,让我对云计算有了全新认识。感谢AI师傅提供的学习机会,推荐大家参与征文活动,共同分享学习成果。
|
17天前
|
人工智能
|
19天前
|
人工智能 文字识别 Java
SpringCloud+Python 混合微服务,如何打造AI分布式业务应用的技术底层?
尼恩,一位拥有20年架构经验的老架构师,通过其深厚的架构功力,成功指导了一位9年经验的网易工程师转型为大模型架构师,薪资逆涨50%,年薪近80W。尼恩的指导不仅帮助这位工程师在一年内成为大模型架构师,还让他管理起了10人团队,产品成功应用于多家大中型企业。尼恩因此决定编写《LLM大模型学习圣经》系列,帮助更多人掌握大模型架构,实现职业跃迁。该系列包括《从0到1吃透Transformer技术底座》、《从0到1精通RAG架构》等,旨在系统化、体系化地讲解大模型技术,助力读者实现“offer直提”。此外,尼恩还分享了多个技术圣经,如《NIO圣经》、《Docker圣经》等,帮助读者深入理解核心技术。
SpringCloud+Python 混合微服务,如何打造AI分布式业务应用的技术底层?
|
26天前
|
数据采集 人工智能 自然语言处理
Python实时查询股票API的FinanceAgent框架构建股票(美股/A股/港股)AI Agent
金融领域Finance AI Agents方面的工作,发现很多行业需求和用户输入的 query都是和查询股价/行情/指数/财报汇总/金融理财建议相关。如果需要准确的 金融实时数据就不能只依赖LLM 来生成了。常规的方案包括 RAG (包括调用API )再把对应数据和prompt 一起拼接送给大模型来做文本生成。稳定的一些商业机构的金融数据API基本都是收费的,如果是以科研和demo性质有一些开放爬虫API可以使用。这里主要介绍一下 FinanceAgent,github地址 https://github.com/AI-Hub-Admin/FinanceAgent
|
26天前
|
人工智能 开发者 Python
python读取word文档 | AI应用开发
在RAG系统中,构建知识库时需读取多种外部文档,其中Word文档较为常见。本文介绍如何使用`python-docx`库读取Word文档(.docx格式)中的标题、段落、表格和图片等内容。首先通过`pip install python-docx`安装库,然后利用提供的接口提取所需信息。尽管该库功能强大,但在识别标题样式时需自定义逻辑,并且仅提供图片的URI而非直接加载。示例代码展示了读取文本、识别标题、读取表格及获取图片URI的方法。【10月更文挑战第2天】
65 2
|
5天前
|
安全 搜索推荐 机器学习/深度学习
AI赋能教育:深度学习在个性化学习系统中的应用
【10月更文挑战第26天】在人工智能的推动下,个性化学习系统逐渐成为教育领域的重要趋势。深度学习作为AI的核心技术,在构建个性化学习系统中发挥关键作用。本文探讨了深度学习在个性化推荐系统、智能辅导系统和学习行为分析中的应用,并提供了代码示例,展示了如何使用Keras构建模型预测学生对课程的兴趣。尽管面临数据隐私和模型可解释性等挑战,深度学习仍有望为教育带来更个性化和高效的学习体验。
23 0
|
26天前
|
JSON API 数据格式
Python| 如何使用 DALL·E 和 OpenAI API 生成图像(2)
Python| 如何使用 DALL·E 和 OpenAI API 生成图像(2)
44 0
Python| 如何使用 DALL·E 和 OpenAI API 生成图像(2)

热门文章

最新文章