問題
言語モデルは確率分布から次のトークンを選びます。その分布は2つの設定で形が決まります。
- 'Top-k:ロジットが最も高い k 個のトークンだけを残します(ロジットが同じなら、インデックスが小さいほうが上位)。'
- '温度 T:ソフトマックスの前に、残したロジットを T で割ります。T が低いと選択は予測しやすく、T が高いとランダムになります。'
テストできるように、乱数は与えられます。
- 上位 k 個のトークンを残し、元のインデックスの昇順に並べます。
- 残したトークンについて softmax(logit / T) を計算します(e^x を計算する前に最大値を引きます)。
- リストを順にたどって確率を足していき、累積値が
random_valueを初めて超えたトークンのインデックスを返します。どれも超えない場合(丸め誤差)は、最後に残したトークンを返します。
k = 1 なら貪欲デコーディング、つまり常に最も確率の高いトークンを選びます。
sample_token(logits, temperature, k, random_value) を実装してください。
入力
logits: 語彙内のトークンごとに1つのスコア。
temperature: T、0 より大きい。
k: 残す上位トークンの数。
random_value: [0, 1) の乱数。
出力
選ばれたトークンのインデックスを返してください。
制約
1 ≤ k ≤ ロジットの数 ≤ 1,000
0 < temperature ≤ 100、0 ≤ random_value < 1
-100 ≤ 各ロジット ≤ 100
例
入力:
k = 1
logits = [1.0, 3.0, 2.0, 0.5]
temperature = 1.0
random_value = 0.99
期待される出力:
expected = 1
入力:
long long k = 1;
std::vector<double> logits = {1.0, 3.0, 2.0, 0.5};
double temperature = 1.0;
double random_value = 0.99;
期待される出力:
long long expected = 1;
入力:
long k = 1;
double[] logits = new double[] {1.0, 3.0, 2.0, 0.5};
double temperature = 1.0;
double random_value = 0.99;
期待される出力:
long expected = 1;
解説
k = 1 では最も高いロジット、インデックス 1 の 3.0 だけが残ります。その確率は 1 なので、乱数に関係なく選ばれます。これが貪欲デコーディングです。
入力:
k = 2
logits = [2.0, 1.0, 0.0]
temperature = 1.0
random_value = 0.8
期待される出力:
expected = 1
入力:
long long k = 2;
std::vector<double> logits = {2.0, 1.0, 0.0};
double temperature = 1.0;
double random_value = 0.8;
期待される出力:
long long expected = 1;
入力:
long k = 2;
double[] logits = new double[] {2.0, 1.0, 0.0};
double temperature = 1.0;
double random_value = 0.8;
期待される出力:
long expected = 1;
解説
Top-2 ではインデックス 0 と 1(ロジット 2 と 1)が残ります。ソフトマックスは約 0.731 と 0.269 です。累積値はインデックス 0 の後で 0.731(0.8 を超えない)、インデックス 1 の後で 1 なので、インデックス 1 が選ばれます。
参考資料
この課題はCodeUtility用に調整されています。上記の説明と制約に従ってください。