搞人工智慧開源大語言模型GPT2、Llama的正確姿勢

果冻人工智能發表於2024-11-02

(如果想及時收到人工智慧相關的知識更新,請點選關注!!)

序言:目前我們每一小節的內容都講解得非常慢,因為這是人工智慧研發中的最基礎知識。如果我們不能紮實掌握這些知識,將很難理解後續更復雜且實用的概念。因此,我們甚至採用一個概念一節的方式來編排內容,區分得清清楚楚、明明白白,以便大家能夠非常明確地瞭解各知識點之間的關聯關係和界限。本節將講述一種在人工智慧領域中被視為“泰斗絕學”的方法,幫助我們高效地完成模型訓練——這項絕學就是“遷移學習”。

遷移學習

正如我們在本章中已經看到的那樣,使用卷積操作來提取特徵是識別影像內容的一個強大工具。生成的特徵圖可以輸入到神經網路的密集層中,與標籤匹配,從而更準確地確定影像的內容。透過這種方法,結合一個簡單、易於訓練的神經網路和一些影像增強技術,我們構建了一個模型,在非常小的資料集上訓練時,能夠以80-90%的準確率區分馬和人。

但是我們可以透過一種叫做遷移學習的方法進一步改進我們的模型。遷移學習的理念很簡單:與其從零開始為我們的資料集學習一組濾波器,為什麼不使用一個在更大資料集上學習到的濾波器集合呢?該資料集包含了比我們自己“從零開始構建”所能負擔得起的更多特徵。我們可以將這些濾波器放入我們的網路中,然後使用這些預學習的濾波器訓練一個適合我們資料的模型。例如,我們的馬或人資料集只有兩個類別,而我們可以使用一個已經為一千個類別預訓練過的現有模型,但到某個階段我們不得不捨棄部分已有的網路結構,新增適合兩分類的層來構建分類器。

圖 3-14 展示了類似於我們這種分類任務的卷積神經網路架構。我們有一系列的卷積層,連線到一個密集層,進而連線到輸出層。

                                  圖 3-14. 卷積神經網路架構

我們已經看到,使用這種架構,我們能夠構建一個相當不錯的分類器。但是,透過遷移學習,如果我們可以從另一個模型中提取預學習的層,凍結或鎖定它們以使其不可訓練,然後將它們置於我們的模型之上,就像圖 3-15 所示,這會怎麼樣呢?

                                        圖 3-15. 透過遷移學習從另一個架構中獲取層

當我們考慮到,一旦這些層被訓練好,它們實際上只是一些數字,表示濾波器的值、權重和偏置,配合一個已知的架構(每層濾波器的數量、濾波器的大小等),那麼重用它們的想法就非常直接了當了。

讓我們看看程式碼中的實現。這方面有很多預訓練的模型可以使用。我們將使用來自谷歌的流行模型Inception的第3版,它在一個名為ImageNet的資料庫中用超過一百萬張圖片進行了訓練。該模型有幾十層,可以將影像分類為一千個類別。一個包含預訓練權重的已儲存模型也已經可以使用。要使用它,我們只需下載這些權重,建立一個Inception V3架構的例項,然後將這些權重載入到這個架構中,程式碼如下:

from tensorflow.keras.applications.inception_v3 import InceptionV3

weights_url = "https://storage.googleapis.com/mledudatasets/inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5"

weights_file = "inception_v3.h5"

urllib.request.urlretrieve(weights_url, weights_file)

pre_trained_model = InceptionV3(input_shape=(150, 150, 3),

include_top=False,

weights=None)

pre_trained_model.load_weights(weights_file)

現在我們有一個完整的預訓練Inception模型。如果你想檢視它的架構,可以用以下程式碼:

pre_trained_model.summary()

不過要小心,它很龐大!可以瀏覽一下,看看層和它們的名稱。我喜歡用一個叫做mixed7的層,因為它的輸出很小——7 × 7的影像——不過你可以隨意嘗試其他層。

接下來,我們將凍結整個網路,使其不再重新訓練,然後設定一個變數指向mixed7的輸出,作為我們要裁剪網路的位置。程式碼如下:

for layer in pre_trained_model.layers:

layer.trainable = False

last_layer = pre_trained_model.get_layer('mixed7')

print('last layer output shape: ', last_layer.output_shape)

last_output = last_layer.output

注意,我們列印了最後一層的輸出形狀,你會看到我們在這時得到了7 × 7的影像。這表示當影像被傳遞到mixed7時,濾波器輸出的影像大小為7 × 7,所以很容易管理。同樣,你不必選擇這個特定層,可以嘗試其他層。

現在讓我們看看如何在這個輸出下新增我們的密集層:

/將輸出層展開為1維/

x = layers.Flatten()(last_output)

/新增一個帶有1,024個隱藏單元和ReLU啟用的全連線層/

x = layers.Dense(1024, activation='relu')(x)

/新增一個用於分類的最終sigmoid層/

x = layers.Dense(1, activation='sigmoid')(x)

就這麼簡單,我們將最後的輸出展平,因為我們將把結果傳遞到密集層中。然後,我們新增一個包含1,024個神經元的密集層,和一個帶有1個神經元的輸出層。

現在我們可以簡單地將模型定義為預訓練模型的輸入,接著是剛剛定義的x,然後以通常的方式編譯它:

model = Model(pre_trained_model.input, x)

model.compile(optimizer=RMSprop(lr=0.0001),

loss='binary_crossentropy',

metrics=['acc'])

在這個架構上訓練模型40個週期後,準確率達到99%+,驗證準確率則達到96%+(見圖3-16)。

                                圖 3-16. 使用遷移學習訓練馬或人分類器

這裡的結果比我們之前的模型要好得多,但你可以繼續進行微調和改進。你還可以試試這個模型在更大資料集上的表現,比如Kaggle上著名的貓狗大戰(Dogs vs. Cats)。這是一個非常多樣化的資料集,包含了25,000張貓和狗的圖片,很多圖片中的主體都有一定遮擋——比如被人抱著的情況下。

使用之前的同樣演算法和模型設計,你可以在Colab上訓練一個貓狗分類器,利用GPU每個週期大約3分鐘。訓練20個週期,大約需要1小時。

在測試一些非常複雜的圖片時(如圖3-17所示),這個分類器全都判斷正確。我特意選擇了一張長著像貓耳朵的狗的圖片,還有一張背對著的狗的圖片。另外兩張貓的圖片也都是非典型的。

                                    圖 3-17. 成功分類的非典型貓狗圖片

右下角的那隻貓,閉著眼睛、耳朵下垂、伸著舌頭舔爪子,把它載入到模型中時,得到了圖3-18中的結果。你可以看到,它給出了一個非常低的值(4.98 × 10⁻²⁴),這表明網路幾乎可以確定它是一隻貓!

                                    圖 3-18. 分類舔爪子的貓

你可以在作者的一個GitHub倉庫中找到馬或人分類器以及貓狗分類器的完整程式碼。

本節我們介紹了使用“遷移學習”的方法來完成模型訓練,省去了繁瑣的前期訓練過程,透過遷移已有知識並結合少量資料進行微調即可實現模型的適應性。這種方法是通用的,適用於小型神經網路,同樣也適用於如2024年Facebook的開源大型語言模型Llama等知名大模型。在這些預訓練模型的基礎上,遷移學習可以有效節省大量GPU資源的預訓練成本。下一節我們要講解的也是人工智慧模型訓練中的很重要的技能“隨機失活”法。

相關文章