卷积神经网络能够算是深度神经网络中很流行的网络了。本文从基础入手,介绍了卷积网络的基本原理以及相关的其它技术,并利用卷积网络作了一个简单项目做为示例参考。想入手 CNN 的朋友不可错过~
选自medium,做者:Tirmidzi Faizal Aflahi,参与:韩放、王淑婷。
python
首先,咱们先看看下面这张照片:算法
这不是一张真实的照片,你能够新建一个窗口来打开它,放大看看,能够看到马赛克。浏览器
实际上,这张照片是由 AI 生成的,是否是看起来很真实?bash
从 Alex Krizhevsky 及其朋友经过 ImageNet 公布这项技术至今,不过才七年。ImageNet 是一个大规模图像识别竞赛,每一年都会举办,识别种类达 1000 多种,从阿拉斯加雪橇犬到厕纸应用尽有。以后,他们又建立了 AlexNet,得到了 ImageNet 竞赛冠军,远超第二名。网络
这项技术就是卷积神经网络。它是深度神经网络的一个分支,处理图像的效果格外好。架构
上图是几年来赢得 ImageNet 挑战赛的软件产生的偏差率。能够发现,2016 年偏差率降到了 5%,已经超越人类水平。app
深度学习的引入与其说是改变规则,不如说是在打破规则。框架
卷积神经网络架构函数
那么问题来了,卷积神经网络究竟是怎么运做的呢?性能
卷积神经网络之因此优于其它深度神经网络是因为它特殊的操做。相比一次只计算图像中的单个像素,CNN 将多个像素的信息组合在一块儿(好比上图中计算了 3*3 的像素),所以可以理解时间模式。
另外,CNN 能够「看到」一组像素组合成一条直线或者曲线。因为深度神经网络一般都是多层卷积的堆叠,经过上一层获得了直线或者曲线后,下一层再也不组合像素,而是将线组合成形状,一层一层进行下去,直到造成完整的图片。
要想深刻理解 CNN,你须要学习不少基础知识,好比什么是核,什么是池化层。可是如今有不少优秀的开源项目,你能够直接在他们的基础上进行研究并加以利用。
这就引入了另外一门技术——迁移学习。
迁移学习
迁移学习使用训练好的深度学习模型来学习特定的任务。
举个栗子,好比你在火车调度公司工做,大家想在不增长劳动力的状况下,预测火车是否晚点。
你彻底能够利用 ImageNet 上的卷积神经网络模型,好比说 2015 年的冠军 ResNet。用火车图片从新训练网络,相信我,结果不会让你失望的。
迁移学习主要有两大优点:
相比于从头开始训练,只须要少许图片就能够获得很好的效果。ImageNet 竞赛提供了一百万张图片用于训练。使用迁移学习,你只须要 1000 甚至 100 张图片就能够训练出一个很好的模型,由于你的预训练模型已经在一百万张图片上训练过了。
较少的训练时间就能实现良好的性能。为了获得和 ImageNet 模型一样好的效果,你可能须要训练数天,这还不包括模型效果很差时对其进行调整所需的时间。然而使用迁移学习,你可能只须要几个小时甚至几分钟就能够完成特定任务的训练,大大节省了时间。
图像分类到图像生成
有了迁移学习以后你们产生了许多有趣的想法。既然咱们能够处理图像、识别图像中的信息,那咱们为何不本身生成图像呢?
因吹斯汀!
生成对抗网络由此应运而生。
给定某些输入,这项技术能够生成对应的图片。
如上图所示,CycleGAN 能够根据一幅画生成对应的真实照片,也能够根据草图生成背包的照片,甚至能够进行超分辨率重建。
很神奇,对吗?
固然,你能够学习构建这些网络。但如何开始呢?
卷积神经网络教程
首先你要知道,入门很简单,但掌握就不是那么容易了。
咱们先最基础的开始。
航拍仙人掌识别
这是 Kaggle 上的学习项目,你的任务是识别航拍图像中是否有柱状仙人掌。
是否是看起来很是简单?
Kaggle 提供了 17500 张图片,其中 4000 张未标注的做为测试集。若是你的模型可以正确标注 4000 张图片,就会得满分 1 或者 100%。
我找了很久,终于找到下面这个很是适合新手入门的项目。
这张图像与上面的相似。它大小为 32*32,其中包含或者不包含柱状仙人掌。由于是航拍图片因此包含各类不一样角度。
因此你须要什么呢?
用 python 构建卷积神经网络
是的,Python——深度学习领域最受欢迎的语言。至于深度学习框架,你有不少种选择,能够本身逐一尝试:
Tensorflow,最受欢迎的深度学习框架,由谷歌工程师构建,而且拥有最多的贡献者和粉丝。因为社群比较庞大,当你有问题时能够很容易找到解决方案。它们的高阶 API keras,在入门者中很受欢迎。
Pytorch,我最喜欢的深度学习框架。纯 Python 实现,所以继承了 Python 的各类优缺点。Python 开发者会很容易上手。它还有 FastAI 库提供抽象,就像 Keras 之于 Tensorflow。
MXNet,Apache 开发的深度学习框架。
Theano,Tensorflow 的前身。
CNTK,微软开发的深度学习框架。
这篇教程中使用的就是我最喜欢的 Pytorch,而且使用 FastAI。
开始以前,你须要安装 Python。浏览 Python 的官网,下载你须要的版本。须要确保的是必定要用 3.6+的版本,不然将不支持你须要用到的一些库。
如今,打开你的命令行或者终端,安装下面这些库:
pip install numpy pip install pandas pip install jupyter复制代码
Numpy 用于存储输入图像,pandas 用于处理 CSV 文件,Jupyter notebook 用于编码。
而后,去 Pytorch 官网下载须要的版本,而且若是你想加速训练的话,要安装 CUDA 版本的 Pytorch,而且版本至少是 1.0 以上。
上面这些搞定以后,安装 torchvision 和 FastAI:
pip install torchvision pip install fastai复制代码
运行 Jupyter notebook 命令,打开 Jupyter,它将打开一个浏览器窗口。
这样所需环境就配置好了,咱们开始吧。
准备数据
导入须要的代码:
import numpy as npimport pandas as pd from pathlib import Path from fastai import * from fastai.vision import * import torch %matplotlib inline复制代码
Numpy 和 Pandas 基本是作什么任务都会须要的。FastAI 和 Torch 是你的深度学习库。Matplotlib Inline 用于显示图表。
下面就能够从 Kaggle 竞赛官网上下载数据了。
解压 zip 文件,并放置于 Jupyter notebook 文件夹中。
假设你的 notebook 被命名为 Cacti。你的文件夹结构会是下面这样:
Train 文件夹里包含全部的训练图片。
Test 文件夹是用于提交的测试图片。
Train CSV 文档里包含训练数据的信息,将图片名与列 has_cactus 映射,若是该列有 cactus,则值为 1,不然为 0。
Sample Submission CSV 中是提交所需的格式。文件名和 Test 文件夹中的图片相对应。
train_df = pd.read_csv("train.csv")复制代码
将 Train CSV 文档加载到数据帧中。
data_folder = Path(".") train_images = ImageList.from_df(train_df, path=data_folder, folder='train')复制代码
利用 ImageList from_df 方法建立加载生成器,以便将 train_df 数据帧和 train 文件夹中的图像进行映射。
数据加强
这是一种根据现有数据建立更多数据的技术。一张猫的图片水平翻转以后仍然是猫的图片。但经过这样作,你能够把你的数据扩增至两倍、四倍甚至 16 倍。
若是你数据量比较少,能够尝试这种方法。
transformations = get_transforms(do_flip=True, flip_vert=True, max_rotate=10.0, max_zoom=1.1, max_lighting=0.2, max_warp=0.2, p_affine=0.75, p_lighting=0.75)复制代码
FastAI 提供了 get_transform 函数来作这些事情。你能够水平翻转、垂直翻转、旋转、放大、提升光度/亮度或者加仿射变换来加强数据。
你能够用我上边提供的参数试一下图片会变成什么样。或者你能够详细阅读官方文档。
而后,对你的图像序列作上述预处理。
train_img = train_img.transform(transformations, size=128)复制代码
参数大小将用于放大或缩小输入,以匹配你将使用的神经网络。我所用的网络是 DenseNet——ImageNet 2017 最佳论文奖的成果,它要输入的图像大小为 128*128。
准备训练
读取数据以后,就到了深度学习最关键的一步——训练。这个过程也是深度学习中学习的由来。网络从你的数据中学习而且依据学习到的结果调整自身参数,直到在数据上获得比较好的效果。
test_df = pd.read_csv("sample_submission.csv") test_img = ImageList.from_df(test_df, path=data_folder, folder='test')train_img = train_img .split_by_rand_pct(0.01) .label_from_df() .add_test(test_img) .databunch(path='.', bs=64, device=torch.device('cuda:0')) .normalize(imagenet_stats)复制代码
在训练这一步,你须要把训练数据分出一小部分作验证集。你不能够用这部分数据来训练,由于它们只是用来作验证的。当你的卷积神经网络在验证集上效果较好时,颇有可能在测试集上也能够提交一个比较好的结果。
FastAI 提供了 split_by_rand_pct 函数,能够很方便地进行以上操做。
databunch 函数能够进行批处理。因为 GPU 内存限制,个人批大小为 64。若是你没有 GPU,忽略 device 参数这一项。
以后,因为你使用的是预训练网络,用 normalize 函数来进行图像归一化。imagenet_stats 函数会根据 ImageNet 预训练模型的训练方式归一化输入图像。
把测试数据也加入训练数据列表里,可使稍后预测更容易,省得再进行一次预处理。记住,这些图像不能用于训练,也不能够用来作验证。这样作只是为了确保训练图片和测试图片采用了彻底相同的预处理方式。
learn = cnn_learner(train_img, models.densenet161, metrics=[error_rate, accuracy])复制代码
如今数据准备工做已经作完了。如今,用 cnn_leaner 建立一个训练器。如上所述,我是采用 DenseNet 做为预训练网络的,固然你也能够选择 TorchVision 提供的其余网络。
单周期技术
如今你能够开始训练了。可是,包括卷积神经网络在内,深度学习训练的一大难题就是,如何选择正确的学习率。学习率决定了进行梯度降低时更新参数减少偏差的幅度。
如上图所示,大一些的学习率使训练过程更快,但更容易错过偏差边界,甚至会跳出可控范围,没法收敛。然而,当使用稍微小一点的学习率时,训练过程会更慢,但不会发散。
因此,选择合适的学习率很是重要。咱们要找到的是足够大却又不会使训练发散的恰当学习率。
但提及来容易作起来难。
因此,一个叫 Leslie Smith 的人提出了单周期策略。
简单来讲,就是先暴力查找几个不一样的学习率,而后选择一个最接近最小偏差但还有进步空间的。代码以下:
learn.lr_find() learn.recorder.plot()复制代码
你会获得以下输出:
偏差最小值在 10^-1 位置,因此咱们可使用略小于这个值的学习率,好比 3*10^-2。
lr = 3e-02 learn.fit_one_cycle(5, slice(lr))复制代码
训练几个 epoch(这里我选择 5,不太大也不过小),而后看看结果。
等等,怎么回事?!
验证集准确率达到了 100%!训练过程其实是很是高效的,只用了六分钟时间。多么幸运!实际上,你可能须要数次迭代才能找到合适的算法。
我等不及要提交了!哈哈。下面让咱们预测并提交测试集结果吧。
preds,_ = learn.get_preds(ds_type=DatasetType.Test) test_df.has_cactus = preds.numpy()[:, 0]复制代码
因为以前已经把测试图片放入训练图片列表中了,所以不须要再对测试图片作预处理。
test_df.to_csv('submission.csv', index=False)复制代码
上面这行代码会建立一个 CSV 文件,其中包含 4000 张测试图像的名称以及每张图像是否包含仙人掌的 label。
当我尝试提交时,我发现须要经过 Kaggle 核来提交 CSV,这是我以前没有注意到的。
幸运的是,核的操做和 Jupyter notebook 很是类似。你彻底能够把 notebook 里建立的东西复制粘贴过来,而后提交。
而后,Duang~完成了!
天呐!得分居然为 0.9999,这已经很是好了。固然若是第一次尝试就获得这么好的分数,应该还有进步的空间。
因此,我调整了网络结构,又尝试了一次。
得分为 1!我作到了!!因此你也能够,实际上并非那么困难。
(另外,这个排名是 4 月 13 号的,个人排名如今颇有可能已经降低了…)
我学到了什么
这个项目很简单,你在解决任务的过程当中也不会遇到什么奇怪的挑战,因此这个项目很是适合入门。
而且因为已经有不少人得满分了,我以为主办方应该另外建立一个用于提交的测试集,难度最好更高一点。
无论怎么样,从这个项目开始基本没有什么困难。你能够立刻尝试而且得到高分。
卷积神经网络对各类不一样的任务都颇有效,不管是图像识别仍是图像生成。如今分析图像并不像之前那么难。固然,若是你尝试的话也能够作到。
因此,选择一个好的卷积神经网络项目,准备好高质量的数据,开始吧!