見出し画像

Transformers の generate()のテキスト生成戦略

以下の記事が面白かったので、簡単にまとめました。

Text generation strategies

1. generate() の テキスト生成戦略

テキスト生成」は、自由形式のテキスト生成、要約、翻訳など、多くの NLP タスクに不可欠です。また、音声からのテキスト変換やビジョンからのテキスト変換など、テキスト出力を持つマルチモーダルなアプリケーションでも役割を果たします。テキスト生成できるモデルには、「GPT2」「XLNet」「OpenAI GPT」「CTRL」「TransformerXL」「XLM」「Bart」「T5」「GIT」「Whisper」などがあります。

generate() を使用して様々なタスクのテキスト生成を行う例を、以下で確認できます。

テキスト要約
画像キャプショニング
音声トランスクリプション

generate() への入力はモデルのモダリティに依存します。これらは、AutoTokenizerAutoProcessor など、モデルのプリプロセッサクラスによって返されます。プリプロセッサが複数の種類の入力を必要とする場合は、すべての入力をgenerate()に渡します。

2. GenerationConfig

モデルのテキスト生成戦略は、「GenerationConfig」で定義します。モデルを読み込むと、model.generation_config でモデルに付属する「GenerationConfig」を確認できます。

from transformers import AutoModelForCausalLM

# モデルの準備
model = AutoModelForCausalLM.from_pretrained(
    "rinna/japanese-gpt-neox-3.6b-instruction-ppo",
    load_in_8bit=True,
    device_map="auto",
)

# 生成コンフィグの確認
model.generation_config
GenerationConfig {
  "_from_model_config": true,
  "bos_token_id": 2,
  "eos_token_id": 3,
  "transformers_version": "4.30.2"
}

model.generation_config の出力は、デフォルトの「GenerationConfig」と異なる値のみが表示され、デフォルト値は表示されません。

デフォルトの「GenerationConfig」では、リソース制限に遭遇するのを避けるために、入出力の合計サイズが最大 20 トークンに制限されます。デフォルトのテキスト生成戦略は「Greedy Search」です。これは、次のトークンとして最も高い確率のトークンを選択する、最も単純な戦略です。 出力サイズが小さい場合、これはうまく機能します。ただし、長い出力を生成する場合、「Greedy Search」は反復的な結果を生成しはじめる可能性があります。

3. GenerationConfigのカスタマイズ

パラメータを直接generate()に渡すことで、「GenerationConfig」をオーバーライドできます。

my_model.generate(**inputs, num_beams=4, do_sample=True)

一般的に調整するパラメータには、次のとおりです。

・max_new_tokens : 生成するトークンの最大数です。言い換えると、プロンプトのトークンを含まない、出力シーケンスのサイズになります。
・num_beams : 1 より大きい数を指定すると、「Greedy Search」から「Beam Search」に切り替わります。この戦略では、タイムステップごとにいくつかの仮説を評価し、最終的にシーケンス全体で最も確率の高い仮説を選択します。これには、確率の低い初期トークンで始まり、「Greedy Search」では無視されていたシーケンスを識別できるという利点があります。
・do_sample : Trueに設定すると、「Multinomial Sampling」「Beam-Search Multinomial Sampling」「Top-K Sampling」「Top-p Sampling」などの戦略を有効にします。これら戦略は、さまざまな戦略固有の調整を使用して、語彙全体の確率分布から次のトークンを選択します。
・num_return_sequences : 各入力に対して返されるシーケンス候補数です。このオプションは、複数のシーケンス候補をサポートする戦略でのみ使用できます。「Greedy Search」「Contrastive Search」では、単一の出力シーケンスを返します。

4. ストリーミング

generate() は、「Streamer Input」を通じてストリーミングをサポートします。「Streamer Input」は、put() および end() を持つクラスのインスタンスと互換性があります。内部的には、put() は新しいトークンをプッシュするために使用され、end() はテキスト生成の終了にフラグを立てるために使用されます。

あらゆる種類の目的に合わせて独自のストリーミングクラスを作成できます。すぐに使える基本的なストリーミングクラスも用意されています。たとえば、「TextStreamer」を使用して、generate() の出力を一度に 1 単語ずつ画面にストリーミングできます。

from transformers import AutoModelForCausalLM, AutoTokenizer, TextStreamer

# トークナイザーとモデルの準備
tok = AutoTokenizer.from_pretrained("gpt2")
model = AutoModelForCausalLM.from_pretrained("gpt2")

# Streamer Inputの準備
streamer = TextStreamer(tok)

# Streamer Inputつきでテキスト生成
inputs = tok(["An increasing sequence: one,"], return_tensors="pt")
_ = model.generate(**inputs, streamer=streamer, max_new_tokens=20)

5. テキスト生成戦略

GenerationConfig と generate() のパラメータの組み合わせで、特定のテキスト生成戦略を有効にすることができます。

一般的なテキスト生成戦略がどのように機能するかは、以下の記事が参考になります。

5.1 Greedy Search

generate() はデフォルトで「Greedy Search」を使用するため、これを有効にするためにパラメータを渡す必要はありません。これは、num_beams=1 およびdo_sample=False が設定されることを意味します。

from transformers import AutoModelForCausalLM, AutoTokenizer

# トークナイザーとモデルの準備
tokenizer = AutoTokenizer.from_pretrained("distilgpt2")
model = AutoModelForCausalLM.from_pretrained("distilgpt2")

# テキスト生成
inputs = tokenizer("I look forward to", return_tensors="pt")
outputs = model.generate(**inputs)
tokenizer.batch_decode(outputs, skip_special_tokens=True)

5.2 Contrastive Search

「Contrastive Search」は、2022 年の論文「A Contrastive Framework for Neural Text Generation」で提案されました。 非反復的でありながら一貫した長い出力を生成する場合に優れています。 「Contrastive Search」の仕組みについては、この記事を参照してください。

この戦略を有効にして制御する主なパラメータは、「penalty_alpha」と「top_k」です。

from transformers import AutoTokenizer, AutoModelForCausalLM

# トークナイザーとモデルの準備
tokenizer = AutoTokenizer.from_pretrained("gpt2-large")
model = AutoModelForCausalLM.from_pretrained("gpt2-large")

# テキスト生成
inputs = tokenizer("Hugging Face Company is", return_tensors="pt")
outputs = model.generate(**inputs, penalty_alpha=0.6, top_k=4, max_new_tokens=100)
tokenizer.batch_decode(outputs, skip_special_tokens=True)

5.3 Multinomial Sampling

常に最も確率の高いトークンを次のトークンとして選択する「Greedy Search」とは対照的に、「Multinomial Sampling」は、モデルによって与えられた語彙全体の確率分布に基づいて次のトークンをランダムに選択します。 確率がゼロではないすべてのトークンが選択される可能性があるため、反復のリスクが軽減されます。

この戦略を有効にするには、do_sample=True および num_beams=1 を設定します。

from transformers import AutoTokenizer, AutoModelForCausalLM

# トークナイザーとモデルの準備
tokenizer = AutoTokenizer.from_pretrained("gpt2-large")
model = AutoModelForCausalLM.from_pretrained("gpt2-large")

# テキスト生成
inputs = tokenizer("Today was an amazing day because", return_tensors="pt")
outputs = model.generate(**inputs, do_sample=True, num_beams=1, max_new_tokens=100)
tokenizer.batch_decode(outputs, skip_special_tokens=True)

5-4. Beam-Search Decoding

「Greedy Search」とは異なり、「Beam-Search Decoding」では各タイムステップでいくつかの仮説が保持され、最終的にシーケンス全体で全体的に最も高い確率を持つ仮説が選択されます。これには、確率の低い初期トークンで始まり、「Greedy Search」では無視されていたシーケンスを識別できるという利点があります。

この戦略を有効にするには、1 より大きい num_beams を設定します。

from transformers import AutoModelForCausalLM, AutoTokenizer

# トークナイザーとモデルの準備
tokenizer = AutoTokenizer.from_pretrained("gpt2-medium")
model = AutoModelForCausalLM.from_pretrained("gpt2-medium")

# テキスト生成
inputs = tokenizer("It is astonishing how one can", return_tensors="pt")
outputs = model.generate(**inputs, num_beams=5, max_new_tokens=50)
tokenizer.batch_decode(outputs, skip_special_tokens=True)

5-5. Beam-search Multinomial Sampling

この戦略は「Beam-Search Decoding」と「Multinomial Sampling」を組み合わせたものです。

この戦略を有効にするには、1 より大きい num_beams および do_sample=True を設定します。

from transformers import AutoTokenizer, AutoModelForSeq2SeqLM

# トークナイザーとモデルの準備
tokenizer = AutoTokenizer.from_pretrained("t5-small")
model = AutoModelForSeq2SeqLM.from_pretrained("t5-small")

# テキスト生成
inputs = tokenizer("translate English to German: The house is wonderful.", return_tensors="pt")
outputs = model.generate(**inputs, num_beams=5, do_sample=True)
tokenizer.decode(outputs[0], skip_special_tokens=True)

5-6. Diverse Beam-Search Decoding

「Diverse Beam-Search Decoding」は、より多様なビームシーケンスのセットを生成して選択できるようにする「Beam-Search」の拡張です。その仕組みについては、「Diverse Beam Search: Decoding Diverse Solutions from Neural Sequence Models」を参照してください。 このアプローチには、num_beamsnum_beam_groups という 主要なパラメータがあります。 グループは、他のグループと比較して十分に区別できるように選択され、各グループ内で通常の「Beam-Search」が使用されます。

from transformers import AutoTokenizer, AutoModelForSeq2SeqLM

checkpoint = "google/pegasus-xsum"
prompt = "The Permaculture Design Principles are a set of universal design principles \
that can be applied to any location, climate and culture, and they allow us to design \
the most efficient and sustainable human habitation and food production systems. \
Permaculture is a design system that encompasses a wide variety of disciplines, such \
as ecology, landscape design, environmental science and energy conservation, and the \
Permaculture design principles are drawn from these various disciplines. Each individual \
design principle itself embodies a complete conceptual framework based on sound \
scientific principles. When we bring all these separate  principles together, we can \
create a design system that both looks at whole systems, the parts that these systems \
consist of, and how those parts interact with each other to create a complex, dynamic, \
living system. Each design principle serves as a tool that allows us to integrate all \
the separate parts of a design, referred to as elements, into a functional, synergistic, \
whole system, where the elements harmoniously interact and work together in the most \
efficient way possible."

# トークナイザーとモデルの準備
tokenizer = AutoTokenizer.from_pretrained("google/pegasus-xsum")
model = AutoModelForSeq2SeqLM.from_pretrained("google/pegasus-xsum")

# テキスト生成
inputs = tokenizer(prompt, return_tensors="pt")
outputs = model.generate(**inputs, num_beams=5, num_beam_groups=5, max_new_tokens=30)
tokenizer.decode(outputs[0], skip_special_tokens=True)

5-7. Assisted Decoding

「Assisted Decoding」は、同じトークナイザ (理想的にははるかに小さいモデル) を持つアシスタントモデルを使用して、いくつかの候補トークンをGreedyに生成する、上記の戦略の修正版です。メインモデルは単一のフォワードパスで候補トークンを検証し、テキスト生成を高速化します。 現在、「Assisted Decoding」では「Greedy Search」と「Sampling」のみがサポートされており、バッチ入力はサポートされていません。「Assisted Decoding」の詳細については、この記事を参照してください。

この戦略を有効にするには、assistant_model を設定します。

from transformers import AutoModelForCausalLM, AutoTokenizer

# トークナイザーとモデルの準備
tokenizer = AutoTokenizer.from_pretrained("EleutherAI/pythia-1.4b-deduped")
model = AutoModelForCausalLM.from_pretrained("EleutherAI/pythia-1.4b-deduped")

# アシスタントモデルの準備
assistant_model = AutoModelForCausalLM.from_pretrained("EleutherAI/pythia-160m-deduped")

# テキスト生成
inputs = tokenizer("Alice and Bob", return_tensors="pt")
outputs = model.generate(**inputs, assistant_model=assistant_model)
tokenizer.batch_decode(outputs, skip_special_tokens=True)

サンプリング手法で使用する場合、「Multinomial Sampling」と同様に、temperarure を使用してランダム性を制御できます。ただし、「Assisted Decoding」では、temperarureを下げると遅延の改善に役立ちます。

from transformers import AutoModelForCausalLM, AutoTokenizer

# トークナイザーとモデルの準備
tokenizer = AutoTokenizer.from_pretrained("EleutherAI/pythia-1.4b-deduped")
model = AutoModelForCausalLM.from_pretrained("EleutherAI/pythia-1.4b-deduped")

# アシスタントモデルの準備
assistant_model = AutoModelForCausalLM.from_pretrained("EleutherAI/pythia-160m-deduped")

# テキスト生成
inputs = tokenizer("Alice and Bob", return_tensors="pt")
outputs = model.generate(**inputs, assistant_model=assistant_model, do_sample=True, temperature=0.5)
tokenizer.batch_decode(outputs, skip_special_tokens=True)



この記事が気に入ったらサポートをしてみませんか?