TextToSpeech-Word Embedding

閱讀時間約 17 分鐘

一. 引言

上回我們講到 Word Embedding 能夠將字詞表示從使用字典索引改成詞向量表示,且這個詞向量能夠包含一定程度上的語義訊息,今天就讓我們探討 Word Embedding 到底是如何訓練成的。

二. 常見的 Word Embedding 技術

1. Word2Vec

Word2Vec 是 Google 提出的兩種模型:CBOW(Continuous Bag of Words)和 Skip-gram。

  • CBOW:根據上下文預測目標詞。適合小數據集,訓練速度快。
  • Skip-gram:根據目標詞預測上下文。適合大數據集,效果更好。

2. GloVe

GloVe(Global Vectors for Word Representation)是 Stanford 提出的基於共現矩陣的 Word Embedding 方法。它通過統計整個語料庫中單詞共現的頻率來訓練向量。

3. FastText

FastText 是 Facebook 提出的改進版 Word2Vec。它不僅考慮單詞,還考慮單詞內部的字符 n-grams,使得模型能夠處理未見過的單詞(OOV)。

本篇將以 Word2Vec 為主進行說明

三. Word2Vec

  Word2Vec 有兩種訓練方式,Skip-gram 及 Continuous Bag of Words (CBOW)

  • Skip-Gram

Skip-Gram 的目標是根據給定的中心詞來預測其上下文詞。具體來說,給定一個詞 ,模型試圖預測它前後一定範圍內的詞。

例如 : 對於句子 "人是動物",中心詞 "是" 的上下文詞包括 "人" 和 "動物"。

  • Continuous Bag of Words (CBOW)

CBOW 的目標是根據給定的上下文詞來預測中心詞。具體來說,給定一組上下文詞 ​,模型試圖預測中心詞。

例如,對於句子 "人是動物",上下文詞 "人" 和 "動物" 用來預測中心詞 "是"。

  在實際訓練中,以 Skip-Gram 方法為例,"人是一種從動物進化的生物" 這句話若我們使用"人"作為中心詞,然後設定範圍為2,那麼就可以產生"[人,是]","[人,一種]"兩個組合去訓練,接下來讓我一步步提供示例 :

import jieba

# 準備訓練數據
sentences = [
"臺灣鐵路已放棄興建的路線",
"人是一種從動物進化的生物",
"你是英文系的,可以幫我翻譯一下嗎?"
]
# 將句子分詞
tokenized_sentences = [list(jieba.cut(sentence)) for sentence in sentences]
print(tokenized_sentences)

上篇我們做到這邊就直接使用套件,現在來看看套件都幫我們做了什麼

到這邊我們會拿到切分後的句子

['臺灣', '鐵路', '已', '放棄', '興建', '的', '路線']

['人', '是', '一種', '從', '動物', '進化', '的', '生物']

['你', '是', '英文系', '的', ',', '可以', '幫', '我', '翻譯', '一下', '嗎', '?']

再來我們需要根據這些字詞建立出字典庫

# ​將大列表切割成字詞列表
words = [word for sentence in tokenized_sentences for word in sentence]
# 處理重複字詞並計算詞頻
word_counts = Counter(words)
# 根據詞頻排序(多的在前)​
vocab = sorted(word_counts, key=word_counts.get, reverse=True)
# 賦予編號
word_to_idx = {word: i for i, word in enumerate(vocab)}
idx_to_word = {i: word for word, i in word_to_idx.items()}
vocab_size = len(vocab)

經過處理,我們的字典如下 :

0: '的 '3: '鐵路 '6: '興建' 9: '一種' 12: '進化' 15: '英文系' 18: '幫' 21: '一下'

1: '是 '4: '已 '7: '路線' 10: '從' 13: '生物' 16: ',' 19: '我' 22: '嗎'

2: '臺灣 ' 5: '放棄 '8: '人' 11: '動物' 14: '你' 17: '可以' 20: '翻譯' 23: '?'

然後我們接著設計訓練資料產生器,他需要符合Skip-Gram的訓練方法

def generate_training_data(corpus, word_to_idx, window_size=2):
training_data = []
for sentence in corpus:
sentence_indices = [word_to_idx[word] for word in sentence]
for center_pos in range(len(sentence_indices)):
center_word = sentence_indices[center_pos]
for w in range(-window_size, window_size + 1):
context_pos = center_pos + w
if context_pos < 0 or context_pos >= len(sentence_indices) or center_pos == context_pos:
continue
context_word = sentence_indices[context_pos]
training_data.append((center_word, context_word))
return np.array(training_data)

training_data = generate_training_data(tokenized_sentences, word_to_idx)
print(training_data)

最終的輸出會變成這樣

[[ 2 3] [ 2 4] [ 3 2] [ 3 4] ...... [22 20] [22 21] [22 23] [23 21] [23 22]]

如同前面所講的會變成一個中心詞加上定義的 window_size 範圍內的字詞索引

  另外我們還需要定義一個負樣本生成器,這個是用在訓練中可以優化訓練效率,其概念也很簡單,在最標準的 Loss 計算下,我們理論上需要對整個字典庫的單詞都計算相關性來優化模型,但這樣的效率低下(考慮到字典庫的大小),於是便有這種使用負樣本的方式,改成在計算 Loss 時,不再計算全部的單詞,而是隨機選取一些不相干的詞,模型的目標變成最大化中心詞與正樣本的相似度,同時最小化中心詞與負樣本的相似度,其實現如下 :

def get_negative_samples(batch_size, num_neg_samples, vocab_size):
neg_samples = np.random.choice(vocab_size, size=(batch_size, num_neg_samples), replace=True)
return torch.tensor(neg_samples, dtype=torch.long)

  這樣我們資料前處理其訓練資料的準備終於告一段落,再來我們便可以設計我們的神經網路的部分 :

class Word2Vec(nn.Module):
def __init__(self, vocab_size, embedding_dim):
super(Word2Vec, self).__init__()
self.center_embeddings = nn.Embedding(vocab_size, embedding_dim)
self.context_embeddings = nn.Embedding(vocab_size, embedding_dim)

def forward(self, center_words, context_words, neg_samples):
center_embeds = self.center_embeddings(center_words)
context_embeds = self.context_embeddings(context_words)
neg_embeds = self.context_embeddings(neg_samples)

pos_scores = torch.bmm(context_embeds.view(context_embeds.size(0), 1, context_embeds.size(1)),
center_embeds.view(center_embeds.size(0), center_embeds.size(1), 1)).squeeze()

neg_scores = torch.bmm(neg_embeds.neg(), center_embeds.unsqueeze(2)).squeeze()

return pos_scores, neg_scores

  可以看到我們網路分成兩個部分,一個是中心詞的 Embedding 層,一個是其他詞的Embedding 層,這兩者是不連通的(nn.Embedding可以以字典索引做輸入,不用特意處理輸入轉換成vocab_size維),其可以分別輸出中心詞的詞向量及其他詞的詞向量,根據一開始 Skip-Gram 的說明,Skip-Gram 是由中心詞預測其他詞的訓練方式。 

  所以我們定義 forward 內,中心詞的詞向量與其他詞的詞向量進行矩陣相乘,取得其值作為分數,並同時使用方才所講的負樣本進行同樣的運算取得負樣本分數並輸出,損失函數便需要最大化正樣本分數並最小化負樣本分數,損失函數如下 :

import torch.nn.functional as F

def negative_sampling_loss(pos_scores, neg_scores):
pos_loss = -F.logsigmoid(pos_scores).mean()
neg_loss = -F.logsigmoid(-neg_scores).mean()
return pos_loss + neg_loss

  我們使用 logsigmoid 函數來實現使用 sigmoid 來將分數調整到0-1之間,並同時取 log ,這樣的損失函數能很好的表現出相似度的呈現且容易進行梯度下降。

再來便是喜聞樂見的訓練環節

embedding_dim = 100
model = Word2Vec(vocab_size, embedding_dim)

optimizer = optim.SGD(model.parameters(), lr=0.01)

num_epochs = 100
num_neg_samples = 5
for epoch in range(num_epochs):
total_loss = 0
for center, context in training_data:
center_tensor = torch.tensor([center], dtype=torch.long)
context_tensor = torch.tensor([context], dtype=torch.long)
neg_samples = get_negative_samples(1, num_neg_samples, vocab_size)

optimizer.zero_grad()
pos_scores, neg_scores = model(center_tensor, context_tensor, neg_samples)
loss = negative_sampling_loss(pos_scores, neg_scores)
loss.backward()
optimizer.step()

total_loss += loss.item()
print(f"Epoch {epoch+1}, Loss: {total_loss}")

並且可以根據需求定義出測試函數

def get_word_vector(word):
word_idx = word_to_idx[word]
word_tensor = torch.tensor([word_idx], dtype=torch.long)
return model.center_embeddings(word_tensor).detach().numpy()

def find_similar_words(word, top_n=5):
word_vec = get_word_vector(word)
similarities = []
for other_word in vocab:
if other_word == word:
continue
other_vec = get_word_vector(other_word)
sim = cosine_similarity(word_vec, other_vec)[0][0]
similarities.append((other_word, sim))
similarities.sort(key=lambda x: x[1], reverse=True)
return similarities[:top_n]

similar_words = find_similar_words('人', top_n=3)
print(similar_words)

經過100代訓練後,與[人]相關的前3名為 :

('進化', 0.2668535), ('興建', 0.16363981), ('生物', 0.10142076)

恩......畢竟資料為了演示方便還是使用上一篇的三句話,但是確實是有點相關的

我會將程式碼上傳至Github,有興趣的人也可以自行試試。

四.結語

  這篇詳細的講解了 Word2Vec 的邏輯及全部搭建流程,雖然實際應用還是直接使用套件會輕鬆許多,但理解架構的話,對於套件提供的參數設定也會有更深的理解,希望這篇帶入了全部程式碼並列出運算結果能幫助不了解的人理解過程,下篇預計會說明音訊重建,還請敬請期待。

8會員
21內容數
AI、電腦視覺、圖像處理、AWS等等持續學習時的學習筆記,也包含一些心得,主要是幫助自己學習,若能同時幫助到不小心來到這裡的人,那也是好事一件 : )
留言0
查看全部
發表第一個留言支持創作者!
貓貓學習筆記 的其他內容
上篇我們簡單的了解了 TTS 想要達到的目標,但是對於訓練資料的處理、網路架構、損失函數、輸出分析等考慮到篇幅尚未解釋清楚,這篇將針對訓練資料處理中的文字部分進行詳細說明,讓我們開始吧。
  在 AI 應用中,圖像、語音、文字三種可以說是主要應用,其中我一直以來都是專注於圖像上的研究,對於另兩種僅止於淺嚐,接下來就往音訊上研究看看,先從入門級的Text-To-Speech (TTL) 入場並一個個嘗試其他類型的應用,那麼,就讓我們開始吧。
不知道大家會不會有這種感覺,在使用現今的一些預訓練模型時,雖然好用,但是實際在場域部屬時總感覺殺雞焉用牛刀,實際使用下去後續又沒有時間讓你去優化它,只好將錯就錯反正能用的想法持續使用,現在有個不錯的方法讓你在一開始就可以用相對低廉的成本去優化這個模型,讓後續使用不再懊悔。
  經過三篇的進展,我們目前實作的網路已經能做到同時訓練多種風格,且後續可以直接進行轉換,不用重新訓練,但是這種方法畢竟還是受到了預訓練的風格制約,無法跳脫出來,那麼有什麼辦法能夠讓他對於沒學過的風格也有一定的反應能力呢?
上篇我們已經把風格融入在一個網路之中,實現了訓練一次就可以轉換不同的圖片成我們訓練的風格,但是這樣還不夠,因為這樣每個風格都得訓練一個網路來轉換,太浪費了,那麼,我們有沒有辦法在同一個網路中訓練多個風格呢?
在第一篇我講到一開始的圖像風格轉換,每產生一張圖片都得重新訓練,這對於使用上難免綁手綁腳,所以理所當然的下一步就是要解決這個問題,看看能不能只要訓練一次,就可以重複使用。
上篇我們簡單的了解了 TTS 想要達到的目標,但是對於訓練資料的處理、網路架構、損失函數、輸出分析等考慮到篇幅尚未解釋清楚,這篇將針對訓練資料處理中的文字部分進行詳細說明,讓我們開始吧。
  在 AI 應用中,圖像、語音、文字三種可以說是主要應用,其中我一直以來都是專注於圖像上的研究,對於另兩種僅止於淺嚐,接下來就往音訊上研究看看,先從入門級的Text-To-Speech (TTL) 入場並一個個嘗試其他類型的應用,那麼,就讓我們開始吧。
不知道大家會不會有這種感覺,在使用現今的一些預訓練模型時,雖然好用,但是實際在場域部屬時總感覺殺雞焉用牛刀,實際使用下去後續又沒有時間讓你去優化它,只好將錯就錯反正能用的想法持續使用,現在有個不錯的方法讓你在一開始就可以用相對低廉的成本去優化這個模型,讓後續使用不再懊悔。
  經過三篇的進展,我們目前實作的網路已經能做到同時訓練多種風格,且後續可以直接進行轉換,不用重新訓練,但是這種方法畢竟還是受到了預訓練的風格制約,無法跳脫出來,那麼有什麼辦法能夠讓他對於沒學過的風格也有一定的反應能力呢?
上篇我們已經把風格融入在一個網路之中,實現了訓練一次就可以轉換不同的圖片成我們訓練的風格,但是這樣還不夠,因為這樣每個風格都得訓練一個網路來轉換,太浪費了,那麼,我們有沒有辦法在同一個網路中訓練多個風格呢?
在第一篇我講到一開始的圖像風格轉換,每產生一張圖片都得重新訓練,這對於使用上難免綁手綁腳,所以理所當然的下一步就是要解決這個問題,看看能不能只要訓練一次,就可以重複使用。
你可能也想看
Google News 追蹤
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
在使用 Word 編輯文件時,我們經常會遇到需要分隔內容的需求,例如將文字分隔成段落、將表格分隔成欄位、將圖片分隔成區塊等。在 Word 中,提供了多種分隔線工具,可以幫助我們快速完成分隔內容的操作。 哪種職場工作者需要學習這個技巧? 這些分隔線可以用在任何需要使用 Word 的職場工作中,例如
Thumbnail
Word 是辦公室必備的軟體之一,無論是企業、小商家或是個人,都可能會用到 Word 來製作各種文件。在製作文件時,我們常常需要製作問卷,而問卷中通常會包含 ABCD 等選項。如果我們要手動對齊這些選項,可能需要花費一些時間和精力。
介面 標籤操作 標籤點2下可將標籤隱藏摺疊,再點2下可展開功能區。 在折疊的標籤上按右鍵,點選『摺疊功能區』,可取消摺疊並展開功能區。 介面色彩 『檔案』>選項→一般>Office佈景主題 選取 拖曳 滑鼠指標放在段落的前方(呈現白色箭頭)點一下,選取一行。 滑鼠指標放在段落內
Thumbnail
在工作中,我們常常需要處理大量的資料,而表格是整理資料最有效的方式之一。然而,如果資料原本是文字格式,就需要先將其轉換成表格,才能進行後續的操作。將文字轉換成表格,可以讓資料更加清晰易讀,也方便進行整理和分析。
Thumbnail
在職場上,我們經常需要製作各種文件,例如簡報、報告、合約等。在製作這些文件時,我們常常會遇到一個問題:名字長度不一致。有些名字很短,有些名字很長,這樣看起來會很不協調,也會影響整體美觀。快來學字體排版技巧,讓文字更協調
Thumbnail
當您編寫論文或文章時,提高工作效率是非常重要的。下面將分享3個Word必學快速鍵操作,這些技巧可以幫助您在一秒內輕鬆完成一些常見的任務,讓您的寫作過程更加順暢。
Thumbnail
在今天的數位世界中,Word排版不僅僅是專業文書處理的一部分,也是最常用到的文書工具。然而,許多人在使用Word進行排版時,常常遇到了刪不掉的謎之空白頁的問題,不論怎麼按下"Delte"就是刪除不掉,硬生生就多出一頁,看起來既不美觀又不專業,今天一起來學學怎麼怎麼刪除。
Thumbnail
如果你是Word的新手,不必擔心!這裡有3個簡單的基本技巧,可以幫助在處理文件資料時候更節省時間,提高文件的排版和呈現效果。讓我們一起來看看這些技巧吧。
Thumbnail
不用在慢慢按空白鍵,就可以快速對齊文字! 1、在「檢視」中開啟「尺規」
Thumbnail
我們將介紹如何利⽤VBA實現字體的調、蜂巢式標標題內文設定以及表格加框線等常用排版操作。希望這些介紹能夠幫助您更好地進⾏Word文檔排版,提⾼工作效率和文檔品質。
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
在使用 Word 編輯文件時,我們經常會遇到需要分隔內容的需求,例如將文字分隔成段落、將表格分隔成欄位、將圖片分隔成區塊等。在 Word 中,提供了多種分隔線工具,可以幫助我們快速完成分隔內容的操作。 哪種職場工作者需要學習這個技巧? 這些分隔線可以用在任何需要使用 Word 的職場工作中,例如
Thumbnail
Word 是辦公室必備的軟體之一,無論是企業、小商家或是個人,都可能會用到 Word 來製作各種文件。在製作文件時,我們常常需要製作問卷,而問卷中通常會包含 ABCD 等選項。如果我們要手動對齊這些選項,可能需要花費一些時間和精力。
介面 標籤操作 標籤點2下可將標籤隱藏摺疊,再點2下可展開功能區。 在折疊的標籤上按右鍵,點選『摺疊功能區』,可取消摺疊並展開功能區。 介面色彩 『檔案』>選項→一般>Office佈景主題 選取 拖曳 滑鼠指標放在段落的前方(呈現白色箭頭)點一下,選取一行。 滑鼠指標放在段落內
Thumbnail
在工作中,我們常常需要處理大量的資料,而表格是整理資料最有效的方式之一。然而,如果資料原本是文字格式,就需要先將其轉換成表格,才能進行後續的操作。將文字轉換成表格,可以讓資料更加清晰易讀,也方便進行整理和分析。
Thumbnail
在職場上,我們經常需要製作各種文件,例如簡報、報告、合約等。在製作這些文件時,我們常常會遇到一個問題:名字長度不一致。有些名字很短,有些名字很長,這樣看起來會很不協調,也會影響整體美觀。快來學字體排版技巧,讓文字更協調
Thumbnail
當您編寫論文或文章時,提高工作效率是非常重要的。下面將分享3個Word必學快速鍵操作,這些技巧可以幫助您在一秒內輕鬆完成一些常見的任務,讓您的寫作過程更加順暢。
Thumbnail
在今天的數位世界中,Word排版不僅僅是專業文書處理的一部分,也是最常用到的文書工具。然而,許多人在使用Word進行排版時,常常遇到了刪不掉的謎之空白頁的問題,不論怎麼按下"Delte"就是刪除不掉,硬生生就多出一頁,看起來既不美觀又不專業,今天一起來學學怎麼怎麼刪除。
Thumbnail
如果你是Word的新手,不必擔心!這裡有3個簡單的基本技巧,可以幫助在處理文件資料時候更節省時間,提高文件的排版和呈現效果。讓我們一起來看看這些技巧吧。
Thumbnail
不用在慢慢按空白鍵,就可以快速對齊文字! 1、在「檢視」中開啟「尺規」
Thumbnail
我們將介紹如何利⽤VBA實現字體的調、蜂巢式標標題內文設定以及表格加框線等常用排版操作。希望這些介紹能夠幫助您更好地進⾏Word文檔排版,提⾼工作效率和文檔品質。