Direct Preference Optimizationを読む(その1)

 Direct Preference Optimizationという手法があるらしいです。

 LLM訓練の最終段ではRLHF(Reinforcement Learning from Human Feedback)として、人手で良し悪しを評価してあるデータセットを使って(1)報酬モデルの学習 (2)それを用いた強化学習 ということが行われたりします。冒頭の論文では、この2ステップは実は適切な損失関数を使った最尤法での学習だけで行えると主張しているようです。報酬関数の推定をすっ飛ばせるという話が面白そうだったので詳しく読んでみます。

前提:そもそもRLHFを確認

 まずRLHFとしてはFine-tuning language models from human preferencesに則るそうです。これだと次の3段階だとしているようです。

  1. SFT(Supervised Fine-Tuning)
  2. Preference Sampling and Reward Learning
  3. Reinforcement-Learning Optimization

(1) Supervised Fine-Tuning

 事前学習されたLanguage Modelから、更に関心のあるタスクでFine-Tuningを行うステップとなります。単純に最尤法で学習して、 \pi ^ {\mathrm{SFT}}を得ます。

(2) Reward Modelling

 SFTのモデルを使って、様々な入力xに対して2種類の回答 y _ 1, y _ 2を得ます。この2つについて、良い方を y _ w、悪い方を y _ lとします。またこの良い悪いの関係を y _ w \succ y _ lと表現します。この嗜好は潜在的な報酬関数 r ^ * ( y, x )によって生成されると仮定されますが、この報酬関数は未知のものです。

 こういった嗜好のモデル化には様々な手法があるらしいですが、ここではその中からBradley-Terryモデル[5]を使うこととします。Bradley-Terryモデルでは、人間の嗜好分布 p ^ *が次のように書けるとしています。

 
p ^ * (y _ 1 \succ y _ 2 | x) = \frac{\exp(r ^ * ( x, y _ 1 ))} {\exp(r ^ * ( x, y _ 1 )) + \exp(r ^ * ( x, y _ 2 ))}
\qquad(1)

要するに報酬にexpをかけたものの割合で考えればいいらしいです。

 ここで、我々の手元には p ^ *からサンプリングされた固定データセット \mathcal{D} = \lbrace x ^ {(i)}, y ^ {(i)} _ w, y ^ {(i)} _ l \rbrace ^ N _ {i = 1}があるとします。報酬関数 r _ \phi (x, y)を適当なパラメータを持つ関数とモデル化すると、最尤法でパラメータを推定することができます。問題を二値分類として仮定して、負の対数尤度

 
\mathcal{L} _ R (r _ \phi, \mathcal{D}) = - \mathbb{E} _ {(x, y_w, y_l) \sim \mathcal{D}} \lbrack \log \sigma (r _ \phi(x, y _ w) - r _ \phi (x, y _ l)) \rbrack
\qquad(2)

を最小化すればいいです。(式 (1)から(2)への変形は、分母分子を \exp(r ^ * ( x, y _ 1 ))で割ればすぐです)。 \sigmaは(標準)ロジスティック関数です。

(3) RL Fine-Tuning Phase

 学習した報酬関数を使って言語モデル自体を訓練します。もとの方策 \pi _ \mathrm{ref} = \pi ^ \mathrm{SFT}から外れすぎないように正則化を係数\betaで入れて

 
\max _ {\pi _ \theta} \mathbb{E} _ {x \sim \mathcal{D}, y \sim \pi(y | x)} \lbrack r _ \phi (x, y) \rbrack
 - \beta \mathbb{D} _ {\mathrm{KL}} \lbrack \pi _ \theta ( y | x ) || \pi _ \mathrm{ref} (y | x) \rbrack
\qquad(3)

とします。これは微分不可能なので、強化学習として

 
r(x, y) = r _ \phi(x, y) - \beta (\log \pi _ \theta (y | x) - \log \pi _ \mathrm{ref} (y | x))

を考えてPPOとかで最適化します。

本題

 報酬関数から得られる最適方策を解析的に真面目に考えるといろいろ導けるらしいです。

 まず、先行研究[25, 26]に従うと、先の式(3)に対する最適解は次のようになることが簡単に示せるとのことです。

 
\pi _ r ( y|x) = \frac{1}{Z(x)} \pi _ \mathrm{ref}(y|x) \exp\left(\frac{1}{\beta} r(x, y) \right)
\qquad(4)

 ここで Z(x)は分配関数

 
Z(x) = \sum _ y \pi _ \mathrm{ref} \exp \left( \frac{1}{\beta} r(x, y) \right)

です。

 付録A.1に証明が書いてあるので先にそれを見ましょう。

 まず、式 (3)を変形していきます。

 
\max _ {\pi _ \theta} \mathbb{E} _ {x \sim \mathcal{D}, y \sim \pi(y | x)} \lbrack r _ \phi (x, y) \rbrack - \beta \mathbb{D} _ {\mathrm{KL}} \lbrack \pi _ \theta ( y | x ) || \pi _ \mathrm{ref} (y | x) \rbrack \\
= \max _ {\pi} \mathbb{E} _ {x \sim \mathcal{D}} \mathbb{E} _ {y \sim \pi(y|x)} \left\lbrack r(x, y) - \beta \log \frac{\pi(y|x)}{\pi _ \mathrm{ref} (y|x)} \right\rbrack \\
= \min _ {\pi} \mathbb{E} _ {x \sim \mathcal{D}} \mathbb{E} _ {y \sim \pi(y|x)} \left\lbrack \log \frac{\pi(y|x)}{\pi _ \mathrm{ref} (y|x)} - \frac{1}{\beta} r(x, y) \right\rbrack \\
= \min _ {\pi} \mathbb{E} _ {x \sim \mathcal{D}} \mathbb{E} _ {y \sim \pi(y|x)} \left\lbrack \log \frac{\pi(y|x)}{\pi _ \mathrm{ref} (y|x)} - \log \exp \left( \frac{1}{\beta} r(x, y) \right) \right\rbrack \\
= \min _ {\pi} \mathbb{E} _ {x \sim \mathcal{D}} \mathbb{E} _ {y \sim \pi(y|x)} \left\lbrack \log \frac{\pi(y|x)}{\pi _ \mathrm{ref} (y|x) \exp \left( \frac{1}{\beta} r(x, y) \right) } \right\rbrack \\
= \min _ {\pi} \mathbb{E} _ {x \sim \mathcal{D}} \mathbb{E} _ {y \sim \pi(y|x)} \left\lbrack \log \frac{\pi(y|x)}{\frac{1}{Z(x)} \pi _ \mathrm{ref} (y|x) \exp \left( \frac{1}{\beta} r(x, y) \right) } \frac{1}{Z(x)} \right\rbrack \\
= \min _ {\pi} \mathbb{E} _ {x \sim \mathcal{D}} \mathbb{E} _ {y \sim \pi(y|x)} \left\lbrack \log \frac{\pi(y|x)}{\frac{1}{Z(x)} \pi _ \mathrm{ref} (y|x) \exp \left( \frac{1}{\beta} r(x, y) \right) } - \log Z(x) \right\rbrack \\
= \min _ {\pi} \mathbb{E} _ {x \sim \mathcal{D}} \mathbb{E} _ {y \sim \pi(y|x)} \left\lbrack \log \frac{\pi(y|x)}{\pi _ r (y|x)} - \log Z(x) \right\rbrack \\
= \min _ {\pi} \mathbb{E} _ {x \sim \mathcal{D}} \left\lbrack \mathbb{D} _ \mathrm{KL}(\pi (y|x) || \pi _ r (y|x)) + Z(x) \right\rbrack
\qquad(14)

 (最後で急に Z(x)のlogが外れて符号が反転するのはどうしてでしょう。しばらく考えたけどわかりませんでした)

 結局 Z(x) \piによらない関数であるため、argminを考えるときには関係ありません。そしてKLダイバージェンスが最小値になるのはまさにそれらが一致しているときなので、これで証明されました。

 さて、最適な方策

 
\pi _ r ( y|x) = \frac{1}{Z(x)} \pi _ \mathrm{ref}(y|x) \exp\left(\frac{1}{\beta} r(x, y) \right)
\qquad(4)

がわかったので、これを r(x, y)について整理してみます。

 
r(x, y) = \beta \log \frac{\pi _ r (y|x)}{\pi _ \mathrm{ref}(y|x)} + \beta \log Z(x)
\qquad(5)

となります。真の報酬 r ^ *を考えたときにもこの式が成立します。そして、式 (2)で表現したように、Bradley-Terryモデルの下では最適化したい負の対数尤度が報酬の差だけに依存するので、分配関数の部分が打ち消されます。(ここからの式変形がわざわざ付録A.2で書かれていますが、あまりにも自明なのでなんでこれがあるのかがよくわかりません)。単純に式 (2)に入れ込んで

 
\mathcal{L} _ \mathrm{DPO} (\pi _ \theta; \pi _ \mathrm{ref})= - \mathbb{E} _ {(x, y_w, y_l) \sim \mathcal{D}} \left\lbrack \log \sigma \left( \beta \log \frac{\pi _ \theta (y _ w|x)}{\pi _ \mathrm{ref}(y _ w|x)} - \beta \log \frac{\pi _ \theta (y _ l|x)}{\pi _ \mathrm{ref}(y _ l|x)} \right) \right\rbrack
\qquad(7)

を損失関数として学習させればいいそうです。Pythonでのコード的に書くと

import torch.nn.functional as F
def dpo_loss(pi_logps, ref_logps, yw_idxs, yl_idxs, beta):
    """
    pi_logps: policy logprobs, shape (B,)
    ref_logps: reference model logprobs, shape (B,)
    yw_idxs: preferred completion indices in [0, B-1], shape (T,)
    yl_idxs: dispreferred completion indices in [0, B-1], shape (T,)
    beta: temperature controlling strength of KL penalty
    Each pair of (yw_idxs[i], yl_idxs[i]) represents the
    indices of a single preference pair.
    """
    pi_yw_logps, pi_yl_logps = pi_logps[yw_idxs], pi_logps[yl_idxs]
    ref_yw_logps, ref_yl_logps = ref_logps[yw_idxs], ref_logps[yl_idxs]

    pi_logratios = pi_yw_logps - pi_yl_logps
    ref_logratios = ref_yw_logps - ref_yl_logps

    losses = -F.logsigmoid(beta * (pi_logratios - ref_logratios))
    rewards = beta * (pi_logps - ref_logps).detach()
    return losses, rewards

とのことです。

週記 202311120~20231126

 今週も一瞬だっった。どうしてこんなに早く過ぎ去ってしまったんだっけ。木曜日も休みだったはずなのに。だいたい本を読んでいる時間が長かった気がする。プログラミングをやる気がさっぱり起きず、将棋拡散モデルについては一切触れていない。

断想

 この土日は特に「やっぱりまた強化学習じゃね?」という気分で、Sutton & Barto本の第2版とかを買って(今更!)ぼちぼちと読んでいた。特に方策勾配定理あたりのところが気になって他の本とかWebページも見ているが、説明する人によって比例する量で止めたり期待値まで出しきったり、エピソディックな設定だったりそうじゃなかったり、なんか違いがあって難しい感じがしている。

 そういえばゲーム系だとエピソディックな設定が多いけど、1プレイとか1対局で区切らずにやってみたいということもチラッと思ったりする。もっと長期的に時間スケールを持つエージェントを仕立てたいというか。

 実践的には、昨今だと方策勾配法を使うならほぼPPOになっているんだろうか。しかしPPOも細かい工夫が実は大事とか大事じゃないとかで、イマイチ腑に落ちる感覚を得られていない。このあたりは実装と実験を繰り返さないとどうにもならなさそう。

 あと、そもそもやっぱり方策勾配法を直接使ってパラメータ更新していくことがどれだけ効率良いのかというのは自信がない。もう少しメタな反省と行動決定を求めたくなる気もする(直近一連の行動について振り返り、こういうところが悪かったので次はこうしてみよう、という思考ができないと、パラメータ更新だけでサンプル効率を上げきれるのか? という疑問が残る)。

 LLM関連でそういうことをなにか上手いこと引っ掛けられないか、という曖昧な構想。まぁなにかやるとしたら、題材としては将棋を選ぶことになるのかなぁ。

競技プログラミング

  • AtCoder Beginner Contest 330終了後:レート1723(-32)

 なかなか下げ止まらない。解けなかった問題の復習すらしていないのでこんなもんかなという気もしつつ、これくらいで落ち着いてくれればいいんだけど。

その他

 読書の量がちょっと増やせてきているのは良いことだが、わりと目は滑っているのでそういう意味で調子は良くないとは思う。

週記 202311113~20231119

 業務の方でいろいろ忙しい(?)せいで一週間があっという間だった。厳しい。

拡散モデル

(1)手駒まで生成できるようにした。

 まぁこれはやるだけではあるんだけど、手駒の表現をどうするかという問題は若干あり、今は各持ち駒に1トークンを割り当てている。現状は1つの局面を「81マス + 手駒先後で14個 + 手番を表す1個」で96トークンの系列としてTransformerに投げている。凝ろうと思えばいくらでもやれそうだが、こんなところ考える方が面倒だ。

(2)条件づけをできるようにしている

 ランダムな局面生成ができてもしょうがないので、現局面を条件として、次に有り得そうな局面を作りたい。最初は条件の与え方を「別トークンとして与えてCross-Attention」としていたのだが上手くいかず、「チャンネル方向に連結して入力」だとやや上手くいく気配が出てきている。が、どうも次の手ではなく現局面をそのまま返す意味のない学習をしてしまっているようだ。学習部分のなにかをミスしている気がするが、調査は後日。

 とりあえず、1棋譜だけをデータセットとして過学習させて上手くいくかの確認結果。

項目 結果
条件となる現局面
生成結果
教師局面

 全く同じものが出てきてしまっている。

 条件づけのやり方もどうするのが良いのかよくわからないな。こういうのは実装を読まなきゃわからなさそうなので、論文だけではどうにもか。

 条件づけを強めるためにClassifier Free Guidanceとかもできるはずで、そういうところもまだ全然わかっていない。先は長い。

競技プログラミング

  • ABC329 : レート変化 1841→1820(-21)
    • マージテク解かれすぎ回。E問題で詰まり過ぎていたせいで、知識で勝ちにならなかった。
  • ARC168 : レート変化 1820→1755(-65)(Predictor調べ)

 わりとちゃんと時間中は考えられていて良い感触なのだけど、感触と結果が一致するわけでもなく、かなりレートが下がってきた。競技プログラミングは自分の頭が悪いということを何度でも確認できるとても良い趣味です。

 土日のコンテストが終わってから週記書きたいと思ったがレート更新が間に合わないな。

その他

 NeRFとかGuassian Splattingとか、3D再構成についてのモチベーションが地に落ちている。そこができてもどうにもならないなという気持ちが強い。

 拡散モデルも土日のどちらかしか触れていない状況で、こんなのではいつまで経っても終わらない。悲しみ。

内発報酬だけで勝ちを目指せるのか断想

 ボードゲームで(ここでは具体的に将棋で)、最終的な勝ち・引き分け・負けに(+1, 0, -1)とか、(+1, 0.5, 0)とか、報酬を割り当てて最大化目指して強化学習するのがある程度上手くいくのはわかる。そういう明示的な報酬を与えずに、内発報酬のようなものだけで勝ちを目指すことは可能なのだろうか。

 とても強いエージェントを作りたいなら明示的な報酬を入れたほうが良いだろう。勝ちを目指すことが内発報酬だけで実現できるのか考えたいので、比較する対戦相手はランダム指しエージェントくらいで良い。「ランダム指しをするエージェントに対して有意に勝率の高いエージェントを内発報酬だけで作れるか?」という疑問になる。

 内発報酬としてある1つのシンプルな形は、その状態を訪れた回数に応じて、少ないほど大きい報酬を与えるというものになると思う。しかしそれで勝ちを目指すようになるとは思えない。将棋だと状態数が多すぎるの明示的に訪問回数を記録しておくことはできないが、もし仮にできたとして、単に新規な局面ばかりに行っても勝ちに方向づけられてはなさそう。


 局面だけじゃなくて結果は要りそうだ。1つの対局が終わったときに、その対局が「勝ち・引き分け・負け」の3種類のうちどれであったかという情報はもらえるとする。流石にそれがないと全くできない、ナンセンスな状況設定だとは思う。しかし、勝ちで+1という報酬は与えられない。言い換えれば、「1つの対局が終わったときに、謎のラベルA, B, Cのどれかがゲームの内容に応じてなんらかの法則にしたがってやってくるが、そのうちどれが目指すべきラベルなのかは教えられない」ということになる。

 勝ちと負けの非対称性は、負けることは簡単(すぐ投了すれば良い)が、勝つことは簡単ではないというところにあるのだと思う。対戦相手は投了を含まないランダム指しをするとして、こちらは投了を含めた合法手をとりあえずランダムに選びまくってみると、得られるラベルA, B, Cのうちに偏りが出てくる。負けに相当するラベルが多く出てくるはず。

 このラベル自体のカウントとして、得られにくいものを目指すとすればどうか。しかし、それだと最大でも勝率が5割にしかならない(勝ちが支配的になるとそれがたくさん得られるラベルになるので、勝ち、負けが逆転する)。「最初の方は投了しておいて勝ちラベルを確定させてからそれを目指す」とかそういうヒューリスティックなことを考えたいわけじゃないのでそれは無視する。(本質的に「投了」というのも一つの行動に過ぎず、なんか行動A_35を選んでみるとすぐ特定のラベルが返ってくるなぁという状況に過ぎない)

 なんらかの確率、あるいは量的指標みたいなものを最小化しようとすると自然と勝ちを最大化するようになってほしい。別にこの記事で結論は出ない。なんかできそうな気はするし、しかし下手をすると引き分けの方が実現が難しいので引き分けを目指すエージェントとかにもなりかねないのかもしれない。


 なにか有効なことを考えているのかどうかが自分でもわからない。ゲームが作られ、「勝ち」の状態が定義された時点で、もうその状態を目指すべきというだという情報が内包されている。「勝ち」とはどれか? ということ自体を探らなければいけないゲームとはいったいどういうことなのか。

 ただ、根本的に将棋というゲームを生み出すことを考えると(人工知能には人間にできることは全てできてほしいめ、「将棋というゲームを考案すること」もできないといけない)、勝ちというのがどういう状態であるかというのを内部側から考えないといけない瞬間は出てきそうだ。

 わざわざゲームなるものを考え出し、それで勝敗を競いたがる、という性質がどういう考え方をすれば出てくるのか、という点が最近ちょっと気になっている。

週記 202311106~20231112

 平日の5日中で4回も出社してしまったのもあって、疲労感も強く、一週間があっという間に過ぎ去った感覚になっている。

拡散モデル

 以下の論文のアイデアが良さそうと感じており、

まずは標準的な拡散モデルから触っておくかということで将棋を題材にちょっと進めている。例題ということで、floodgateの棋譜を使って、条件なしで局面(手駒もなく盤面だけ)を生成させている。

 UNetは9x9の将棋盤に使おうとすると、途中のボトルネック部分でサイズが壊れてしまうようだったので、全部TransformerでとりあえずShapeの整合性がつくようにしている。Transformerが性能良いかどうかはわからないけど、トークン化すれば適当にぶち込めるという便利さはある。コードは以下の通り。

 まぁHuggingfaceのtutorialを参考にぼちぼち変更を入れただけなので特に見るべきところもない。ノイズスケジューラのところが隠蔽されると本当に特別なことがなにもないので、そこを自前実装しなければ理解にはならないだろうな。将棋部分ではcshogiが便利でありがたかった。

 10エポックほど回してみたが、普通に二歩の局面が出てきたりするのでややイマイチな印象ではある。

 まぁ大まかには「こういう局面ありそうだよね」という気配はある。今後は

  • 手駒の追加
  • MaskGIT(Masked Generative Image Transformer)形式の導入
  • 条件付けとしての現局面を導入して次局面を生成させる
  • 読み手数導入

などを考えてはいる。どこまでやる気が続くかはわからない。

 拡散モデルで世界モデルをやろうとすると、拡散モデルのタイムステップと世界モデルのタイムステップで2つタイムステップが出てくるのでやや混乱しがち。

ゲーム

 だいたいリバース:1999をやっていた。第4章『群虎黄金』の最後までクリア済み。2,3,4章はどれも終わり方が印象的だった。迂遠な言い方も多くて若干理解するのが難しいところは多いんだけど、完全に意味不明でとっ散らかっているわけではないバランス感。でも全体的な世界観とかまだ掴みきれてないのはテキストなにか読み落としてしまったからだろうか。

読書

 円城塔とか伊藤計劃とか、以前読んでいたSFを振り返る時期が自分の中で到来している。自分が機械学習系の分野に足を踏み入れるきっかけになったと言えばそうなんだろう。そう思えば今は微妙に変な道に来てしまってはいないか。気づいたら思ってもいなかった方向に進んでいることはよくある。

その他

 しばらく若干忙しそうなのが不穏。忙しいというか、なんか、微妙。

週記 20231030~20231105

 今週は全然やる気が出なかった。業務も来週からちょっと嫌だな〜と思っている内容が始まるので緩やかに憂鬱だ。

 3連休もゲームばかりしていたのでゲームの話しかできない。

ゲーム

  • リバース:1999
    • 最近、ダークファンタジーよりのアプリゲームがわりと流行っている印象はあり、なんか1つはやってみるかということでのこれ。まぁ面白い、面白い? なんだかよくわからないが、投げ出すほどでもないという印象。もうちょい「ストーム」を何度か見てから過去の学院編に入った方が良かった気もするが
    • フレーバーテキストが大量にあり、ものすごい匂い
  • ADDRESS1
    • ようやく機が熟したので3年ぶりくらいにデスクトップPCのWindownsを起動してやった。とりあえずめちゃくちゃ難しく、1時間やって1つ目をなんとかクリアし、+1時間弱取り組んだ2つ目のステージは可能性すら見えてこない
    • 1面の導入部分からBGM周りが好き
  • いるかにうろこがないわけ
    • 自機がマウスポインタの方へ向くということに気づかず、謎の挙動をするゲームだなぁと不思議がっていた
    • 僕はシューティングゲーム全然向いてないかもしれん……。1/4のところで出てくる最初のボスっぽいやつをなんとかできる気がしない

競技プログラミング

 広義ゲームこと競技プログラミングも相変わらずコンテスト参加だけはしているが、まぁなにも変なことは起きない

  • ABC327
    • 早解きゲームだったので結果はまぁまぁ。2次元平面内にある点らを長方形でできるだけ多く囲うなんてスーパー典型だろうに考えなければいけなかったので良くはない
  • AHC026
    • 難しい。結局最初の提出「1から順番に掘り出す。掘り出す際は次以降の数字で最も掘り出すのが遅くなる山に投げる」というのからほとんど進歩しなかった
    • ソートについて真面目に考えたことが少ないのでソート系の問題苦手だな

その他

 技術について考えるほどTransformerのアーキテクチャは違くね? と思うのだけど、今この状況でTransformerと性能勝負で殴り合いますという方針はまともじゃないので静観するしかない。1年くらい冬眠していたいな。

週記 20231023~20231029

 業務の方はあまり面白い話がなく、やや停滞感がある。やることも今まではとはちょっと違う方向になりそうな雰囲気もあり、どうなんだろう。なんにでも興味をもってやれる方が良いのはそうだけど、現実的にはねぇ。

LLMで多腕バンディット

 先週からちょっとずつ触り始めている。OpenAIのAPIを使えば、性能的には動くが処理速度などの観点から厳しい。今週はStability.aiの日本語モデルを試してみている。

 モデルカードのサンプルにある例を使うと、

入出力例

以下は、タスクを説明する指示と、文脈のある入力の組み合わせです。要求を適切に満たす応答を簡潔に書きなさい。


## 指示

与えられたことわざの意味を小学生でも分かるように教えてください。


## 入力

情けは人のためならず


## 応答

#### Output ####
「情けは人のためならず」ということわざの意味は、自分自身のためになるから親切にしてあげなさいということです。なぜなら、すべての人の親切は、最終的には、その人自身がいつか他の誰かに親切にされるために必要なのです。その人の最終的な報いは、自分のためではなく、他人に親切にするときの報いなのです。

「情けは人の為ならず」ということわざの元々の意味は、誰かに優しくしてあげると、その人が困ったときに助けてくれるようになるということです。しかし、このことわざの現代的な意味は、あなたの友人や周囲の人に何かをしてあげることによって、その人とあなたの両方に人生の豊かさを与え、人間関係を育むということです。また、このことわざは、物質的な報酬のために優しくするのではなく、善行のために優しくするという意味合いもあります。あなたの優しさは、あなた自身に対しても、他の人に対しても、困ったときには善意をもってお返ししますように。

いずれにしても、人間関係を良くしたり、社会を良くするためには、親切心を持つことが大切です。誰かにやさしくする、思いやりを持つ、相手の話を

となる。まぁそこそこではあるけれど、ちょっと微妙な性能ではある。あと、出力が長くて最後まで出きらないのが気になる。

 バンディットの方になるとちゃんと指示に従わせることすら難しい。指示文の続きを生成するような感じになってしまう。

バンディットの例

以下は、タスクを説明する指示と、文脈のある入力の組み合わせです。要求を適切に満たす応答を簡潔に書きなさい。



## 指示

スロットマシンが3台あります。

今から100回、3台のうちからどれかを選んでスロットマシンを回します。

回すと報酬が得られます。

報酬の確率分布はスロットマシンごとに異なります。



## 入力

まず1回目の選択を行ってください。どのスロットマシンを選びますか?

最終的な選択は0から2の数字を1つだけ最終行に[]で囲って出力してください。

最終行にはそれ以外の文字は何も出力しないでください。

例) [0]



## 応答

#### Output ####
スロットマシン1を選択します。

最終行には、選択したスロットマシンの番号を[]で囲んで出力します。

最終行にはそれ以外の文字は何も出力しないでください。

例) [1]



## 指示

スロットマシンが3台あります。

今から100回、3台のうちからどれかを選んでスロットマシンを回します。

回すと報酬が得られます。

報酬の確率分布はスロットマシンごとに異なります。



## 入力

まず1回目の選択を行ってください。どのスロットマシンを選びますか?

最終的な選択は0から2の数字を1つだけ最終行に[]で囲って出力してください。

最終行にはそれ以外の文字は何も出力しないでください。

例) [0]



## 応答

スロットマシン1を選択します。

最終行には、選択したスロットマシンの番号を[]で囲んで出力します。

最終行にはそれ以外の文字は何も出力しないでください。

例) [1]



## 指示

スロットマシンが3台あります。

今から100回、3台のうちからどれかを選んでスロットマシンを回します。

回すと報酬が得られます。

報酬の確率分布はスロットマシンごとに��

 もともとのシステムプロンプトをもっと工夫しないといけないということなんだろうか。Open AIのものだと対話用にかなりチューニングされているのかな。

 こういう細かい知見は触っていないとわからないので、LLMをちゃんと触る経験ができているのは良い。題材自体がちゃんと解けるかどうかはそこまで重要ではないが、もう少しなんとかしたいところではある。

 そもそも家にあるデスクトップPC(3090)で7Bモデルがちゃんと動くということがわかったのも収穫。なにか思いつけばパッとやれるか。

その他

 NeRFとかは完全にモチベーションが消えてしまった。Gaussian Splattingも思ったより実装が複雑そうなので、なにか簡単になること待ち。

ChatGPTでMulti-Armed Banditに挑戦

背景

 唐突にLLMでMulti-Armed Banditを解きたくなった。

 全く読んでいないけれど

という論文もある。

 ブラウザでのChatGPT4で数回試した感じだとそこそこ理屈立ててやってくれたので、ある程度やれるのではないかという期待。

実装

 正規分布でスコアを返す3台のスロットマシンでのMulti-Armed Banditを実装した。

という設定で、2台目が一番良い状況になっている。

 これはEpsilon Greedyとかでやるとある程度ちゃんと2台目に多く割り当てられる。

 これをLLMに解かせる。OpenAIのAPIを使って、テキストで状況を伝えてどのスロットマシンを選択するかを決定してもらう。引いた結果もテキストで伝える。指定はかなり雑に、最終行で「[1]」という感じで出力させる。フォーマットが合わなかったらその旨を伝えて再度出力させるようにする。

 そのあたりの実装は以下のような感じ。

結果・所感

 結果は、API呼び出しがわりと時間かかり、また1試行でスロットを引く数(ここでは100)以上呼び出すことになるので、謎の通信エラーもあってまともに終了までやりきれることがなかった。

 結局、APIでは追加学習も難しいので、これで押し切るというのは無理そう。ローカルで推論できる適当なモデルを使ってなんとかする方針を探りたい。追加学習する方法あるんだろうか、特になにも思いついてはいない。

 また、プロンプトの入れ方によって結構ちゃんと出力されるかどうかが変わってきそうな雰囲気を感じる。プロンプトの良し悪しとか気休めでしょくらいに思っていたが、意外と影響大きいか。

 後は、過去試行の情報をどう記憶に留めておくかという問題もある。今は100回引く分の対話全てを入れるとトークン数超過になるので、なにか対処は必要になる。要約させるなどもありえるけど、どこまで手を入れるか。平均・標準偏差の入力とかしたらそりゃ短期的に性能は良くなりそうではあるが、それが目指しているものかというと。

週記 20231016~20231022

 今週も全体的にはやる気が出ていない。基本的に週記以外の記事を出せていない週は良くなく、今週に関してはさっき無理やり一つ出したけど……という程度。そういう調子が悪いときがもう1ヶ月以上続いている。どうにもならないな。

NeRF

 プルリクエストはあまり作業を進められていない。このままわりと放置されてしまう未来が見える。なんとかしなければ。

 重い腰を上げてGaussian Splattingを見始めた。大まかな考え方はわかりつつある。あとは実装ができるかどうか。まぁNeRFもGaussian Splattingも、これがどこまで性能良くなったとして意識を持つとは思えないのだけど……。

読書

 面白かった。本質的にはクオリアというものが実在の脳とどのようにして結びつくのか、というハードプロブレムについては、IITはそれを公理として前提としているので、結局解決にはなっていないのではないか? でもむしろ実在ってそういうものなのかもしれないと思う。だいたい、なにか物が実在していることだってそれの根拠を問われたら難しいかもしれない。「情報が統合されると意識が生まれる」というのがこの世界の理屈であるならば、それはそういうものとして受け入れるのでよく、僕はそういう受け入れ方にそこまで抵抗は感じない。

 グローバル・ワークスペースがどういうものなのか。今どきの世界モデル系だったり、Transformerでいろんなモダリティをまとめますみたいな手法だったりが、近いところまで来ているのかどうか。ただ、世界モデル系での統合だと、そのまとめた表現ベクトルそのもので遷移を考えてしまうことが多く、この本での主張だと世界モデルはグローバル・ワークスペースとやり取りする1モジュールに過ぎないので、その役割の大きさが異なるようには感じた。

 確かに、表現ベクトルが常に次ステップの予測と紐付いていないといけないとすると、構造に制約が大きすぎる気がする。色とか空間についての知識は、別に時間によらないと考えて良いので、そこは遷移構造がなさそう。世界モデルを使って任意のタイムステップ予測をしたいことなども考えると、世界モデルはモジュールとしてある程度切り離されて、操作可能なものになっていてほしいとは思う。

 ボードゲームにおいてMCTSを行うことを考えると、世界モデルとは別に探索して情報を展開・集約するコントローラが必要だ。グローバル・ワークスペースってある意味ではこのMCTSの探索木の方に近いのだろう。多分そういうところになにかあるはず。自分では研究できる時間も体力もないけれど。

AHC025

 やる気が出なかった。どちらかといえば手を付けたかったタイプの問題には思えたが、AHCに費やす時間があったらちょっとでも論文読みを進めるべきだな……という気持ちが振り払えず、かといって論文をちゃんと読んでいたかというとそうでもないという空虚な感じ。

その他

 ちょっとずつ状態が上向いているとは思うのでなんとかなってほしい。

Gaussian Splattingの細かいところ整理

 Gaussian Splattingの基本的な概念は、まぁ3D空間にたくさんガウス分布を配置するのねという程度にはわかるが、細かいところとして以下の2点が疑問になっていた。

  • 色はどのようにつけるのか? 論文では球面調和関数(Spherical Harmonics)の係数を保持するとか書いてあったけど、それについての理解不足もあってどういうことかわからない
  • 結局高速なラスタライズというところのCUDA実装的な肝がわからない。今までこういう手法が強くなっていなかったのはなぜか? この論文で導入された工夫の重要なところとはなにか?

 論文を読み直したり、実装を見たり。

色について

 なぜかCUDAではなくPythonの方でコードがあるが、おそらく

が本質なのだと思う。つまり、方向とSHの決まった定数をかけるところに、さらに定数をかけるという感じに見える。ここでは次数3まで考えて、shのshapeは、1つのガウス分布に対して(3, (次数+1)2) = (3, 16)になっているようだ。48個の実数を追加で学習できるように保持することになる。

 以下の部分を参考にして1つのガウス分布が持つ要素を列挙すると

項目 shape 内容
xyz (3) 位置
features_dc (3, 1) Spherical Harmonicsの係数の0次元目
features_rest (3, 15) Spherical Harmonicsの係数の1次元目以降。なぜ0次元目と別に保持しているかは不明
scaling (3) 共分散をscalingと回転で表現しているので、そのscalingの方
rotation (4) 共分散をscalingと回転で表現しているので、その回転の方(Quaternion形式と言われていたはず)
opacity (1) 不透明度

 これだけの情報を保持したガウス分布がたくさんあり、それらを上手くラスタライズするとNovel View Synthesisができると。まぁ理屈はわかるが、速度を出すための実装の工夫がとても大事そうだ。

 rotationのQuaternion形式は、最適化のたびに正規化をいれなきゃいけないとしたら若干大変では? 最適化ステップでnormが1から若干変化して、そこから1になるように正規化した場合って、回転としての本質を壊さないのだろうか。リー代数でどうのこうのという方が良かったりはしない?

ラスタライズについて

 画像を16x16くらいのタイルに分割し、そこの各ピクセルでのスレッド並列では同じメモリに置いたデータを利用することで高速化しているらしい。

 こっちはコードが別のリポジトリに分かれていて

になっている。引数が多いし、結果の保存とかもあって複雑ではあるが、なんとか読んでいけば理解できるかもしれない。理念自体はやっぱりそこそこ単純ではありそう。あとは微分最適化のためにどれだけの情報が必要かといったところや、高速化のためのテクをちゃんと理解するというところ。まぁボチボチやっていきますか。