【ハグフェイスシリーズ学習】トランスフォーマーの使い方

序文

  • 実験では多くのモデルや操作に遭遇するためhuggingface-transformers、コースに沿って最初から整理する予定です
  • このシリーズは今後も更新していきます
  • フォローアップではfairseqフレームワークについても学ぶ必要があります

変圧器の使用

処理中に何が起こるかを確認するために完全な例から始めましょう

from transformers import pipeline

classifier = pipeline("sentiment-analysis")
classifier(
    [
        "I've been waiting for a HuggingFace course my whole life.",
        "I hate this so much!",
    ]
)

[{'ラベル': 'ポジティブ', 'スコア': 0.9598047137260437},
{'ラベル': 'ネガティブ', 'スコア': 0.9994558095932007}]

このパイプラインは、前処理、モデルへの入力、後処理の 3 つの部分で構成されます。

ここに画像の説明を挿入

トークナイザーによる前処理

transformer生のテキストを直接処理できない他のモデルと同様に、最初にtokenizerテキストをモデルが理解できる数値に変換します。Tokenizerいくつかのタスクがあります

  • 入力を単語、サブワード、記号などのトークンに分割します。
  • 各トークンを数値にマッピングする
  • モデルに役立つ可能性のある追加の入力を追加します

事前にトレーニングされたTokenizer、 through 、AutoTokenizer classおよびそのfrom_pretrained()メソッドを使用してロードします

from transformers import AutoTokenizer

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)

Tokenizerにテキストを入力できるようになりました。

raw_inputs = [
    "I've been waiting for a HuggingFace course my whole life.",
    "I hate this so much!",
]
inputs = tokenizer(raw_inputs, padding=True, truncation=True, return_tensors="pt")
print(inputs)

>>{
    
    
    'input_ids': tensor([
        [  101,  1045,  1005,  2310,  2042,  3403,  2005,  1037, 17662, 12172, 2607,  2026,  2878,  2166,  1012,   102],
        [  101,  1045,  5223,  2023,  2061,  2172,   999,   102,     0,     0,     0,     0,     0,     0,     0,     0]
    ]), 
    'attention_mask': tensor([
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
    ])
}

文または文のリストを入力し、同時に文tensorのタイプを指定できます。

Transformers モデルは入力としてテンソルのみを受け入れます

出力は、key次の 2 つの を含む辞書です。

  • input_ids
  • attention_mask

詳細なトークナイザー

上で述べたように、Tokenizerこの関数の機能は、元のテキストをモデルが理解できる形式 (数値) に変換することです。

pythonテキストをスペースに応じて単語に分割するの関数など、テキストを分割する方法は数多くあります.split()句読点を使用して区切ることもでき、このトークナイザーを使用して、最終的に大きな「辞書」を取得することもできます。語彙は、コーパス内にある独立したトークンの総数によって定義されます。各単語には ID (0 から始まる) が割り当てられ、モデルは ID を使用して単語を区別します。

さまざまな単語分割方法の詳細については、トークナイザー - ハグ顔コースを参照してください。

ロードと保存

from_oretrained()と の2 つの方法に基づいていますsave_pretrained()これらのメソッドは、トークナイザーによって使用されるアルゴリズム (モデル構造と同様) と使用される辞書 (モデルの重みと同様) を保存します。

負荷

from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") # 根据checkpoint名字自动找到对应的class

#还可以直接加载特定的 tokennizer
tokenizer = BertTokenizer.from_pretrained("bert-base-cased")

保存

tokenizer.save_pretrained("directory_on_my_computer")

エンコーディング

input_ids生成 (エンコード) がどのように行われるかを見てみましょう。エンコードは 2 つのステップに分かれています。

  • トークン化(テキストをトークンに分割)

    tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")
    sequence = "Using a Transformer network is simple"
    tokens = tokenizer.tokenize(sequence)
    
  • 入力 ID への変換: で.from_pretrained()トークナイザーをインスタンス化すると、辞書がダウンロードされます。辞書を通じてマッピングを行います

    ids = tokenizer.convert_tokens_to_ids(tokens)
    

デコード

Decoding が行うことは、ID (実際には語彙内のトークンのインデックス) を指定すると、その ID に対応するトークンを取得できることです。この時点で使用できるのは、

decoded_string = tokenizer.decode([7993, 170, 11303, 1200, 2443, 1110, 3014])
print(decoded_string)
  • decode() 関数は、インデックスをトークンに復元するだけでなく、同じ単語に属するトークンを結合して読みやすい文を生成します。

さまざまなモデルのトークナイザーをロードしてシーケンスを処理すると、モデルに必要なすべての入力 (入力 ID、アテンション マスクなど) を取得できます。

モデル

トランスフォーマーを作成する

BERT を例に挙げます。BERT をインスタンス化するには、まず構成オブジェクトをロードします。

from transformers import BertConfig, BertModel

# Building the config
config = BertConfig()

# Building the model from the config
model = BertModel(config)

さまざまな読み込み方法

上記はモデルのランダム初期化のロード方法を示しています。同様に、事前トレーニングされたモデルをロードできます。

from transformers import BertModel

model = BertModel.from_pretrained("bert-base-cased")

重みがダウンロードされてキャッシュ (デフォルトのパスは*~/.cache/huggingface/transformers*) に保存され、HF_HOMEキャッシュ フォルダーは環境変数を設定することでカスタマイズできます。

モデルの保存

model.save_pretrained("directory_on_my_computer")

これにより、2 つのファイルが保存されます。

  • config.json: モデル構造を構築するために必要な属性を含めます。また、いくつかのメタデータ (最後に保存および使用したトランスフォーマーのバージョンなど) も含めます。

  • pytorch_model.bin: すべてのモデルの重みが含まれます

  • これら 2 つのファイルは補完的であり、1 つはモデル アーキテクチャを知ることができ、もう 1 つはモデル パラメーターを提供できます。

モデルを使った推論

import torch
sequences = ["Hello!", "Cool.", "Nice!"]
encoded_sequences = [
    [101, 7592, 999, 102],
    [101, 4658, 1012, 102],
    [101, 3835, 999, 102],
]
model_inputs = torch.tensor(encoded_sequences)
output = model(model_inputs)
  • モデルはさまざまなパラメーターを受け入れることができますが、必要なのは input_ids のみです

テンソルは長方形データのみを受け入れます。各データの長さが異なる場合、テンソルに変換するときにエラーが報告されます

複数のシーケンスの処理

モデルは入力のバッチを期待します

まず、トークナイザーの動作を分解し、それを使用して何が起こっているのかを確認してみましょう。

import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)

sequence = "I've been waiting for a HuggingFace course my whole life."

tokens = tokenizer.tokenize(sequence)
ids = tokenizer.convert_tokens_to_ids(tokens)
input_ids = torch.tensor(ids)
# This line will fail.
model(input_ids)
  • モデルがデータを受け入れるとエラーが報告されます。Transformers モデルはデフォルトで複数行のデータを受け入れます、シーケンスを 1 つだけ入力しました。

  • 私たちはそれに注意すべきです入力 ID をテンソルに変換することに加えて、トークナイザーは実際に前に次元を追加します。

tokenized_inputs = tokenizer(sequence, return_tensors="pt")
print(tokenized_inputs["input_ids"])
>tensor([[  101,  1045,  1005,  2310,  2042,  3403,  2005,  1037, 17662, 12172,
          2607,  2026,  2878,  2166,  1012,   102]])
  • 上記の操作では、入力 ID をテンソルに変換するときに 1 つの次元を追加する必要があります。

    input_ids = torch.tensor([ids])
    print("Input IDs:", input_ids)
    
    output = model(input_ids)
    print("Logits:", output.logits)
    >Input IDs: [[ 1045,  1005,  2310,  2042,  3403,  2005,  1037, 17662, 12172,  2607, 2026,  2878,  2166,  1012]]
    >Logits: [[-2.7276,  2.8789]]
    

また、複数のデータを一度にモデルに入力することもできます。Batching

batched_ids = [ids, ids]
  • これは 2 つの同一のシーケンスを含むバッチです
  • logitsそれをテンソルに変換してモデルに入力すると、 2 つあることを除いて、前と同じものが得られます。

モデルに複数のデータを同時に入力する場合、それらをすべてテンソルに変換する必要がありますが、それらの長さが同じでない場合、テンソルに変換できません (テンソルは長方形のデータのみを受け入れます)。

入力のパディング

パディングは、[pad_token] をシーケンスの最後に埋めることで、すべてのシーケンスを同じ長さ (最長のものと同じ) にします。

model = AutoModelForSequenceClassification.from_pretrained(checkpoint)

sequence1_ids = [[200, 200, 200]]
sequence2_ids = [[200, 200]]
batched_ids = [
    [200, 200, 200],
    [200, 200, tokenizer.pad_token_id],
]

print(model(torch.tensor(sequence1_ids)).logits)
print(model(torch.tensor(sequence2_ids)).logits)
print(model(torch.tensor(batched_ids)).logits)
>tensor([[ 1.5694, -1.3895]], grad_fn=<AddmmBackward>)
>tensor([[ 0.5803, -0.4125]], grad_fn=<AddmmBackward>)
>tensor([[ 1.5694, -1.3895],
        [ 1.3373, -1.2163]], grad_fn=<AddmmBackward>)

出力に問題があり、2 つの [200,200] の結果が異なっていることがわかります。

  • 理由: Transformer のアテンション操作では、各トークンと Pad_token が確認されます。
  • Pad_token増加による影響を排除したい

トークナイザーは多くのパッド メソッドをサポートしています。Put it all together

アテンションマスク

attention_mask は input_ids と同じ形状をしており、0 と 1 で構成されます。

  • 0 は、この位置のトークンが考慮されないことを意味します (pad_token です)。
  • 1 は、この位置が Pad_token ではないことを意味します
batched_ids = [
    [200, 200, 200],
    [200, 200, tokenizer.pad_token_id],
]

attention_mask = [
    [1, 1, 1],
    [1, 1, 0],
]

outputs = model(torch.tensor(batched_ids), attention_mask=torch.tensor(attention_mask))
print(outputs.logits)
  • こうすることで同じロジットが得られます

より長いシーケンス

Transformer モデルには入力シーケンスの長さに制限があり、そのほとんどは最大 512 / 1024 トークンを処理でき、それ以上は機能しなくなります。解決:

  • より長いシーケンスをサポートするモデルを使用する

  • シーケンスを解凍する

    sequence = sequence[:max_sequence_length]
    

    トークナイザーは切り捨てられたデータもサポートします (後述)。

すべてをまとめて

Tokenizer でサポートされる一部の機能

  • いくつかの目的に従ってパディングします (トークナイザーはデフォルトではパディングを実行しません)

    # Will pad the sequences up to the maximum sequence length(输入中最长的seq)
    model_inputs = tokenizer(sequences, padding="longest")
    
    # Will pad the sequences up to the model max length(需要模型有指定的 max_length)
    # (512 for BERT or DistilBERT)
    model_inputs = tokenizer(sequences, padding="max_length")
    
    # Will pad the sequences up to the specified max length
    model_inputs = tokenizer(sequences, padding="max_length", max_length=8)
    
  • 切り捨てられたシーケンス

    sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"]
    
    # Will truncate the sequences that are longer than the model max length
    # (512 for BERT or DistilBERT)
    model_inputs = tokenizer(sequences, truncation=True)
    
    # Will truncate the sequences that are longer than the specified max length
    model_inputs = tokenizer(sequences, max_length=8, truncation=True)
    
  • 返されるテンソルのタイプを選択します

    sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"]
    
    # Returns PyTorch tensors
    model_inputs = tokenizer(sequences, padding=True, return_tensors="pt")
    
    # Returns TensorFlow tensors
    model_inputs = tokenizer(sequences, padding=True, return_tensors="tf")
    
    # Returns NumPy arrays
    model_inputs = tokenizer(sequences, padding=True, return_tensors="np")
    
  • 特別なトークン

    seq を input_ids に変換することに基づいて、トークナイザーは最初と最後にさらに 2 つのトークンを追加します (異なるトークナイザーは異なるトークンを追加する場合があります)。

    sequence = "I've been waiting for a HuggingFace course my whole life."
    
    model_inputs = tokenizer(sequence)
    print(model_inputs["input_ids"])
    
    tokens = tokenizer.tokenize(sequence)
    ids = tokenizer.convert_tokens_to_ids(tokens)
    print(ids)
    >[101, 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012, 102]
    >[1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012]
    

    デコードして見る

    print(tokenizer.decode(model_inputs["input_ids"]))
    print(tokenizer.decode(ids))
    >"[CLS] i've been waiting for a huggingface course my whole life. [SEP]"
    >"i've been waiting for a huggingface course my whole life."
    

これは、モデルが事前トレーニング中にこれらのトークンを使用し、同じ結果を得るためにこれらのトークンも追加したためです。もちろん、モデルが異なれば追加されるトークンも異なりますし、トークンが追加されない場合もあります

完全なプロセス

import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)
sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"]

tokens = tokenizer(sequences, padding=True, truncation=True, return_tensors="pt")
output = model(**tokens)

おすすめ

転載: blog.csdn.net/qq_52852138/article/details/128978420