この辺の実装がどのようになっているのかを勉強したい。ChatGPTにお願いしながら、読み進めていくことにする。
テーブルのアップデート方法
void hashed_perceptron::last_branch_result(champsim::address pc, champsim::address branch_target, bool taken, uint8_t branch_type) { // 1) グローバル履歴レジスタ群の更新 for (auto &hist : ghist_words) { hist.push_back(taken); } // 2) 学習条件の判定:誤予測または「弱い正解」のときに更新 bool prediction_correct = (taken == (last_result.yout >= THRESHOLD)); bool prediction_weak = (std::abs(last_result.yout) < theta); if (!prediction_correct || prediction_weak) { // 3) 重みテーブルの更新(パーセプトロン学習則) for (std::size_t i = 0; i < std::size(tables); i++) tables[i][last_result.indices[i]] += taken ? 1 : -1; // 4) 閾値の動的調整 adjust_threshold(prediction_correct); } }
1. グローバル履歴の更新
for (auto &hist : ghist_words) { hist.push_back(taken); }
ghist_wordsは先ほど初期化した「各テーブル対応の折り畳み履歴レジスタ群」である。
ここで分岐がtaken(true)だったかnot taken(false)だったかを、すべてのレジスタにpush_backする。
各レジスタは自身の長さ(例:3ビット、4ビット、…232ビット)に合わせて古いビットを捨て、新しいビットを折り畳みに反映する。
2. 学習の"いつ"を判断するか
bool prediction_correct = (taken == (last_result.yout >= THRESHOLD)); bool prediction_weak = (std::abs(last_result.yout) < theta); if (!prediction_correct || prediction_weak) { … }
prediction_correct:実際の結果takenと、「パーセプトロンの出力が閾値以上かどうか」(yout >= THRESHOLD)を比較して、予測が当たっていたかを判定する。prediction_weak:出力の絶対値|yout|が、動的閾値thetaより小さい=「自信が低い」正解だった場合である。
学習条件:誤予測した場合、もしくは自信の低い正解(弱い正解)の場合に重みを更新する。弱い正解にも学習をかけることで、予測境界をはっきりさせ、次回以降の自信を高める狙いがある。
3. 重みの更新(パーセプトロン学習則)
for (std::size_t i = 0; i < std::size(tables); i++) tables[i][last_result.indices[i]] += taken ? 1 : -1;
last_result.indices[i]は前回の予測時に計算した「テーブルiを参照するためのインデックス」である。tables[i][…]は8ビット幅の飽和カウンタ(重み)である。
更新ルール:
- 実際にtakenなら+1、not takenなら-1を足す。
- 飽和カウンタなので、あらかじめ決めた最大/最小値を超えないように飽和する。
これにより、誤予測ならば「正しい結果方向」に全テーブルの重みを弱め/強め、自信のなかった正解でも「もっと自信が持てるよう」重みを調整する。