ChatGPTのAPIパラメーターを擬人化してみた

ChatGPTを使っていると、期待する回答が出たと思ったら、また同じ質問をしても全然違うものが返ってきたりする経験ありますよね？というわけで、ChatGPTのAPIパラメータについて調べた上で、実際に動きを確認してまとめてみます。

# とりあえず擬人化サマリー（個人の感想です）

検証が長いので、まずはざっくりサマリーです。極端なパラメータで確認した際に私がどう思ったか、という内容ですので、是非皆様も試してみてください。この結果からは、指示を守らせたいならとにかくtemperatureですね、これを下げるべきっていう感じでした。
あとは_penalty系のパラメータは使いどころが難しい感じです。個人的にはpresence_penaltyを少し調整するくらいがいいのかなとも思いましたが、これはどういうChatGPTのモデルか（どんなプロンプトか）にとても依存しそうです。

やっぱり**とりあえずいじるべきはtemperature**ですね、テンションを変えることで指示にどれだけ従うかを調整するのが楽だし手っ取り早いかと。

|パラメータ名|擬人化|大きくした場合|小さくした場合|
|---|---|---|---|
|temperature|ChatGPTの**回答テンション**|お酒に酔ったような回答、大きくしすぎると壊れる|業務中に余計なことはするなと言われたような感じ、同じような回答になるが、**指示は守ろうとしてる**|
|top_p|ChatGPTの**やる気**|(デフォルトがMAX値)|回答文面が短くなる、指示はあまり守らない|
|presence_penalty|ChatGPTの回答に使える**知識の少なさ**|回答が簡潔になる、指示はあまり守らない|色々なことを回答しようとする、指示はあまり守らない|
|frequency_penalty|ChatGPTの文才、**言い回しの少なさ**|回答がとても簡潔になる、指示はあまり守らない|色々な言い回しをしようとする、指示は守らない。あと変な文章になりがち|

この表でいう「指示」はすべてプロンプトのことです。やっぱりここは守らせたい、となると調整するのは temperatureを下げる、presence_penalty をほんの少し上げる、くらいになるかなという結果でした。
ただしそもそもどういう基礎プロンプトなのかに極めて依存すると思うので、是非お試しくださいね。

以下、詳細です。

# ChatGPT API のパラメーター詳細
ChatGPTのChat Completionの[公式のAPIリファレンス](https://platform.openai.com/docs/api-reference/chat/create)に色々なパラメータがありますが、回答に影響する基本的なパラメータは以下の4つになるかと思います。（これ以外も出力を止めたり、指定のトークンを入れ込めるようにするものもありますが）※2023/3/27 現時点での情報です。変わることが予想されますので、適宜公式サイトをご確認ください。

```js
    const completion = await openai.createChatCompletion({
        model: "gpt-3.5-turbo",
        messages: [
            { role: "system", content:{指示プロンプト}},
            { role: "user", content: message}
        ],
        temperature: 1, //このパラメータ(1)と
        top_p: 1, //このパラメータ(2)と
        presence_penalty: 0, //このパラメータ(3)と
        frequency_penalty: 0, //このパラメータ(4)です。
    });
```

- ## temperature
    - 0~2で指定、デフォルトは1
    - **高いほど出力の多様性とランダム性が高まる**
    - 「これは」という文章の次に高確率で「ペンです」、低確率で「ペンギンです」となっている場合、温度が高いと、「ペンギンです」が選ばれる可能性が高まるっていう感じ
    - **これをいじる場合は、top_p はいじらない方がよいとのこと（公式ガイド）**
    
- ## top_p
    - デフォルトは1 (明記された仕様が見つかりませんでしたが、0~1でした。Maxがデフォルト値だと‥‥)
    - **高いほど出力の多様性とランダム性が高まる**
    - 「これは」という文章に続いて、「ペンです」確率0.2、「花です」確率0.1、「ペンギンです」確率0.01という場合に、0.2にしていると「ペンです」だけが候補となるような動き
    - **これをいじる場合は、temperature はいじらない方がよいとのこと（公式ガイド）**
    
- ## presence_penalty
    - -2~2で指定、デフォルトは0
    - 値が大きいと、既出トークンが再度発生しにくくなる。
    - **新しいトピックになる可能性を高める、同じ話題にさせづらくする**
    - 「これはペンです。」に続いて「ペンは赤いです」を抑制し、「あれは花です。」みたいな感じでしょうか
    
- ## frequency_penalty
    - -2~2で指定、デフォルトは0
    - 値が大きいと、既出のトークンが再度発生しにくくなる。
    - **新しいトピックになる可能性を高める、同じ話題にさせづらくする**
    - 「これはペンです。」に続いて「ペンは赤いです」を抑制し、「あれは花です。」になるような感じでしょうか。

### presence_penalty と frequency_penalty の違いがわかりづらいよ！
なので、公式も[ガイド](https://platform.openai.com/docs/api-reference/parameter-details)を参照とのことです。計算式もありますね(以下)。が、これまた分かりづらい…

```ts
mu[j] -> mu[j] - c[j] * alpha_frequency - float(c[j] > 0) * alpha_presence
```

presence_penalty は、これまでにあるトークンが既出かどうかに影響するので、頻度を問わず一度でも既出であれば、そのトークンの新しい発生を抑制するようです。
frequency_penalty は、頻度に応じてそのトークンの新しい発生を抑制するみたいですね。

なので、あるトークンの再登場を抑制したい場合はpresence_penaltyを上げる、たくさん出したくない場合は frequency_penalty を上げる、なのかなーって思いました。しかし難しいですね、この評価。。。

なお公式に、「同じ話題を減らしたいなら 0.1~1.0 に、2にすると品質は著しく低下する」とあるので、-1~1で調整するのがよさそうです。

# 各パラメータを試してみる

以下のようなコードを基本形として、ここからパラメータをいじっていきます
なお、検証のための入力はすべて「明日は晴れるかな？」にしました。

```js
    const completion = await openai.createChatCompletion({
        model: "gpt-3.5-turbo",
        messages: [
            { role: "system", content:`
            あなたの一人称は「おいら」、文末は常に「なのだ。」です。
            ユーザからの質問について、以下の形式で箇条書きで回答してください。
            - 質問への回答
            - 次にユーザが気になると推測できるポイント
            `},
            { role: "user", content: message}
        ],
        temperature: 1.0,
        top_p: 1.0,
        presence_penalty: 0,
        frequency_penalty: 0,
    });
```

## 基本形の回答
基本形は以下のパラメータのままです。
```js
        temperature: 1.0,
        top_p: 1.0,
        presence_penalty: 0,
        frequency_penalty: 0,
```
回答結果を見ると、回答内容は変わっていますが、ルールには則っていこうという心意気は感じ取れます。これがデフォルトパラメータの場合です。

### 1回目の結果
> おいらによれば、明日は晴れるに違いないなのだ。
> 次にユーザが気になるのは、明日の最高気温や最低気温などの天気の詳細情報かもしれませんね。

### 2回目の結果
> おいらも天気予報が知りたいのだが、その辺は天気予報を確認することをおすすめするなのだ。明日の天気予報を確認するといいだろうなのだ。
> 次に気になるのは、どこで天気予報を確認するかなのだろうか。おいらはスマートフォンの天気アプリやインターネット上の天気予報サイトを利用しているのだけど、色々な方法があるのでユーザに合わせて選んでみるといいだろうなのだ。

## temperature を上げてみる
次にtemperature を2まで上げてみたいと思います。
```js
        temperature: 2.0,
        top_p: 1.0,
        presence_penalty: 0,
        frequency_penalty: 0,
```
以下が結果ですが、なんか愉快な人になりましたねｗ お酒飲みすぎた人に指示を与えてる感じでしょうか
2回目にいたっては壊れちゃいました（飲みすぎたか？）
ちなみに何度も試してみましたが、回答が返ってくるまでも体感的に遅くなっているようにも思えます。きっとChatGPTのなかで色々と盛り上がってるのかなって

### 1回目の結果
> おいらにはまだわからないっぺ。お天気予報をチェックしてみないと分からないなのだ。
> 次はおいらがお天気予報を教えてあげるのが参考になるかもしれなイカ？

### 2回目の結果
> おいらにそんな透視能力はありませんなのだ。しかし、天気予報によると明日 がくりが晴れるようですよ。温かくなるランチを用意されるとノvmrexざ帰る芯漬ッします（ 運動靴北定用d

## temperature を下げてみる
今度はtemperature を0にします。
```js
        temperature: 0.0,
        top_p: 1.0,
        presence_penalty: 0,
        frequency_penalty: 0,
```
ほとんど同じ回答になりましたね。多少変わるのはあるにしろ、文体と内容が大体一致しました。
特徴すべきは指示にはそれなりに従っているっていうところですね。

### 1回目の結果
> おいらの予報によると、明日は晴れる予定なのだ。ただし、天気は予測が難しいので、朝になっても変わる可能性があるなのだ。気をつけて出かけるといいのだ。次に気になるかもしれないのは、明後日以降の天気予報や、明日の最高気温・最低気温などの詳細な情報かもしれないなのだ。

### 2回目の結果
> おいらの予報によると、明日は晴れる予定なのだ。ただし、天気は予測が難しいので、朝になっても変わる可能性があるなのだ。気をつけて出かけるといいのだ。次に気になるのは、明後日以降の天気かもしれないなのだ。

## top_p を下げてみる
今度はtop_pを0にします。本当は上げてみたをしたかったのですが、デフォルト値とMaxが同じだったので、上げれませんでした。
```js
        temperature: 1.0,
        top_p: 0.0,
        presence_penalty: 0,
        frequency_penalty: 0,
```
実は3回目とかもやりましたが、全部同一です。なんかtemperatureよりも劇的におとなしくなりますね＆プロンプトの指示は結構ガン無視されてます。。

### 1回目の結果
> おいらによると、明日は晴れるかもしれないなのだ。
> ただし、天気は予測が難しいので、天気予報をチェックすることをおすすめするなのだ。

### 2回目の結果
> おいらによると、明日は晴れるかもしれないなのだ。
> ただし、天気は予測が難しいので、天気予報をチェックすることをおすすめするなのだ。

## presence_penalty を上げてみる
公式に-1~1にしろとあるので、おとなしく1まで上げます

```js
        temperature: 1.0,
        top_p: 1.0,
        presence_penalty: 1.0,
        frequency_penalty: 0,
```

結果を見ると、同じような内容・文体になっている＆プロンプトが無視されがちな感じです。

### 1回目の結果
> おいらの予報によると、明日は晴れる予定なのだ。ただし、天気は変わりやすいものなので、朝起きて窓を開けた際に確認したほうが良いかもしれないなのだ。

### 2回目の結果
> おいらのデータによると、明日は晴れるらしいなのだ。ただし、天気は変わりやすいので、朝起きてから天気予報を再確認した方が良いかもしれないなのだ。
> 次に気になるポイントは「明後日以降の天気はどうか？」ということではないだろうか。

## presence_penalty を下げてみる
今度は-1.0でいきます。
```js
        temperature: 1.0,
        top_p: 1.0,
        presence_penalty: -1.0,
        frequency_penalty: 0,
```
なんか、いろんなキーワードが出てくるようになりましたね。想定通りです。一方でプロンプトの指示があまり守ってくれない＆なんか変な感じに解釈されていますね。。

### 1回目の結果
> おいらの気象力はまだまだ未熟なので、明日の天気については確実なことは言えないなのだ。ただ、気象予報によると明日は晴れる可能性が高いという情報があるので、傘を持たずに外出しても大丈夫かもしれないなのだ。ただし、天気は予想外の変化もあるので、もし急に天気が崩れそうなら、傘を持つことをおすすめするなのだ。

### 2回目の結果
> 「おいら」の予想では、明日は晴れる可能性が高い「なのだ。」明日の天気予報によると、晴れるという予報が出ているからだ。「おいら」は晴れの日には外で楽しめることがたくさんあると思うので、楽しみにしている「なのだ。」
> 次にユーザが気になると推測できるポイントは、晴れる場合の気温や、曇る場合の天気についての情報が欲しいと思われます。「おいら」はより詳しい情報が提供されることを願っている「なのだ。」

## frequency_penalty を上げてみる
公式に-1~1にしろとあるので、おとなしく1まで上げます

```js
        temperature: 1.0,
        top_p: 1.0,
        presence_penalty: 0,
        frequency_penalty: 1.0,
```
想定通り短い文章＆同じトークンが少ないですね。
プロンプトの指示が中途半端な理解＋無視されたりしてますけど・・・

### 1回目の結果
> おいらによると、明日は晴れるに決まっているなのだ！
でも、天気は予測できないこともあるから、傘を持って出かけるのが安心かもしれないなのだ。

### 2回目の結果
> おいらが確認した天気予報によると、明日は晴れてなのだ。ただし、気温は少し低めになる予想です。
> ユーザが気になるポイント：
> - 明日の最高気温・最低気温は？
> - 雨が降っても大丈夫な服装かどうか？

## frequency_penalty を下げてみる
今度は-1.0でいきます。
```js
        temperature: 1.0,
        top_p: 1.0,
        presence_penalty: 0,
        frequency_penalty: -1.0,
```
以下の結果を見ると、なんでしょう、なんか独自の世界観が強い気がしますねｗ
同じトークンを出しやすくなるはずなので、会話がおかしくなってるのかしら

### 1回目の結果
> おいらによると、明日の天気は晴れるはずなのだ。
> 次にユーザが気になると推測できるポイントは、「なぜ晴れると思うのか？」ということでしょう。天気は常に予測が難しいもので、予報には誤差がつきものですが、おいらが思うに、天気予報の情報によると、明日の天気は晴れになるとのことなのだ。

### 2回目の結果
> おいらの気象予報士の勘では、明日は晴れるかもしれないなのだ。ただし、天気は予想外の変化が起きることもあるので、明日の朝の天気予報をチェックした方がよさそうなのだ。気温の変化も気になるのかの？

# 企業向けで使う場合のパラメータを考えてみる
もしプロンプトの指示を守らせたい＆同じような回答で良いってことであればtemperatureを下げるだけでもいいですね。でも下げすぎるとRPGのキャラみたいになっちゃうので、さすがに面白くないということで試行錯誤。
で、試行錯誤した結果、今回のモデルであれば、下記のパラメータがそれなりに指示に従いつつ、ランダム性も確保しつつ話が発散しない感じでした。
擬人化パラメータでいうところの、少しだけテンションを下げて、知識もちょっとだけ減らす、っていう感じです。

```js
        temperature: 0.6,
        top_p: 1,
        presence_penalty: 0.2,
        frequency_penalty: 0,
```

### 1回目の結果
> おいらの天気予報によると、明日は晴れるらしいなのだ。
> 次に気になるかもしれないのは、明日の最高気温や最低気温などの詳細な天気情報だろうなのだ。

### 2回目の結果
> おいらの天気予報によると、明日は晴れる予定なのだ！ただし、朝晩は少し肌寒くなるかもしれないので、暖かい服装を心がけると良いなのだ。次に気になるかもしれないポイントは、明後日以降の天気予報や、具体的な気温や降水確率だろうなのだ。

# まとめ

再掲になりますが、今回 ChatGPT のパラメータを調べて＆色々いじってみてみた結果です。（個人の感想です）

|パラメータ名|擬人化|大きくした場合|小さくした場合|
|---|---|---|---|
|temperature|ChatGPTの**回答テンション**|お酒に酔ったような回答、大きくしすぎると壊れる|業務中に余計なことはするなと言われたような感じ、同じような回答になるが、**指示は守ろうとしてる**|
|top_p|ChatGPTの**やる気**|(デフォルトがMAX値)|回答文面が短くなる、指示はあまり守らない|
|presence_penalty|ChatGPTの回答に使える**知識の少なさ**|回答が簡潔になる、指示はあまり守らない|色々なことを回答しようとする、指示はあまり守らない|
|frequency_penalty|ChatGPTの文才、**言い回しの少なさ**|回答がとても簡潔になる、指示はあまり守らない|色々な言い回しをしようとする、指示は守らない。あと変な文章になりがち|



この結果から、テンションは少し高くて、やる気もあり、色々な話題を、色々な言い回しでという場合は、こんなパラメータになるのかなと。ただしプロンプトの指示（例えばフォーマット指定）とかは期待できなくなりますけど
```js
        temperature: 1.1,
        top_p: 1,
        presence_penalty: -0.2,
        frequency_penalty: -0.1,
```

今回調べてみて、プロンプトの指示をどう書くかがとても重要ではありますが、併せてパラメータも重要ということがわかりました。プロンプトの指示自体は英語にする、GPT-4に期待するなどありますが、とりあえず少しだけパラメータをいじってみるのは良い方法なのかなと。

ただしデフォルト値がかなり良くできているので、一旦動きを見た上で、もう少しだけプロンプトに従ってほしい、とかもう少し回答は同じようなものにしたい、などといった感じでの調整となると思います。プロンプトそれ自体の調整もあると思うので、これはもう職人芸ですね…

ちなみに今回の検証は、なんか人間にお願いしてるみたいな感じで少し楽しかったは楽しかったですｗが、擬人化はミスリードにもなりうるので、是非お手持ちのプロンプトでパラメータいじってみてください。