「TransformersとTokenizersを使用して、ゼロから新しい言語モデルを訓練する方法」

Training a new language model from scratch using Transformers and Tokenizers

ここ数か月間で、私たちはtransformerstokenizersライブラリにいくつかの改良を加え、新しい言語モデルをゼロからトレーニングすることをこれまで以上に簡単にすることを目指しました。

この記事では、”小さな”モデル(84 Mパラメータ = 6層、768隠れユニット、12アテンションヘッド)を「エスペラント」でトレーニングする方法をデモンストレーションします。その後、モデルを品詞タグ付けの下流タスクでファインチューニングします。

エスペラントは学習しやすいことを目標とした人工言語です。このデモンストレーションのために選んだ理由は以下のとおりです:

  • 比較的リソースが少ない言語です(約200万人が話すにもかかわらず)、このデモンストレーションはもう1つの英語モデルのトレーニングよりも面白くなります 😁
  • 文法が非常に規則的です(例:一般的な名詞は-oで終わり、すべての形容詞は-aで終わります)。そのため、小さなデータセットでも興味深い言語的結果が得られるはずです。
  • 最後に、この言語の基盤となる目標は人々をより近づけることです(世界平和と国際理解を促進すること)。これはNLPコミュニティの目標と一致していると言えるでしょう 💚

注:この記事を理解するためにはエスペラントを理解する必要はありませんが、学びたい場合はDuolingoには280,000人のアクティブな学習者がいる素敵なコースがあります。

私たちのモデルの名前は…待ってください…EsperBERTo 😂

1. データセットを見つける

まず、エスペラントのテキストコーパスを見つけましょう。ここでは、INRIAのOSCARコーパスのエスペラント部分を使用します。OSCARは、WebのCommon Crawlダンプの言語分類とフィルタリングによって得られた巨大な多言語コーパスです。

データセットのエスペラント部分はわずか299Mですので、Leipzig Corpora Collectionのエスペラントサブコーパスと連結します。このサブコーパスには、ニュース、文学、ウィキペディアなど様々なソースのテキストが含まれています。

最終的なトレーニングコーパスのサイズは3 GBですが、モデルに先行学習するためのデータが多ければ多いほど、より良い結果が得られます。

2. トークナイザーをトレーニングする

GPT-2と同じ特殊トークンを持つバイトレベルのバイトペアエンコーディングトークナイザーをトレーニングすることにしましょう。そのサイズは任意に52,000とします。

私たちは、バイトレベルのBPE(BERTのWordPieceトークナイザーの代わりに)をトレーニングすることをお勧めします。なぜなら、バイト単位のアルファベットから語彙を構築し始めるため、すべての単語はトークンに分解できるからです(<unk>トークンが必要ありません!)。

#! pip install tokenizers

from pathlib import Path

from tokenizers import ByteLevelBPETokenizer

paths = [str(x) for x in Path("./eo_data/").glob("**/*.txt")]

# トークナイザーを初期化
tokenizer = ByteLevelBPETokenizer()

# トレーニングをカスタマイズ
tokenizer.train(files=paths, vocab_size=52_000, min_frequency=2, special_tokens=[
    "<s>",
    "<pad>",
    "</s>",
    "<unk>",
    "<mask>",
])

# ファイルをディスクに保存
tokenizer.save_model(".", "esperberto")

そして、出力のわずかに加速されたキャプチャは次のようになります:

私たちのデータセットでは、トレーニングに約5分かかりました。

🔥🔥 うわー、それは速い! ⚡️🔥

これで、最も頻度の高いトークンのリストであるvocab.jsonと、マージのリストであるmerges.txtを持っています。

{
    "<s>": 0,
    "<pad>": 1,
    "</s>": 2,
    "<unk>": 3,
    "<mask>": 4,
    "!": 5,
    "\"": 6,
    "#": 7,
    "$": 8,
    "%": 9,
    "&": 10,
    "'": 11,
    "(": 12,
    ")": 13,
    # ...
}

# merges.txt
l a
Ġ k
o n
Ġ la
t a
Ġ e
Ġ d
Ġ p
# ...

素晴らしいことは、私たちのトークナイザーはエスペラントに最適化されていることです。一般的な英語のトークナイザーと比較して、より多くのネイティブワードが1つの分割されていないトークンで表されます。エスペラントで使用されるアクセント記号(ĉĝĥĵŝŭ)もネイティブにエンコードされます。また、シーケンスもより効率的な方法で表現されます。このコーパスでは、事前学習済みのGPT-2トークナイザーを使用する場合と比較して、エンコードされたシーケンスの平均長は約30%短くなります。

以下は、tokenizersを使用してそれをどのように利用できるかを示したものです。もちろん、transformersから直接使用することもできます。

from tokenizers.implementations import ByteLevelBPETokenizer
from tokenizers.processors import BertProcessing


tokenizer = ByteLevelBPETokenizer(
    "./models/EsperBERTo-small/vocab.json",
    "./models/EsperBERTo-small/merges.txt",
)
tokenizer._tokenizer.post_processor = BertProcessing(
    ("</s>", tokenizer.token_to_id("</s>")),
    ("<s>", tokenizer.token_to_id("<s>")),
)
tokenizer.enable_truncation(max_length=512)

print(
    tokenizer.encode("Mi estas Julien.")
)
# Encoding(num_tokens=7, ...)
# tokens: ['<s>', 'Mi', 'Ġestas', 'ĠJuli', 'en', '.', '</s>']

3. ゼロから言語モデルをトレーニングする

更新: 関連するColabノートブックは、スクリプト経由ではなく、直接新しいTrainerを使用します。お好みのアプローチを選んでください。

次に、transformersrun_language_modeling.pyスクリプトを使用して、言語モデルをトレーニングします(run_lm_finetuning.pyから改名され、ゼロからのトレーニングをよりシームレスにサポートするようになりました)。ただし、既存のモデルやチェックポイントからトレーニングする場合は、--model_name_or_pathNoneのままにしておく必要があります。

私たちは、変更がいくつか加えられたBERTのようなモデルであるRoBERTaのようなモデルをトレーニングします(詳細についてはドキュメントを参照してください)。

モデルがBERTのようなモデルであるため、データセット内のランダムにマスクされた任意のトークンを埋める方法を予測するマスク言語モデリングのタスクでトレーニングします。この例のスクリプトによって処理されます。

以下の2つのことを行う必要があります:

  • データをロードするDatasetのシンプルなサブクラスを実装する
    • 使用用途によっては、提供されている例(TextDatasetLineByLineTextDataset)のいずれかを使用するだけで、独自のDatasetのサブクラスを書く必要はないかもしれませんが、コーパスの特性に基づいてカスタマイズを行いたい場合もあります。
  • 異なるハイパーパラメータのセットを選択して実験する。

以下は、私たちのEsperantoDatasetのシンプルなバージョンです。

from torch.utils.data import Dataset

class EsperantoDataset(Dataset):
    def __init__(self, evaluate: bool = False):
        tokenizer = ByteLevelBPETokenizer(
            "./models/EsperBERTo-small/vocab.json",
            "./models/EsperBERTo-small/merges.txt",
        )
        tokenizer._tokenizer.post_processor = BertProcessing(
            ("</s>", tokenizer.token_to_id("</s>")),
            ("<s>", tokenizer.token_to_id("<s>")),
        )
        tokenizer.enable_truncation(max_length=512)
        # or use the RobertaTokenizer from `transformers` directly.

        self.examples = []

        src_files = Path("./data/").glob("*-eval.txt") if evaluate else Path("./data/").glob("*-train.txt")
        for src_file in src_files:
            print("🔥", src_file)
            lines = src_file.read_text(encoding="utf-8").splitlines()
            self.examples += [x.ids for x in tokenizer.encode_batch(lines)]

    def __len__(self):
        return len(self.examples)

    def __getitem__(self, i):
        # We’ll pad at the batch level.
        return torch.tensor(self.examples[i])

データセットが非常に大きい場合、前処理のステップではなく、必要に応じて例を動的に読み込んでトークン化することができます。

以下はスクリプトに渡すハイパーパラメータと引数の一つの具体的なセットです:

    --output_dir ./models/EsperBERTo-small-v1
    --model_type roberta
    --mlm
    --config_name ./models/EsperBERTo-small
    --tokenizer_name ./models/EsperBERTo-small
    --do_train
    --do_eval
    --learning_rate 1e-4
    --num_train_epochs 5
    --save_total_limit 2
    --save_steps 2000
    --per_gpu_train_batch_size 16
    --evaluate_during_training
    --seed 42

通常のように、GPUに収まる最大のバッチサイズを選択してください。

🔥🔥🔥 トレーニングを開始しましょう!! 🔥🔥🔥

ここでは、特定のハイパーパラメータのテンソルボードをチェックできます:

デフォルトでは、例のスクリプトはTensorboard形式でログインします。runs/に保存されます。その後、ボードを表示するには、tensorboard dev upload --logdir runsを実行します。これにより、tensorboard.devがセットアップされ、誰とでもML実験を共有できるようになります。

4. 言語モデルが実際にトレーニングされたかどうかの確認

トレーニングと評価の損失が減少しているかどうかを確認する以外に、言語モデルが興味深いものを学習しているかどうかを確認する最も簡単な方法は、FillMaskPipelineを使用することです。

パイプラインは、トークナイザーとモデルを簡単にラップしたもので、’fill-mask’の場合、マスクされたトークン(ここでは<mask>)を含むシーケンスを入力し、最も確率の高い埋め込まれたシーケンスのリストとその確率を返します。

from transformers import pipeline

fill_mask = pipeline(
    "fill-mask",
    model="./models/EsperBERTo-small",
    tokenizer="./models/EsperBERTo-small"
)

# The sun <mask>.
# =>

result = fill_mask("La suno <mask>.")

# {'score': 0.2526160776615143, 'sequence': '<s> La suno brilis.</s>', 'token': 10820}
# {'score': 0.0999930202960968, 'sequence': '<s> La suno lumis.</s>', 'token': 23833}
# {'score': 0.04382849484682083, 'sequence': '<s> La suno brilas.</s>', 'token': 15006}
# {'score': 0.026011141017079353, 'sequence': '<s> La suno falas.</s>', 'token': 7392}
# {'score': 0.016859788447618484, 'sequence': '<s> La suno pasis.</s>', 'token': 4552}

OK、シンプルな構文/文法が機能しています。少し興味深いプロンプトを試してみましょう:

fill_mask("Jen la komenco de bela <mask>.")

# This is the beginning of a beautiful <mask>.
# =>

# {
#     'score':0.06502299010753632
#     'sequence':'<s> Jen la komenco de bela vivo.</s>'
#     'token':1099
# }
# {
#     'score':0.0421181358397007
#     'sequence':'<s> Jen la komenco de bela vespero.</s>'
#     'token':5100
# }
# {
#     'score':0.024884626269340515
#     'sequence':'<s> Jen la komenco de bela laboro.</s>'
#     'token':1570
# }
# {
#     'score':0.02324388362467289
#     'sequence':'<s> Jen la komenco de bela tago.</s>'
#     'token':1688
# }
# {
#     'score':0.020378097891807556
#     'sequence':'<s> Jen la komenco de bela festo.</s>'
#     'token':4580
# }

美しい日の始まり」、実に!

より複雑なプロンプトでは、言語モデルがより多くの意味知識や、(統計的な)常識的な推論を捉えているかどうかを探ることができます。

5. 下流のタスクで言語モデルを微調整する

今、新しいエスペラント語の言語モデルを、品詞タグ付けの下流タスクで微調整することができます。

前述した通り、エスペラント語は単語の語尾が一般的に文法的な品詞を制約する高度に規則的な言語です。CoNLL-2003形式でフォーマットされた注釈付きエスペラント語POSタグのデータセットを使用して、transformersrun_ner.pyスクリプトを使用することができます。

POSタグ付けはNERと同じくトークン分類のタスクであるため、まったく同じスクリプトを使用することができます。

再度、こちらがこの微調整のためのホストされたTensorboardです。GPUごとにバッチサイズ64で3エポックトレーニングします。

トレーニングと評価の損失は収束し、タスクが非常に簡単であるため(言語が規則的であるため)、残余値は非常に小さくなります-それでもエンドツーエンドでトレーニングできるのは楽しいです😃。

今回はTokenClassificationPipelineを使用しましょう:

from transformers import TokenClassificationPipeline, pipeline


MODEL_PATH = "./models/EsperBERTo-small-pos/"

nlp = pipeline(
    "ner",
    model=MODEL_PATH,
    tokenizer=MODEL_PATH,
)
# またはTokenClassificationPipelineを直接インスタンス化する。

nlp("Mi estas viro kej estas tago varma.")

# {'entity': 'PRON', 'score': 0.9979867339134216, 'word': ' Mi'}
# {'entity': 'VERB', 'score': 0.9683094620704651, 'word': ' estas'}
# {'entity': 'VERB', 'score': 0.9797462821006775, 'word': ' estas'}
# {'entity': 'NOUN', 'score': 0.8509314060211182, 'word': ' tago'}
# {'entity': 'ADJ', 'score': 0.9996201395988464, 'word': ' varma'}

うまくいったようです!🔥

NERのより難しいデータセットについては、@stefan-itさんから、WikiANNのシルバースタンダードデータセットでトレーニングすることをおすすめします。

6. モデルを共有する 🎉

最後に、素晴らしいモデルを持っている場合は、ぜひコミュニティと共有することを考えてください:

  • CLIを使用してモデルをアップロードする:transformers-cli upload
  • README.mdのモデルカードを作成し、model_cards/以下のリポジトリに追加します。モデルカードには、理想的には以下を含めるべきです:
    • モデルの説明
    • トレーニングパラメータ (データセット、前処理、ハイパーパラメータ)
    • 評価結果
    • 意図される使用方法と制約
    • その他役立つ情報!🤓

タダー!

➡️ あなたのモデルはhttps://huggingface.co/modelsでページを持ち、誰でもAutoModel.from_pretrained("username/model_name")を使用してロードできます。

異なる言語のモデルを見るには、https://huggingface.co/modelsをチェックしてください。

ありがとうございました!

We will continue to update VoAGI; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more

コンピュータサイエンス

認知的な燃焼を引き起こす:認知アーキテクチャとLLMの融合による次世代コンピュータの構築

技術はシステムに統合されることで、ブレークスルーとなりますこの記事では、言語モデルを統合する取り組みについて探求し、...

AIニュース

開発者や企業のためのジェミニAPIとさらに新しいAIツール

「ジェミニAPIおよびそれ以外にも4つのAIツール、Imagen 2、MedLM、開発者向けのDuet AI、セキュリティオペレーション向けのD...

機械学習

クラウドストライクは、Fal.Con 2023におけるAI駆動のセキュリティに関するビジョンを概説します

「クラウドネイティブアーキテクチャを使用し、AIと統合データを活用して、ますます速い攻撃に対する検出と対応を加速する」

機械学習

「ONNXフレームワークによるモデルの相互運用性と効率の向上」

ONNXは、異なるプラットフォーム間でのディープラーニングモデルの簡単な転送と実行を可能にするオープンソースのフレームワ...

AIニュース

「イギリスの全ての人に無料のAIトレーニングを提供しています」

「ジョニー・コットムは、一人でスタートアップを運営する際に必要なジャグリングの技術を知っています昨年、エコフレンドリ...

機械学習

このAI論文では、「PolyID:高性能バイオベースポリマーの発見における機械学習の先駆者」として、ポリ-ンにおける機械学習を紹介しています

人工知能は生活のあらゆる側面で使用されています。AIは生活のあらゆる方面で使用され、化学やポリマーなどさまざまな分野で...