😎

大規模計算時代におけるパラメータ推定自動化の歴史

に公開

はじめに

これはポエムに近い。ので、技術的にすぐ使える情報を求めている人には合わない。しかし、技術的な教養とか文化みたいなものを使って文章を楽しむ分には良い記事だと思う。

テーマはタイトルの通りであるが、特にLLMのコンテキスト適応方法がハンドチューニングからオートマチック方面へ本格的に変わりつつある状況を思い浮かべてつけたタイトルだ。本記事のキーワードとしてはMIPROv2GEPAなどの最近のプロンプト最適化手法から、コンテキスト適応自体をAgenticに実施するACEなどが挙げられる。これらの出現と、伝統的な機械学習、はたまた統計推論にまで遡り、計算機を利用したパラメータ調整技術についてみてみたいと思う。

GEPAとACE

これはそれなりに新しい手法だ。これらが実際に未来永劫残るかは分からないが、舵取りとしては確実に方向性を与えたと自分は考えている。重要な観点としては既に述べた通り、ハンドチューニングや決め打ちだったものが実データ(実情)に合わせて調整されるようになったところだ。

GEPA

GEPAの方に至ってはDSPyという非常に取り回しがしやすいライブラリで実装されているため、すぐに試してみることができる。OpenAIの安いモデルやオープンウェイトモデルでも十分に違いを感じられるはずだ。要点はLLMへの入力と、上手くいった出力のセットを利用してシステムプロンプト相当のメタなインストラクションを最適化で求めようというものである。
人手で作りこんだり、より上位のLLMにプロンプトを書かせてみるということは皆やっていることだと思うが、これらはモデルが変わるとやり直しになる。上位のLLMが個々のモデルに応じて良いシステムプロンプトを個別チューニングしてくれるかも怪しい(おそらくユニバーサルにまともな無難なプロンプトが出るだろう)。
GEPAでは活用するLLMを定めて、そのLLMの入出力が良くなるようなシステムプロンプトを最適化で求める。そしてその最適化手法自体は比較的軽い計算であるので、同じ手法を同じデータセットで、異なるLLMに使いまわせる。 これを持って、プロンプトエンジニアリングをプログラムに落とし込んだと述べている(DSPy)。

https://zenn.dev/cybernetics/articles/39fb763aca746c

ACE

ACEの方に関しては、外部メモリと自己反省、記録すべき内容の精査を行うことでプロンプト含む一連のAgenticな振舞のコンテキストを継続的に改善していく。Serenaのように外部メモリを持つだけでも十分にClaude Codeの使い心地が良くなったのを自分は体験している(Serenaはその他、検索の工夫もあるのだが、それは一旦置いておく)。なので、それに工夫を盛り込みましたというこの方針は、(細かい手段がベストかはおいておくとして)今後も発展を続けるだろうと思う。
ACEでは改善対象がシステムプロンプト(LLMにとっての初期状態)のみならず、途中経過の出力やツール呼び出しまで、一連の操作を含む。 改善対象はGEPAより広いが、その代わりGEPAほど凝っている感じではない。というのもACEは推論時に動き続けるオンライン型で、GEPAはデータを集めたバッチ処理をするオフライン型であるからだ。通常、同じものだけを最適化対象にしたときは、オンライン型とオフライン型では、オフライン型の方が安定して性能を出すことが多い(ちなみに僕は、ミニバッチ学習をオンライン学習とは言わないタイプの人間だ。ここではオンラインかオフラインかは、今まさにデータを推論して本番環境で動かしながらパラメータの調整も行っているか?で分類している)。

もしもACEのようなオンライン手法が最高性能を常に引き出すのであれば、オフライン型の手法は淘汰されうるが、おそらく当面は両社合わせ技になると思われる。ともわれ、初期システムプロンプトをGEPAで、運用時の改善をACEで… のような仕組みができたら、それはもう色々な人が幸せになるだろう。(そう簡単にはいかないだろうが)

https://zenn.dev/cybernetics/articles/c0115ee1a01dd5

主張

言いたいのは、何事も0にはならないことは認めたうえで、それでも人間は手作業を必ず自動化していく方向に向かうだろうということである。そして、その火ぶたは切って落とされており、実際にGEPAは実運用で利用している企業も出てきているようである。

まだ確信は持てない状況であるにしても、これまでにも自動化方面に舵を取り成果を上げてきた歴史があるので、それらを簡単に紹介しよう。

特徴量エンジニアリングと深層学習

特徴量エンジニアリング+機械学習モデル

特徴量エンジニアリングを用いる手法では、多くの場合下記のような構成となる。

特徴関数を構成し、データ \mathbf x を特徴量 \mathbf z に変換する。数式で書くと下記のような形式になる。

\mathbf z = \phi(\mathbf x)

このとき関数 \phi(\cdot) はデータ\mathbf xの特性を人間が調べ上げ、手で設計する。変数同士の割り算を使ったり欠測ラベルを作り出したりも含まれる。特徴量エンジニアリングを実施したら、機械学習モデル f_\theta(\cdot) を選ぶ。これはLightGBMかもしれないし、SVMかもしれないし、ロジスティクス回帰モデルかもしれない。特徴量を食ってラベルを返す関数 \mathbf y = f_\theta(\mathbf z)だ。これをデータから出力までのパイプラインをつなげてみると

\mathbf y = f_\theta(\mathbf z) = f_\theta (\phi(\mathbf x))

という形式になる。一番外側の関数 f の具体的な形状を決める \theta のみが学習対象だ。

実はカーネル法を用いたSVMやGPなどは、内部的に特徴関数 \phi(\cdot) をデータから大量に作り上げる仕組みがある。 理屈上は無限次元に飛ばして、無限次元の空間で線形結合をして分類や回帰を行う。無限次元での線形は、有限次元では非線形に見える。なので特徴量でデータを非線形変換して作るようなことを明示的にやらなくても、「表現論」的にはカーネル法で特徴量の学習は包含される。(ただし解釈性は皆無である)

深層学習

知っての通り、深層学習では下記のパイプラインを

\mathbf y = f_\theta(\mathbf z) = f_\theta (\phi(\mathbf x))

下記のように書き換えてみる。違いは、特徴関数にパラメータ \eta が付与されている点だ。

\mathbf y = f_\theta(\mathbf z) = f_\theta (\phi_\eta(\mathbf x))

外側のf_\theta には大抵、ロジスティック回帰モデルや線形回帰モデル、ソフトマックス回帰モデルがくっついている。この部分はこれまでとそんなに変わらない。では内側の特徴関数はどんなものになっているのかというと、最もプリミティブなものはアフィン変換と活性化関数を組み合わせたものだ。

\phi_\eta(\mathbf x) = \mathrm {ReLU}(\mathbf {Wx} + \mathbf b)

これはもっと多重になっていても良い。

\phi_\eta(\mathbf x) = \mathrm{ReLU} (\mathbf W_2 (\mathrm {ReLU}(\mathbf {W_1x} + \mathbf b_1)) + \mathbf b_2 )

これは多層パーセプトロンと呼ばれるニューラルネット初期の形式だ。今でもFNNと略されているコンポーネントはこれのことを指すことが多い。活性化関数や層数はまちまちだが。

要は、最終層を線形回帰やロジスティック回帰などの伝統的な回帰・分類手法で構えて置き、そこに至るまでの特徴作りをそれまでの中間層でやり切ろうという仕組みになっている。すでに述べたが、カーネル法も同じことをやっている。カーネル法は無限次元で1層だけ、圧倒的な表現力を持つ変換をかませている。一方で深層学習は、1層1層の表現力は乏しいがそれを多数繰り返すことで全体として高い表現力を持つ。

現代では深層という名に恥じないくらい特徴関数相当の部分が複雑怪奇になっている。個々の手法を個別に説明しだすときりがないほどにだ。細かい(本質的でない?)工夫もこれまでの幾度となく繰り返されてきた。その結果、一つの到達点として知られているコンポーネントがTransFormerなのである。これがどういうものなのかは説明しないが、キーワードとしてはAttensionとFNN、そしてSkip Connectionを挙げておく。

深層学習の実態

あらゆる手法に深層学習が使われるようになったかというと、実はそうでもない。テーブルデータや物理特性の強いデータに対してはそれぞれ特徴量エンジニアリングを実施し、Gradient Boostingや物理的なグレーボックスモデリングが今でも使われている。

深層学習が強いのは、1.データが高次元で、2.その部分空間に重要な項目が埋め込まれており、3.部分空間から情報を取り出すときに滑らかさが場所ごとに変わるような関数が必要な時だ。 これらをハンドチューニング関数で実施できるなら深層学習は要らない。だが、画像(これは高次元)のようにすべてのピクセルが重要なわけではない(部分空間に重要な項目がある)が領域を見るのか輪郭を見るのか色を見るのかによって必要な解像度や領域が変わる(情報の滑らかさや取り出し方が変わる)データにはめっぽう強かった。これが世の中に普及し始めたのはちょうど10年ちょっと前である。

音声や言語もどうやらそのたぐいであったことが後々にわかってきて、今は言語モデル大流行の時代である。他にも囲碁などのようなゲームの空間でも良い手筋の判断を深層モデルにさせるのが良いことが分かった。結果的に、勝ち負けだけをシグナルに深層モデルにゲーム中の手筋の評価を強化学習させる仕組みが人間(プロ棋士)の判断を上回り、実際の対局ではAIが最強という状況となった。更に現在はPhysical AIという名のもと物理的な計測値を得る時系列センサーデータおよび時系列指令値の生成にも深層学習は使われ始めている。

ここで重要なのは、人間がハンドチューニングを諦める(これは経済的な観点も含まれるだろう)ような領域では特徴量エンジニアリングを自動化した深層学習は確かに大きな進展をもたらしたということである。

もちろん度合いはある。何を特徴量エンジニアリングと呼ぶかは甚だ怪しく、例えば我々は既に良いカメラを持っているので生画像を突っ込めてはいるのだが、実は日々ハードウェア側がデータを送信する前に電子回路で様々なフィルタリングをしていたり、そもそも物理層で質の良い情報を取ろうと努力しているのであって、それは特徴量エンジニアリングを誰かがしてくれているともいえる。そういうことを誰かがしてくれていない領域では、深層学習を使う分野とて、データに対して何らかのハンドチューニングが入ることはあるだろう。だいたい、自然言語はトークナイザーで程よく良い感じの区切りにしているのを特徴量エンジニアリングをしていると呼ぼうと思えば呼べる。

統計的推測

更に時代をさかのぼろう。
かつて、データから平均や分散を言い当てる関数を作ろうという試みがあった。例えばデータが5個あって、平均を求める式は当たり前のように下記が使われる。

\hat \mu = \rm {mean} (x_1,x_2,x_3,x_4,x_5) = \frac{1}{5} (x_1+x_2+x_3+x_4+x_5)

このような具体的な計算式を「推定関数」と呼ぶ。この推定関数は背後にあるであろう平均値をなかなかに良く言い当てる関数になっている。しかしどうだろう、5個のデータがあっても

\hat \mu = \rm {mean} (x_1,x_3,x_5) = \frac{1}{5} (x_1+ x_3+ x_5)

としても平均値は求まりそうだ。そもそも5個しか持ってないから、5個で計算してみただけで本来はもっとたくさんデータを取れたかもしれない。平均値を求めるに当たってどのデータを何個使うかはいかにも憑依的に見える。とはいえ、これは3個か5個かなら5個の方が信頼できそうである。実際にそれは標準誤差という言葉でまとめられている。

ここで意識してほしいのは、推定関数は作っているものであるということだ。

「良い推定関数」の作成

平均の推定関数が登場したあと、人類はデータの散らばり具合、つまり分散を知りたくなった。すると次のような推定関数が考案される。データはN個としてしまおう。

\hat\sigma ^2 = \frac{1}{n} \sum_{i=1}^n (x_i - \hat{\mu})^2

「平均からの二乗でのズレを、更に平均してみた」という式だ。これで上手く推定できそうである。ところが、これがどうも「真の分散」より少し小さめに出がちだと分かる。そこで今度は

\hat{\sigma}^2=\frac{1}{n-1}\sum_{i=1}^n (x_i - \hat{\mu})^2

という式が現れる。これがいわゆる不偏分散だ。これは同じような実験データを集めて推定をする試みを繰り返すと、平均的に真の分散とズレませんよ、というやつだ。これはよさそうだということで、そのような性質を不偏推定量と名付けた。

しかし一方で、データ数が無限に大きくなったときに1回だけ推定を行うというケースでは、上記の推定量は少しずれが生じていた。むしろ最初のナイーブなNで割る式の方がデータが多いときの一発勝負には強いという結果なのである。このような推定量を一致推定量という。

つまり「どの性質を“良さ”とみなすか」は人間が決めているのである。グローバルに良いといえる推定量は実は一般的には定まっていない。

  1. 何を“良い”推定量と呼ぶかを人間が決める
  2. その基準(不偏性・一致性・分散の小ささなど)を満たすように手で推定関数を作る
  3. 数式をいじくり回してその性質を証明する

つまり、ここでも設計者(統計学者)が推定関数エンジニアリングを頑張っていたというわけだ。持っていてほしい性質に合わせて推定関数をハンドチューニングできるのは、かなり数学的操作に長けた一部の人間だけであった。

自動推定の登場「最尤推定」

しかし、やがてこの構図を根元からひっくり返す発想が現れる。それが**最尤推定(MLE)**だ。
最尤推定では「良い性質から推定関数を作る」というプロセスそのものを放棄する。代わりに次のような手続きを規定した。

  • ある確率モデルP(X \mid \theta)を仮定する(例:ガウス分布)
  • 観測データがそのモデルから出たと仮定して“すべてのデータの同時生成確率が最も高くなるように”パラメータを最適化で求める
\argmax_\theta \prod _ i P(X_i\mid\theta)

つまり、推定対象のパラメータ \theta をデータを使い最適化問題で直接決めるというわけだ。すると、最適化の解がそのまま推定値になる。推定値を返す推定関数を数式で事前に書き下さなくてもよいし、最適化問題を形式的に解いて閉形式を作っておいても良い。重要なのは推定関数およびその性質は後からついてくるもので、「最適化問題という手続き」から入ったのである。これは自動化以外の何物でもない。

しかも、驚くことにこの方法で得られる推定量は「漸近的に正規分布になる」「情報量に対して良い性質を持つ」など、事後的に理論的な保証がついてくるケースが多かった。もちろんあらゆる分布で絶対にベストだとは限らないが、ある程度の種類の現実的な分布に対して“データが多ければだいたい良い推定量になる”というところまで来ていた。データや分布ごとに最高の推定関数をハンドチューニングすることに対して圧倒的に使いやすい。 結果として最尤推定は統計推定の主流になっていった。

最尤推定はパラメータが識別不能(同じ確率を返す複数の別のパラメータの組が存在する)などのケースで上手くいかない。こういうのを正則でないと呼ぶ。正則でない状況では最尤推定を後付け的に理論保証した途中式が破綻することが知られている。またそうでないにしても予測バリアンスが大きくなる(過剰適合する)ことも知られており、推定量の性質を後付けにした結果、見逃されてしまったこともたくさんあったりはする。これらは、正則化やベイズ推論の枠組みで更なる発展を続けている。

深層学習と最尤推定

統計的推定でもポイントは同じで、人が推定関数を手で設計するフェーズが最適化問題に吸収されたということだ。しかもこれは計算機との相性が非常に良い。Closed-form の解(紙の上で書き下せる式)を無理に追わなくても、数値最適化で解を探せばいい。

  • 解析的に微分して解けるならそれでよし
  • 解けないなら勾配法などで数値的に探索すればよし
  • 凸性があるならさらに高速
  • そうでなくてもロバストな手法が増えてきた

要するに「推定関数を先に作る必要がなくなった」という時代に突入した。実を言うと深層モデルの推定関数を作りこむなんて試みは正気の沙汰ではない。 数学お化けだけが頑張れる世界で、とても実用には間に合わない。というわけで、深層学習におけるパラメータの推定も基礎は最尤推定に基づいている(実際には加えて多数の正則化技術が用いられる)。

例えばその名残として、PyTorchの損失関数には NLLLossなるものがある。これは最尤推定のことを直接的に指している。最尤推定の最適化問題は下記だった。

\argmax_\theta \prod _ i P(X_i\mid\theta)

\logが単調増加なので

\argmax_\theta \log \{\prod _ i P(X_i\mid\theta)\}

として良いし、\log内部の掛け算は \log外部の足し算になるので

\argmax_\theta \sum_i \log\{P(X_i\mid\theta)\}

とできる。最適化問題では「最大化」よりも「最小化」で記述するという傾向があるので

\argmin_\theta \sum_i -\log\{P(X_i\mid\theta)\}

とできる。これは Negative Log Likelihood と呼ぶ。これを損失関数にしているからNLLLossなのだ。

ちなみに「最尤推定」とはとあるパラメータでの生成確率(尤度)を最大にするように最適化問題でパラメータを求める、という意味であるのでPyTorchが分類問題の学習にNLLLossという言葉を割り当てているのはミスリーディングである。

最後に

統計では推定が最適化に変化していき、機械学習では特徴量エンジニアリングが深層モデルの最適化に変化していった。コンテキスト適応のような後続の潮流にも連綿とつながっていくだろうと思うのだ。

GEPAやACEがやっていることも結局は「何かしらの目的関数を置いて、パラメータやプロンプト、あるいは行動方針を最適化で求める」という文脈に位置づけられる。大きく違うのは、これまでは損失関数とか尤度関数とか「数値」を使って評価をしていた。言い換えるならばパラメータを求める直接的な関数は準備しなくてよいが、何をもって良しとするかを定量的に評価する方法だけは人間が準備していた。

LLMの文脈では、何をもって良しとするかを数値評価するのはもちろんのこと、自然言語でフィードバックを与えることができるようになったのは大きな変化かもしれない。 システムプロンプトを手工芸で作っていた時代から、数値最適化問題と自然言語でのフィードバックを利用して、自動でシステムプロンプトやコンテキストを構成させる時代へ進んでいくことを期待している。

Discussion