卷積神經網絡能夠算是深度神經網絡中很流行的網絡了。本文從基礎入手,介紹了卷積網絡的基本原理以及相關的其它技術,並利用卷積網絡作了一個簡單項目做爲示例參考。想入手 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 號的,個人排名如今頗有可能已經降低了…)
我學到了什麼
這個項目很簡單,你在解決任務的過程當中也不會遇到什麼奇怪的挑戰,因此這個項目很是適合入門。
而且因爲已經有不少人得滿分了,我以爲主辦方應該另外建立一個用於提交的測試集,難度最好更高一點。
無論怎麼樣,從這個項目開始基本沒有什麼困難。你能夠立刻嘗試而且得到高分。
卷積神經網絡對各類不一樣的任務都頗有效,不管是圖像識別仍是圖像生成。如今分析圖像並不像之前那麼難。固然,若是你嘗試的話也能夠作到。
因此,選擇一個好的卷積神經網絡項目,準備好高質量的數據,開始吧!