モデル
このセクションでは、モデルの作成と使用について詳しく見ていきます。ここでは、チェックポイントから任意のモデルをインスタンス化する際に便利な AutoModel
クラスを使用します。
AutoModel
クラスとその関連クラスは、実際にはライブラリで利用可能な様々なモデルを覆うシンプルなラッパーです。このクラスは、チェックポイントに適したモデルのアーキテクチャを自動的に推測し、そのアーキテクチャを持つモデルをインスタンス化することができる賢いラッパーです。
しかし、使用したいモデルの種類がわかっている場合は、そのアーキテクチャを定義するクラスを直接使用することができます。BERTモデルでこれがどのように機能するかを見てみましょう。
トランスフォーマーモデルを作成する
BERTモデルを初期化するために最初にしなければならないことは、コンフィギュレーションオブジェクトをロードすることです。
from transformers import BertConfig, BertModel
# Building the config
config = BertConfig()
# Building the model from the config
model = BertModel(config)
コンフィギュレーションには、モデルを構築するために使用される多くの属性が含まれています。
print(config)
BertConfig {
[...]
"hidden_size": 768,
"intermediate_size": 3072,
"max_position_embeddings": 512,
"num_attention_heads": 12,
"num_hidden_layers": 12,
[...]
}
我々は、これらの属性のすべてが何をするかまだ見ていませんが、そのうちのいくつかを認識する必要があります: hidden_size
属性は hidden_states
ベクトルのサイズを定義し、num_hidden_layers
は Transformer モデルが持つレイヤーの数を定義します。
さまざまなローディング方法
デフォルトのコンフィギュレーション(設定)からモデルを作成すると、ランダムな値で初期化されます。
from transformers import BertConfig, BertModel
config = BertConfig()
model = BertModel(config)
# Model is randomly initialized!
この状態でもモデルは使えますが、意味不明な出力になってしまうので、まず学習させる必要があります。手元のタスクに対して一からモデルを学習させることもできますが、第1章で見たように、長い時間と多くのデータを必要とし、環境負荷も無視できないものになるでしょう。無駄な努力や重複を避けるためには、既に学習済みのモデルを共有・再利用できることが必須です。
既に学習済みのTransformerモデルをロードするのは簡単です。from_pretrained()
メソッドを使ってこれを行うことができます。
from transformers import BertModel
model = BertModel.from_pretrained("bert-base-cased")
先ほど見たように、 BertModel
を同等のクラスである AutoModel
に置き換えることができます。チェックポイントに依存しないコードを生成するため、今後はこの方法をとります。あるチェックポイントで動作するコードは、別のチェックポイントでもシームレスに動作するはずです。これはアーキテクチャが異なっていても、チェックポイントが同様のタスク (例えばセンチメント分析タスク) に対して学習されたものである限り、当てはまります。
上記のコードサンプルでは BertConfig
を使用せず、代わりに bert-base-cased
を介して事前に学習されたモデルをロードしています。これはBERTの作者自身によって学習されたモデルのチェックポイントです。これについての詳細はそのモデルカードに記載されています。
このモデルは現在、チェックポイントのすべての重みで初期化されています。これは訓練されたタスクの推論に直接使用することができ、また、新しいタスクでファインチューニングすることができます。ゼロからではなく、事前に学習させた重みを用いて学習させることで、迅速に良い結果を得ることができます。
重みはダウンロードされ、キャッシュフォルダ(デフォルトは ~/.cache/huggingface/transformers )に保存されます(将来 from_pretrained()
メソッドを呼び出したときに再ダウンロードされないようにするため)。環境変数 HF_HOME
を設定することで、キャッシュフォルダをカスタマイズすることができます。
モデルをロードするために使用される識別子は、BERTアーキテクチャと互換性がある限り、モデルハブ上の任意のモデルの識別子を使用することができます。利用可能なBERTチェックポイントの全リストは、ここで確認できます。
保存方法
モデルの保存はロードするのと同じくらい簡単で、from_pretrained()
メソッドに類似した save_pretrained()
メソッドを使用します。
model.save_pretrained("directory_on_my_computer")
これにより、2つのファイルがディスクに保存されます。
ls directory_on_my_computer
config.json pytorch_model.bin
config.json ファイルを見てみると、モデルアーキテクチャを構築するために必要な属性がわかると思います。このファイルには、チェックポイントがどこで発生したのか、最後にチェックポイントを保存したときに使用していた🤗 Transformersのバージョンなどのメタデータも含まれています。
pytorch_model.bin ファイルは state dictionary として知られており、モデルのすべての重みが含まれています。この2つのファイルは密接に関係しています。コンフィギュレーションはモデルのアーキテクチャを知るために必要であり、モデルの重みはモデルのパラメータです。
推論のためのトランスフォーマーモデルの使用
さて、モデルをロードして保存する方法がわかったので、それを使って予測をしてみましょう。トランスフォーマーモデルは数値、つまりトークナイザが生成する数値だけを処理することができます。しかし、トークナイザについて説明する前に、モデルがどのような入力を受け入れるかを探ってみましょう。
トークナイザは入力を適切なフレームワークのテンソルにキャストすることを引き受けてくれますが、何が起こっているかを理解するために、入力をモデルに送る前に行わなければならないことを簡単に見てみましょう。
例えば、いくつかの文があるとします。
sequences = ["Hello!", "Cool.", "Nice!"]
トークナイザはこれらを一般に入力IDと呼ばれる語彙のインデックスに変換します。各文は今は数字の羅列です。その結果、出力は次のようになります。
encoded_sequences = [
[101, 7592, 999, 102],
[101, 4658, 1012, 102],
[101, 3835, 999, 102],
]
これはエンコードされた文のリストであり、リストのリストです。テンソルは長方形の形しか受け付けません(行列を考えてみましょう)。この「配列」はすでに矩形であるので、テンソルに変換するのは簡単です。
import torch
model_inputs = torch.tensor(encoded_sequences)
モデルの入力としてのテンソルの使用
モデルでテンソルを使うのは非常に簡単で、モデルの呼び出し時に入力として渡すだけです。
output = model(model_inputs)
このモデルは多くの異なる引数を受け付けますが、必要なのは入力IDだけです。他の引数が何をするのか、いつ必要なのかは後で説明します。 しかし、まずはTransformerモデルが理解できる入力を構築するトークナイザを詳しく見る必要があります。