見出し画像

[Guidance#4]Guidance Accelerationとは何か

Guidance Accelerationについてまとめていきます。この記事ではGPT-4に日本語で解釈してもらっている都合上、"ガイダンス加速"とも明記されていますが、同一のものを指しています。ご留意ください。

さて、Guidance Accelerationについては、その名前から生成速度が速くなる代物なのだろうということは分かるものの、一体何者なのかがよくわからなかったので、調査してみました。

※NLPへの専門知識には乏しいので、この記事に記載されていることが表面的な理解なのはご了承ください。。


結論

Guidance Accelerationは、Transformerベースのモデルで一度計算した内部状態(エンコードで生成されるKeyとValueのベクトル)を保存し、再利用する仕組みです。

これにより、過去に同一のプロンプトテンプレートを利用している場合は、各生成タスクの計算を一部省略することが可能となり、文章の生成速度が速くなります。

少し踏み込んだ概念の理解

以下の図は、TransformerにあるMulti-Head Attention層の基礎となるAttentionのメカニズムです。
※この図は、正確にはSource-Target-Attentionで、Multi-Head Attentionとはメカニズムが異なりますが、理解しやすいなと思ったので引っ張ってきました。

Source-Target Attentionの図
出典:論文解説 Attention Is All You Need (Transformer)

Key, Valueは入力されたプロンプトから生成されます。過去に同一のプロンプトが用いられていれば、そのキャッシュを再利用して高速化を図ることができるようです。

Guidanceの内部処理を見る限り、このようなTransformerで用いられるAttention部分のKey, Valueを再利用する仕組みを取り入れているようです。

Transformerの理解は、主にこちらを参考にしました。


利用できるケース

Guidance Accelerationは以下のケースでのみ用いることができるようです。

  1. guidance.llms.transformerで定義できるモデル

  2. transformer系列のLLMsのみサポート

    1. 公式Readmeにそのような記載あり

そのためOpenAIのAPIなど(例えば'text-davinci-003')への適用は無理そうです。オープンなLLMsの処理速度を高めるという用途で活躍してきそうですね。


どれくらい速くなるのか

実際、どれくらいの速度向上につながるのかについて試すことができる公式notebookがありましたので、そちらを日本語にして試してみました。

以下のColabで試せます(GPUで実行できます)

検証内容としては、gpt-2を利用した次の4パターンについての生成時間について計測をして比較しています。

各手法の比較


以下、各パターンについて計測するプログラムです。

!pip3 install guidance transformers

# ref: https://pytorch.org/get-started/locally/
!pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118


import time
import torch
import guidance

# 小さなモデルで容易に拡張できる分かりきった文字列を定義します
reps = 20
prefix = "Repeat this. Repeat this. "*5 + "Repeat this. Repeat this."
llm = guidance.llms.Transformers('gpt2', device='cpu')
print("# prefix tokens:", len(llm.encode(prefix)))
del llm.model_obj


# 1.ガイダンス加速とトークンヒーリングを使用
model = 'gpt2-large'
device = 'cuda'
llm = guidance.llms.Transformers(model, device=device)
guidance.llms.Transformers.cache.clear()
start = time.time()
template = """{{prefix}}{{gen 'story' stop="." max_tokens=50}}."""*reps
program = guidance(template, llm=llm)
a = program(prefix=prefix)
end = time.time()
print(f"ガイダンス加速とトークンヒーリングを使用:", end - start)
del llm.model_obj
torch.cuda.empty_cache()


# 2.ガイダンス加速のみを使用
llm = guidance.llms.Transformers(model, device=device, token_healing=False)
guidance.llms.Transformers.cache.clear()
start = time.time()
template = """{{prefix}}{{gen 'story' stop="." max_tokens=50}}."""*reps
program = guidance(template, llm=llm)
b = program(prefix=prefix)
end = time.time()
print(f"ガイダンス加速のみを使用:", end - start)
del llm.model_obj
torch.cuda.empty_cache()


3. ガイダンス加速を使用せず
llm = guidance.llms.Transformers(model, device=device, acceleration=False, token_healing=False)
guidance.llms.Transformers.cache.clear()
start = time.time()
template = """{{prefix}}{{gen 'story' stop="." max_tokens=50}}."""*reps
program = guidance(template, llm=llm)
b = program(prefix=prefix)
end = time.time()
print(f"ガイダンス加速を使用せず:", end - start)
del llm.model_obj
torch.cuda.empty_cache()


4. 同じ長さのシングル生成呼び出し
llm = guidance.llms.Transformers(model, device=device)
guidance.llms.Transformers.cache.clear()
start = time.time()
template = """{{prefix}}{{gen 'story' max_tokens=max_tokens}}"""
program = guidance(template, llm=llm)
b = program(prefix=prefix, max_tokens=len(llm.encode(str(a))) - len(llm.encode("Repeat this. Repeat this.")))
end = time.time()
print(f"同じ長さのシングル生成呼び出し:", end - start)
del llm.model_obj
torch.cuda.empty_cache()


検証結果

Guidance Acceleration=Trueとすると、生成速度が速くなっているようでした。どれくらい向上するかについては、プロンプトの形式やモデルの大きさなどによってくるようです。

Guidance Accelerationあり、Token healingあり
処理時間:4.58秒
Guidance Accelerationあり、Token healingなし
処理時間:3.17秒
Guidance Accelerationなし、Token healingなし
処理時間:6.93秒
同じ長さを全て生成
処理時間:28.33秒


所感

Guidance Accelerationに関する内部処理についてざっくりと理解することができました。

生成した文字列をキャッシュして再利用するだけではなく、内部状態(Key, Value)についても保持しておくことで、OSSのようなLLMモデルでパフォーマンスを出せるように工夫が施されているのですね。

現状のところ、私はLLM APIを利用することが多いため、あまり恩恵を受けることはなさそうですが、今後OSS LLMの発展によりお世話になることが増えてきそうな気がします。


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