Posted on 2025/11/22, 3:19 PM By admin22
LLMが処理した結果にどれだけ自信があるのだろうかとか、分類に使いたい時があります。システムプロンプトで指示するのもいいのですが、定量的に知る方法に、どういったパラメータがあるのかちょっと調べてみました。
サーバ起動
llama.cpp/build/bin/llama-server -m "/mnt/c/Users//.lmstudio/models/mmnga/ELYZA-japanese-Llama-2-7b-fast-instruct-gguf/ELYZA-japanese-Llama-2-7b-fast-instruct-q4_K_S.gguf" --host 0.0.0.0 --port 8080 --ctx-size 4096 --n-predict -1
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
from openai import OpenAI import numpy as np import math import sys client = OpenAI( base_url="http://localhost:8080/v1", api_key="not-needed" # llama.cppではAPIキーは不要 ) #question = "富士山の高さは?" question = "プリウスの重さは?" # 1️⃣ 回答と log probability 情報を取得 try: resp = client.chat.completions.create( model="local-model", # llama.cppでは任意のモデル名でOK messages=[{"role": "user", "content": question}], logprobs=True, top_logprobs=5, # トップ5候補を取得してエントロピーを計算 temperature=0, max_tokens=200, # 最大200トークンに制限(無限ループ防止) timeout=30, # 30秒でタイムアウト ) except Exception as e: print("=" * 60) print("⚠️ エラーが発生しました") print(f"エラー種類: {type(e).__name__}") print(f"エラー内容: {str(e)}") if "timeout" in str(e).lower(): print("\n🕐 タイムアウトしました(30秒以内に応答が完了しませんでした)") print("=" * 60) sys.exit(1) # デバッグ: レスポンスの内容を確認 print("=" * 60) print("レスポンス情報:") print(f"回答: {resp.choices[0].message.content}") # 終了理由をチェック finish_reason = resp.choices[0].finish_reason print(f"\n終了理由: {finish_reason}") if finish_reason == "length": print("⚠️ 最大トークン数(200トークン)に達しました。回答が途中で切れている可能性があります。") elif finish_reason == "stop": print("✅ 正常に完了しました。") elif finish_reason == "content_filter": print("⚠️ コンテンツフィルターにより停止されました。") else: print(f"ℹ️ その他の理由で終了: {finish_reason}") print(f"\nlogprobs: {resp.choices[0].logprobs}") print("=" * 60) # logprobs が None の場合の処理 if resp.choices[0].logprobs is None: print("\n⚠️ LMStudio は logprobs をサポートしていないようです。") print("回答のみ表示します。\n") print(f"質問: {question}") print(f"回答: {resp.choices[0].message.content}") else: # 各トークンの情報を取得 tokens = resp.choices[0].logprobs.content log_probs = [] entropies = [] for token_info in tokens: # トークンの log prob lp = token_info.logprob log_probs.append(lp) # トップkの確率を正規化してエントロピーを計算 probs = [math.exp(t.logprob) for t in token_info.top_logprobs] probs = np.array(probs) / np.sum(probs) H = -np.sum(probs * np.log(probs + 1e-10)) # エントロピー entropies.append(H) # 2️⃣ スコア計算 avg_logprob = np.mean(log_probs) # 平均対数確率 avg_entropy = np.mean(entropies) # 平均エントロピー # 3️⃣ 正規化(0〜1スケールへ) # logprob → 高いほど良い → sigmoidで圧縮 conf_from_logprob = 1 / (1 + math.exp(-avg_logprob * 2)) # entropy → 低いほど良い → 反転して正規化 conf_from_entropy = math.exp(-avg_entropy) # 4️⃣ 統合スコア final_confidence = 0.7 * conf_from_logprob + 0.3 * conf_from_entropy print(f"質問: {question}") print(f"平均log probability: {avg_logprob:.3f}") print(f"平均entropy: {avg_entropy:.3f}") print(f"確信度(logprob由来): {conf_from_logprob:.3f}") print(f"確信度(entropy由来): {conf_from_entropy:.3f}") print(f"最終確からしさスコア: {final_confidence:.3f}") print(f"回答: {resp.choices[0].message.content}") |
・・・
終了理由: length
⚠️ 最大トークン数(200トークン)に達しました。
・・・
質問: プリウスの重さは?
平均log probability: -0.137
平均entropy: 0.201
確信度(logprob由来): 0.432
確信度(entropy由来): 0.818
最終確からしさスコア: 0.548
回答: プリウスの車両重量は、グレードによって異なります。
・・・
結果は、なかなか判定が難しいということでした。もう少しいろいろな実験をしたいと思います。ただ不確かな答えの場合、出力トークンが多くなるという特性はあるようです。いろんな条件の元、総合的に判定することはできる可能性はあるように感じました。
Categories: 未分類
