自然言語処理には多くの興味深いアプリケーションがあり、テキスト生成もその一つです。
機械学習モデルがリカレントニューラルネットワーク、LSTM-RNN、GRUなどのシーケンスモデルで動作する場合、それらは入力テキストの次のシーケンスを生成することができます。
PyTorchは、これらのNLPベースのタスクにパワーを与える強力なツールとライブラリのセットを提供します。前処理が少なくて済むだけでなく、学習プロセスも高速化します。
この記事では、リカレントニューラルネットワークをPyTorchで複数の言語について学習します。学習に成功すると、RNNモデルは入力文字で始まる言語に属する名前を予測します。
PyTorch
この実装はGoogle Colabで行われ、データセットはGoogle Driveから取得されます。まず、Colab Notebookを使ってGoogle Driveをインストールします。
from google.colab import drive
drive.mount('/content/gdrive')
これで、必要なライブラリがすべてインポートされます。
from __future__ import unicode_literals, print_function, division
from io import open
import glob
import os
import unicodedata
import string
import torch
import torch.nn as nn
import random
import time
import math
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
次のコード・スニペットはデータセットを読み込みます。
all_let = string.ascii_letters + " .,;'-"
n_let = len(all_let) + 1
def getFiles(path):
return glob.glob(path)
# Unicode文字列をASCIIに変換する
def unicodeToAscii(s):
return ''.join(
c for c in unicodedata.normalize('NFD', s)
if unicodedata.category(c) != 'Mn'
and c in all_let
)
# ファイルを読み込み、行に分割する
def getLines(filename):
lines = open(filename, encoding='utf-8').read().strip().split('
')
return [unicodeToAscii(line) for line in lines]
# catを作成する_lin辞書、各カテゴリの行のリストを格納する
cat_lin = {}
all_ctg = []
for filename in getFiles('gdrive/My Drive/Dataset/data/data/names/*.txt'):
categ = os.path.splitext(os.path.basename(filename))[0]
all_ctg.append(category)
lines = getLines(filename)
cat_lin[categ] = lines
n_ctg = len(all_ctg)
次のステップでは、モジュール・クラスを定義して名前を生成します。モジュールはリカレント・ニューラル・ネットワークになります。
class NameGeneratorModule(nn.Module):
def __init__(self, inp_size, hid_size, op_size):
super(NameGeneratorModule, self).__init__()
self.hid_size = hid_size
self.i2h = nn.Linear(n_ctg + inp_size + hid_size, hid_size)
self.i2o = nn.Linear(n_ctg + inp_size + hid_size, op_size)
self.o2o = nn.Linear(hid_size + op_size, op_size)
self.dropout = nn.Dropout(0.1)
self.softmax = nn.LogSoftmax(dim=1)
def forward(self, category, input, hidden):
inp_comb = torch.cat((category, input, hidden), 1)
hidden = self.i2h(inp_comb)
output = self.i2o(inp_comb)
op_comb = torch.cat((hidden, output), 1)
output = self.o2o(op_comb)
output = self.dropout(output)
output = self.softmax(output)
return output, hidden
def initHidden(self):
return torch.zeros(1, self.hid_size)
以下の関数を使用して、リストから無作為に項目を選択したり、カテゴリから無作為に行を選択したりします。
def randChoice(l):
return l[random.randint(0, len(l) - 1)]
def randTrainPair():
category = randChoice(all_ctg)
line = randChoice(cat_lin[category])
return category, line
以下の関数は、RNNモジュールと互換性のある形式にデータを変換します。
def categ_Tensor(categ):
li = all_ctg.index(categ)
tensor = torch.zeros(1, n_ctg)
tensor[0][li] = 1
return tensor
def inp_Tensor(line):
tensor = torch.zeros(len(line), 1, n_let)
for li in range(len(line)):
letter = line[li]
tensor[li][0][all_let.find(letter)] = 1
return tensor
def tgt_Tensor(line):
letter_indexes = [all_let.find(line[li]) for li in range(1, len(line))]
letter_id.append(n_let - 1) # EOS
return torch.LongTensor(letter_id)
以下の関数は、カテゴリ、入力、ターゲットテンソルを持つ確率的学習例を作成します。
#
criterion = nn.NLLLoss()
#
lr_rate = 0.0005
def train(category_tensor, input_line_tensor, target_line_tensor):
target_line_tensor.unsqueeze_(-1)
hidden = rnn.initHidden()
rnn.zero_grad()
loss = 0
for i in range(input_line_tensor.size(0)):
output, hidden = rnn(category_tensor, input_line_tensor[i], hidden)
l = criterion(output, target_line_tensor[i])
loss += l
loss.backward()
for p in rnn.parameters():
p.data.add_(p.grad.data, alpha=-lr_rate)
return output, loss.item() / input_line_tensor.size(0)
トレーニング中の時間を表示するには、以下の関数を定義します。
def time_taken(since):
now = time.time()
s = now - since
m = math.floor(s / 60)
s -= m * 60
return '%dm %ds' % (m, s)
次のステップでは、RNNモデルを定義します。
model = NameGenratorModule(n_let, 128, n_let)
定義されたRNNモデルのパラメータが表示されます。
print(model)
次のステップでは、モデルを10,000エポック学習させます。
epochs = 100000
print_every = 5000
plot_every = 500
all_losses = []
total_loss = 0 # 各反復でリセットする
start = time.time()
for iter in range(1, epochs + 1):
output, loss = train(*rand_train_exp())
total_loss += loss
if iter % print_every == 0:
print('Time: %s, Epoch: (%d - Total Iterations: %d%%), Loss: %.4f' % (time_taken(start), iter, iter / epochs * 100, loss))
if iter % plot_every == 0:
all_losses.append(total_loss / plot_every)
total_loss = 0
トレーニングのロスが可視化されます。
plt.figure(figsize=(7,7))
plt.title("Loss")
plt.plot(all_losses)
plt.xlabel("Epochs")
plt.ylabel("Loss")
plt.show()
最後に、アルファベットで始まる文字が与えられた言語に属する名前を生成するモデルをテストします。
max_length = 20
# カテゴリーと開始文字の例
def sample_model(category, start_letter='A'):
with torch.no_grad(): # no need to track history in sampling
category_tensor = categ_Tensor(category)
input = inp_Tensor(start_letter)
hidden = NameGenratorModule.initHidden()
output_name = start_letter
for i in range(max_length):
output, hidden = NameGenratorModule(category_tensor, input[0], hidden)
topv, topi = output.topk(1)
topi = topi[0][0]
if topi == n_let - 1:
break
else:
letter = all_let[topi]
output_name += letter
input = inp_Tensor(letter)
return output_name
# カテゴリーからの複数のサンプルと複数の開始文字
def sample_names(category, start_letters='XYZ'):
for start_letter in start_letters:
print(sample_model(category, start_letter))
サンプルモデルは、言語と開始文字を指定して名前を生成します。
print("Italian:-")
sample_names('Italian', 'BPRT')
print("
Korean:-")
sample_names('Korean', 'CMRS')
print("
Russian:-")
sample_names('Russian', 'AJLN')
print("
Vietnamese:-")
sample_names('Vietnamese', 'LMT')
このように、このモデルは、入力文字から始まる言語カテゴリに属する名前を生成しています。
パンチャンAIブログサイトへようこそ:
Panchuangのブログリソースラウンドアップへようこそ: