Python

fastai 深度學習函式庫安裝、入門教學與範例

介紹如何在 Linux 中安裝與使用 fastai 深度學習函式庫,使用 ResNet 預訓練模型辨識貓的圖片。

安裝 fastai

若要在 Miniconda 環境中安裝 fastai,可以執行:

# miniconda 環境安裝 fastai
conda install -c fastchan fastai

若要在 Anaconda 環境中安裝 fastai,則可以執行:

# Anaconda 環境安裝 fastai
conda install -c fastchan fastai anaconda

若要以 pip 安裝 fastai,則必須先安裝好 PyTorch 之後,再執行:

# pip 環境安裝 fastai
pip install fastai

fastai 程式基本架構

在使用 fastai 函式庫進行深度學習的程式中,都會包含以下四個部分:

  1. 建立適當的 DataLoaders
  2. 建立一個 Learner
  3. 呼叫 fit() 方法。
  4. 進行預測或查看結果。

這樣的程式架構適用於各種不同類型的應用程式與資料集,雖然影用類型差異很大,但是程式碼的架構都類似。

下載 Oxford-IIIT Pet 資料集

untar_data() 函數下載 Oxford-IIIT Pet 資料集,解壓縮後取得影像路徑:

from fastai.vision.all import *

# 下載 Oxford-IIIT Pet 資料集
path = untar_data(URLs.PETS)/'images'

由於在 Oxford-IIIT Pet 資料集中,貓類別的圖片檔案名稱都是以大寫字母開頭,而狗類別的圖片檔案名稱則是以小寫字母開頭,因此這裡我們自行定義一個產生標註影像用的函數,依據檔案名稱開頭大小寫來決定影像是否為貓類別,此函數將用於隨後的 ImageDataLoaders

# 依據檔案名稱第一個字母大小寫產生標註
def is_cat(x): return x[0].isupper()

建立 DataLoader

在 fastai 中有非常多的類別可以用來處理不同的資料與問題,這裡我們使用 ImageDataLoaders 建立一個 DataLoader 來載入影像資料,並以 from_name_func() 方式搭配 is_cat() 來產生影像標註:

# 建立 DataLoader
dls = ImageDataLoaders.from_name_func(
    path, get_image_files(path), valid_pct=0.2, seed=42,
    label_func=is_cat, item_tfms=Resize(224))

此處的影像轉換(transform)是以 item_tfms 參數指定以 Resize(224) 將每張影像轉為邊長為 224 的正方形圖片,另外也可以改用 batch_tfms 參數以 GPU 批次進行轉換,轉換速度會更快。

將圖片統一轉為邊長為 224 的正方形圖片,只是過去大家的習慣而已,某些舊的模型會要求圖片必須符合這樣的尺寸,但一般的情況下我們也可以採用其他尺圖片,較大的圖片會有較高的準確率,但也會耗費較多的計算資源,反之小圖片則準確率低、計算資源相對也較節省。

而這裡的 valid_pct=0.2 代表保留 20% 的資料作為驗證用的資料,不要放入訓練過程,僅用於驗證模型的準確率,這些 20% 的資料稱為驗證資料集(validation set),而用於訓練的 80% 資料則稱為訓練資料集(training set)。

在預設的情況下,fastai 會以隨機的方式挑選 20% 的資料作為驗證資料集,而 seed=42 這個參數則是用來指定亂數種子,也就是說若指定相同的亂數種子,就可以產生相同的驗證資料集,當我們更改模型參數並重新訓練時,就可以用相同的驗證資料集來評估模型的準確率,方便比較模型的差異。

由於模型是根據訓練資料集所訓練出來的,模型本身就含有大量的訓練資料集資訊,因此在估算模型的準確率時,fastai 只會以驗證資料集來驗證模型,並不會使用到訓練資料集的資料,這樣才能估算出模型對於新資料的預測效果。

建立 Learner

接著建立一個 CNN 的 Learner,指定 CNN 網路模型、DataLoader、損失函數:

# 建立 Learner(指定模型、DataLoader、損失函數)
learn = cnn_learner(dls, resnet34, metrics=error_rate)

這裡我們採用 ResNet 的模型,而 34 是代表模型的層數,除了 34 之外,還有 1850101152 可以選擇,層數越高則需要的訓練時間越久、也越有可能 overfitting,當資料量較大的時候才會較準確。

metrics 是代表使用驗證資料集進行模型驗證時,所採用的衡量基準,在每一個 epoch 結束時都會計算出這個 metric 值做為參考,以這個例子所採用的 error_rate 來說就是計算分類錯誤的比例,而另一個常見的 accuracy 則是分類正確的比例,也就是 1.0 - error_rate。fastai 中提供了很多種 metric 可供使用者選用,詳細說明可參考 fastai 的網頁

cnn_learner() 中有一個 pretrained 參數,可以用來指定是否採用預訓練的模型,當參數設定為 True 的時候,fastai 會將最後一層移除,再添加一層或多層隨機的權重,通常使用預訓練模型可以有效提高模型的準確率,減少訓練時間。將預訓練模型用於不同的應用上就是所謂的遷移學習(transfer learning)。

訓練模型

最後使用 fine_tune() 進行模型的訓練,並指定要進行幾個 epoch 的訓練:

# 訓練模型
learn.fine_tune(1)

事實上 Learner 也有一個 fit() 函數,而這裡採用 fine_tune() 來訓練模型的原因是因為我們採用了預訓練模模型,fine_tune() 預設會先以一個 epoch 訓練部分的預訓練模型參數,讓添加的網路層能夠正確運作,再接著以指定數量的 epoch 訓練整個模型。

以模型進行預測

訓練完成之後,我們就可以使用這個模型進行預測了。我們使用 Wikimedia Commons 的一張貓的圖片作為示範,先下載這張圖片:

# 下載圖片
wget https://commons.wikimedia.org/wiki/File:A-Cat.jpg

接著使用 fastai 的 PILImage 載入圖片之後,以剛剛訓練好的模型進行預測:

# 載入圖片
img = PILImage.create("A-Cat.jpg")

# 使用模型預測
is_cat,_,probs = learn.predict(img)
print(f"是否為貓:{is_cat}.")
print(f"是貓的機率:{probs[1].item():.6f}")
是否為貓:True.
是貓的機率:1.000000

影像分割

以下是一個使用 fastai 搭配 CamVid 資料集訓練影像分割模型的範例程式,雖然應用不同,但整個程式架構也都很類似:

from fastai.vision.all import *

# 下載 CamVid 資料
path = untar_data(URLs.CAMVID_TINY)

# 建立 DataLoader
dls = SegmentationDataLoaders.from_label_func(
    path, bs=8, fnames = get_image_files(path/"images"),
    label_func = lambda o: path/'labels'/f'{o.stem}_P{o.suffix}',
    codes = np.loadtxt(path/'codes.txt', dtype=str)
)

# 建立 Learner
learn = unet_learner(dls, resnet34)

# 訓練模型
learn.fine_tune(8)

模型訓練完成之後,觀看幾筆模型預測的結果:

# 觀看 3 筆預測結果
learn.show_results(max_n=3, figsize=(7,8))
觀看 3 筆預測結果

自然語言處理

以下是使用 fastai 搭配 IMDb Large Movie Review Dataset 訓練自然語言處理模型的範例程式:

from fastai.text.all import *

# 下載 IMDb Large Movie Review Dataset,建立 DataLoader
dls = TextDataLoaders.from_folder(untar_data(URLs.IMDB), valid='test')

# 建立 Learner
learn = text_classifier_learner(dls, AWD_LSTM, drop_mult=0.5, metrics=accuracy)

# 訓練模型
learn.fine_tune(4, 1e-2)

模型訓練完成之後,可以使用此模型來辨識句子是屬於正面還是反面:

# 辨識句子屬於正面或反面
learn.predict("I really liked that movie!")
('pos', tensor(1), tensor([0.0041, 0.9959]))

這裡的結果中,第一個 'pos' 代表預測結果為正面(positive),而第二個 tensor(1) 則是代表 'pos' 的索引,而最後一個 tensor([0.0041, 0.9959]) 則代表負面與正面的機率分別為 0.41% 與 99.59%。

表格資料

分類問題

以下是拿 Adult Data Set 資料集,以 fastai 訓練模型並預測一個人是否為高收入族群的範例:

from fastai.tabular.all import *

# 下載 Adult Data Set
path = untar_data(URLs.ADULT_SAMPLE)

# 建立 DataLoader
dls = TabularDataLoaders.from_csv(path/'adult.csv', path=path, y_names="salary",
    cat_names = ['workclass', 'education', 'marital-status', 'occupation',
    'relationship', 'race'],
    cont_names = ['age', 'fnlwgt', 'education-num'],
    procs = [Categorify, FillMissing, Normalize])

# 建立 Learner
learn = tabular_learner(dls, metrics=accuracy)

這裡在使用 TabularDataLoaders 建立 DataLoader 的時候,必須區分連續型(continuous)與類別型(categorical)的變數。

在這個例子中並沒有預訓練模型,所以我們改用 fit_one_cycle() 來進行模型訓練,從頭開始訓練模型時,時常都會使用這種方式。

# 訓練模型
learn.fit_one_cycle(3)

訓練完成之後,觀看幾筆預測結果:

# 觀看幾筆預測結果
learn.show_results()

迴歸問題

以下是拿 MovieLens 資料集,以 fastai 訓練模型並預測人對於電影喜好程度的範例,也就是一個推薦系統:

from fastai.collab import *

# 下載 MovieLens 資料集
path = untar_data(URLs.ML_SAMPLE)

# 建立 DataLoader
dls = CollabDataLoaders.from_csv(path/'ratings.csv')

# 建立 Learner
learn = collab_learner(dls, y_range=(0.5,5.5))

# 訓練模型
learn.fine_tune(10)

# 觀看幾筆預測結果
learn.show_results()

由於這個例子所輸出的預測值屬於連續型的分數,所以在建立 Learner 要加上 y_range 參數指定輸出值的範圍。

雖然這個例子也沒有使用預訓練模型,但是仍然可以使用 fine_tune() 來訓練模型,有時候我們可以直接嘗試使用分別 fine_tune()fit_one_cycle() 來訓練模型,選擇結果比較好的來使用。

fastai 函數說明

若要查詢 fastai 中各種函數的使用說明,除了可以從 fastai 官方網站查詢之外,也可以使用 doc() 函數來查詢,例如若要查詢 learn.predict() 函數的使用方式,則可執行:

# 查詢函數使用方法
doc(learn.predict)

fastai 內建資料集與預訓練模型

fastai 中內建了許多常用的資料集,包含影像分類、自然語言處理、影像分割、聲音分類、醫學影像等各類的資料集,詳細的資料集說明可以參考 fastai 的網頁

參考資料

Share
Published by
Office Guide
Tags: fastai

Recent Posts

Python 使用 PyAutoGUI 自動操作滑鼠與鍵盤

本篇介紹如何在 Python ...

1 年 ago

Ubuntu Linux 以 WireGuard 架設 VPN 伺服器教學與範例

本篇介紹如何在 Ubuntu ...

1 年 ago

Linux 網路設定 ip 指令用法教學與範例

本篇介紹如何在 Linux 系...

1 年 ago

Linux 以 Cryptsetup、LUKS 加密 USB 隨身碟教學與範例

介紹如何在 Linux 系統中...

1 年 ago