如何入手卷積神經網路

机器之心發表於2019-06-03
卷積神經網路可以算是深度神經網路中很流行的網路了。本文從基礎入手,介紹了卷積網路的基本原理以及相關的其它技術,並利用卷積網路做了一個簡單專案作為示例參考。想入手 CNN 的朋友不可錯過~

如何入手卷積神經網路

首先,我們先看看下面這張照片:

如何入手卷積神經網路

圖源:Pix2PixHD

這不是一張真實的照片,你可以新建一個視窗來開啟它,放大看看,可以看到馬賽克。

實際上,這張照片是由 AI 生成的,是不是看起來很真實?

從 Alex Krizhevsky 及其朋友通過 ImageNet 公佈這項技術至今,不過才七年。ImageNet 是一個大規模影象識別競賽,每年都會舉辦,識別種類達 1000 多種,從阿拉斯加雪橇犬到廁紙應用盡有。之後,他們又建立了 AlexNet,獲得了 ImageNet 競賽冠軍,遠超第二名。

這項技術就是卷積神經網路。它是深度神經網路的一個分支,處理影象的效果格外好。

如何入手卷積神經網路

圖源:ImageNet

上圖是幾年來贏得 ImageNet 挑戰賽的軟體產生的誤差率。可以發現,2016 年誤差率降到了 5%,已經超越人類水平。

深度學習的引入與其說是改變規則,不如說是在打破規則。

卷積神經網路架構

那麼問題來了,卷積神經網路到底是怎麼運作的呢?

如何入手卷積神經網路

卷積神經網路之所以優於其它深度神經網路是由於它特殊的操作。相比一次只計算影象中的單個畫素,CNN 將多個畫素的資訊組合在一起(比如上圖中計算了 3*3 的畫素),因此能夠理解時間模式。

另外,CNN 可以「看到」一組畫素組合成一條直線或者曲線。由於深度神經網路通常都是多層卷積的堆疊,通過上一層得到了直線或者曲線後,下一層不再組合畫素,而是將線組合成形狀,一層一層進行下去,直到形成完整的圖片。

如何入手卷積神經網路

來自 Mynepalli 的深度卷積神經網路

要想深入理解 CNN,你需要學習很多基礎知識,比如什麼是核,什麼是池化層。但是現在有很多優秀的開源專案,你可以直接在他們的基礎上進行研究並加以利用。

這就引入了另一門技術——遷移學習

遷移學習

遷移學習使用訓練好的深度學習模型來學習特定的任務。

舉個栗子,比如你在火車排程公司工作,你們想在不增加勞動力的情況下,預測火車是否晚點。

你完全可以利用 ImageNet 上的卷積神經網路模型,比如說 2015 年的冠軍 ResNet。用火車圖片重新訓練網路,相信我,結果不會讓你失望的。

遷移學習主要有兩大優勢:

  • 相比於從頭開始訓練,只需要少量圖片就可以得到很好的效果。ImageNet 競賽提供了一百萬張圖片用於訓練。使用遷移學習,你只需要 1000 甚至 100 張圖片就可以訓練出一個很好的模型,因為你的預訓練模型已經在一百萬張圖片上訓練過了。

  • 較少的訓練時間就能實現良好的效能。為了得到和 ImageNet 模型同樣好的效果,你可能需要訓練數天,這還不包括模型效果不好時對其進行調整所需的時間。然而使用遷移學習,你可能只需要幾個小時甚至幾分鐘就可以完成特定任務的訓練,大大節省了時間。

影象分類影象生成

有了遷移學習之後大家產生了許多有趣的想法。既然我們可以處理影象、識別影象中的資訊,那我們為什麼不自己生成影象呢?

因吹斯汀!

生成對抗網路由此應運而生。

如何入手卷積神經網路

朱儁彥等人提出的 CycleGAN

給定某些輸入,這項技術可以生成對應的圖片。

如上圖所示,CycleGAN 可以根據一幅畫生成對應的真實照片,也可以根據草圖生成揹包的照片,甚至可以進行超解析度重建。

如何入手卷積神經網路

超解析度生成對抗網路

很神奇,對嗎?

當然,你可以學習構建這些網路。但如何開始呢?

卷積神經網路教程

首先你要知道,入門很簡單,但掌握就不是那麼容易了。

我們先最基礎的開始。

如何入手卷積神經網路

圖源:Thomas Verbruggen on Unsplash

航拍仙人掌識別

這是 Kaggle 上的學習專案,你的任務是識別航拍影象中是否有柱狀仙人掌。

是不是看起來非常簡單?

Kaggle 提供了 17500 張圖片,其中 4000 張未標註的作為測試集。如果你的模型能夠正確標註 4000 張圖片,就會得滿分 1 或者 100%。

我找了好久,終於找到下面這個非常適合新手入門的專案。

如何入手卷積神經網路

仙人掌

這張影象與上面的類似。它大小為 32*32,其中包含或者不包含柱狀仙人掌。因為是航拍圖片所以包含各種不同角度。

所以你需要什麼呢?

用 python 構建卷積神經網路

是的,Python——深度學習領域最受歡迎的語言。至於深度學習框架,你有很多種選擇,可以自己逐一嘗試:

  1. Tensorflow,最受歡迎的深度學習框架,由谷歌工程師構建,並且擁有最多的貢獻者和粉絲。由於社群比較龐大,當你有問題時可以很容易找到解決方案。它們的高階 API keras,在入門者中很受歡迎。

  2. Pytorch,我最喜歡的深度學習框架。純 Python 實現,因此繼承了 Python 的各種優缺點。Python 開發者會很容易上手。它還有 FastAI 庫提供抽象,就像 Keras 之於 Tensorflow。

  3. MXNet,Apache 開發的深度學習框架。

  4. Theano,Tensorflow 的前身。

  5. 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 np
import 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,這是我之前沒有注意到的。

如何入手卷積神經網路

圖源:Kaggle

幸運的是,核的操作和 Jupyter notebook 非常相似。你完全可以把 notebook 裡建立的東西複製貼上過來,然後提交。

然後,Duang~完成了!

如何入手卷積神經網路

天吶!得分竟然為 0.9999,這已經非常好了。當然如果第一次嘗試就得到這麼好的分數,應該還有進步的空間。

所以,我調整了網路結構,又嘗試了一次。

如何入手卷積神經網路

得分為 1!我做到了!!所以你也可以,實際上並不是那麼困難。

(另外,這個排名是 4 月 13 號的,我的排名現在很有可能已經下降了…)

我學到了什麼

這個專案很簡單,你在解決任務的過程中也不會遇到什麼奇怪的挑戰,所以這個專案非常適合入門。

並且由於已經有很多人得滿分了,我覺得主辦方應該另外建立一個用於提交的測試集,難度最好更高一點。

不管怎麼樣,從這個專案開始基本沒有什麼困難。你可以馬上嘗試並且獲得高分。

如何入手卷積神經網路

圖源:Mario Mrad on Unsplash

卷積神經網路對各種不同的任務都很有效,不論是影象識別還是影象生成。現在分析影象並不像以前那麼難。當然,如果你嘗試的話也可以做到。

所以,選擇一個好的卷積神經網路專案,準備好高質量的資料,開始吧!

原文連結:https://medium.freecodecamp.org/everything-you-need-to-know-to-master-convolutional-neural-networks-ef98ca3c7655

相關文章