用谷歌經典ML方法方法來設計生成式人工智慧語言模型

果冻人工智能發表於2024-12-04

上一篇:《人工智慧模型學習到的知識是怎樣的一種存在?》

序言:在接下來的幾篇中,我們將學習如何利用 TensorFlow 來生成文字。需要注意的是,我們這裡並不使用當前最熱門的 Transformer 模型,而是探討傳統的機器學習方法。這麼做的目的,是讓你對當前主流的生成式人工智慧模型有一個對比性的理解。透過了解這些傳統模型和現代 Transformer 模型的差異,你會發現,現代生成式模型的成功,背後的技術,其實就是“規模法則”(Scaling Law)的推動。你可能會好奇,為什麼以前的模型無法以同樣的方式取得成功?這主要歸結為兩個原因:

1. 硬體計算能力的不足:早期的硬體資源和計算能力無法支撐大規模模型的訓練,尤其是在資料量和模型規模不斷擴充套件時,計算能力成了瓶頸。

2. 傳統模型的並行化困難:像 RNN、CNN、DNN 等模型,雖然在特定任務上有優勢,但它們在處理長篇幅或複雜依賴關係的文字時存在侷限,尤其是 RNN 和 LSTM 的訓練效率低,無法像 Transformer 那樣進行高效的平行計算。

而 Transformer 的核心優勢正是在於它能夠充分並行化計算,利用自注意力機制高效捕捉長距離依賴,這也是它取得成功的關鍵原因。因此,隨著硬體和計算能力的提升,Transformer 終於能夠脫穎而出,成為了現代生成式模型的主流架構。

讓我們開始吧!

You know nothing, Jon Snow

the place where he’s stationed

be it Cork or in the blue bird’s son

sailed out to summer

old sweet long and gladness rings

so i’ll wait for the wild colleen dying

你一無所知,喬恩·雪諾

他駐紮的地方

無論是在科克,還是在藍鳥的兒子

航行到夏天

古老的甜美、長久和歡樂的鐘聲響起

所以我會等待那個野性姑娘的死去

這段文字是由一個非常簡單的模型生成的,訓練的語料庫很小。

我稍微進行了改進,新增了換行符和標點符號,但除了第一行外,其餘的內容都是由你將在本篇中學習構建的模型生成的。

它提到一個“野性姑娘的死去”挺有意思——如果你看過喬恩·雪諾出自的那個劇集,你會明白為什麼!

在過去幾章中,你看到如何使用TensorFlow處理基於文字的資料,

首先將其標記化為數字和序列,這些可以被神經網路處理,

然後使用嵌入向量來模擬情感,最後利用深度和迴圈神經網路來分類文字。

我們使用了一個小而簡單的諷刺資料集,來說明這一切是如何運作的。

在這一篇中,我們將換個方向:不再分類現有文字,而是建立一個神經網路,

它可以預測文字。給定一個文字語料庫,它將嘗試理解其中的詞彙模式,以便當給定一個新的文字片段(即種子)時,預測接下來應該出現哪個詞。

一旦預測出一個詞,種子和預測的詞就成為新的種子,接下來的詞可以繼續預測。

因此,當神經網路在一個文字語料庫上訓練時,它可以嘗試以類似的風格創作新的文字。

為了創作上面的這段詩歌,我收集了一些傳統愛爾蘭歌曲的歌詞,

用它們訓練了一個神經網路,並用它來預測詞彙。

我們將從簡單的開始,用少量文字來說明如何建立一個預測模型,

最後建立一個包含更多文字的完整模型。之後,你可以嘗試看看它能創作出什麼樣的詩歌!

開始時,你必須以不同於之前的方式處理文字。

在前幾篇中,你將句子轉化為序列,然後基於其中標記的嵌入向量進行分類。

而在建立可以用於訓練預測模型的資料時,有一個額外的步驟,

即需要將序列轉化為輸入序列和標籤,其中輸入序列是一組詞彙,標籤是句子中的下一個詞。

然後,你可以訓練一個模型,使其將輸入序列與其標籤匹配,以便在未來的預測中,選擇一個接近輸入序列的標籤。

將序列轉換為輸入序列

在預測文字時,你需要用一個包含相關標籤的輸入序列(特徵)來訓練神經網路。將序列與標籤匹配是預測文字的關鍵。

舉個例子,如果你的語料庫中有一句話“Today has a beautiful blue sky”,你可以將其拆分為“Today has a beautiful blue”作為特徵,和“sky”作為標籤。然後,如果你輸入“Today has a beautiful blue”進行預測,模型很可能會預測出“sky”。如果在訓練資料中你還有一句話“Yesterday had a beautiful blue sky”,按同樣的方式拆分,而你輸入“Tomorrow will have a beautiful blue”進行預測,那麼接下來的詞很有可能也是“sky”。

透過大量的句子,訓練一組詞語序列,其中下一個詞就是標籤,你可以迅速構建出一個預測模型,使得從現有的文字中能夠預測出句子中最可能出現的下一個詞。

我們從一個非常小的文字語料庫開始——一個來自1860年代的傳統愛爾蘭歌曲的片段,其中部分歌詞如下:

In the town of Athy one Jeremy Lanigan

Battered away til he hadnt a pound.

His father died and made him a man again

Left him a farm and ten acres of ground.

He gave a grand party for friends and relations

Who didnt forget him when come to the wall,

And if youll but listen Ill make your eyes glisten

Of the rows and the ructions of Lanigan’s Ball.

Myself to be sure got free invitation,

For all the nice girls and boys I might ask,

And just in a minute both friends and relations

Were dancing round merry as bees round a cask.

Judy ODaly, that nice little milliner,

She tipped me a wink for to give her a call,

And I soon arrived with Peggy McGilligan

Just in time for Lanigans Ball.

在阿西鎮,有個傑里米·拉尼根

他拼命幹活,直到一分錢都沒剩

他的父親去世後又讓他變成了男人

給了他一塊農田和十英畝的土地

他為朋友和親戚們舉辦了一個盛大的派對

當他面臨困境時,他們沒有忘記他

如果你肯聽,我會讓你的眼睛閃閃發光

講講拉尼根舞會上的爭吵和混亂

我自己當然也收到了免費邀請

因為我可以請任何我喜歡的女孩和男孩

很快,朋友和親戚們

就像蜜蜂圍著桶一樣開心地跳起舞來

朱迪·奧達利,那位可愛的帽子商

她對我眨了眨眼,示意我給她打個招呼

我很快就和佩吉·麥吉利根一起到達

剛好趕上了拉尼根舞會

將這段文字合併成一個字串,並用 \n 作為換行符。然後,語料庫就可以像這樣方便地載入和標記化:

tokenizer = Tokenizer()

data="In the town of Athy one Jeremy Lanigan \n Battered away ... ..."

corpus = data.lower().split("\n")

tokenizer.fit_on_texts(corpus)

total_words = len(tokenizer.word_index) + 1

這個過程的結果是將單詞替換成它們的標記值,如圖8-1所示。

                                                    圖8-1. 對句子進行標記化

為了訓練一個預測模型,我們應該進一步處理——將句子拆分成多個較小的序列。例如,我們可以得到一個由前兩個標記組成的序列,再一個由前三個標記組成的序列,依此類推(見圖8-2)。

                                                    圖8-2. 將一個序列轉化為多個輸入序列

為了做到這一點,你需要遍歷語料庫中的每一行,並使用texts_to_sequences將其轉化為標記列表。然後,你可以透過迴圈遍歷每個標記,製作出一個包含所有標記的子列表。

這裡是程式碼:

input_sequences = []

for line in corpus:

token_list = tokenizer.texts_to_sequences([line])[0]

for i in range(1, len(token_list)):

n_gram_sequence = token_list[:i+1]

input_sequences.append(n_gram_sequence)

print(input_sequences[:5])

一旦你得到了這些輸入序列,你就可以對它們進行填充,使它們具有統一的形狀。我們將使用前填充(見圖8-3)。

                                  圖8-3. 對輸入序列進行填充

為了做到這一點,你需要找到輸入序列中最長的句子,然後將所有序列填充到那個長度。這裡是程式碼:

max_sequence_len = max([len(x) for x in input_sequences])

input_sequences = np.array(pad_sequences(input_sequences,

maxlen=max_sequence_len, padding='pre'))

最後,一旦你得到了填充後的輸入序列,就可以將它們分成特徵和標籤,其中標籤就是輸入序列中的最後一個標記(見圖8-4)。

                                圖8-4. 將填充後的序列轉化為特徵(x)和標籤(y)

在訓練神經網路時,你將每個特徵與其對應的標籤進行匹配。舉個例子,像這樣的輸入序列 [0 0 0 0 4 2 66 8 67 68 69],它的標籤就是 [70]。

這裡是將標籤與輸入序列分開的程式碼:

xs, labels = input_sequences[:, :-1], input_sequences[:, -1]

接下來,你需要對標籤進行編碼。現在它們只是標記,比如圖8-4頂部的數字2。但是,如果你想把標記作為分類器的標籤使用,它就必須對映到一個輸出神經元上。因此,如果你想要分類n個詞,每個詞都是一個類別,你就需要n個神經元。這時,控制詞彙表的大小非常重要,因為詞彙越多,你需要的類別(神經元)就越多。記得在第2章和第3章中,你用Fashion MNIST資料集來分類服飾專案,當時你有10種不同的服飾型別嗎?那時你需要在輸出層有10個神經元。如果這次你想預測最多10,000個詞彙呢?你就需要一個包含10,000個神經元的輸出層!

另外,你還需要對標籤進行一熱編碼,以便它們能匹配神經網路所需的輸出。看一下圖8-4。如果神經網路輸入的X是一個由一系列0後跟4組成的序列,你希望預測結果是2,而網路實現這個預測的方法是透過讓輸出層包含詞彙大小數量的神經元,其中第二個神經元的機率最大。

為了將標籤編碼成一組Y,然後用來訓練,你可以使用tf.keras中的to_categorical工具:

ys = tf.keras.utils.to_categorical(labels, num_classes=total_words)

你可以在圖8-5中看到這個過程的視覺化效果。

                                                  圖8-5. 標籤的one-hot編碼

這是一個非常稀疏的表示方式,如果你有大量的訓練資料和潛在的詞彙,記憶體會被很快消耗掉!假設你有100,000個訓練句子,詞彙表中有10,000個單詞——你需要10億位元組的記憶體來儲存這些標籤!但這是我們必須這樣設計網路的原因,因為我們要進行詞彙的分類和預測。

總結:本章透過一個簡單的例子介紹瞭如何用 TensorFlow 訓練一個文字生成模型,重點在於如何透過神經網路學習文字中的詞彙模式,從而生成與輸入文字相似的內容。透過理解資料處理、模型訓練及其背後的原理,我們為進一步深入學習生成式人工智慧奠定了基礎,在下一篇中我們將再次用一完整的例子跟大家一起學習如何動手製作一個AI模型,並訓練它來預測(生成)下一個單詞。

相關文章