TorchTextの使用例と完全なコード
TorchText
最近PyTorchを用いたNLPニューラルネットワークモデルの構築が開始され,torchtextというテキスト処理神器が発見され,テキストの前処理が容易になり,例えば,切り捨て補長,ワードテーブルの構築などが可能となった.しかしnlpの熱はcvに及ばないため、torchtextが紹介した関連ブログの数もtorchvisionに及ばない.使用中に主にA Comprehensive Introduction to TorchtextとLanguage modeling tutorial in torchtextの2つのブログとtorchtextの公式ドキュメントを参考にして、torchtextの基本的な使い方について大まかに理解しました.私のもう一つのブログ:PyTorchはNLPタスクで予備訓練語ベクトルを使用する上でtorchtextの使い方にも少し関与しています.以上の2つのブログの基礎の上で、本文はtorchtextの使用に対して1つの概括的な総括をして、更に複雑で高級な用法は依然としてみんなに公式のドキュメントを読むことを推薦します.本明細書で説明する完全な実行可能コードは、次のとおりです.https://github.com/atnlp/torchtext-summary
torchtextの概要
torchtextによるデータの処理は,Field,Dataset,反復器の3つの部分に要約できる.
Fieldオブジェクト
Fieldオブジェクトは、フィールドをどのように処理するかを指定します.
Dataset
データセットは、データソース情報を定義する.
反復器
反復器は、モデルに必要な処理後のデータを返す.反復器は主にIterator,BucketIerator,BPTTIteratorの3種類に分けられる.
データセットクラスの使用
実験データセットはA Comprehensive Introduction to Torchtextで使用されている小ロットデータセットを依然として使用しており,コードを簡略化するためにtoxicというラベル列のみが保持されている.
from torchtext import data
from torchtext.vocab import Vectors
from torch.nn import init
from tqdm import tqdm
tokenize = lambda x: x.split()
# fix_length ,
TEXT = data.Field(sequential=True, tokenize=tokenize, lower=True, fix_length=200)
LABEL = data.Field(sequential=False, use_vocab=False)
torchtextプリセットのDatasetクラスのAPIは、少なくともexamplesとfieldsの2つのパラメータを入力する必要があります.examplesはtorchtextのExampleオブジェクトのリストであり、Exampleはデータセットの1つのデータの抽象である.Fieldsは、各列のデータとFieldオブジェクトのバインド関係として簡単に理解でき、以下のコードではtrain_牙列缺损examplesトレーニングセットとテストセットのexamplesオブジェクトを構築するために、train_fieldsとtest_fieldsデータセットのfieldsオブジェクト.
class torchtext.data.Dataset(examples, fields, filter_pred=None)
#
train_data = pd.read_csv('data/train_one_label.csv')
valid_data = pd.read_csv('data/valid_one_label.csv')
test_data = pd.read_csv("data/test.csv")
TEXT = data.Field(sequential=True, tokenize=tokenize, lower=True)
LABEL = data.Field(sequential=False, use_vocab=False)
# get_dataset Dataset examples fields
def get_dataset(csv_data, text_field, label_field, test=False):
# id , None field
fields = [("id", None), # we won't be needing the id, so we pass in None as the field
("comment_text", text_field), ("toxic", label_field)]
examples = []
if test:
# , label
for text in tqdm(csv_data['comment_text']):
examples.append(data.Example.fromlist([None, text, None], fields))
else:
for text, label in tqdm(zip(csv_data['comment_text'], csv_data['toxic'])):
examples.append(data.Example.fromlist([None, text, label], fields))
return examples, fields
# Dataset examples fields
train_examples, train_fields = get_dataset(train_data, TEXT, LABEL)
valid_examples, valid_fields = get_dataset(valid_data, TEXT, LABEL)
test_examples, test_fields = get_dataset(test_data, TEXT, None, test=True)
# Dataset
train = data.Dataset(train_examples, train_fields)
valid = data.Dataset(valid_examples, valid_fields)
test = data.Dataset(test_examples, test_fields)
data.Exampleは単一のサンプルを返し、fromCSVやfromJSONなどの複数の方法を提供し、データセットに必要な標準データを様々な形式で構築することができます.また,idのようなモデルトレーニングに不要な特徴については,Datasetの構築中にNoneを直接用いることができる.特に、testのlabelについては、マシン学習試合では最終的なテストセットのラベルが分からないため、ここではfieldsとexamplesを構築する際に相応にNoneに設定しており、自分で区切ったテストセットであれば、このときテストセットにも対応するラベルlabelがあり、対応コードを修正し、対応するField項でNoneを置き換える必要がある.
カスタムデータセットクラス
簡単なデータセットを構築する場合、torchを直接使用することができる.text.Datasetは、元のデータセットに対して単純な分割処理のみを行う場合、例えば、データの読み出しやトレーニングセット検証セットの分割などの操作を行う場合にも、csv、tsvなどのフォーマットの読み取りをサポートするTabularDatasetクラスやsplitクラスメソッドを直接使用して実現することができる.しかし、shuffle、dropoutなどのデータ強化操作など、データのより多くの前処理が必要な場合、カスタムデータsetはより柔軟になります.
from torchtext import data
from torchtext.vocab import Vectors
from tqdm import tqdm
import pandas as pd
import numpy as np
import torch
import random
import os
train_path = 'data/train_one_label.csv'
valid_path = "data/valid_one_label.csv"
test_path = "data/test.csv"
# Dataset
class MyDataset(data.Dataset):
def __init__(self, path, text_field, label_field, test=False, aug=False, **kwargs):
fields = [("id", None), # we won't be needing the id, so we pass in None as the field
("comment_text", text_field), ("toxic", label_field)]
examples = []
csv_data = pd.read_csv(path)
print('read data from {}'.format(path))
if test:
# , label
for text in tqdm(csv_data['comment_text']):
examples.append(data.Example.fromlist([None, text, None], fields))
else:
for text, label in tqdm(zip(csv_data['comment_text'], csv_data['toxic'])):
if aug:
# do augmentation
rate = random.random()
if rate > 0.5:
text = self.dropout(text)
else:
text = self.shuffle(text)
# Example: Defines a single training or test example.Stores each column of the example as an attribute.
examples.append(data.Example.fromlist([None, text, label - 1], fields))
# , super , Dataset 。
super(MyDataset, self).__init__(examples, fields, **kwargs)
def shuffle(self, text):
text = np.random.permutation(text.strip().split())
return ' '.join(text)
def dropout(self, text, p=0.5):
# random delete some text
text = text.strip().split()
len_ = len(text)
indexs = np.random.choice(len_, int(len_ * p))
for i in indexs:
text[i] = ''
return ' '.join(text)
torchtextを継承するMyDatasetクラスを定義しました.data.Datasetクラスは、initメソッド内でデータとfieldsパラメータのバインドを実現します.クラス内部でもshuffleとdropoutの2つのデータ前処理方法が実現された.最後にsuperを使用して親クラスを初期化し、torchtextの標準データセットを実現する.
MyDatasetオブジェクトの構築testデータセットにラベルlabelがないため、label_を作成する必要があります.fieldはNoneでtrainに関する情報を表示できます
反復の作成
ニューラルネットワークを訓練する際にはbatchのデータを操作するのでtorchtext内部の反復器を用いてデータを処理する必要がある.
from torchtext.data import Iterator, BucketIterator
#
# train_iter = data.BucketIterator(dataset=train, batch_size=8, shuffle=True, sort_within_batch=False, repeat=False)
#
train_iter, val_iter = BucketIterator.splits(
(train, valid), #
batch_sizes=(8, 8),
device=-1, # gpu, -1 GPU
sort_key=lambda x: len(x.comment_text), # the BucketIterator needs to be told what function it should use to group the data.
sort_within_batch=False,
repeat=False # we pass repeat=False because we want to wrap this Iterator layer.
)
test_iter = Iterator(test, batch_size=8, device=-1, sort=False, sort_within_batch=False, repeat=False)
BucketIteratorは、Iteratorと比較して、サンプルの長さが似ているデータを自動的に選択してバッチ・データを構築する利点があります.しかし、テストセットでは通常、サンプルの順序を変更したくないため、テストセットはIterator反復器を使用して構築されます. sort_within_batchパラメータがTrueに設定されている場合はsort_keyは、各小ロット内のデータを降順に並べ替えます.paddedシーケンスでpackを使用する必要がある場合はpadded_sequenceがPackedSequenceオブジェクトに変換される場合、これは非常に重要です.pack_padded_sequenceメソッドでは、バッチサンプルを降順に並べ替える必要があります.このことから,torchtextはテキストデータを四角化するだけでなく,torchtextの多くの組み込み方法と組み合わせて容易に使用できることが分かる.
実験的に選択したトレーニングセットには25のサンプルがあり,次にpythonに組み込まれたiterを用いて構築された反復器情報を表示することができる.出力結果から分かるように、反復器は、各ロットのデータに対して、サンプル長を統一的な長さに構築し、第1ロットのデータに対するcomment_textフィーチャーは,反復器が[200*8]の次元に統一的に構築された.TEXTを構築する際にfix_を通過するのでlength=200はシーケンスの長さを指定します.
バッチデータの使用
反復器を使用してバッチデータを構築した後、pythonのforループを直接使用して遍歴し、出力結果を観察することができ、25個のデータを共有するトレーニングセットに対してtorchtextの反復器はトレーニングセットを4ロットのデータに構築した.これに基づいて、モデルにデータを転送することができます.
用語集の作成
用語表の構築とは,各単語を符号化する必要があり,すなわち各単語を数字で表す必要があり,モデルに伝達できる.
最も簡単な方法、bulid_vocab()メソッドには、用語集を構築するためのデータセットが入力されます。
TEXT.build_vocab(train)
事前に訓練された語ベクトルを使用する
pytorchやtensorflowなどのニューラルネットワークフレームワークを用いてnlpタスクの処理を行う場合は,対応するEmbedding層を用いてワードベクトルの処理を行うことができ,より多くの場合,予め訓練されたワードベクトルを用いることでより優れた性能をもたらすが,torchtextで予め訓練されたワードベクトルを用い,さらにニューラルネットワークモデルに伝達して訓練する方法を紹介する.
方法1:torchtextデフォルトでサポートされているプリトレーニングワードベクトルを使用する
デフォルトでは、対応するプリトレーニングワードベクトルファイルが現在のフォルダに自動的にダウンロードされます.vector_Cacheディレクトリの下で、.vector_Cacheは、デフォルトのワードベクトルファイルとキャッシュファイルのディレクトリです.
from torchtext.vocab import GloVe
from torchtext import data
TEXT = data.Field(sequential=True)
#
# TEXT.build_vocab(train, vectors="glove.6B.200d")
TEXT.build_vocab(train, vectors=GloVe(name='6B', dim=300))
# , glove.6B.zip , glove.6B.50d.txt, glove.6B.100d.txt, glove.6B.200d.txt, glove.6B.300d.txt , glove.6B.zip glove.6B.200d.txt .vector_cache ( , )。
方式2:外部予習した語ベクトルを使う
上記の予備訓練語ベクトルファイルの使用方法には、nlpタスクを行うたびに、語表を作成する際に対応する必要があるという大きな問題がある.vector_Cacheフォルダにプリトレーニングワードベクトルファイルをダウンロードし、この問題をどのように解決しますか?torchtextを使用できます.vocab.Vectorsのnameパラメータとcachaeパラメータは、事前に訓練されたワードベクトルファイルとキャッシュファイルのディレクトリを指定します.したがって,word 2 vecなどのツールで訓練したワードベクトルファイルを用いて,ネームで指定したディレクトリにワードベクトルファイルを置くだけでよい.
デフォルトでは、プリトレーニングワードベクトルファイルとキャッシュファイルのディレクトリの位置は、いずれも現在のディレクトリの下にある.vector_Cacheディレクトリは、nameパラメータでプリトレーニングワードベクトルファイルが存在するディレクトリを指定するが、キャッシュファイルのディレクトリは特に指定されていないため、現在のディレクトリの下に存在する必要がある.vector_Cacheディレクトリ.
# glove.6B.200d.txt
if not os.path.exists(.vector_cache):
os.mkdir(.vector_cache)
vectors = Vectors(name='myvector/glove/glove.6B.200d.txt')
TEXT.build_vocab(train, vectors=vectors)
# , name , .vector_cache
cache = '.vector_cache'
if not os.path.exists(cache):
os.mkdir(cache)
vectors = Vectors(name='myvector/glove/glove.6B.200d.txt', cache=cache)
TEXT.build_vocab(train, vectors=vectors)
モデルでEmbeddingレイヤのウェイト値を指定するには
事前に訓練された語ベクトルを用いる場合,埋め込み行列の初期重みをニューラルネットワークモデルのEmbedding層で明確に伝達する必要がある.ウェイトは語彙のvectorsプロパティに含まれます.Pytorchによって構築されたEmbeddingレイヤを例に挙げます.
# pytorch Embedding
embedding = nn.Embedding(2000, 256)
#
weight_matrix = TEXT.vocab.vectors
embedding.weight.data.copy_(weight_matrix )
# requires_grad=True
# embeddings.weight = nn.Parameter(embeddings, requires_grad=True)
torchtextを使用して構築されたデータセットはLSTM用である
データセットが小さすぎて収束できないため、demoとしてtorchtextとpytorchの間の使い方を熟知しているだけです.
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
weight_matrix = TEXT.vocab.vectors
class LSTM(nn.Module):
def __init__(self):
super(LSTM, self).__init__()
self.word_embeddings = nn.Embedding(len(TEXT.vocab), 300) # embedding shape: torch.Size([200, 8, 300])
# ,
# embedding.weight.data.copy_(weight_matrix)
self.lstm = nn.LSTM(input_size=300, hidden_size=128, num_layers=1) # torch.Size([200, 8, 128])
self.decoder = nn.Linear(128, 2)
def forward(self, sentence):
embeds = self.word_embeddings(sentence)
lstm_out = self.lstm(embeds)[0] # lstm_out:200x8x128
#
final = lstm_out[-1] # 8*128
y = self.decoder(final) # 8*2
return y
def main():
model = LSTM()
model.train()
optimizer = optim.Adam(filter(lambda p: p.requires_grad, model.parameters()), lr=0.01)
loss_funtion = F.cross_entropy
for epoch, batch in enumerate(train_iter):
optimizer.zero_grad()
start = time.time()
# text = batch.text.permute(1, 0)
predicted = model(batch.comment_text)
loss = loss_funtion(predicted, batch.toxic)
loss.backward()
optimizer.step()
print(loss)
if __name__ == '__main__':
main()
説明
torchtextを使用するほか、kerasにおけるpreprocessingパッケージにおける関連方法を用いてデータの前処理を行い、torchを使用することもできる.utils.data.TensorDatasetはデータセットを構築し、torchを使用する.utils.data.DataLoaderは反復器を構築します.このコードの一部は後日更新されます.
コードの例
本明細書に関連するコンテンツの完全なコード
torchtextを使用してデータセットを内蔵する例
import torch
from torchtext import data
from torchtext import datasets
from torchtext.vocab import GloVe
import numpy as np
def load_data(opt):
# use torchtext to load data, no need to download dataset
print("loading {} dataset".format(opt.dataset))
# set up fields
text = data.Field(lower=True, include_lengths=True, batch_first=True, fix_length=opt.max_seq_len)
label = data.Field(sequential=False)
# make splits for data
train, test = datasets.IMDB.splits(text, label)
# build the vocabulary
text.build_vocab(train, vectors=GloVe(name='6B', dim=300))
label.build_vocab(train)
# print vocab information
print('len(TEXT.vocab)', len(text.vocab))
print('TEXT.vocab.vectors.size()', text.vocab.vectors.size()
昨年、個人ブログで書いたブログのオリジナル記事を転載し、許可を得ずに転載してはならない.