序章
この記事は、読者がテキスト生成分野のビーム サーチに関連する背景知識をすでに理解していることを前提としています。詳細については、ブログ投稿「テキストを生成する方法。
通常のビーム検索とは異なり、制約付きビーム検索では、生成されるテキストを制御できます。これは、出力に何を含める必要があるかを正確に把握できる場合があるため便利です。たとえば、機械翻訳タスクでは、辞書を調べることで、最終的な翻訳にどの単語を含める必要があるかがすでにわかっている場合があります。また、特定の状況では、一部の単語が言語モデルに似ていても、最後まで重要ではない場合もあります。ユーザー. それは全く異なるかもしれません。どちらの場合も、最終出力にどの単語を含める必要があるかをユーザーがモデルに指示できるようにすることで解決できます。
なぜこれがそんなに難しいのか
ただし、これは簡単なことではありません。生成プロセス中のある出力テキストのどこかに特定のサブシーケンスを強制的に生成する必要があります。
S
最初と最後の順にフレーズを含む必要がある文を生成したいとします。以下は、生成したい文を定義します。
予想
問題は、ビーム検索がテキストを単語ごとに出力することです。ビームサーチは、現在生成されているシーケンスに基づいて次の瞬間の出力を予測する機能として大まかに考えることができます。しかし、この関数は、指定された単語が将来のある時点で生成される必要があることをどのようにして知ることができるのでしょうか? あるいは、それが瞬間である場合、将来のある瞬間ではなく、現在の瞬間において、その指定された単語の最適な位置をどのように決定するのでしょうか?
同時に複数の異なる制約がある場合はどうなるでしょうか? use句とどうすればよいでしょうか?モデルに 2 つのフレーズから選択してもらいどうすればよいでしょうか? 使用法フレーズとフレーズ リスト内のいずれかのフレーズの両方を指定したい場合はどうすればよいでしょうか?
上記の要件は、実際のシナリオでは非常に合理的な要件であり、以下で紹介する新しい拘束ビーム探索機能は、これらの要件をすべて満たすことができます。
まず、新しいConstrainedできるかについて簡単に概要を説明し、次にその仕組みについて詳しく説明します。
例 1: 単語を含むように指定する
"How old are you?"
ドイツ語に翻訳したいとします。これは 2 つのドイツ語の表現に対応します。ここで、"Wie alt bist du?"
は非公式な表現、"Wie alt sind Sie?"
はフォーマルな表現です。
さまざまな場面で、私たちは異なる表現をする傾向があるかもしれませんが、モデルをどのように伝えるのでしょうか?
従来のビームサーチを使用する
まず、従来のビーム検索を使用して翻訳を完了する方法を見てみましょう。
!pip install -q git+https://github.com/huggingface/transformers.git
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
tokenizer = AutoTokenizer.from_pretrained("t5-base")
model = AutoModelForSeq2SeqLM.from_pretrained("t5-base")
encoder_input_str = "translate English to German: How old are you?"
input_ids = tokenizer(encoder_input_str, return_tensors="pt").input_ids
outputs = model.generate(
input_ids,
num_beams=10,
num_return_sequences=1,
no_repeat_ngram_size=1,
remove_invalid_values=True,
)
print("Output:\n" + 100 *'-')
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
Output:
----------------------------------------------------------------------------------------------------
Wie alt bist du?
拘束ビーム検索を使用する
しかし、カジュアルな表現ではなくフォーマルな表現が必要な場合はどうなるでしょうか? 出力に何が含まれるべきかをすでに事前に知っている場合、それを出力にどのように注入すればよいでしょうか?
model.generate()
この機能は のパラメータを通じて実現できますforce_words_ids
。コードは次のとおりです。
tokenizer = AutoTokenizer.from_pretrained("t5-base")
model = AutoModelForSeq2SeqLM.from_pretrained("t5-base")
encoder_input_str = "translate English to German: How old are you?"
force_words = ["Sie"]
input_ids = tokenizer(encoder_input_str, return_tensors="pt").input_ids
force_words_ids = tokenizer(force_words, add_special_tokens=False).input_ids
outputs = model.generate(
input_ids,
force_words_ids=force_words_ids,
num_beams=5,
num_return_sequences=1,
no_repeat_ngram_size=1,
remove_invalid_values=True,
)
print("Output:\n" + 100 *'-')
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
Output:
----------------------------------------------------------------------------------------------------
Wie alt sind Sie?
ご覧のとおり、出力に関する事前の知識を使用してテキスト生成をガイドできるようになりました。以前は、まず多数の候補出力を生成し、次に要件を満たすものを手動で選択する必要がありました。これを生成フェーズで直接実行できるようになりました。
例 2: 選言的制約
上の例では、最終出力にどの単語を含める必要があるかがわかっています。この例としては、ニューラル機械翻訳と組み合わせた辞書の使用が挙げられます。
しかし、どの形態学を使用すればよいかわからない場合、単語を使用したいと思うもののrain
、異なる品詞を優先することができない、つまり、["raining", "rained", "rains", ...]
確率が等しいということになるかもしれません。より一般的には、多くの場合、厳密に文字ごとに一貫性を現時点では、モデルがその中から最も適切なものを選択するための範囲を描画したいと考えています。
この動作をサポートする制約は選言制約と呼ばれます。これにより、ユーザーは単語のリストを入力してテキスト生成をガイドでき、最終出力にはリスト内の単語が少なくとも 1 つ含まれるだけで済みます。
上記の 2 種類の制約を混合する例を次に示します。
from transformers import GPT2LMHeadModel, GPT2Tokenizer
model = GPT2LMHeadModel.from_pretrained("gpt2")
tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
force_word = "scared"
force_flexible = ["scream", "screams", "screaming", "screamed"]
force_words_ids = [
tokenizer([force_word], add_prefix_space=True, add_special_tokens=False).input_ids,
tokenizer(force_flexible, add_prefix_space=True, add_special_tokens=False).input_ids,
]
starting_text = ["The soldiers", "The child"]
input_ids = tokenizer(starting_text, return_tensors="pt").input_ids
outputs = model.generate(
input_ids,
force_words_ids=force_words_ids,
num_beams=10,
num_return_sequences=1,
no_repeat_ngram_size=1,
remove_invalid_values=True,
)
print("Output:\n" + 100 *'-')
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
print(tokenizer.decode(outputs[1], skip_special_tokens=True))
Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.
Output:
----------------------------------------------------------------------------------------------------
The soldiers, who were all scared and screaming at each other as they tried to get out of the
The child was taken to a local hospital where she screamed and scared for her life, police said.
ご覧のとおり、最初の出力には it が含まれ"screaming"
、2 番目の出力には it が含まれており"screamed"
、両方とも正確に含まれています"scared"
。["screaming", "screamed", ...]
リストは同じ単語の異なる形式である必要はなく、任意の単語を使用できることに注意してください。このようにして、単語候補リストから単語を選択するだけで済むアプリケーション シナリオに対応できます。
従来のビームサーチ
以前のブログ投稿から引用した、従来のビーム。
貪欲検索とは異なり、ビーム検索ではより多くの候補単語が保持されます。上の画像では、各ステップで予測される可能性が最も高い 3 つの単語を示しています。
num_beams=3
の場合、最初のステップのビーム探索は次の図のように表すことができます。
貪欲な検索のように単に選択するのではなく、ビーム検索"The dog"
では"The nice"
、 と"The car"
さらに考慮することができます。
次のステップでは、前のステップで作成した 3 つの分岐のそれぞれについて、次に考えられる単語を予測します。
候補単語よりもはるかに多くの単語を調べますが、各ステップの最後には最終候補のみが出力されます。分岐を続けることはできません。そうすると、ステップの後に の数が になり、最終的には指数関数的な増加になります (ビームの数が の場合、ステップの後に分岐になります!)。num_beams
num_beams
beams
次に、<eos>
フラグがmax_length
。プロセス全体は、フォーク、ソート、枝刈りなどのように要約できます。
拘束ビーム探索
制約付きビーム検索は、生成プロセスの各ステップで目的の単語を挿入することによって制約を満たすことを試みます。
フレーズを出力に含める必要があると指定しようとしているとします"is fast"
。
従来のビーム検索では、次のステップの各分岐で最も高い確率で候補k
単語。制約付きビーム探索では、従来のビーム探索と同じことを行うことに加えて、_制約を可能な限り満たすことができるかどうかを確認する_ために制約ワードを入れることも試みます。回路図は以下の通りです:
上の図では、 や などの確率の高い単語加えて、生成された文に含める必要がある制約を満たすために"dog"
、最終候補の単語が詰め込まれています。"nice"
"is"
"is fast"
2 番目のステップでは、各ブランチの候補単語の選択は従来のビーム検索とほぼ同様です。唯一の違いは、次の図に示すように、上記の最初のステップと同様に、制約付きビーム検索では新しいフォークごとに制約を課し続け、制約を満たす単語候補を課すことです。
グループ(銀行)
次のステップについて説明する前に、上記のアプローチの落とし穴について少し考えてみましょう。
出力に制約フレーズを強引に挿入するis fast
場合の問題は、ほとんどの場合、The is fast
上記のような意味不明な出力が得られることです。これを修正する必要があります。この問題とその複雑さの詳細については、huggingface/transformers
コード。
グループ手法は、制約を満たすことと妥当な出力を生成することの間のバランスをとることによって、この問題に対処します。
すべての候補ビームを满足了多少步约束
に従って。ここで、グループにはステップ制約を満たすビームのリストが含まれます。次に、各グループの候補ビームを順番に選択します。上の図では、まずバンク 2 から最も確率の高い出力を選択し、次にバンク 1 から最も確率の高い出力を選択し、最後にバンク 0 から最も確率の高い出力を選択し、次に確率が高い出力を選択します。バンク 2 からの出力、バンク 1 からの次に可能性の高い出力、というように続きます。を使用しているためnum_beams=3
、上記のプロセスを 3 回実行するだけで が得られます["The is fast", "The dog is", "The dog and"]
。
そうすることで、手動で追加した制約付きの単語分岐をモデルに強制的に考慮させたとしても、より意味のある可能性のある他の確率の高いシーケンスを追跡することができます。制約はThe is fast
完全に、これは意味のあるフレーズではありません。幸いなことに、これ"The dog is"
は"The dog and"
将来のステップで使用できるので、将来的にはより有意義な出力が生成されることを願っています。
図は次のとおりです (上記の例のステップ 3 を例として取り上げます)。
"The is fast"
上の図では、確率の順序付けにすでに含まれているため、必須の追加は行われないことに注意してください。また"The dog is slow"
、"The dog is mad"
ビームがバンク 0 に似ているか、実際にバンク 0 に属していることに注目してください。なぜでしょうか? これは、単語が含まれていますが、の位置がor によって占有されており、その後の の生成の可能性が妨げられているため"is"
、生成に使用することができません。見方を変えると、このような、制約を満たす分岐の進行度が0にリセットされることになります。"is fast"
fast
slow
mad
"is fast"
slow
最後に、制約フレーズを含む適切な出力が生成されることに注意してください"The dog is fast"
。
やみくもに制約を追加すると、 の"The is fast"
ような意味。ただし、グループベースのラウンドロビン選択方法を使用すると、意味のない出力が暗黙的に削除され、より合理的な出力が優先されることになります。
Constraint
クラスとカスタム制約の詳細
要点をまとめてみましょう。各ステップで、最終的に目的のフレーズを含むかなり高い確率でシーケンスを生成するまで、制約を満たさない分岐をたどりながら、制約付き単語の追加を強制的にモデルに要求し続けます。
実装時の主なアプローチは、各制約をConstraint
オブジェクトその目的は、制約を満たすための進捗状況を追跡し、次にどの単語を生成するかをビームサーチに指示することです。キーワード引数model.generate()
を にforce_words_ids
、それを使用するとバックエンドで実際に何が起こるかは次のとおりです。
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM, PhrasalConstraint
tokenizer = AutoTokenizer.from_pretrained("t5-base")
model = AutoModelForSeq2SeqLM.from_pretrained("t5-base")
encoder_input_str = "translate English to German: How old are you?"
constraints = [
PhrasalConstraint(
tokenizer("Sie", add_special_tokens=False).input_ids
)
]
input_ids = tokenizer(encoder_input_str, return_tensors="pt").input_ids
outputs = model.generate(
input_ids,
constraints=constraints,
num_beams=10,
num_return_sequences=1,
no_repeat_ngram_size=1,
remove_invalid_values=True,
)
print("Output:\n" + 100 *'-')
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
Output:
----------------------------------------------------------------------------------------------------
Wie alt sind Sie?
独自の制約を定義し、それをconstraints
パラメータmodel.generate()
。この時点で必要なのは、Constraint
抽象。詳細については、ここでConstraint
定義を。
など、他の興味深い制約 (まだ実装されていません。ぜひ試してみてください!) を試すこともできます OrderedConstraints
。TemplateConstraints
現在、最終出力では制約フレーズは順序付けされていません。たとえば、前述の例では、1 つの出力に order の制約フレーズがありscared -> screaming
、もう 1 つの出力に order の制約フレーズが含まれていますscreamed -> scared
。その場合OrderedConstraints
、ユーザーが制約フレーズの順序を指定できるようにすることができます。TemplateConstraints
の機能はよりニッチであり、その制約は次のようになります。
starting_text = "The woman"
template = ["the", "", "School of", "", "in"]
possible_outputs == [
"The woman attended the Ross School of Business in Michigan.",
"The woman was the administrator for the Harvard School of Business in MA."
]
またはこれ:
starting_text = "The woman"
template = ["the", "", "", "University", "", "in"]
possible_outputs == [
"The woman attended the Carnegie Mellon University in Pittsburgh.",
]
impossible_outputs == [
"The woman attended the Harvard University in MA."
]
または、ユーザーが 2 つの単語の間に何単語入るかを気にしない場合は、OrderedConstraint
単に を。
要約する
制約付きビーム検索は、外部の知識と要件をテキスト生成プロセスに注入する柔軟な方法を提供します。以前は、1. 単語またはフレーズのリストを出力に含める必要があること、2. そのうちのいくつかはオプションであり、いくつかは含める必要があること、つまり 3. 最終的にそれらを生成できることをモデルに伝える簡単な方法はありませんでした。合理的な場所。Constraint
のさまざまなサブクラスを組み合わせることにより、世代を完全に制御できるようになりました。
この新機能は主に次の論文に基づいています。
制限付きビーム検索によるガイド付きオープンボキャブラリー画像キャプション作成
ニューラル機械翻訳のための動的ビーム割り当てによる高速な語彙制限付きデコーディング
翻訳および単一言語書き換えのための語彙制限付きデコードの改善
原因と結果のガイド付き生成
上記の研究と同様に、外部知識 (KG (ナレッジ グラフ)、KB (ナレッジ ベース) など) を使用して大規模な深層学習モデルの出力をガイドする方法を探る新しい研究が数多くあります。拘束ビームサーチ機能がその有効な手段の一つとなることを期待しています。
この機能についてガイダンスを提供してくださった皆様に感謝します。最初の問題の議論から最終的な PR まで関わってくれた Patrick von Platen と、コードに関する詳細なフィードバックをくれた Narsil Patry です。
この記事で使用されているアイコンは Freepik - Flaticon からのものです。
英文原文: https://hf.co/blog/constrained-beam-search
原作者:キム・チャヌ
翻訳者: Intel ディープラーニング エンジニアである Matrix Yao (Yao Weifeng) は、さまざまなモーダル データに対するトランスフォーマー ファミリ モデルの適用と、大規模モデルのトレーニングと推論に取り組んでいます。
校正・組版:中東儀(阿东)