[譯] Pytorch 實戰:使用 RNN 網路對姓名進行分類
專案地址:https://github.com/spro/practical-pytorch
專案作者: spro
翻譯: 大鄧
注意:文章末尾有jupyter notebook獲取方式
本文我們構建基於 字母層級
(粒度是字母而不是單詞或者單個的字) 迴圈神經網路RNN
來姓名進行分類預測。
在每一次迴圈過程中, 字母層級的RNN
會以 字母列表
方式輸入 姓名(單詞),神經網路會輸出一個 預測結果outpu
和 隱藏狀態hidden_state
,且 隱藏狀態hidden_state
會作為引數傳入到下一個層網路中。我們將RNN最終的輸出的結果作為預測結果(類別標籤)。
具體的,我們從 18
種語言的成千上萬個姓名資料中開始訓練,並根據姓氏 拼寫
來預測該姓名所屬
語言類別 。
pridict('Hinton') (-0.47) Scottish (-1.52) English (-3.57) Irish pridict('Schmidhuber') (-0.19) German (-2.48) Czech (-2.68) Dutch
準備資料
在 data資料夾
中有 18
個txt檔案,且都是以 某種語言名.txt
命名。 每個txt檔案中含有很多姓氏名,每個姓氏名獨佔一行,有些語言使用的是 Unicode碼(含有除了26英文字母以外的其他字元)
,我們需要將其統一成 ASCII碼
。
from IPython.core.interactiveshell import InteractiveShell InteractiveShell.ast_node_interactivity = 'all' import glob # *是萬用字元,匹配出data資料夾中的所有txt檔案 all_filenames = glob.glob('data/*.txt') all_filenames
all_filenames結果
['data/Czech.txt', 'data/German.txt', 'data/Arabic.txt', 'data/Japanese.txt', 'data/Chinese.txt', 'data/Vietnamese.txt', 'data/Russian.txt', 'data/French.txt', 'data/Irish.txt', 'data/English.txt', 'data/Spanish.txt', 'data/Greek.txt', 'data/Italian.txt', 'data/Portuguese.txt', 'data/Scottish.txt', 'data/Dutch.txt', 'data/Korean.txt', 'data/Polish.txt']
將將Unicode碼轉換成標準的ASCII碼,直接谷歌找到的stackoverflow上的解決辦法。
http://stackoverflow.com/a/518232/2809427
import unicodedata import string #姓氏中所有的字元 #string.ascii_letters是大小寫各26字母 all_letters = string.ascii_letters + " .,;'" #字元的種類數 n_letters = len(all_letters) # 將Unicode碼轉換成標準的ASCII碼 def unicode_to_ascii(s): return ''.join( c for c in unicodedata.normalize('NFD', s) if unicodedata.category(c) != 'Mn' and c in all_letters ) print(n_letters) #字元數為57個 print(unicode_to_ascii('Ślusàrski'))
列印結果
57 'Slusarski'
構建 語言類別-姓名對映字典
,形如 {language1: [name1, name2, ...], language2: [name_x1, name_x2, ...]}
category_names = {} all_categories = [] #讀取txt檔案,返回ascii碼的姓名 列表 def readNames(filename): names = open(filename).read().strip().split('\n') return [unicode_to_ascii(name) for name in names] for filename in all_filenames: category = filename.split('/')[-1].split('.')[0] all_categories.append(category) names = readNames(filename) category_names[category] = names #語言種類數 n_categories = len(all_categories) print('n_categories =', n_categories)
n_categories = 18
現在我們有 category_names
語言-姓名對映詞典。
#檢視Italian語言中前5個姓名 category_names['Italian'][:5]
顯示前5個姓名
['Abandonato', 'Abatangelo', 'Abatantuono', 'Abate', 'Abategiovanni']
將姓名轉化為Tensors
跟機器學習類似,在這裡我們也需要將文字轉化為具體的計算機能理解的資料形式。
為了表徵單個的字元, 我們使用 獨熱編碼向量one-hot vector
, 該向量的尺寸為 1 x n_letters
(每個字元是2維向量)
例如
a對應的是 [[1, 0, 0, 0, 0...]] b對應的是 [[0, 1, 0, 0, 0...]] c對應的是 [[0, 0, 1, 0, 0...]] ...
每個由多個字元(每個字元是2維)組成的姓名 轉化為3維,尺寸為 name_length x 1 x n_letters
在pytorch中,所有輸入的資料都假設是在batch中。所以才能看到尺寸 name_length x 1 x n_letters
中的 1
。
import torch as t print(t.zeros(5))#1維 print(t.zeros(1, 5)) #2維 print(t.zeros(3, 1, 5)) #3維
列印上面三行程式碼執行結果
tensor([0., 0., 0., 0., 0.]) tensor([[0., 0., 0., 0., 0.]]) tensor([[[0., 0., 0., 0., 0.]], [[0., 0., 0., 0., 0.]], [[0., 0., 0., 0., 0.]]])
定義letter_to_tensor函式
import torch # 將字元轉化為 <1 x n_letters> 的Tensor def letter_to_tensor(letter): tensor = torch.zeros(1, n_letters) letter_index = all_letters.find(letter) tensor[0][letter_index] = 1 return tensor # 將姓名轉化成尺寸為<name_length x 1 x n_letters>的資料 # 使用的是one-hot編碼方式轉化 def name_to_tensor(name): tensor = torch.zeros(len(name), 1, n_letters) for ni, letter in enumerate(name): letter_index = all_letters.find(letter) tensor[ni][0][letter_index] = 1 return tensor
現在我們執行letter_to_tensor('J')
print(letter_to_tensor('J'))
顯示上面程式碼執行結果
tensor([[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]])
name_to_tensor('Jones').size() print(name_to_tensor('Jones'))
顯示上面程式碼執行結果
torch.Size([5, 1, 57]) tensor([[[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]], [[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]], [[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]], [[0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]], [[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]]])
構建神經網路
注意看圖中各個引數解讀:
-
input
: 輸入的資料 -
hidden
: 神經網路現有的引數矩陣 -
combined
: input矩陣與hidden矩陣合併,兩個矩陣的行數一致,input和hidden分佈位於新矩陣的 左側和右側 -
i2o
:對輸入的資料轉化為output的計算過程 -
12h
:將輸入的資料轉化為hidden引數的計算過程 -
output
:當前網路的輸出 -
hidden
:當前網路傳遞給下層網路的引數
大家仔細看看琢磨琢磨這個圖構造。現在我們先看看 combined
這個操作
a = t.Tensor(3,1) b = t.Tensor(3,2) print(a) #a print(b) #b print(t.cat((a,b), 1)) #a、b合併後的樣子
列印結果
tensor([[0.0000], [0.0000], [0.0000]]) tensor([[ 0.0000,0.0000], [ 0.0000, -0.0000], [ 0.0000,0.0000]]) tensor([[ 0.0000,0.0000,0.0000], [ 0.0000,0.0000, -0.0000], [ 0.0000,0.0000,0.0000]])
開始DIY我們第一個迴圈神經網路RNN,各個引數解讀:
-
input_size
: 表徵字母的向量的特徵數量(向量長度) -
hidden_size
: 隱藏層特徵數量(列數) -
output_size
: 語言數目,18 -
i2h
: 隱藏網路引數的計算過程。輸入的資料尺寸為input_size + hidden_size
, 輸出的尺寸為hidden_size
-
i2o
: 輸出網路引數的計算過程。輸入的資料尺寸為input_size + hidden_size
, 輸出的尺寸為output_size
import torch.nn as nn class RNN(nn.Module): def __init__(self, input_size, hidden_size, output_size): super(RNN, self).__init__() self.input_size = input_size self.hidden_size = hidden_size self.output_size = output_size self.i2h = nn.Linear(input_size + hidden_size, hidden_size) self.i2o = nn.Linear(input_size + hidden_size, output_size) def forward(self, input, hidden): #將input和之前的網路中的隱藏層引數合併。 combined = torch.cat((input, hidden), 1) hidden = self.i2h(combined) #計算隱藏層引數 output = self.i2o(combined) #計算網路輸出的結果 return output, hidden def init_hidden(self): #初始化隱藏層引數hidden return torch.zeros(1, self.hidden_size)
檢驗我們構建的RNN網路
定義好 RNN
類之後,我們可以建立RNN的例項
rnn = RNN(input_size=57,#輸入每個字母向量的長度(57個字元) hidden_size=128, #隱藏層向量的長度,神經元個數。這裡可自行調整引數大小 output_size=18)#語言的種類數目
要執行此網路,我們需要給網路傳入:
-
input(在我們的例子中,是當前字母的Tensor)
-
hidden(我們首先將隱藏層引數初始化為零)
經過網路內部的運算,我們將得到:
-
output(每種語言的可能性的大小)
-
next_hidden(傳遞給下一個網路的隱藏狀態hidden)
input = letter_to_tensor('A') hidden = rnn.init_hidden() output, next_hidden = rnn(input, hidden) print('output.size =', output.size())
顯示上面程式碼執行結果
output.size = torch.Size([1, 18])
現在我們使用 line_to_tensor
替換 letter_to_tensor
來構件輸入的資料。注意在本例子中,給RNN網路一次輸入一個姓名資料,但對該網路而言,是將姓名資料拆分成字母陣列資料,逐次輸入訓練網路,直到這個姓名最後一個字母陣列輸入完成,才輸出真正的預測結果(姓名所屬的語言類別)。
輸入 RNN神經網路
的資料的粒度變細,不再是 姓名陣列資料(三維)
,而是 組成姓名的字母的陣列或矩陣(二維)
。
input = name_to_tensor('Albert') hidden = torch.zeros(1, 128) #這裡的128是hidden_size #給rnn傳入的初始化hidden引數是尺寸為(1, 128)的zeros矩陣 #input[0]是傳入姓名的第一個字元陣列,注意這個陣列是batch_size=1的矩陣。因為在pytorch中所有輸入的資料都是batch方式輸入的 output, next_hidden = rnn(input[0], hidden) print(output.shape) print(output)
顯示上述結果
torch.Size([1, 18]) tensor([[-0.0785,0.0147,0.0940, -0.0518, -0.0286,0.0175, -0.0641, -0.0449, -0.0013,0.0421,0.0153,0.0269, -0.0556,0.0304, -0.0133, -0.0572, 0.0217,0.1066]], grad_fn=<ThAddmmBackward>)
現在我們看看output這個tensor中的含有資料,想辦法從中提取出預測的 語言類別資訊
。
具體思路:
-
因為output是tensor,我們可以先獲取這個tensor中的data
-
再使用基於data的topk方法,提取tensor中似然值最大的索引值。
該索引值就是 所屬語言類別的索引值
,具體我們可以看下面的例子更好的理解tensor的操作方法。
output.data output.data.topk(1)
顯示上面兩行程式碼執行結果
tensor([[-0.0785,0.0147,0.0940, -0.0518, -0.0286,0.0175, -0.0641, -0.0449, -0.0013,0.0421,0.0153,0.0269, -0.0556,0.0304, -0.0133, -0.0572, 0.0217,0.1066]]) (tensor([[0.1066]]), tensor([[17]]))
上面的兩行程式碼,
其中第一行程式碼得到tensor中的data
第二行程式碼得到某姓姓名(這裡我們實際上只輸入了一個字母,姑且當成只有一個字母的姓名)的 所屬語言的似然值
及 所屬語言類別的索引值
top_n, top_i = output.data.topk(1) top_n #所屬語言的似然值,我們可以將其想象成概率 top_i #所屬語言類別資訊
顯示上面tpo_n和 top_i
tensor([[0.1066]]) tensor([[17]])
接下來我們繼續看
top_n, top_i = output.data.topk(1) top_i[0][0]#所屬語言類別的索引值
顯示top_i[0][0]
tensor(17)
準備訓練RNN
在訓練前,我們把上面剛剛測試的求 所屬語言類別的索引值
方法封裝成函式 category_from_output
。
該函式輸入:
-
output
: RNN網路輸出的output
該函式輸出:
-
語言類別
-
語言類別索引值
def category_from_output(output): _, top_i = output.data.topk(1) category_i = top_i[0][0] return all_categories[category_i], category_i category_from_output(output)
顯示category_from_output(output)執行結果
('Polish', tensor(17))
類比機器學習中需要將資料打亂,這裡我們也要增入隨機性(打亂)。
但不是將訓練資料打亂,而是每次訓練時隨機的從資料集中抽取一種語言中的一個姓名。
這裡我們定義了 random_training_pair
函式, 函式返回的是一個元組 (category, name, category_tensor, name_tensor)
:
-
category: 語言名
-
name: 姓名
-
category_tensor
-
name_tensor
在定義函式前先看下面幾個例子,更好的理解函式內部的運算過程。
category = random.choice(all_categories) category
顯示category
'Polish'
上面的隨機抽取了 一種語言
, 接下來我們在 該語言
中抽取一個 姓名
name = random.choice(category_names[category]) name
顯示name
'Krol'
訓練過程中我們要有標籤資料,在本文中 所屬語言的索引值
作為 標籤
。
由於pytorch中訓練過程中使用的都是tensor結構資料,其中的元素都是浮點型數值,所以這裡我們使用LongTensor, 可以保證標籤是整數。
另外要注意的是,pytorch中運算的資料都是batch。所以我們要將 所屬語言的索引值
放入一個list中,再將該list傳入torch.LongTensor()中
category_tensor = torch.LongTensor([all_categories.index(category)]) category_tensor
顯示category_tensor
tensor([17])
同理,name也要轉化為tensor,這裡我們呼叫name_to_tensor函式即可。
name_tensor = name_to_tensor(name) name_tensor
顯示name_tensor
tensor([[[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]], [[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]], [[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]], [[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]]])
剛剛幾個例子,相信大家已經明白了函式內部的實現方法,現在將其封裝成 random_training_pair函式
import random def random_training_pair(): category = random.choice(all_categories) name = random.choice(category_names[category]) category_tensor = torch.LongTensor([all_categories.index(category)]) name_tensor = name_to_tensor(name) return category, name, category_tensor, name_tensor #我們從資料集中抽取十次 for i in range(10): category, name, category_tensor, name_tensor = random_training_pair() print('category =', category, '/ name =', name)
上述程式碼塊執行結果
category = Vietnamese / name = Truong category = Arabic / name = Malouf category = German / name = Messner category = Arabic / name = Boulos category = English / name = Batchelor category = Spanish / name = Guerrero category = Italian / name = Monti category = Scottish / name = Thomson category = Irish / name = Connell category = Korean / name = Youn
訓練RNN網路
我們使用 nn.CrossEntropyLoss
作為評判標準,來檢驗 姓名真實所屬的語言truth
與 預測該姓名得到預測所屬語言類別predict
比對,計算RNN網路訓練的誤差。
criterion = nn.CrossEntropyLoss()
我們也建立了 優化器optimizer
, 常用的優化器是 SGD演算法
。當 每次訓練網路,我們比對結果, 好則改之, 無則加勉, 讓該網路改善的學習率learning rate(改進的速度)設定為0.005
。
注意學習率learning rate不能設定的太大或者太小:
-
所謂欲速則不達,太大導致訓練效果不佳。容易大條
-
太小了會導致訓練速度太慢,遙遙無期。
learning_rate = 0.005 optimizer = torch.optim.SGD(rnn.parameters(),#給優化器傳入rnn網路引數 lr=learning_rate) #學習率
每輪訓練將:
-
建立input(name_tensor)和 input對應的語言類別標籤(category_tensor)
-
當輸入姓名第一個字母時,需要初始化隱藏層引數。
-
讀取姓名中的
每個字母的陣列資訊
,傳入rnn,並將網路輸出的hidden_state和下一個字母陣列資訊傳入之後的RNN網路中 -
使用criterion比對 最終輸出結果 與 姓名真實所屬的語言標籤 作比較
-
更新網路引數,改進網路。
-
迴圈往復以上幾步
def train(category_tensor, name_tensor): rnn.zero_grad() #將rnn網路梯度清零 hidden = rnn.init_hidden() #只對姓名的第一字母構建起hidden引數 #對姓名的每一個字母逐次學習規律。每次迴圈的得到的hidden引數傳入下次rnn網路中 for i in range(name_tensor.size()[0]): output, hidden = rnn(name_tensor[i], hidden) #比較最終輸出結果與 該姓名真實所屬語言,計算訓練誤差 loss = criterion(output, category_tensor) #將比較後的結果反向傳播給整個網路 loss.backward() #調整網路引數。有則改之無則加勉 optimizer.step() #返回預測結果和 訓練誤差 return output, loss.data[0]
現在我們可以使用一大堆姓名和語言資料來訓練RNN網路,因為 train函式
會同時返回 預測結果
和 訓練誤差
, 我們可以列印並可視化這些資訊。
為了方便,我們每訓練5000次(5000個姓名),就列印 一個姓名的預測結果
,並 檢視該姓名是否預測正確
。
我們對每1000次的訓練累計誤差,最終將誤差 可視化出來。
import time import math n_epochs = 100000# 訓練100000次(可重複的從資料集中抽取100000姓名) print_every = 5000 #每訓練5000次,列印一次 plot_every = 1000#每訓練1000次,計算一次訓練平均誤差 current_loss = 0 #初始誤差為0 all_losses = [] #記錄平均誤差 def time_since(since): #計算訓練使用的時間 now = time.time() s = now - since m = math.floor(s / 60) s -= m * 60 return '%dm %ds' % (m, s) #訓練開始時間點 start = time.time() for epoch in range(1, n_epochs + 1): # 隨機的獲取訓練資料name和對應的language category, name, category_tensor, name_tensor = random_training_pair() output, loss = train(category_tensor, name_tensor) current_loss += loss #每訓練5000次,預測一個姓名,並列印預測情況 if epoch % print_every == 0: guess, guess_i = category_from_output(output) correct = '✓' if guess == category else '✗ (%s)' % category print('%d %d%% (%s) %.4f %s / %s %s' % (epoch, epoch / n_epochs * 100, time_since(start), loss, name, guess, correct)) # 每訓練5000次,計算一個訓練平均誤差,方便後面視覺化誤差曲線圖 if epoch % plot_every == 0: all_losses.append(current_loss / plot_every) current_loss = 0
上面程式碼塊執行結果
5000 5% (0m 8s) 1.6642 San / Chinese ✗ (Korean) 10000 10% (0m 15s) 3.1045 Sobol / Arabic ✗ (Polish) 15000 15% (0m 23s) 2.9460 Hill / Vietnamese ✗ (Scottish) 20000 20% (0m 30s) 1.3255 Uemura / Japanese ✓ 25000 25% (0m 37s) 0.0889 Antonopoulos / Greek ✓ 30000 30% (0m 45s) 2.0578 Keighley / Russian ✗ (English) 35000 35% (0m 53s) 3.4646 Gaspar / Arabic ✗ (Spanish) 40000 40% (1m 1s) 2.6537 Soto / Japanese ✗ (Spanish) 45000 45% (1m 8s) 0.7883 Lykoshin / Russian ✓ 50000 50% (1m 17s) 3.1190 Blau / Vietnamese ✗ (German) 55000 55% (1m 26s) 1.4374 Sacco / Portuguese ✗ (Italian) 60000 60% (1m 33s) 0.0793 O'Boyle / Irish ✓ 65000 65% (1m 41s) 1.0468 Kong / Chinese ✓ 70000 70% (1m 47s) 0.6785 Davidson / Scottish ✓ 75000 75% (1m 55s) 3.3509 Serafin / Irish ✗ (Polish) 80000 80% (2m 2s) 0.1848 Portelli / Italian ✓ 85000 85% (2m 8s) 1.0430 Gabrisova / Czech ✓ 90000 90% (2m 15s) 1.3065 Loyola / Czech ✗ (Spanish) 95000 95% (2m 22s) 0.2379 Coelho / Portuguese ✓ 100000 100% (2m 29s) 0.3560 Teng / Chinese ✓
繪製訓練誤差
import matplotlib.pyplot as plt %matplotlib inline plt.figure() plt.plot(all_losses)
從誤差圖中可以看出,隨著訓練輪數的增加,模型的每1000次訓練的平均誤差越來越小。
手動檢驗訓練的模型
為了方便,我們定義了 predict(rnn, input_name, n_predictions=3)函式
-
rnn: 訓練得到的rnn網路
-
input_name: 姓名字串
-
n_predictions:該姓名預測結果的前n_predictions個預測結果
def predict(rnn, input_name, n_predictions=3):
hidden = rnn.init_hidden()
#name_tensor.size()[0] 名字的長度(字母的數目)
for i in range(name_tensor.size()[0]):
output, hidden = rnn(name_tensor[i], hidden)
print('\n> %s' % input_name)
# 得到該姓名預測結果中似然值中前n_predictions大的 似然值和所屬語言
topv, topi = output.data.topk(n_predictions, 1, True)
predictions = []
for i in range(n_predictions):
value = topv[0][i]
category_index = topi[0][i]
print('(%.2f) %s' % (value, all_categories[category_index]))
predictions.append([value, all_categories[category_index]])
predict(rnn, 'Dovesky')
predict(rnn, 'Jackson')
predict(rnn, 'Satoshi')
上述程式碼塊執行結果
思考Exercises
比照本文,我們還可做很多類似的訓練,比如
-
根據任意詞彙 -> 所屬語言
-
根據名字 -> 名字的性別
-
文章標題 -> 文章所屬話題
為了得到更準確的神經網路(更準確):
-
新增更多層Add more linear layers
-
嘗試使用 nn.LSTM 或者 nn.GRU
-
聚合多種(如rnn、lstm、gru)為更高階的網路
往期文章