FastAI 2019課程學習筆記 lesson 2:自行獲取數據並創建分類器

數據獲取

數據集在深度學習模型的訓練過程中有着重要的影響,本次課程教大家如何利用google的圖片搜索功能來創建簡單的圖片數據集。

本人使用了Google colab作爲學習fastai的平臺,所以你需要科學上網。本人在實驗的過程中發現fastai官方教程提供的獲取google image的json文件不好用,所以找了一個開源的google image開源庫來代替官方的圖片獲取方案。

google_images_download 的安裝和使用

通過下面代碼在Google colab中安裝google_images_download:

!pip install google_images_download 

我們現在需要製作黑熊,棕熊,泰迪熊的數據集,希望最終的模型可以區分這三種熊,所以我們通過如下的代碼來從Google image上獲取這三種熊的圖片。

from google_images_download import google_images_download   #importing the library

response = google_images_download.googleimagesdownload()   #class instantiation

arguments = {"keywords":"black bear,grizzly bear,teddy bear","limit":100,"print_urls":True}   #creating list of arguments
paths = response.download(arguments)   #passing the arguments to the function
print(paths

在這段代碼中我們需要注意的是"limit":100,由於這個庫的問題,在下載100張以內圖片時候是不需要安裝selenium 庫和 chromedriver 擴展的,但是差不多100張的圖片也足夠我們需要了。

下載的文件在google colab中一般放在/content/downloads/目錄下,爲了方便下次我們對數據的使用,我們可以將這些數據永久保存在我們自己Google 硬盤之中

掛載google 個人硬盤到Google colab中

from google.colab import drive
drive.mount('/content/gdrive', force_remount=True)
root_dir = "/content/gdrive/My\ Drive/"

可以通過如下代碼實現掛載google硬盤到google colab中

然後我們可以通過如下代碼將下載的圖片文件拷貝到個人的文件夾中,後面的目標文件夾大家可以自行更改:

!cp -r /content/downloads/* /content/gdrive/My\ Drive/pytorch/Fast_AI_learning/data/bears/

刪除不能打開文件

通過以下的程序實現刪除不能打開的文件,當然我們也可以自己去https://drive.google.com下去找到對應的文件夾,看看是否存在圖片不能打開的情況,如果存在則刪除這些圖片

path = Path("/content/gdrive/My Drive/pytorch/Fast_AI_learning/data/bears")
classes = ['black bear','grizzly bear','teddy bear']
for c in classes:
    print(c)
    verify_images(path/c, delete=True, max_size=500)

創建ImageDataBunch

與lesson 1類似,我們創建ImageDataBunch:

np.random.seed(42)
data = ImageDataBunch.from_folder(path, train=".", valid_pct=0.2,
        ds_tfms=get_transforms(), size=224, num_workers=4).normalize(imagenet_stats)

在我們在創建data bunch時候,如果不知道分離的驗證集和訓練集,就默認當前文件夾是訓練集,但是我們應該留出20%的數據作爲驗證集,所以我們自動的、隨機的創建一個驗證集。在我們隨機創建一個驗證集時候,我們總是提前設置一個固定的隨機種子,這意味着每次我執行這段代碼的時候都會得到同樣的驗證集結果。
隨機性是一個非常重要的部分來找出穩定的解,每次你運行它的時候它都會起作用。但重要的是,你總是有相同的驗證集,否則當你正試圖決定這個超參數改變改善我的模型,但你有一組不同的數據測試,那麼你不知道也許這組數據恰好是有點簡單。
這就是爲什麼總是把隨機的種子放在這裏。

通過下面代碼顯示出一部分圖像結果:

data.show_batch(rows=3, figsize=(7,8))

在這裏插入圖片描述通過下面代碼顯示數據種類結果以及訓練集和驗證集的數量:

data.classes, data.c, len(data.train_ds), len(data.valid_ds)

得到:

(['black bear', 'grizzly bear', 'teddy bear'], 3, 204, 51)

訓練模型

根據lesson 1的訓練模型方式,我們通過resnet34模型來進行訓練:

learn = cnn_learner(data, models.resnet34, metrics=error_rate)
learn.fit_one_cycle(4)

得到如下的結果:
在這裏插入圖片描述然後我們先保存當前狀態,然後通過運行學習率尋找工具並繪製出學習率:

learn.save('stage-1')
learn.unfreeze()
learn.lr_find()
learn.recorder.plot()

最後得到這樣的圖像:
在這裏插入圖片描述
通過圖像我們發現在區間[1e-4, 1e-3]中間loss是下降最快的,所以我們通過下面的代碼進一步的優化模型:

learn.fit_one_cycle(2, max_lr=slice(3e-5,3e-4))

在這裏插入圖片描述
經過我們到現在的努力,我們的錯誤率維持在了1.9%,這已經是一個相對來說比較好的結果的了。我們通過google image創建了一個數據集,然後創建了一個分類器,最後我們得到了1.9%的錯誤率,現在我們保存下這個狀態。

learn.save('stage-2')

解釋模型

learn.load('stage-2')
interp = ClassificationInterpretation.from_learner(learn)
interp.plot_confusion_matrix()

繪製得到混淆矩陣如下:
在這裏插入圖片描述我們發現其中有個黑熊被我們預測成了棕熊

將模型投入生產

首先將模型導出:

learn.export()

這會在目錄中創建一個名爲export.pkl的文件,它包含了部署模型所需要的所有內容(模型,權重以及一些元數據)
我們可以選擇再cpu上執行這個預測程序,當我們的機器沒有gpu時候,這是自行發生的

defaults.device = torch.device('cpu')

我們可以選擇一張圖片:

img = open_image(path/'grizzly bear/2.grizzly_pam-hartman_0_epv0457.jpg')
img

在這裏插入圖片描述我們在保證路徑下包含的export.pkl,然後我們在生產環境中創建學習器:

learn = load_learner(path)

然後我們就可以進行我們的預測工作了

pred_class, pred_idx, outputs = learn.predict(img)
pred_class

我們得到如下結果,預測表明這張圖片表示的是棕熊。

Category grizzly bear

可能出故障的情況

在大多數情況之下,我們按照官方指定的教程去運行程序是沒有產生正確的結果的,所以我們來談談當我們遇到問題時候會發生什麼?這就是我們爲什麼開始學習一些理論的原因,因爲爲了方便我們理解爲什麼會有這些問題以及我們如何解決這些問題。
首先我們先看下一些典型的問題案例,如下:

  • 你的學習率太高或者太低
  • 你的epoch的數量太多或者太少

所以我們來學習下這意味着什麼以及爲什麼他們發揮重要的作用。

學習率太高(Learning rate too high)

所以讓我們用我們的泰迪熊探測器來提高我們的學習速度。默認的學習率是0.003,這在大多數情況下是可行的。如果我們試着把學習率設爲0.5,這是非常大的,會發生什麼呢?我們的驗證損失相當大,它通常是1以下的數。如果你看到你的驗證損失,在我們知道驗證損失是什麼之前,只要出現這樣的情況,證明你的learning rate就太高了,你只需要知道這些讓它更低就可以了。不管你經歷了多少個epoch,如果發生這種情況,就沒有辦法挽回了,你必須回去重新建立你的神經網絡,從零開始適應一個較低的學習率(learning rate)。

learn = create_cnn(data, models.resnet34, metrics=error_rate)
learn.fit_one_cycle(1, max_lr=0.5)

在這裏插入圖片描述

學習率太低(Learning rate too low)

如果我們傳入的最大的學習率不是 0.003而是0.00001呢?

learn = create_cnn(data, models.resnet34, metrics=error_rate)
learn.fit_one_cycle(5, max_lr=1e-5)

在這裏插入圖片描述
雖然使用很低的學習率,我們的錯誤率有所下降但是下降的速度非常的緩慢。

可以通過使用learn.recorder.plot_losses來繪製出驗證和訓練損失,可以看見他們在慢慢的下降。
在這裏插入圖片描述
如果你看見這種情況,就證明你的學習速率太小了,所以你可以嘗試10倍,100倍的放大學習率然後再次進行訓練。**還有一個需要注意的是如果你的學習率太小了,那麼你的訓練損失會高於你的驗證損失,你永遠不會希望這樣的情況發生在你的訓練模型中的。**這就意味着你沒訓練夠,意味着你的學習率太低了或者你的epoch的數量太小了。所以如果你的訓練模型發生這樣的情況,使用更高的學習率再多訓練幾次。

Too few epochs

learn = cnn_learner(data, models.resnet34, metrics=error_rate)
learn.fit_one_cycle(1)

在這裏插入圖片描述
如果使用一個epoch,並且錯誤率在7%,這是低於隨機預測的,但是看看訓練損失和驗證損失之間的差別,我們發現訓練損失是遠遠高於驗證損失的,所以太少的epoch和太小的learning rate的結果是相似的。所以你可以嘗試更多的epoch,如果結果還是一樣,那麼你可以嘗試更高的學習率。如果嘗試一個更高的學習率,損失會達到10億,然後你再把學習率設爲原來的值,再增加一個epoch,這就是平衡,也就是調參,99%的時候你只關心這些,只有1/20的情況下,默認值是無效的。

Too many epochs

太多的epoch會造成過擬合。當你訓練你的模型時間太長,模型可能就會只識別特定的泰迪熊而不是一般的泰迪熊了。儘管你可能聽過在深度學習中很難產生過擬合,所以現在爲大家展示一個過擬合的案例,並且關閉一些其他選項,我關閉了數據增強,dropout,以及weight decay(權值衰減),我儘可能的讓模型過擬合。我以一個很小的學習率訓練模型,並且訓練模型很長時間,我可能會得到一個過擬合的模型。

唯一能告訴你過擬合的是錯誤率短暫的提升,然後開始變得更差。你可能會聽見很多人,甚至那些聲稱瞭解機器學習的人告訴你說如果你的training loss 比validation loss低,那麼就是過擬合,但是這其實並不是完全正確。

任何一個正確的訓練模型的training loss都比validation loss低

這並不是過擬合的跡象,這並不意味着你做錯了什麼,這恰恰證明你做的是對的。你過擬合的標誌是錯誤率開始變得更糟,這纔是你應該關心的。你希望你的模型擁有更低的錯誤率,所以只要你在訓練的時候,你的模型的錯誤在改善,那麼你就沒有過擬合。

np.random.seed(42)
data = ImageDataBunch.from_folder(path, train=".", valid_pct=0.9, bs=26, 
        ds_tfms=get_transforms(do_flip=False, max_rotate=0, max_zoom=1, max_lighting=0, max_warp=0
                              ),size=224, num_workers=4).normalize(imagenet_stats)
learn = cnn_learner(data, models.resnet50, metrics=error_rate, ps=0, wd=0)
learn.unfreeze()
learn.fit_one_cycle(40, slice(1e-6,1e-4))

結果如下:

epoch	train_loss	valid_loss	error_rate	time
0	1.281925	1.141897	0.694323	00:07
1	1.346654	1.129421	0.694323	00:03
2	1.340803	1.107458	0.681223	00:03
3	1.355779	1.085071	0.646288	00:03
4	1.295381	1.050753	0.589520	00:03
5	1.224308	1.000656	0.497817	00:03
6	1.159185	0.938931	0.397380	00:03
7	1.088768	0.867412	0.310044	00:03
8	1.008123	0.788017	0.231441	00:03
9	0.938289	0.708754	0.157205	00:03
10	0.864608	0.634222	0.122271	00:03
11	0.793969	0.566193	0.096070	00:03
12	0.733825	0.508754	0.082969	00:03
13	0.680985	0.458568	0.069869	00:03
14	0.632074	0.418085	0.061135	00:03
15	0.589376	0.385271	0.056769	00:03
16	0.551403	0.356482	0.056769	00:03
17	0.516843	0.330840	0.052402	00:03
18	0.485706	0.311566	0.052402	00:03
19	0.457809	0.295450	0.052402	00:03
20	0.432226	0.281761	0.052402	00:03
21	0.408979	0.269984	0.052402	00:03
22	0.387673	0.259906	0.048035	00:03
23	0.368162	0.251425	0.039301	00:03
24	0.350114	0.245693	0.034934	00:03
25	0.333477	0.238942	0.034934	00:03
26	0.318159	0.232099	0.030568	00:03
27	0.303887	0.226424	0.030568	00:03
28	0.290654	0.222446	0.030568	00:03
29	0.278258	0.218786	0.034934	00:03
30	0.266660	0.215658	0.030568	00:03
31	0.255738	0.214105	0.030568	00:03
32	0.245596	0.209824	0.030568	00:03
33	0.236173	0.205443	0.034934	00:03
34	0.227359	0.204399	0.030568	00:03
35	0.218893	0.202812	0.030568	00:03
36	0.210922	0.202212	0.039301	00:03
37	0.203402	0.201633	0.039301	00:03
38	0.196221	0.201402	0.039301	00:03
39	0.189409	0.201313	0.039301	00:03

綜上是在訓練深度模型時候容易出錯的四點

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章