5-2の宿題は「つまみ(潜在変数)[注]はどこから来るのか」だった。今回はデータだけを見てつまみを見つける。棒人間の場面600個を使い、1,196個の数値をk個に畳むエンコーダと、k個を再び1,196個に広げるデコーダを作る。16個の数値に畳んで広げても、動作の99.8%が戻ってくる。そしてその畳んだ数値で揺れを消し、隠れたひじを埋め、5-1の投棄検出を少ないデータでより正確にし、5-2の生成をつまみなしでやってのける。
5-2の生成器Dは、3つのつまみ(速さ・位置・大きさ)をあらかじめ知っていたから勝った。実際のデータにはつまみが付いてこない。今回のミッションは、場面600個だけを見てつまみを自力で見つけることである。
左の元データをエンコーダがk個の数値(中央の紫の棒)に畳み、デコーダが再び1,196個に広げる(右)。ボトルネックのサイズkを減らしながら、どこまで畳めるかを見てみよう。
| ボトルネック k | 圧縮率 | 説明した分散 | 復元誤差(RMSE) | 骨の長さの誤差 |
|---|---|---|---|---|
| 1 | 1,196倍 | 85.72% | 0.1021 | 6.16% |
| 2 | 598倍 | 95.07% | 0.0598 | 7.65% |
| 3 | 398.7倍 | 97.84% | 0.0395 | 2.78% |
| 5 | 239.2倍 | 99.02% | 0.0266 | 1.95% |
| 8 | 149.5倍 | 99.46% | 0.0195 | 1.86% |
| 16 | 74.8倍 | 99.80% | 0.0123 | 1.50% |
| 32 | 37.4倍 | 99.90% | 0.0088 | 1.43% |
テスト場面には姿勢推定の揺れ(σ = 0.008)が混ざっている。k = 32 の誤差0.0088は、その揺れの大きさとほぼ同じである。それより下では、動作ではなく揺れを覚えることになる。
場面600個を集め、「動作が最も大きく変わる方向」を順に見つけた(主成分分析、PCA)。エンコーダは場面から平均場面を引き、このk個の方向に映してk個の数値を得る。デコーダは平均場面にk個の方向をその数値の分だけ足す。足し算と掛け算だけの、最も単純なオートエンコーダである。ニューラルネットで作ったオートエンコーダは、層と活性化関数を使って曲がった関係までとらえる(3-7)。このページの16個の方向は、コード1が計算した値をそのまま載せた。
場面600個をつまみ1・2で打った地図である。点を押して場面を選び、下の4つのつまみを回してみよう。つまみには名前がない。何が変わるかを見て、自分で名前を付けてみよう。
同じ種類の場面は地図上で近くに集まる。誰も「これは投げ」と教えていないのに、畳んだだけでそうなる。つまみの値は学習場面の標準偏差(σ)単位である。±2σの外は学習データにほとんどなかった領域なので、広げた形がぎこちなくなる。
| つまみ | 最も大きく動くところ | 観察して付けたあだ名 | 場面別の平均(コード1) |
|---|---|---|---|
| 1(動きの85.7%) | 全関節のx、場面の後半 | 「終わったときにどこにいるか」 — ゴミ箱の前に残るか、右へ歩いて出ていくか | 入れる −15.3 · 投げる +8.3 · 通り過ぎる +6.4 · 落とす +6.7 |
| 2 (9.4%) | 右手首・ひじと足首のx、場面の前半 | 「最初にどこで、右腕をどちら側に置いて始めるか」 | 通り過ぎる −4.4 · 手を振る +4.1 |
| 3 (2.8%) | 右手首・ひじ・頭のy | 「腕を上げるか、腰をかがめるか」 | 手を振る +2.6 · 拾う −2.1 |
| 4 (1.2%) | 右手首と足首のx、場面の中盤 | 「真ん中の時間帯の腕・脚の左右の揺れ」 | 拾う +1.3 · 投げる −0.9 |
5-2のつまみ(速さ・位置・大きさ)は、人が場面を作るときに決めたものだった。ここでのつまみは、データが最も大きく変わる方向を順に取り出したものである。だから名前がなく、1つのつまみに複数の意味が混ざっている(つまみ1は位置でもあり、「歩いて出ていったか」でもある)。その代わり、人が何も教えなくても見つけられる。これが潜在空間である。
実際の姿勢推定では関節の点が揺れ、腕が体に隠れると点を見失う。じょうごは「人の動作らしいもの」だけを通すので、畳んで広げると揺れはこし取られ、空欄はもっともらしく埋められる。
揺れ σ = 0.01 なら誤差 0.0100 → 0.0082、σ = 0.03 なら 0.0300 → 0.0090、σ = 0.05 なら 0.0501 → 0.0104。揺れが大きいほど効果が大きい。揺れは方向がでたらめなので、じょうごの16個の方向にほとんど引っかからないからである。
見えている欄だけで16個の潜在数値を最小二乗法で合わせてからデコーダで広げると、空欄まで埋まる。位置の誤差は「肩と手首の中点で埋める」0.0230 対「デコーダで埋める」0.0108で、約2.1倍正確である。5-1で述べた「腕が体に隠れると関節を見つけられない」を、こうして補う。
5-1で「座標をそのまま学習するとデータがずっと多く必要になる」と述べた。今回は関節と缶の座標(1,288個)をまずエンコーダで畳み、畳んだk個の数値で最も単純なロジスティック回帰を学習する。
| 学習場面(種類ごと) | 1,288個そのまま + MLP | k = 8に畳んで + ロジスティック回帰 | k = 16に畳んで + ロジスティック回帰 |
|---|---|---|---|
| 25(全体150) | 96.7% | 95.0% | 99.7% |
| 50(全体300) | 97.0% | 95.3% | 100.0% |
| 100(全体600) | 98.0% | 98.0% | 100.0% |
k = 16 + ロジスティック回帰:種類ごとに25個(全体150個)だけで、テスト300個のうち299個を当てた。16個の数値の中に「缶が最後にどこにあるか」と「人がどこへ行ったか」がいっしょに畳み込まれているので、直線1本でも分けられるようになったのである。
k = 8では足りない:缶の最後の位置のような小さな動きは9番目以降の方向に入っているので、8個に畳むと一部が抜け落ちる。とにかく小さく畳めばよいというものではない。
5-1の92.3%と違う理由:5-1では「物体なし」を座標 −9 で表し、ここでは (0, 0) で表した。入力の表し方を変えるだけで、MLPは98%まで上がる。この表の3つの列はすべて同じ入力で比較した。
エンコーダは名札なしで場面だけを見て作った(600個をすべて使ったが、投棄・正常の正解は見ていない)。そうして得た「動作の要約」は雑音がこし取られ、数値も少ないので、正解の付いた場面が少なくても分類器が迷わない。名札のないデータで先に表現を学び、少ない正解で仕上げるやり方は、今日の大規模モデル学習の基本的な流れと同じである。ただし、この数値は合成データでの結果である。実際の映像ではこれより低くなる。
5-2の審査官がまたやって来た。今回の生成器Eは、人が決めたつまみを知らない。潜在マップで投げが集まった場所(平均と標準偏差)を見て、16個の新しい点を抜き出し、デコーダで広げる。
| 生成器 | つまみをあらかじめ知っているか | 骨の長さの誤差 | 揺れ | 手首の最大速度 | 多様性 | 新しさ |
|---|---|---|---|---|---|---|
| A 平均ひとつ | — | 1.7% | 0.0045 | 1.36 | 0.000 | 0.033 |
| B 座標ごとにサイコロ | — | 44.2% | 0.2659 | 10.00 | 0.149 | 0.109 |
| C 1つ選んでコピー | — | 4.7% | 0.0300 | 2.75 | 0.125 | 0.000 |
| D つまみ3個から抽出 | 知っている(人が決めた) | 0.0% | 0.0125 | 2.71 | 0.123 | 0.022 |
| E 潜在16個から抜き出す | 知らない(データが見つけた) | 3.7% | 0.0122 | 1.76 | 0.114 | 0.047 |
Eができたこと:つまみを知らなくても、Bのように壊れない(骨の誤差 44.2% → 3.7%、揺れ 0.27 → 0.012)。多様で(0.114)、丸写しもしていない(0.047)。
Eができなかったこと:手首の最大速度が1.76で、投げる力が抜けてしまった。潜在空間で平均の近くを抜き出し、直線的な方向を足し合わせるだけなので、素早く振る短い瞬間がつぶれてしまう。骨の長さも本物(0%)ほど正確ではない。
エンコーダ・デコーダは検出と生成の両方を押し上げた。それでも残ったものがある。
どちらのコードも、Colabに標準でインストールされているライブラリだけを使う。「ノートブック(.ipynb)をダウンロード」したあと、Colabでファイル → ノートブックをアップロードから開くか、コピーして新しいノートブックのセルに貼り付ける。
場面600個でencode・decodeを作り、kごとの復元誤差、揺れの除去、隠れたひじの穴埋め(fill)を測る。このページの16個の方向はここから生まれた。自分のデータに置き換えるには Sの位置に(場面数, 数値の数)の形の自分のデータを入れる。センサーやログのデータも同じ方法で畳める。
5-1の投棄検出を「そのままMLP」対「畳んでロジスティック回帰」で、学習場面の数を変えながら比較し、5-2の審査官の採点で生成器Eを測る。セクション5・6の表はこの出力からそのまま作られる。
ChatGPT、Qwen、ClaudeのようなAIアシスタントに貼り付けるプロンプトである。「コピー」を押すと、プロンプトの後ろに選んだコードが一緒に付く。〔 〕の中を自分の状況に書き換えて使えばよい。
AIの答えは出発点にすぎない。提案された論文・数値・ライブラリ関数は、必ず原文と公式ドキュメントで確認する。実際の人の動作データを使うときは、撮影の同意とデータセットの利用条件を先に確認する。
本文の黄色い点線下線と同じ辞書である。セクション名を押すと、最初に出てきた場所へ移動する。
たとえは理解の第一歩だが、誤解の種にもなる。人の知覚と比べたたとえには強さを示した。直接 実際に同じ働きをするという根拠がある · 部分 一部の性質だけが似ている · なし 対応するものが知られていない
| 概念 | 日常のたとえ | 人の知覚のたとえ | たとえが外れるところ |
|---|---|---|---|
| エンコーダ・デコーダ | 旅行かばんに服を畳んで入れ、宿で広げる | 部分的 長いダンスを「左足、拍手、回転」のように数語で覚えておき、また踊る | 服は畳んでもそのままだが、じょうごは小さなしわ(揺れ)を捨てる。捨てたものは広げ直しても戻ってこない |
| ボトルネックのサイズ k | 要約文の文字数制限 | なし | 要約では人が大事なものを選ぶが、このじょうごは「大きく変わるもの」を選ぶ。小さくても大事な違い(缶の最後の位置)を見落とすことがある |
| 潜在空間 | 飲食店を「価格・辛さ」の2つの軸の地図に打つ | なし | 飲食店の地図の軸は人が決めるが、潜在空間の軸はデータが決め、名前がない |
| 隠れの復元 | 消えた文字を前後の文脈から推測して読む | 部分的 隠れた腕も体全体の姿勢から推測する人の知覚 | 推測が当たるのは学習した動作の範囲内だけである。初めて見る姿勢だと、知っている姿勢のほうへ間違って埋めてしまう |
| 潜在空間から抜き出す | 地図で「この辺りの近く」を指して行ってみる | なし | 地図の空き地(学習データがなかった場所)を指すと、おかしな場所にたどり着く |
E-1 著者紹介 · E-2 学術参考文献 · E-3 図と数字の出典
講師、実務OJT担当者、チューター向けの運営ガイドである。時間は目安なので、実際の授業に合わせて調整する。
| 対象 | 5-1・5-2を終えた大学生・社会人。センサー・映像・ログのように大きくて雑音の多いデータを扱う実務者 |
|---|---|
| 前提知識 | 5-2の「動作は表である」と生成器の採点、ベクトルの内積(同じ位置どうしを掛けて足す) |
| 学習目標 | ① エンコーダ・デコーダとボトルネックkの意味を、じょうごの図で説明する ② 畳んで広げることが揺れの除去・隠れの復元・少ないデータでの学習・生成にそれぞれどう使われるか、例を挙げる ③ 線形エンコーダの限界とVAEが必要な理由を述べる |
| 目安時間 | 読む35〜45分・アニメーションのデモ25分・Colab実習30分(コード1 10分、コード2 実行1分 + 解釈19分) |
導入5分(セクション1、5-2の宿題)→ セクション2 じょうごのkを減らす12分 → セクション3 つまみを回す10分 → セクション4 揺れ・隠れ8分 → セクション5・6 表を読む10分 → 確認問題5分。
セクション2 15分 → 自分たちのデータ(センサー、ログ)の「数値の数」と「実際に独立な数値の数」についての討論15分 → セクション4・5で雑音除去・少ない正解での学習の事例20分 → コード1に自分たちのデータを入れる30分 → セクション7 限界の整理10分。
入門者はセクション2・4だけ。中級者にはコード1のencode・decodeを手でたどらせたあと、セクション3のつまみ1がなぜ「終わったときの位置」なのかを、Vt[0]を描いて確かめさせる。
| セクション | 立ち止まって問いかける質問 | 操作のコツ |
|---|---|---|
| 2 じょうご | 「数値がいくつあれば、投げが投げらしく見えるだろうか?」 | k = 1 → 3 → 8 と上げながら右の結果を見る |
| 3 潜在マップ | 「誰も教えていないのに、なぜ同じ種類どうしが集まったのだろうか?」 | 赤い点(投げ)を1つ選び、つまみ1を −2σ に回す |
| 4 揺れ・隠れ | 「じょうごは揺れと動作をどう区別するのだろうか?」 | σ = 0.05 とひじ隠しを同時にオンにする |
| 5 投棄検出 | 「k = 8 はなぜ k = 16 に及ばないのだろうか?」 | 表の「25」の行を先に読む |
| 6 生成 | 「EはDより何を知らず、何がうまくできないのだろうか?」 | 「作り直す」を押して手首の最大速度の欄を見る |
| 誤解 | 正しい説明 | 見せる場面 |
|---|---|---|
| 圧縮すると情報が減って性能が落ちる | 捨てるものが主に雑音なら、かえって良くなる。揺れの除去、少ないデータでの学習がその例である | セクション4、セクション5 |
| kは大きいほど良い | kが大きいと揺れまでとらえてしまう。小さいと大事な小さな動きを見落とす。目的に合わせて選ぶ | セクション2の表の k = 32、セクション5の k = 8 |
| 潜在数値の一つひとつに、人が理解できる意味がある | 方向はデータが決め、名前がない。あだ名は人が後から付けた解釈である | セクション3の表 |
| オートエンコーダはニューラルネットでなければならない | 最も単純な線形オートエンコーダはPCAと同じことをする。ニューラルネットは曲がった関係までとらえる | セクション2の下の解説 |
| 潜在空間のどの点を抜き出しても、もっともらしい動作が出てくる | そうなるのは学習データがあった近くだけである。その空間を均等に整えるのがVAEの仕事である | セクション3の±2σの外、セクション6 |
1,196 ÷ 16 = 74.75、約74.8倍。コード1での説明した分散は99.80%である。
エンコーダ:z = (x·v₁, x·v₂) = (3, −2)。デコーダ:3v₁ − 2v₂ = (3, −2, 0)。3番目の値0.4は2つの方向に引っかからないので消える。これが「揺れが消える」仕組みである。
ひじは曲がっているので中点より外側にある。デコーダは場面600個から学んだ「この姿勢ならひじはたいていここ」という関係(16個の方向)を使い、見えているほかの関節といっしょに合わせる。コード1では誤差が0.0230 → 0.0108に減った。
エンコーダは動作の構造(何がいっしょに動くか)だけを学び、1,288個を16個の要約に変えた。要約は雑音が少なく数値も少ないので、正解の付いた場面が150個しかなくても、単純な分類器が迷わない。
潜在空間で投げの平均の近くを抜き出し、デコーダが方向を直線的に足すだけだからである。タイミングが少しずつ違う素早い振りは、数個の直線的な方向では表せずにつぶれてしまう。非線形デコーダや時間軸を扱うモデルが必要である。
コード1で隠す関節を右ひじから左ひざ(9番 → 10番の関節)に変え、隠す区間を21フレームから40フレームに延ばす。デコーダで埋めたときの誤差がどう変わるかを表にして報告する。
学習にない動作「転ぶ」(pose関数でleanを1.4まで大きくした場面)を作り、6種類の場面より復元誤差がどれだけ大きいかを測る。復元誤差で「初めて見る動作」の警報を作れるかどうか、しきい値とともに提案する。
| 入門者 | セクション2のkボタンとセクション4の3つの図だけでも、「畳んで広げるとこし取られる」がつかめる |
|---|---|
| 発展 | コード1の線形エンコーダをKerasのオートエンコーダ(1,196 → 64 → 16 → 64 → 1,196)に置き換え、復元誤差と生成器Eの手首の速度を比較させる |
| 次回 | 5-4 単語から動作へ — 言葉も同じ地図上の点にする |
「5-3 エンコーダ・デコーダ」編を最後まで読みました。研究室の仲間たちがひと言ずつまとめます。