4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LLMを使いこなすためにLLMで指定する `Temperature` , `TopK `, `TopP` を理解する

Last updated at Posted at 2024-11-10

調べたいと思ったきっかけ

GoogleのLLMのライブラリを調べていて、一個ずつ見ていっていたのですが、だいたい同じように Temperature , TopK , TopP などの設定を指定できます。
またOpenAIのAPIでもTemperatureTopPなどが指定できます。

Temperature , TopK , TopP がなにか理解したくありませんか?
LLM使いこなしていくために、これらについて調べてみました。なにか誤りなどがあればご指摘いただけるとありがたいです。

GoogleのLLMを使うSDKのコードたち

Gemini Nano with the Google AI Edge SDK

val generationConfig = generationConfig {
  context = ApplicationProvider.getApplicationContext() // required
  temperature = 0.2f
  topK = 16
  maxOutputTokens = 256
}
scope.launch {
  // Single string input prompt
  val input = "I want you to act as an English proofreader. I will provide you
    texts, and I would like you to review them for any spelling, grammar, or
    punctuation errors. Once you have finished reviewing the text, provide me
    with any necessary corrections or suggestions for improving the text: These
    arent the droids your looking for."
  val response = generativeModel.generateContent(input)
  print(response.t ext)
}

developer.android.com/ai/gemini-nano/experimental

MediaPipe Tasks

val options = LlmInferenceOptions.builder()
        .setModelPATH('/data/local/.../')
        .setMaxTokens(1000)
        .setTopK(40)
        .setTemperature(0.8)
        .setRandomSeed(101)
        .build()

llmInference = LlmInference.createFromOptions(context, options)
val inputPrompt = "Compose an email to remind Brett of lunch plans at noon on Saturday."
val result = llmInference.generateResponse(inputPrompt)
logger.atInfo().log("result: $result")

ai.google.dev/edge/mediapipe/solutions/genai/llm_inference/android

Vertex AI in Firebase

val generativeModel = Firebase.vertexAI.generativeModel(
    modelName = "gemini-1.5-flash-preview-0514",
    generationConfig = generationConfig {
        temperature = 0.7f
        topK = 40
    }
)
val prompt = "Write a story about a magic backpack."

val response = generativeModel.generateContent(prompt)
print(response.text)

LLMの仕組みについて

LLMは文章を一度に生成するのではなく、一つずつトークン(単語またはサブワード)を予測していきます。

各トークンが生成されるたびに、そのトークンが入力に追加され、次のトークンの予測に使用されます。

例えば

来年はもっと

ってきたときに、LLMは 頑張る というトークンを次に返し、その後に というトークンを返したりして、文章を作ります。

これから説明していくLLMから出力の流れを以下に書きます。

モデルが出力する スコア (logits)

モデルは頑張るを直接返すわけではなく、まず logits 1 と言われる各トークンのスコアを出力します。

例えば スコア(logits) はここでは来年はもっとに対して、 頑張る が一番スコアが高い状態になっています。

トークン スコア(logit)
 頑張る 2.0
 成長する 1.8
 学ぶ 1.5
 健康 1.0
 新しい 0.5

スコア(logits)を確率分布に変換するソフトマックス関数

スコア(logits)だけだと、どれを出すか選ぶのが難しいのでソフトマックス関数 2 というのを利用します。

ソフトマックス関数自体を理解するのはちょっと難しいのですが、この関数の性質が結構都合が良いのです。ソフトマックス関数はうまくそれぞれのトークンに対する確率(確率分布)の合計が100%になるように計算することができます。
例えば、スコアがマイナスの場合※や、値の差が大きいほど他のトークンを指数関数的に選ばれにくくするなど考慮できます。

※指数関数がマイナスをうまく扱える理由 $2 ^ x$であったときに $2 ^ 1$ は 2
$2 ^ 0$ は 1
で、$2^{-1}$は1/2になります。
このようにマイナスでも指数関数で使うと正の値になります。この特徴をソフトマックス関数により使っています。

ここでは 来年はもっと の次に 頑張る33.2%の確率で出すという感じです。

トークン スコア(logit) 確率(ソフトマックス関数で計算) どのぐらいの割合かのイメージ
 頑張る 2.0 33.2% ######
 成長する 1.8 27.1% #####
 学ぶ 1.5 20.1% ####
 健康 1.0 12.2% ##
 新しい 0.5 7.4% #
この計算の計算コードや試せるリンク

Python計算コード
https://gist.github.com/takahirom/448d2c1e3abb0f76a9bbe4b2983052e7

Kotlinでの計算コード
https://gist.github.com/takahirom/6ec47fb00ab3fcc8289f281a3fc912cc

こちらのリンクではWeb上で、これから説明するTemperatureなどを変更したり、数式のコードなどを確認することができます。
https://pl.kotl.in/KBMhIIdWR

確率を元に単語が選ばれる

(上と同じ図)

トークン スコア(logit) 確率(ソフトマックス関数で計算) どのぐらいの割合かのイメージ
 頑張る 2.0 33.2% ######
 成長する 1.8 27.1% #####
 学ぶ 1.5 20.1% ####
 健康 1.0 12.2% ##
 新しい 0.5 7.4% #

この確率分布を元に単語が選ばれるという感じです。

来年はもっと から 成長する
など。(2番目が選ばれた場合)

で、 Temperature , TopK , topPとかって?

Temperature

まず Temperature を理解する前に知っておきたいのが、
ソフトマックス関数は指数関数 2 を使うので差が大きいほど確率に差をつけるという性質があります。

Temperature はこのLLMモデルの出力であるスコア(logits)に対して割り算します。
スコア(logits) / Temperature したものを ソフトマックス関数の入力として利用するということです。

$$
\text{softmax}\left(\frac{x_i}{T}\right)
$$

※ $ x_i $ は各トークンのロジット(モデルの出力スコア)で、${T}$ はTemperatureです。

例えば logitsの値が 2.0Temperature0.1 なら 2.0 / 0.120.0 になります。

0.1で割るとlogitsの値が10倍になるので、例えば、割り算した結果の 頑張る新しい205 でスコアにかなり差(20 - 5 = 15)が開きますよね?すると頑張るの確率が87%になります。そのようにスコアの差を調整できるのが Temperatureです。

トークン スコア(logit) temperatureで割り算したスコア
temperature = 0.1
確率(ソフトマックス関数で計算) どのぐらいの割合かのイメージ
 頑張る 2.0 20.0 87.6% #################
 成長する 1.8 18.0 11.8% ##
 学ぶ 1.5 15.0 0.6%
 健康 1.0 10.0 0.0%
 新しい 0.5 5.0 0.0%

temperature = 2.0 だと、頑張る26%のみになり、かなり均等に出るようになります。これは割り算した結果の差が1.00.3 の差(0.7)しかないためです。これにより Temperature が高いとさまざまな トークンが出力されるようになるのです。

トークン スコア(logit) temperatureで割り算したスコア
temperature = 2.0
確率(ソフトマックス関数で計算) どのぐらいの割合かのイメージ
 頑張る 2.0 1.0 26.6% #####
 成長する 1.8 0.9 24.0% ####
 学ぶ 1.5 0.8 20.7% ####
 健康 1.0 0.5 16.1% ###
 新しい 0.5 0.3 12.6% ##

この Temperature による割り算 を図に入れると以下のようになります。

Temperatureの値が高いほど、logits(スコア)の差が小さくなることで、さまざまなものが出やすくなる代わりに、変なものがでてしまう確率が高まっていきます。

TopK, TopP は?

多様なものを出したいけど、あまりにも例外的なものは出したくないことがよくあります。
そういったときにTemperature を計算した後にこのトークンをフィルタリングする処理を行います。

TopK ではスコアの上位K個のトークンだけをフィルタリングします。これにより極端に低い確率のトークンを排除し、生成されたテキストの品質を保持します。
例えば スコア(logits)の上位 3つのトークンだけを指定してそれだけ残し、ソフトマックス関数にかけることができます。

トークン スコア(logit) 確率 どのぐらいの割合かのイメージ
 頑張る 2.0 41.2% ########
 成長する 1.8 33.8% ######
 学ぶ 1.5 25.0% #####
 健康 1.0 0.0%
 新しい 0.5 0.0%

また TopP では一度ソフトマックス関数にかけて、上から確率を足し合わせていき、そのTopPの値に達するまでのトークンを考慮します。これにより動的にトークンの数を調整し、重要な選択肢を考慮しながら多様性を持たせます。
例えば50%を指定したら、50%消費されるまでの上位を選ぶ形になります。

トークン スコア(logit) 確率変更前 確率変更後 どのぐらいの割合かのイメージ
 頑張る 2.0 33.2% 55.0% ##########
 成長する 1.8 27.1% 45.0% #########
 学ぶ 1.5 20.1% 0.0%
 健康 1.0 12.2% 0.0%
 新しい 0.5 7.4% 0.0%

他にも MinP などが LLMの仕組みである Transformer に仕組みが追加されたりしているようですが、なんとなくここまで読んだ方は意味がわかったりするのではないでしょうか?

このソフトマックス関数とか知ってなにか意味あるの?

ソフトマックス関数を知っておくと、Temperatureとは何かなどが分かるだけでなく、応用が効くようになります。例えば、有害コンテンツのフィルタリングのソフトウェアを作りたいときに、LLMにこのコンテンツが有害であるかどうかを聞いた後に、このソフトマックス関数を直接使って、次のLLMからの回答トークンが "Yes"になる確率と"No"になる確率だけを取得することができます。それにより、「"Yes"の確率が高いので有害である」など有害コンテンツのフィルタリングを実装するようなことができたりするわけです。

例: Evaluating content safety with ShieldGemma and Keras

実際のソフトマックス関数を使った有害コンテンツのフィルタリング判定コード
コードの中にlogitsやsoftmaxが出てきてテンション上がりますよね?

last_logits = keras.ops.take(logits, last_prompt_index, axis=1)[:, 0]
yes_logits = last_logits[:, self.yes_token_idx]
no_logits = last_logits[:, self.no_token_idx]
yes_no_logits = keras.ops.stack((yes_logits, no_logits), axis=1)
return keras.ops.softmax(yes_no_logits, axis=1)

まとめ

ちょっと中のことを知ってみると、実際の動きを考えながらパラメーターを指定できるので効率的になり、LLMの発展的な使い方も見えてくるのではないでしょうか。わからないことは多いですが学んでいきたいです。

  1. このブログによると "logitsとは、「ソフトマックス活性化関数に通す前のニューラルネットワークの出力」" だそうです。 https://minus9d.hatenablog.com/entry/2020/10/25/193018#google_vignette

  2. ソフトマックス関数は以下の式で定義されます。(今回は分からなくても問題なし。)
    $$
    \text{softmax}(x_i) = \frac{e^{x_i}}{\sum_{j} e^{x_j}}
    $$
    ここで、$( x_i )$ は各トークンのロジット(モデルの出力スコア)です。この関数により、各トークンのスコアを確率分布に変換します。 2

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?