⚠️ このページは機械翻訳されています

この日本語訳は機械翻訳によるもので、誤りや不自然な表現が含まれている場合があります。正確な内容については英語版をご参照ください。

This page was machine-translated and may contain errors. Please refer to the English version for accuracy.

誤りを見つけられた場合は、joseph.austerweil@gmail.com までご連絡いただくか、GitHub リポジトリにプルリクエストをお送りください

セットアップとフレームワーク

これまでに学んできたこと

この章では、すでに知っていることからただ一つのことを変えます — そして何が変わらないかをあらかじめ述べておく価値があります。なぜなら、ほとんどすべては変わらないからです。

📦 これらはすべてすでに持っています

この章のすべては、以前の章で使ったツールを組み合わせて構築されています:

  • ベイズの定理(事後分布 ∝ 尤度 × 事前分布)。 学習を含む全章でこれを使ってきました — 事前分布に尤度を掛けて再正規化することで信念を更新する方法です。 ← 第4章で復習する
  • 予測分布 — 「これまで見てきたことを踏まえ、次の観測として何が期待できるか?」第4章で事後予測分布に出会いました(「次の弁当の重さはどのくらいか?」)。 ← 第4章で復習する
  • 条件付け = データと整合するものへの制限。 何かを観察するとそれに矛盾するあらゆる可能性が排除され、生き残ったものの上で再正規化します。 ← GenJAXチュートリアル、第4章で復習する
  • カテゴリ分類 — あるアイテムがいくつかのグループのいずれかに属する場合に P(カテゴリ | 観測) を計算すること。第4章のプレビューとガウスクラスタリングで、二つのガウス分布を使ってこれに出会いました。 ← 第5章で復習する

唯一の新しいアイデア: これらの章のいずれにおいても、推論の対象となる未知量数値(平均μ)かはい/いいえの事実(この弁当はとんかつか?タクシーは青か?)でした。この章では、未知量が集合 — あるプロパティを共有するものを決めるルール — になります。「どの値か?」から「どの集合か?」へのこの一つの変化が、ベイズ汎化の全内容です。それについて推論するための機構は、すでに持っている機構そのものです。


金のシール

Chibany は何ヶ月も弁当を受け取っており、最近ある奇妙なことに気づきました。一部の弁当には側面に小さな金のシールが貼られています。それ以外の弁当には貼られていません。

Chibany はそのシールが何を意味するか全くわかりません。弁当が作られた曜日を示しているのかもしれません。特定のシェフを示しているのかもしれません。価格帯かもしれませんし、ロイヤルティの報酬かもしれませんし、まったく別の何かかもしれません。Chibany にわかるのは、どの弁当にシールがあり、どの弁当にないか、それだけです。

確率論者である Chibany は、唯一できる方法で解明しようと決意します:ルールを推測し、どの推測が生き残るかを観察するのです。シールが従うかもしれないあらゆるもっともらしいルールを書き出します —

「月曜日だけ」 「とんかつ弁当だけ」 「400g以上の弁当だけ」 「すべての弁当」(シールは何も意味しないのかもしれない)

— そして待ちます。シール付きの弁当がさらに届くにつれ、一部のルールは適合し続け、他は除外されるか、ありそうもなく見えてきます。データを見た後もまだ残っているルールが、Chibany が信じるべきものです。

これがこの章の全体的なアイデアであり、それはすでに三つの動く部品を含んでいます:

  • 金のシールは新しいプロパティ — 新しい弁当について予測したいものです。
  • 各ルールは仮説です:そしてルールは実際には弁当の集合に他ならないことに注目してください — 「月曜日だけ」はすべての月曜日の弁当の集合、「すべての弁当」はそれら全部の集合です。
  • Chibany がいくつかのデータを見た後も残っているルールが、仮説に対する事後分布を形成します。

Chibany が実際に答えたい問いは予測です:金のシール付きの弁当が一つある — 次の弁当にもシールがあると期待すべきか? まさにその答えを導き出していきます。

一文で表す変化

この章での仮説ルールであり、ルールは集合 — そのルールがプロパティを持つとするものの集合 — です。「仮説は集合である」を頭に入れておいてください;他のすべてはそこから導かれます。


「どの事象か?」から「どの集合か?」へ

一般的なフレームワークを書き下す前に、可能な限り小さな例で唯一真に新しいアイデアを確認しましょう — 「未知量がはい/いいえの事実」から「未知量が集合」への飛躍が、ここでまだやっていないことの唯一のものだからです。

すでに解いた問題から始める

GenJAXチュートリアル(第4章)のタクシー問題を思い出してください。タクシーが夜間に事故に関与しました。未知量は一つのはい/いいえの事実でした:タクシーは青か緑か? その章では仮説を大文字の $H$ で書きましたが、ここでは一つの仮説(一つの候補となる答え)を小文字の $h$ で表します。なぜなら、すぐに仮説のリスト — $h_1, h_2, \dots$ — を持ち、一つの要素をクリーンなシンボルで表したいからです。二つの競合する可能性として、

$$h \in \{\text{blue},\ \text{green}\}.$$

ベイズの定理がそれらをランク付けしました:二つの色に対する事前分布、証人の報告に対する尤度、そしてそれらを組み合わせた事後分布です。二つの仮説があり、どちらがデータに支持されるかを問いました。

「青」はずっと集合だった

これがこの章全体を開く小さな見方の転換です。タクシーが「青い」と言ったとき、実際に意味していたのは、それがすべての青いタクシーの集合に属するということでした。「緑」はすべての緑のタクシーの集合です。事象 — 最初のチュートリアルで学んだ意味での — は、単に可能な結果の部分集合です。だから、タクシー問題の仮説はずっと集合だったのです。ただ、二つの集合が重ならず、タクシーがどちらに入るかだけを気にしていたので、そのように見る必要がありませんでした。

新しい点:異なるサイズの重なり合う集合

汎化とは、同じ「どの集合か?」という問いを取り上げ、集合を興味深いものにしたときに起こることです:

  • 候補の集合は重なることができます — 一つの弁当が「月曜日だけ」と「すべての弁当」の両方を同時に満たすことができるので、一つのアイテムが多くの仮説に属することができます;そして
  • 候補の集合はサイズが異なります — 「とんかつ弁当だけ」は小さく特定の集合であり、「すべての弁当」は可能な最大の集合です。

これが唯一の真に新しい課題です。仮説が重なり合いサイズが異なる集合である場合、「プロパティはどの集合に従うのか?」は「青か緑か?」よりはるかに豊かな問いになります — しかし、まったく同じベイズの定理で答えられます。

頭の中で保持できる二ルールの例

具体的に、ちょうど二つのルールで考えてみましょう。事後分布全体が一行に収まります。Chibany は四つの弁当の小さなメニューを並べ、重さ順に番号付け、最も軽いものから最も重いものへ — つまり弁当0が最も軽く、弁当3が最も重いです。金のシールに対する二つの候補ルールが候補に挙がります:

  • ルールA — 「最も軽い二つの弁当」: 集合 $\{0, 1\}$。
  • ルールB — 「軽い半分」: 集合 $\{0, 1, 2\}$。

両方のルールは弁当0と弁当1を含みます;それらは弁当2だけが異なります(BにはあるがAにはない)、そして弁当3(最も重い)は外れている点では一致しています。Chibany がどちらのルールも好む理由がない — 一様な事前分布、$p(A) = p(B) = 0.5$ — から始めて、一つのシール付き弁当:弁当1を観測するとします。

更新する前に、尤度 — 各仮説の下で観測がどれだけ確率的かを示すルール — が必要です。最も単純なもの、弱いサンプリングと呼ばれるものを使います:

📌 覚えておくこと:弱いサンプリング(最初の尤度)

弱いサンプリングは、尤度が全か無かであるとします:すべての観測されたアイテムを含む仮説はデータと整合的(尤度1)であり、観測されたアイテムを一つでも欠く仮説は不可能(尤度0)です。つまり、データを観測することは単純にそれと整合するルールを保ち、残りを除外します — タクシー問題からの「条件付け = 標本空間の制限」という動きとまったく同じです。

正式には、仮説(集合)を $h$、観測されたアイテムを $X$ として、弱いサンプリングの尤度

$$p(X \mid h) = \begin{cases} 1 & \text{if every observed item is in } h \\ 0 & \text{otherwise} \end{cases}$$

(後ほど§6で、より鋭い尤度 — 強いサンプリング — に出会います。それはより小さなルールも好みます。今は弱いサンプリングで十分です。)

ここに適用します:弁当1はルールAにもルールBにも含まれるので、弱いサンプリングの下では両方の尤度が1 — どちらも除外されません。事後分布 ∝ 尤度 × 事前分布なので、各ルールの事後分布は $1 \times 0.5 = 0.5$(その後正規化)であり、信念は均等に分かれたままです:

$$p(A \mid \text{bento 1 has the sticker}) = p(B \mid \dots) = 0.5.$$

これで Chibany は実際に気にしている予測に答えられます。次の弁当 — 弁当2としましょう — はシールを持つ可能性が高いか? 弁当2はルールBに含まれますが、ルールAには含まれません。だから、弁当2を含むルールだけが「はい」に投票し、現在各ルールをどれだけ信じているかで重み付けされます:

$$p(\text{bento 2 has the sticker} \mid \text{data}) = \underbrace{p(B \mid \text{data})}_{\text{B contains 2}} = 0.5.$$

一方、弁当0は両方の生き残ったルールに含まれているので、予測確率は $p(A) + p(B) = 1.0$ — 確実です。そして弁当3はどちらにも含まれないので、予測確率は $0$ です。

これでベイズ汎化を実行しました。新しいアイテムへの予測はそのアイテムを含むルールに乗っかっている信念の合計です。この章の他のすべて — より大きなルールセット、より小さなルールが勝つ「不審な偶然の一致」、連続的なルール — は、より大きなスケールでのこの同じ計算です。

コードで同じことを

二つの仮説しかないので、タクシーのサンプリングよりもさらに単純なことができます:両方のルールを書き下し、事前分布 × 尤度(まさにベイズの定理)でそれぞれをスコア付けし、正規化します。少数の仮説ではサンプリングは不要 — すべてのルールを直接確認するだけです。(後の章でルールが数十になっても、この「すべてのルールをスコア付けして正規化する」アイデアが必要なすべてです。)

各ルールを0と1の行として表します — メンバーシップリスト、最初のチュートリアルで事象を記述するために使った0/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
import jax.numpy as jnp

# A tiny menu of 4 bentos (columns 0-3). Two candidate rules (rows).
# A 1 means "this bento is in the rule"; a 0 means it is not.
rule_A = jnp.array([1.0, 1.0, 0.0, 0.0])   # Rule A = {0, 1}     ("the two lightest bentos")
rule_B = jnp.array([1.0, 1.0, 1.0, 0.0])   # Rule B = {0, 1, 2}  ("the lighter half")

# Flat (uniform) prior: each rule starts at probability 0.5.
prior_A = 0.5
prior_B = 0.5

# --- We observed that bento 1 has the sticker. ---
# A rule can only "explain" a sticker'd bento if that bento is in the rule. So the
# likelihood of "bento 1 has the sticker" under a rule is 1 if the rule contains bento 1,
# and 0 if it doesn't. We read that straight off the membership list at position 1.
likelihood_A = rule_A[1]    # is bento 1 in Rule A?  -> 1.0
likelihood_B = rule_B[1]    # is bento 1 in Rule B?  -> 1.0

# Bayes' rule: posterior is proportional to prior x likelihood. Then normalize so the
# two posteriors add to 1.
unnormalized_A = prior_A * likelihood_A
unnormalized_B = prior_B * likelihood_B
total = unnormalized_A + unnormalized_B
post_A = unnormalized_A / total
post_B = unnormalized_B / total

print("posterior:  Rule A =", float(post_A), " Rule B =", float(post_B))   # 0.5, 0.5
# (float() unwraps each JAX scalar so it prints as a plain 0.5 instead of Array(0.5, ...),
#  the same de-cluttering trick you saw with int() back in the GenJAX tutorial.)

# Predict: does the sticker generalize to a given bento? Add up the posterior of every
# rule that CONTAINS that bento -- "the total belief sitting on the rules that contain it."
for bento in range(4):
    p = post_A * rule_A[bento] + post_B * rule_B[bento]
    print(f"  predicted P(sticker) for bento {bento} = {float(p)}")

出力:

posterior:  Rule A = 0.5  Rule B = 0.5
  predicted P(sticker) for bento 0 = 1.0
  predicted P(sticker) for bento 1 = 1.0
  predicted P(sticker) for bento 2 = 0.5
  predicted P(sticker) for bento 3 = 0.0

表示された予測は手で計算したものと一致します:弁当0は確実(両方のルールに含まれる)、弁当2はコイントス(一方のルールに含まれる)、弁当3は不可能(どちらにも含まれない)。そのコードの各行はベイズの定理とメンバーシップルックアップ — 新しい機構はなく、ルールは0/1リストとして書かれているだけです。

なぜここに @gen モデルがないのか?

以前の章では @gen 生成モデルを書き、GenJAX にサンプリングで推論させました(generate と重要度重み、タクシー問題のように)。これはここでも機能します — そして @gen def which_rule(): rule = categorical(...) @ "rule" と書くこともできます。しかし、仮説が少ししかない場合、サンプリングはやりすぎです:上記のようにすべてのルールを直接スコア付けする方が、厳密で読みやすいです。仮説が多すぎてサンプリングが難しくなり、ルールをスコア付けするだけでなくシール付き弁当を生成したいときに、@gen 生成ビューを戻します。

何が起きたか

はい/いいえの問い(「青か緑か?」)を集合についての問い(「どのルールか?」)として再構成し、集合を重ならせサイズを変え、新しいアイテムをそれを含むすべてのルールに乗っかっている信念を足し合わせることで予測しました。これがこの章全体のエンジンです。次のセクションでそれに名前を付け、スケールアップし、なぜ — 正しい前提の下で — より小さなルールが勝つことになるのかを説明します。


目指す目標:シェパードの法則

二ルールの例を一般的な方法にスケールアップする前に、良い方法が何を生み出すべきかを知っておくと役立ちます。人(および動物)がどのように汎化するかについて注目すべき経験的事実があり、どんな本格的なモデルもそれを再現すべきです。

1987年の古典的な論文で、Roger Shepard(Shepard, 1987)は、二つの刺激がより異なるにつれて、人々が一方の刺激から他方にプロパティを拡張する意志がどれほどあるかを測定しました。このパターンは感覚と種を越えて著しく一貫していました:汎化の確率は二つの刺激がより離れるほどなめらかに減少し、特定の速度 — 指数的な速度 — で減少します。二つの刺激間の距離を $d$ として、適切な単位で

$$g(d) = e^{-d},$$

ここで $g$ は汎化の確率です。(より一般的には速度が異なる場合があり、ある尺度 $\tau$ に対して $g(d) = e^{-d/\tau}$;ここでは図を単純に保つために $\tau = 1$ に設定します。)ここで $e^{-d}$ は単に $d = 0$ のとき(距離なし、確実に汎化)1から始まり、$d$ が大きくなるにつれてなめらかに0に向かって減衰する曲線 — 第3章のガウスの鐘型曲線の内側で $\exp(-\ldots)$ の形に出会ったことがあります。そこでも中心で1に等しく、0に向かって減衰します(ガウスの曲線は鐘型、シェパードの曲線はより鋭い尖頭 — 同じ「負の量の指数」、異なる曲線)。$e^{-\lambda s}$ を完全な確率分布 — 指数分布 — として後の章の§8で出会います;今は単に曲線として扱います。

一つの微妙な点:心理的空間における距離

重要な距離 $d$ は生の物理的距離ではありません — それは知覚された距離、心がその刺激を表現した後の距離です。波長スケールで離れている二つの色は近く感じるかもしれません;オクターブ離れた二つの音符は大きな周波数差にもかかわらず関連して感じます。シェパードの法則は心の内部の「心理的空間」についてであり、物理的な測定ではありません。この章ではその空間を構築する必要はありませんが — それが法則が物理的な単位ではなく、知覚された距離 $d$ で述べられている理由です。

シェパードの法則は記述的です:汎化が指数的に減衰することを教えてくれますが、なぜかは教えてくれません。その「なぜ」こそが、これから構築するフレームワークが提供するものです。§8では指数を仮定しません — モデルからそれが現れるのを見ます。すでに出会った事後分布加重投票から導かれます(そして、シェパードが最初に示したように、理想化されたケースでは解析的に証明できます)。$g(d) = e^{-d}$ を目標として頭の片隅に置いておいてください。

シェパードの指数的汎化勾配 シェパードの指数的汎化勾配


フレームワークの名称

これで一般的に方法を述べるために必要なすべてが揃いました — そして§2ですでに「仮説は集合である」を二つのルールで具体的にしたので、以下のシンボルは抽象的に感じるべきではありません。それぞれはすでに使ったものであり、わずかに新しいオブジェクトを指しています。この形のフレームワーク — 結果的集合の仮説空間に対するベイズ推論としての汎化、シェパードの法則と類似性・ルールベース汎化を統一するもの — はシェパードの規範的説明を基にした Tenenbaum & Griffiths (2001) によるものです。

記法の確定

この章の残り全体で五つのシンボルを使います。今しばらく時間をかけてください;それぞれは任意の数式に現れる前にここで定義されています。

  • $h$ — 一つの仮説:一つの候補ルール、すなわちアイテムの一つの集合。(タクシー問題では「青」か「緑」でした;今は他の仮説と重なり合い、§2のようにサイズが異なります。)
  • $\mathcal{H}$仮説空間:検討中の候補仮説の全リスト。(スクリプト文字 $\mathcal{H}$ は新しい記法です;「すべての $h$ の集まり」と読んでください。)
  • $X = \{x_1, \dots, x_n\}$観測された例:プロパティを持つと見た $n$ 個のアイテム(シール付き弁当;以下の数字ゲームの例の数字)。
  • $y$ — 判断したい新しいアイテム:それはプロパティを持っているか?
  • $C$ — プロパティが実際に選び出す(未知の)真の集合。これは私たちの $h$ の一つではありません — それは私たちの仮説が推測しようとしている真実です。私たちの目標全体は、例 $X$ から事象「$y \in C$」($y$ は本当に真の集合にあるか?)を予測することです。

三つの構成要素 — まさにベイズの定理、新しいオブジェクト

これらは第4章からの同じ三つの部品であり、今は集合である仮説に適用されます:

  • 事前分布 $p(h)$ — データを見る前に各ルールがどれだけもっともらしいか。
  • 尤度 $p(X \mid h)$ — $h$ が真のルールだとしたら、観測された例がどれだけ確率的か。
  • 事後分布 $p(h \mid X) \propto p(X \mid h) p(h)$ — データ後の各ルールに対する更新された信念。形式的には実行したすべてのベイズ更新と同一;$h$ の意味だけが変わりました。
仮説空間事前分布である

ここで立ち止まる価値のある帰結があります。$\mathcal{H}$ から除外したルールは、事実上、事前確率ゼロを持ちます — どんなデータも決してそれを復活させることはできません。だから、どの仮説を考慮するかという選択自体が、一つの観測の前に焼き込まれた強力な事前信念です。これは§9(ノーフリーランチ)で戻ってきます。そこで、汎化が可能な理由全体がここにあることがわかります。今は、ただ注目してください:考慮することを拒否したものは、決して学習できません。

指示関数:「$y$ は $h$ にあるか?」をコンパクトに尋ねる方法

もう一つのシンボルがあり、それはほぼ見たことがあるものです。予測ルールをコンパクトに書くために、「$y$ が集合 $h$ にある場合は1、そうでなければ0」と言う方法が必要です。それを次のように書きます:

$$\mathbf{1}[y \in h] = \begin{cases} 1 & \text{if } y \in h \\ 0 & \text{if } y \notin h \end{cases}$$

この指示関数は実質的に何も新しくありません:それはまさに§2でルールを0と1の行として書くために使った0/1メンバーシップです。$h$ がメンバーシップ行列の一行なら、$\mathbf{1}[y \in h]$ は単にその行の $y$ 列の値です。§5の予測式が一行に収まるように、これにシンボルを与えるだけです。

コードにおける仮説空間

実際の、少し大きな仮説空間を構築し、この章の残りで使いましょう。Tenenbaum の数字ゲームをプレイします:誰かが1から30のいくつかの数字を選ぶ隠れたルールを持っていて、それに合ういくつかの例の数字を見て、他のどの数字が合うかを判断します。(古典的な1〜100ではなく1〜30を使うので、全空間が一枚の図に収まります。)各仮説はどの数字がプロパティを共有するかについてのルールです — §2の二つのルールと同じように、1〜30の数字に対する0と1の行として書かれます。

小さな混合した七つの候補ルールのセットを考えます:いくつかの「$k$ の倍数」、「2の累乗」、二つの大きさの区間、そして包括的な「すべての数字」。7×30の1と0を手で入力する代わりに、定義的なテストから各行を構築します

 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
import jax
import jax.numpy as jnp

numbers = list(range(1, 31))     # the universe: 1, 2, ..., 30 (these are the COLUMNS)

def make_rule(test):
    """Turn a yes/no test into a membership row: 1 where the test holds, else 0."""
    return jnp.array([1.0 if test(n) else 0.0 for n in numbers])

# Each ROW is one hypothesis (a rule); each COLUMN is one number (1..30, left to right).
labels = ["all numbers", "even numbers", "multiples of 3", "multiples of 10",
          "powers of 2", "numbers 1-10", "numbers 20-30"]
H = jnp.stack([
    make_rule(lambda n: True),                  # h0: all numbers   (catch-all, size 30)
    make_rule(lambda n: n % 2 == 0),            # h1: even numbers              (size 15)
    make_rule(lambda n: n % 3 == 0),            # h2: multiples of 3            (size 10)
    make_rule(lambda n: n % 10 == 0),           # h3: multiples of 10           (size 3)
    make_rule(lambda n: n in (1, 2, 4, 8, 16)), # h4: powers of 2               (size 5)
    make_rule(lambda n: 1 <= n <= 10),          # h5: an interval, numbers 1-10 (size 10)
    make_rule(lambda n: 20 <= n <= 30),         # h6: an interval, numbers 20-30(size 11)
])

# A uniform prior: before any data, every rule is equally plausible.
# H.shape is (rows, columns) = (7 rules, 30 numbers), so H.shape[0] is the number of rules.
prior = jnp.ones(H.shape[0]) / H.shape[0]    # 7 hypotheses -> each starts at ~0.143
どちらが行でどちらが列か?(2次元配列の読み方)

H は2次元配列 — 行のスタックです。マッピングは常に同じで、一度固定しておく価値があります:最初のインデックスは行、二番目は列。ここでは各行は一つのルール(h0、h1、…が上から下にスタックされる)で、各列は一つの数字(列0は数字1、列1は数字2、…、列29は数字30)。つまり H[i, j] は「ルール $i$ は数字 $j{+}1$ を含むか?」と答えます。例えば H[3, 9] は行3(「10の倍数」)、列9(数字10) — 10は10の倍数なので1です。(オフバイワンに注意:数字 $n$ は列 $n-1$ にあります。Pythonは列を0から数えるからです。)

この行列 H が仮説空間 $\mathcal{H}$ の全体です — 三十の数字に対する七つのルール — が行にスタックされています。ルールh0は包括的 — 「すべての数字」、すべての数字がプロパティを持つという仮説です。それはすべてを含むため、どの観測もそれを除外できません;それは常に残ります。これを含めるのは意図的であり、§6と§9でなぜそれが重要なのかを見ます。

全空間を一目で見ることができます — 各行がルール、各点灯セルがルールが含む数字です:

1から30の数字(列)に対する七つの候補ルール(行)のヒートマップ。各行は含む列が網掛けされています:「すべての数字」は行全体を埋めます;「偶数」は一つおきの列に点灯します;「3の倍数」は三つおきに;「10の倍数」はただ列10、20、30;「2の累乗」は1、2、4、8、16;「1〜10の数字」は左側の固まったブロック;「20〜30の数字」は右側の固まったブロック。ルールはカバーする数字の数が大きく異なります — 3から全30まで。 1から30の数字(列)に対する七つの候補ルール(行)のヒートマップ。各行は含む列が網掛けされています:「すべての数字」は行全体を埋めます;「偶数」は一つおきの列に点灯します;「3の倍数」は三つおきに;「10の倍数」はただ列10、20、30;「2の累乗」は1、2、4、8、16;「1〜10の数字」は左側の固まったブロック;「20〜30の数字」は右側の固まったブロック。ルールはカバーする数字の数が大きく異なります — 3から全30まで。

新しいイディオム:行列のに対する vmap

以前の章では jax.vmap を使ってモデルをランダムキーごとに一度実行しました — 多数のパーティクルに対して同じ計算を行います。ここで活用する第二の使い方があります:行列の行ごとに一度計算を実行することです。例えば、仮説のサイズ $|h|$ は行の中の1の数なので、すべてのルールのサイズを一度に取得できます:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import jax
import jax.numpy as jnp
# (H is the hypothesis matrix defined just above.)

# |h| = how many numbers each rule includes. vmap runs jnp.sum once per ROW of H.
# We pass jnp.sum itself as the per-row function -- the same slot where, in earlier
# chapters, you wrote your own function like run_one_day. vmap always works the same way:
# it peels off the first axis and runs the function on each slice. Before, that first axis
# indexed random keys; here it indexes the rows of H.
sizes = jax.vmap(jnp.sum)(H)
for label, size in zip(labels, sizes):
    print(f"|h| for {label:16s} = {int(size)}")

出力:

|h| for all numbers      = 30
|h| for even numbers     = 15
|h| for multiples of 3   = 10
|h| for multiples of 10  = 3
|h| for powers of 2      = 5
|h| for numbers 1-10     = 10
|h| for numbers 20-30    = 11

同じ vmap — 「それぞれに対してこれを実行する」— ただキーではなく H の行に対してマッピングするだけです。§5でこのパターンをそのまま使って、すべての仮説を一度にスコア付けします。(サイズ $|h|$ 自体が§6で重要になります。)

2026/07/02