はじめに
頑張れば、何かがあるって、信じてる。nikkieです。
2019年12月末から自然言語処理のネタで毎週1本ブログを書いています。
初回はこちら:
今週のネタは「自然言語処理のタスクをするkeras(tensorflow
)製のモデルをpytorch
でも書いてみる」です。
前提:nikkieとkeras, そしてtorch
keras
入門+αレベル(一応読める・書ける)pytorch
読み書きできるようになりたい(未入門)
業務で使っているのはtensorflow
で、keras
で書かれたモデルであれば、ドキュメントに当たりながら読めるような感じです。
それに対してpytorch
はこれまで触ったことがありません。
直近ではPython2を見送る前にChainerを見送ることになったり、Kagglerの方々の中でこの本が流行っているらしいとTwitterで見かけたりして、ぼんやりと「pytorch
が流行っているんだなあ」という印象を持ち始めました。
また、この試みでは、今後BERTなど、まだ触ったことのないモデルも触ろうと思っているのですが、BERTはじめ新しいモデルはpytorch
の方が情報が多いという印象があります。
「keras
もpytorch
もどっちも読めたら便利そう」というやや安直な考えから、今後につながる一歩目として、keras
で書いたMLPをpytorch
で書き直してみます。
keras製、ニュースを分類するMLP
- データセット:ロイター通信のニューステキスト
tensorflow.keras.datasets.reuters
- ニュース1つは、単語をインデックス(整数)に変換して表したリスト(インデックスが若い単語ほど頻出する)
- トピックを表すクラスが全部で46ある。ニュースそれぞれはどれか1クラスに分類される(多クラス分類)
- モデル:2層のMLP(ドロップアウトしているだけ)
model = keras.Sequential(
[
layers.Dense(512, input_shape=(max_words,), activation=tf.nn.relu),
layers.Dropout(drop_out),
layers.Dense(number_of_classes, activation=tf.nn.softmax),
]
)
理解を深めるのを目的に、keras製モデル構築はQiitaにアウトプットしています:
それでは、pytorch
で書き直します(コードにならって、以下ではtorch
とします)。
動作環境
$ sw_vers ProductName: Mac OS X ProductVersion: 10.14.6 BuildVersion: 18G103 $ python -V # venvモジュールによる仮想環境を利用 Python 3.7.3 $ pip list # 主要なものを抜粋 ipython 7.11.0 matplotlib 3.1.2 numpy 1.18.0 pip 19.3.1 scipy 1.4.1 tensorflow 2.0.0 torch 1.3.1
kerasからtorchへ
以下の方針で書いてみました:
- ロイター通信のデータと全く同じデータは
torch
にはなさそうなので、データのロードはkeras
を使用 - 2層のMLPを作るところを
torch
で書き換え
以下の2点について見ていきます:
- データの準備
- モデル作成
データの準備(dataset)
torch
で実装するMLPに渡すデータの形式はText Classification with TorchText — PyTorch Tutorials 1.3.1 documentation を参考に準備しました。
In [2]: from torchtext.datasets import text_classification In [8]: train_dataset, test_dataset = text_classification.DATASETS['AG_NEWS']() # .dataというディレクトリがないと落ちるので注意 ag_news_csv.tar.gz: 11.8MB [00:01, 11.7MB/s] 120000lines [00:08, 14080.42lines/s] 120000lines [00:15, 7859.85lines/s] 7600lines [00:00, 8097.48lines/s] In [9]: len(train_dataset) Out[9]: 120000 In [10]: len(test_dataset) Out[10]: 7600 In [11]: type(train_dataset) Out[11]: torchtext.datasets.text_classification.TextClassificationDataset In [12]: train_dataset[0] Out[12]: (2, tensor([ 572, 564, 2, 2326, 49106, 150, 88, 3, 1143, 14, 32, 15, 32, 16, 443749, 4, 572, 499, 17, 10, 741769, 7, 468770, 4, 52, 7019, 1050, 442, 2, 14341, 673, 141447, 326092, 55044, 7887, 411, 9870, 628642, 43, 44, 144, 145, 299709, 443750, 51274, 703, 14312, 23, 1111134, 741770, 411508, 468771, 3779, 86384, 135944, 371666, 4052]))
チュートリアルで使っているAG_NEWS
のデータの1つ1つは、(クラス, tensor([単語のインデックス]))
という形式です。
このリストがdatasetとなっています。
チュートリアルは入力層にEmbeddingBag
レイヤーを使っています。
MLPでは入力の長さを揃える必要があると考え、keras.preprocessing.text.Tokenizer
のsequences_to_matrix
で長さを揃えて0/1で表したテキストをdatasetとすることにしました。
tensorの部分をどう作るか試してみたところ、AG_NEWS
のデータの一部をtorch.tensor
に渡したところ、要素が整数のままでtensor
を作ることができました1。
そこでkeras
のTokenizer
のsequences_to_matrix
の結果をtensor
に渡して、datasetの形式にします。
まとめると、ロイター通信のニューステキストデータをtorch
で扱えるように変換する関数はこちらです:
def convert_to_torch_tensors(texts, labels): torch_tensors = [] for text, label in zip(texts, labels): text_tensor = torch.tensor(text) torch_tensor = (label, text_tensor) torch_tensors.append(torch_tensor) return torch_tensors
モデル作成
torch
でのMLP実装で参考にしたのはこちらのブログ:
PyTorch まずMLPを使ってみる | cedro-blog
上記ブログのMLPNet
を参考にします:
keras.layers.Dense
と同等の層がtorch.nn.Linear
2- ドロップアウトは
torch.nn.Dropout
イニシャライザで層を定義した後は、forward
メソッドで層の重ね方を定義します。
class MLPNet(nn.Module): def __init__(self, max_words, number_of_classes, drop_out): super(MLPNet, self).__init__() self.fc1 = nn.Linear(max_words, 512) self.fc2 = nn.Linear(512, number_of_classes) self.dropout1 = nn.Dropout(drop_out) def forward(self, x): x = F.relu(self.fc1(x)) x = self.dropout1(x) return F.softmax(self.fc2(x), dim=1)
書き換えは学習部分に続くのですが、それは後半で扱います。
学習部分はkeras
とtorch
で全然違うのです!
後半をお楽しみに。
-
ドキュメントのExampleに「Type inference on data」とあるため、整数のままだったようです↩
-
Pytorch equivalent of Keras - PyTorch Forums などpytorchのForumに同様の質問が見つかりました↩