帯域を1つ抜いた広帯域ノイズを止めた直後、抜いた帯域にだけ幻の純音が残像として聞こえることを示した図

ノイズを止めた瞬間、鳴っていない音が残る ── ツヴィッカートーン

明るい窓をじっと見つめてから目を閉じると、窓の形が反転した残像がしばらく浮かんで、やがて消えていきます。誰でも一度は経験したことがあるはずです。同じことが、耳にも起きます。 ザーというノイズを数秒聴いてから、ふっと止める。その直後の静けさのなかに、かすかな「ピー」という細い音が残って、数秒かけてすっと消えていく ── とされています。スピーカーは完全に沈黙しているのに、です。 はじめに正直に書いておきます。この記事を書いている私自身には、この音が聞こえませんでした。あとで触れる条件を文献どおりに揃え直し、静かな部屋でイヤホンを付けて、何度も鳴らしては止めてみましたが、静けさは静けさのままでした。だから以下は「聞こえた」という体験談ではなく、聞こえるとされているものが何で、どういう仕組みだと説明されていて、なぜ人によって聞こえたり聞こえなかったりするのか、という話になります。 ツヴィッカートーンと呼ばれるこの錯覚は、1964年に音響心理学者エバーハルト・ツヴィッカーが報告したもので、この連載の「耳のバグ」の棚では差音 ・ミッシング・ファンダメンタル ・シェパードトーン ・リセ・リズム ・連続性の錯覚 に続く6本目です。 仕掛けは、ノイズに開けた「穴」にある ただのノイズを止めても、この残像は生まれません。仕掛けは鳴らす側にあります。 広い範囲の周波数をまんべんなく含んだノイズを用意して、その中の狭い帯域だけを、フィルターですっぽり抜いておくのです。1オクターブぶんほど、ぽっかりと穴を開けた状態。聴いてみると、ほとんどただのノイズと区別がつきません。少しくぐもったような気もする、という程度です。 ところが、これを止めた瞬間に、抜いたはずの帯域に音が生まれる ── というのが報告されている現象です。しかも生まれる音の高さは、抜いた穴のど真ん中あたり。穴の位置を変えれば、残像の高さもそれについてくるとされています。鳴らしていない場所にだけ音が現れる、というのがこの錯覚のいちばん奇妙なところです。 抑え合いが崩れた反動 なぜ、鳴っていない場所に音が出るのか。有力な説明は、聴覚が持っている「抑え合い」の仕組みにあります。 耳の中では、周波数ごとに担当の神経が並んでいて、隣り合う担当どうしが互いを抑え込んでいます。側抑制と呼ばれる仕組みで、これは視覚にもある一般的な作りです。強く反応している担当が、その隣を押さえつける。おかげで音の輪郭がくっきりし、ぼんやりした音の中から特徴のある成分を拾いやすくなります。 ここでノイズに穴を開けると、何が起きるか。穴の担当だけは、自分は何も受け取っていないのに、両隣のにぎやかな担当から強く抑え込まれ続けます。ずっと押さえつけられた状態です。そしてノイズが止まった瞬間、両隣は静かになり、押さえつけていた力がふっと消える。抑えを失った穴の担当が、その反動で一時的に暴走する ── その暴走が、鳴っていないはずの音として聞こえる、という筋書きです。目を閉じたときの残像が、明るさに順応していた細胞の揺り戻しであるのと、よく似た構図です。 ここまで読むと、耳鳴りも同じ仕組みなのではないか、と思う人がいるはずです。実際この錯覚は、耳鳴りの研究で模型として使われています。理屈のうえでは筋が通っていて、加齢や騒音で内耳のある帯域が働かなくなると、その帯域からの入力が脳に届かなくなる。つまり耳の内側に、あの「穴」が居座った状態になるわけです。そこで抑え合いの均衡が崩れて音が生まれる、という説明は、ツヴィッカートーンに対するものとほとんど同じ形をしています。耳鳴りのある人はこの残像を聞き取れる割合が高い、という報告もあります(耳鳴りのある人で91%、ない人で42%)。 ただし、同じものだと言い切るのは行き過ぎです。ツヴィッカートーンは健康な耳に数秒だけ起きて消えるもので、耳鳴りのように何か月も続く状態ではありませんし、聴力が傷んでいなくても起こせます。そもそも耳鳴りのある人を対象にした研究はまだ1本しかなく、2025年のレビューも「両者を結びつけるにはさらに研究が要る」と結論しています。似た説明で語られている、健康な耳で一時的に真似られる、というところまでが今わかっていることです。 なお、静かな部屋に入った途端に「ピー」と聞こえるあの感じは、これとは別物と考えたほうがいいでしょう。周りの音が消えて、もともとあった小さな音に気づいただけということもあれば、機器の出す本物の高い音のこともあります。ツヴィッカートーンは、穴を開けたノイズを聴かせて止める、という手順を踏まないと起きません。 触ってみる デモを用意しました。鳴らし方が2通りあります。 既定は「刻む」です。0.1秒鳴らして0.1秒黙る、を20秒くり返します。1回だけ鳴らして止めると、残像は1〜2秒で消えてしまい、身構えていないと取り逃がします。ところが短い刻みをくり返すと、黙っている合間に残像が入り込み、途切れずに続いて聞こえる ── 刻みで残像が続くこと自体はレビューが報告している性質ですが、どちらが気づきやすいかを私がきちんと比較したわけではありません。ザーザーという刻みの「すきま」に耳を向けてください。もう一方の「1回だけ」は、8秒鳴らしてひと息に止めるやり方です。ツヴィッカー自身は60秒のノイズを使っていたので、8秒でも短いほうになります。 冒頭に書いたとおり、私には聞こえませんでした。それも珍しいことではなく、2025年のレビューによれば、近年の研究で聞き取れた人の割合は3〜5割程度です。1964年にツヴィッカーが「9割の人が聞こえる」と報告したのに比べるとずいぶん低い。ただしこれは研究ごとに刺激も判定のしかたも違う数字を並べたもので、人口全体での確定した割合ではありません。少なくとも「誰にでも簡単に起きる」現象ではない、という程度に受け取ってください。何度やっても分からなくても、耳が悪いわけでも、この話が嘘なわけでもありません。 デモの刺激は、比較的出やすいとされる条件に寄せてあります。穴の中心は4kHz付近、幅は1オクターブ、穴の深さは30デシベル以上。ただしこれは必要十分条件ではなく、他の周波数や幅でも報告はあります。合わせられたのは周波数の形までで、耳に届く音圧は端末やイヤホンで変わるため校正できていません。静かな部屋で、イヤホンで、音量は控えめに。うるさいほど出やすいわけではないようです。 うまく表示されないときは、デモを別タブで開く 。 比較用に「穴なし」も置いてあります。同じ長さの普通のノイズで、こちらでは残像は出ないとされています。音量は厳密には揃っておらず、穴を開けたぶんエネルギーが減るので、実測すると穴ありのほうが1.4デシベルだけ小さくなります。穴を開けるかどうかだけで、止めたあとの静けさの中身が変わるかどうかが決まる、という理屈です。聞こえた人は、穴の中心を動かすと残像の高さも一緒に動くのが分かるはずなので、そこまで試してみてください。 正直に書いておくと、この錯覚は聞こえ方の個人差がかなり大きく、慣れも要ります。イヤホンで、静かな場所で、音量は控えめに。そして止まった直後の1秒に意識を集中してください。それでも聞こえない耳もあります。聞こえないこと自体は、耳の性能とは関係ありません。 どう実現するか デモの中身は、ノイズにフィルターをかけているだけです。乱数を詰めたバッファをループ再生し、上下をフィルターで挟んで帯域を制限したあと、目的の帯域を抜きます。 ここで素直にノッチフィルターを使うと、うまくいきません。ノッチは中心周波数だけが深く凹むV字の谷で、狙った帯域の縁はほとんど落ちないからです。実際、半オクターブぶんの穴を開けたつもりで3段重ねても、縁では9デシベルしか下がっていませんでした。必要なのは底が平らな帯域除去なので、低い側と高い側に分けて通し、あとで足し合わせます。 // 低域側と高域側に分けて通し、足し合わせて「穴」を作る const loCorner = notchF * 2 ** -0.5 / 1.25; // 穴の下端より少し下 const hiCorner = notchF * 2 ** 0.5 * 1.25; // 穴の上端より少し上 let low = source, high = source; for (const q of BUTTER_Q) { // 16次バターワースのQ列 const l = ac.createBiquadFilter(); l.type = 'lowpass'; l.frequency.value = loCorner; l.Q.value = q; low.connect(l); low = l; const h = ac.createBiquadFilter(); h.type = 'highpass'; h.frequency.value = hiCorner; h.Q.value = q; high.connect(h); high = h; } low.connect(master); high.connect(master); コーナーを穴の外側へ少し追い出しているのは、遷移の傾きぶんを穴の外で使い切って、穴の中を端から端まで深く保つためです。この構成で、2828〜5657ヘルツの全域が30デシベル以上落ちます。実際に鳴っている音を測ると、帯域の縁で30〜37デシベル、中心では66デシベル下がっていました。 数字の勘どころが2つあります。ひとつはいま見た穴の深さで、浅いと知覚が安定しないと報告されています。もうひとつは止め方で、抑えが外れる反動が主役という説明に従うなら、ゆっくりフェードアウトさせるより、スパッと切ったほうが有利なはずです。デモでは10ミリ秒で切っています。完全な瞬断にするとプチッというクリック音が出てしまうので、その手前の急峻さを狙う、という調整です。 参考文献 E. Zwicker, “‘Negative Afterimage’ in Hearing,” The Journal of the Acoustical Society of America, vol. 36, no. 12 (1964), pp. 2413–2415. DOI: 10.1121/1.1919373 。この錯覚を「聴覚の陰性残像」として報告した原論文。 知覚できる人の割合、刺激条件(穴の中心・幅・深さ・長さ)、耳鳴りとの関係については A. Hardy et al., “The Zwicker tone as a model to investigate auditory processing and tinnitus: a scoping review” (2025) PMC12411427 にまとまっています。本記事の数値とデモの設定はこれに拠りました。 側抑制との関係や耳鳴り研究での位置づけは Wikipedia: Zwicker tone がまとまっています。 デモの実装には Web Audio API を使用。ホワイトノイズを BiquadFilterNode を16次バターワースのローパス/ハイパスに組んで並列に足し、1オクターブの帯域を30デシベル以上落として削り、GainNode で急峻に停止しています。 私には聞こえませんでしたが、それは半分くらいの人に起きることで、この現象が怪しいという話ではありません。もし何か聞こえたら、鳴っていない帯域に音を感じているということになります。聞こえなかったら、同じように聞こえない人が半分近くはいる、ということになります。どちらだったか、ぜひ試してみてください。 ...

公開: 2026年7月27日 · Toshihiko Arai
連載『手で動かすAI』第7回のカバー。同じ点の集まりに、ほどよい曲線と、点を全部通るが間がぐにゃぐにゃに暴れる曲線が描かれ、暗記と理解の違いを示すイラスト

覚えるのと分かるのは違う ── 過学習と、それをどう防ぐか

前回 、手書き数字を読むネットワークが95.7%当たる、という話をしました。あの数字には、さらっと流しましたが大事な但し書きがついています。「テスト」正解率、つまり学習には一度も使っていない、見たことのないデータで測った成績だ、ということです。なぜわざわざ、そんな面倒な測り方をするのか。訓練で使ったデータの上での成績なら、もっと簡単に、もっと良い数字が出せるのに。 理由は身も蓋もなくて、訓練データの成績はあてにならないからです。モデルを複雑にしていくと、訓練データの成績はいくらでも良く見せられます。極端には、全部の答えを丸暗記してしまえば、訓練データでは100点が取れる。けれどそれは、数字の形を理解したのとは違います。今回は、この「覚える」と「分かる」の境目を見ます。 訓練データの上では、暗記と理解が見分けられない 第0回 で、AIの学習とは「散らばった点に線や曲線を当てる」ことだ、という見方を出しました。この見方が、今回そのまま効いてきます。 いくつかの点が、あるなめらかな曲線のまわりに、少しばらついて散らばっているとします。私たちが本当に知りたいのは、点そのものではなく、その裏にある「本当の形」のほうです。ここでモデルのつまみを少しずつ増やして、曲線を自由に曲げられるようにしていくと、どうなるか。 はじめのうちは、つまみが足りず、直線に毛が生えた程度のざっくりした線しか引けません(未学習)。つまみを増やすと、曲線が本当の形にほどよく寄り添うようになる(ちょうどいい)。ところが、さらに増やしていくと、曲線は訓練データの一点一点を律儀に通ろうとして、点と点のあいだで激しく暴れだします。訓練データの上ではぴたりと当たっているのに、少しでも外れた場所ではまるで見当違いの値を出す。これが過学習、平たく言えば丸暗記です。 同じ10個の点に、直線・ほどよい曲線・点を全部通る曲線をそれぞれ当てはめたのが下の図です。数字は実際に計算したもので、右へ行くほど訓練データでの誤差は小さくなり、いちばん右では0.000、つまり完璧に当たっています。それなのに、本当の形からのずれは0.144→0.026→0.820と、途中から逆に大きくなる。訓練データの上だけを見ていると、いちばん右がいちばん優秀に見えてしまうところが、この問題の厄介さです。 やっかいなのは、訓練データだけを見ていると、この暗記が「良い成績」に見えてしまうことです。点を全部通っているのだから、訓練データの誤差はほとんどゼロ。数字だけ眺めれば大成功に見える。暗記か理解かは、訓練データの上では区別がつかないのです。 触って、暗記させてみる 下のデモで、実際につまみを増やしていってください。スライダーがモデルの複雑さ(つまみの数)で、右に回すほど曲線が自由に曲がれるようになります。 うまく表示されないときは、デモを別タブで開く 。 黒い点が訓練データ、青い線がネットの引いた曲線、うっすらした破線が本当の形です。下には誤差が二つ並んでいます。青が訓練データでの誤差、オレンジが「未知データでの誤差」── 本当の形とどれだけ一致しているか、つまり本当の実力です。 スライダーを右へ回していくと、青(訓練誤差)はどんどん下がっていきます。点にぴたぴた近づくのだから当然です。ところがオレンジ(本当の実力)は、途中まで一緒に下がったあと、あるところで反転して、逆に悪くなっていく。「暗記(次数12)」を押すと、曲線が点のあいだで大きくうねって、破線から大きく離れているのが見えます。点は全部通っているのに、間はでたらめ。青だけ見て喜んでいると、この暗記に気づけません。 この二本の線の関係が、過学習のすべてです。複雑さを増すほど訓練誤差は下がり続けますが、本当の実力はどこかで底を打ち、そこから先はむしろ悪化する。両者の開きが、そのまま暗記の度合いです。だから成績は、訓練で見たデータではなく、見たことのないデータで測らなければ意味がない。前回の95.7%がわざわざテストデータで測った数字だったのは、このためでした。 なぜ暗記が起きるのか、どう防ぐのか 過学習が起きるのは、モデルのつまみが、データの量に対して多すぎるときです。つまみがあり余っていると、モデルはデータの裏にある本当の形を学ぶかわりに、目の前の一つ一つ(ノイズも含めて)を覚え込むだけの余力を持ってしまう。少ない例題を、必要以上に賢い頭で丸暗記してしまう、という状況です。 だから対策も、裏返しになります。いちばん素直なのは、データを増やすこと。覚えるには多すぎるほどの例を見せれば、暗記では追いつかず、共通する形を学ぶしかなくなります。あるいは逆に、モデルのほうを簡単にする ── つまみを減らして、そもそも暗記できる余力を奪う。 もう少し細かい手立てもあります。一つは正則化と呼ばれるもので、つまみの値が大きくなりすぎたら罰を与える、という縛りを損失に足しておく方法です。曲線が激しく暴れるときは、たいていどこかのつまみが極端に大きくなっているので、それを抑えるだけで、無用なうねりがおとなしくなります。もう一つは早期打ち切りで、さっきの図でいう「本当の実力が底を打つあたり」で学習を止めてしまう、という素朴で効く手です。ニューラルネットではさらに、学習のたびにニューロンの一部をランダムに休ませるドロップアウトという工夫もよく使われます。一部が抜けても答えられるよう、特定の暗記に頼れなくする狙いです。 どれも、やっていることは一つに尽きます。モデルをわざと少し不自由にして、丸暗記の逃げ道をふさぐ。そうやって初めて、モデルは「覚える」のをあきらめて「分かる」ほうへ向かいます。 前回の手書き数字ネットが過学習に陥らずに済んだのは、つまみの数がデータに対して過大ではなく、そして何より、成績をきちんとテストデータで測っていたからでした。とはいえ、あのネットにはまだ大きな伸びしろが残っています。784個の入力を、いまはただの数の袋として扱っていて、それが本当は縦横に並んだ一枚の絵だという事実を、まるで活かせていない。次回はいよいよ、隣り合ったピクセルの関係を見る仕組み ── 畳み込みへ進みます。 連載「手で動かすAI」 ← 前回 自信の大きさまで答えさせる

公開: 2026年7月27日 · Toshihiko Arai
五線譜のド+ソ♯(増5度)とド+ラ♭(短6度)を等号で結び、右にピアノ鍵盤で同じ黒鍵を示したカバー画像

同じ高さの音なのに「増5度」と「短6度」に分かれる ── 音程の名前は距離では決まらない

音感トレーニングのアプリを作っていて、プレイ中の画面に「いま合わせているのは、この和音の中で何の音か」を出すバッジを付けました。ルート、3度、5度、といったあれです。基準の音に自分の声(というか指で動かす音)を重ねる練習をしていても、それが音楽的に何をしているのかは、意外と分からないまま終わってしまう。そこを埋めたかったのです。 作り始めてすぐ、素朴な方法が通らないことに気づきました。「この音は何度か」を機械に判定させたい。ならば基準の音から何半音上かを数えればいい ── そう思うでしょう。私も一瞬そう思いました。これが通らないのです。 ドから8半音上の音は、ひとつではない ドから8半音上がったところに音を置いてみます。書き方は2通りあります。ソ♯と書けば増5度、ラ♭と書けば短6度です。 ピアノで押す鍵は、どちらも同じ1つの黒鍵です。 いま普通に使われている平均律では、鳴る高さも完全に同じ。つまり音として聞いても、鍵盤を見ても、この2つは区別できません。それでも名前は2つに分かれます。 分かれる理由は、度数の数え方にあります。度数は「音の距離」ではなく、ド・レ・ミ・ファ・ソ・ラ・シという音名の階段を何段またいだかで決まります。ドを1段目として数えると、ソは5段目だから5度。ラは6段目だから6度。ソ♯はあくまでソの仲間なので5度の系統、ラ♭はラの仲間なので6度の系統です。そのうえで、5度が半音広がっているから「増5度」、6度が半音狭まっているから「短6度」。 だから譜面の上でも、この2つは違う場所に書かれます。上の楽譜を見比べてください。ソ♯は下から2本目の線をまたぐ位置に、ラ♭はそのすぐ上の空間に置かれています。玉が一段ぶんずれているのです。音は同じでも、書かれる場所と名前が違う。 同じことは6半音でも起こります。ファ♯と書けば増4度、ソ♭と書けば減5度です。 どちらの名前かは、周りが決める では実際にはどちらで呼べばいいのか。それは、その音が置かれた文脈が決めます。 ド・ミ・ソ♯という3つの音が同時に鳴っているなら、これは3度ずつ積み上がった増三和音で、いちばん上は5度が広がったもの、つまり増5度です。一方、ラ♭の和音(ラ♭・ド・ミ♭)を、下からド・ミ♭・ラ♭と積み替えた形の中に出てくるドとラ♭なら、話が変わります。根っこはあくまでラ♭ですが、いちばん下にいるのはド。そのドから見上げたラ♭までが、6度が半音狭まった短6度になります。 同じ「8半音の隔たり」でも、周りに何があるかで役割が変わる。名前はその役割に付いています。ここが、音の距離だけを見ていると絶対に決まらない部分です。 2音だけだと、決め手がない さて、私のアプリの話に戻ります。 ここで扱っているのは重音、つまり2つの音を重ねるだけの練習です。文脈にあたる3つ目の音がありません。ド と ソ♯(=ラ♭)の2つしか鳴っていないとき、これが増5度なのか短6度なのかは、音そのものからは決められないのです。 実際、半音の数だけで名前を決める方式にすると、増4度と短6度がどちらも「5度」に化けます(6・7・8半音をまとめて5度と扱うため)。長2度や長6度にいたっては、対応する役割が無くてバッジそのものが消えてしまう。「短6度の重音」という名前のステージを練習しているのに、画面には「5度」と出る、という間抜けなことになります。 結局どうしたかというと、出題データがすでに答えを持っていました。このアプリの重音の問題は、そもそも「完全5度」「短6度」といった音程ごとにステージが分かれています。つまりデータ側に音程名が書いてある。あとはどちらの音が根っこかさえ分かればいいので、それもデータに持たせました。音から推測するのをやめて、最初から決まっているものを使う、というだけの話です。 3つ以上の音なら、そこまで気にしなくていい 面白いのは、和音(3〜4音)のステージでは、半音を数える素朴な方式のままで困らないことです。理由が2つあります。 ひとつは、和音で出しているのが「ルート・3度・5度・7度」の4種類だけだからです。減三和音の5度は6半音、増三和音の5度は8半音ですが、どちらも画面には「5度」としか出しません。その細かい違いは、ステージ名の「減三和音」「増三和音」がすでに言っている。表示に出ない差は、化けようがないわけです。 もうひとつは、さっき書いたとおり、3つ音がそろえば文脈が自分で決まることです。ド・ミ・ソ♯まで見えていれば、いちばん上はもう増5度としか読めない。和音は自分で文脈を持っているのに対して、重音は持っていない。同じアプリの中に、判定の方針が2つある理由はここにあります。 おまけ:ユーザーからの指摘が、古いバグを掘り当てた ここは私の手柄ではないので、順番どおりに書きます。発端は、アプリを使ってくださっている方からの「増三和音の問4〜6が短三和音になっている」という指摘でした。調べたらそのとおりで、しかも同じ種類の誤りが和音データに計6件ありました。根音を1文字打ち間違えた類のものです。 それを直したあと、バッジの実装でiOS版とAndroid版の判定を揃えるために出題データを全問突き合わせたところ、和音では見ていなかった重音のほうにも1件見つかりました。285問のうち1問です。 「短3度の重音」というステージの中に、長3度の問題が1問だけ紛れていたのです。表示だけの問題ではありません。このデータは鳴らす周波数の元にもなっているので、短3度を練習しているつもりで、その1問だけ長3度を合わせさせられていたことになります。しかもこの重音のデータは月面ステージでも共有しているので、そちらにも同じ問題が出ていました。 この1問がいつから紛れていたのかは、もう分かりません。ステージを作ったときからそのままだった可能性が高く、そうだとすればずいぶん長いあいだ、誰も気づかないまま出題され続けていたことになります。私自身も気づいていませんでした。3半音と4半音の差は、耳が育っていなければ「なんだか合わせにくい問題だな」で流れてしまいます。 見落としの本体は、データ1件そのものより、テストの守備範囲でした。以前に和音のデータについては「ステージ名が名乗る和音と、実際に鳴る音程が一致しているか」を全問検査する仕組みを入れていたのに、重音のデータは検査対象に入れていなかったのです。今回それを重音にも広げて、両OSとも修正しました。ユーザーに指摘されるまで気づけなかったわけで、データの正しさは、目視や自分の耳ではなく機械に見張らせるものだと、あらためて思い知らされました。 まとめ 音程の名前は、鍵盤の上の距離では決まりません。音名の階段を何段またいだか(度数)と、そこから半音ぶん広いか狭いか(完全・長・短・増・減)の組み合わせで決まります。だからソ♯とラ♭のように、同じ鍵を押しても違う名前になる音が出てきます。 耳で聞き分けられない違いに名前を付けるのは、一見わずらわしいのですが、その音が和音の中で何をしている音なのかを書き残すための仕掛けなのだと思います。増5度と書いてあれば、増三和音の広がった5度として置かれている。短6度と書いてあれば、ラ♭の和音を積み替えた形の中にいる。どちらへ動くかまでが決まるわけではありませんが、少なくともどういう役割で置かれた音なのかは読み取れます。楽譜は音の高さだけでなく、役割まで書いている、ということです。 アプリのほうは、この判定を組み込んで、練習中の画面に「いま合わせる音」を出せるようになりました。重音や和音を、ただ合わせるだけの作業から、いま自分が何をしているのか分かる練習にしたいと思っています。 Harmonize 相対音感と純正律の感覚を鍛える音感トレーニングアプリ 今すぐ無料でダウンロード App StoreGoogle Play

公開: 2026年7月27日 · Toshihiko Arai
海に並ぶ5種類の島と、表情を変えた3Dマスコット

島の選択マップと、倒せなかったボス ── AIと作るジャンプゲームの開発記録

前回 は、「次は島の選択マップです」と締めました。今回は予告どおり、島を並べます。 この日やったのは、島の選択マップ、輸送機の作り直し、表情の追加、そしてゲーム側のボス調整と配置ツールです。3DCGとゲーム実装はリポジトリを分けてあり、別々のセッションで並行して進めています。片方でモデルを焼いている間に、もう片方でゲームのバグを潰す。AIに指示して作らせ、出てきたものを確かめて突き返す、その繰り返しを一日ぶんまとめました。 作業の中身は違っても、詰まった場所は同じでした。3D側は拡大するまで、ゲーム側は遊ぶまで、できていないことに気づけない。 完成したという報告と、実際にできていることの差を、どう見つけたかの記録です。 まずは、島を置くだけで使えるようにする 島の選択画面に必要なのは、一枚の完成した地形ではありません。「島は1つ1つ分離して、使い回せるように」という作りです。そこで、草の饅頭島、火山島、環礁、岩礁、森の島の5種類を、それぞれ独立したビルダーに分けました。ビルダーというのは、指定すると島を一式組み立てるコードです。 もうひとつ決めたのが、すべての島で水際をローカル座標の z=0 に揃えることです。海面も z=0 にしておけば、別の場面へ持っていっても高さを調整せず、置くだけで水際が合います。前回消した島は、その場限りの背景でした。今回は、どの海にも持っていける部品として作り直したわけです。 5種類を縦画面へ並べると、ようやくステージを選ぶ地図らしくなりました。 ここまでは予告どおりです。問題は、この画面と同じゲームで使う輸送機を、真横向きの画像へ焼き直したところから始まります。 真横から見た輸送機は、飛行船だった 前回の到着ムービーでは、輸送機を4発プロペラ、高翼、T字尾翼の形まで作り直しました。ところが真横にすると、映画のカメラでは隠れていた粗が全部見えます。 機首の上には意味不明な突起があり、胴体は飛行船のように丸い。輸送機らしい跳ね上がった後部がなく、主翼はただの板です。「輸送機ってこんな形でしたっけ。米軍のを想像していた」と駄目出しし、C-130系を目標に機体を全面的に作り直させました。数秒の映像の中で輸送機に見えればよかったものを、単体で見せられる形にするということです。 ところが形を直して拡大すると、もっと妙なものが見えました。窓の影です。 窓が、機体から最大0.5も浮いていた 胴体は楕円体なので、中央は太く、機首と尾へ行くほど細くなります。それなのに窓は、胴体の太さに関係なく、すべて横方向の座標を x=±2.02 に固定していました。中央付近なら表面に見えても、細くなった端では最大0.5も空中へ離れます。真横から見ると、浮いた窓が胴体へくっきり影を落としていました。 直し方は、窓ごとにその位置の楕円体の表面を解き、胴体の太さに合わせて貼り付けることです。全窓に同じ座標を与えるのをやめると、端の窓まで機体へ降りてきました。 前回の動画では、この窓を不自然だと思っていませんでした。流れる映像なら輸送機に見える。止めて、拡大して、初めて窓が別の物体として宙に並んでいると分かります。 半目が、分類の隙間から黙って消えた 同じことが顔でも起きました。アプリ側に増えた6表情を実測し、3Dへ載せる既存の仕組みへ流したところ、眠い顔の片目がありません。 眠い顔の左右の半目は、形が少し違います。塗られている割合を示す充填率は、一方が0.66、もう一方が0.60でした。この差が分類のしきい値をまたぎ、片方だけが「丸い目」と判定されます。もう片方は、ほかのどの分類にも入りませんでした。エラーにも警告にもならず、黙って捨てられていたのです。同じ穴で「聴く」顔の片目も消えていました。 分類を増やすだけでなく、どこにも入らなかったものを無言で捨てない作りにして、両目を戻しました。あわせて、顔から浮いて影を落としていた眉と、飛び出していた目も表面へ埋め、内側まで黒く塗り潰されていた口の縁取りも、穴のあるリングとして張り直しています。窓と同じで、正面からは接して見えるのに、角度を変えると浮いている。影は、AIが置いた部品と本体の隙間を正直に描いていました。 ここまでが「拡大して見つけた嘘」です。ここからは、拡大しても見つからないほうの話になります。 「必ず倒せます」と報告したボスは、絶対に倒せなかった ゲーム側では、門を守る巨人を作っています。倒し方は、巨人の腹の下に潜り、下から突き上げて3発。腹の真下はフォークの歯が届かない安全地帯で、そこを取り合うのが駆け引きです。 このボスが倒せないと指摘すると、AIは配置の条件を直し、「腹の下に足場がある配置を保証しました」と報告してきました。テストも通っています。ところが自分で遊ぶと、やはり倒せません。 抜けていた条件は、その足場に立ったとき、頭が腹にめり込まないことでした。めり込む高さだと、体の押し返し判定が毎フレーム働いて横へ弾かれ、腹の下に居座れません。突き上げる姿勢を作れないので、何度挑んでも0発です。プレイヤーからは「絶対無理」に見えます。 「腹の下に板がある」までは合っていました。足りなかったのは、そこに人が立てるかです。画面を拡大しても、この嘘は映りません。立って、跳んで、初めて分かります。 私と同じ操作で、AIに遊ばせる そこで、実際に遊ぶ検証ボットを書かせました。使える操作は左右キーだけ。ジャンプは着地で自動的に跳ねる仕様なので、私が指で遊ぶのと完全に同じ条件です。座標を直接書き換える瞬間移動は禁止しました。それを許した瞬間、証明になりません。 最初の実行は、和音を集める前に落下死しました。次は、ボスの真下へ潜れず、68秒間ただ跳ね続けて終わりました。倒せないのではなく、そもそも潜れないという事実が、ここではっきりします。 配置の条件を直したあとの走りが、これです。和音を3つ集め、鍵を取り、突き上げ3発で撃破し、門を開けるまで約12秒でした。 このボットは回帰テストとしてリポジトリに常駐させました。攻略できなければ失敗として落ちます。「倒せる配置になっているか」を、私が毎回自分で確かめなくてよくなりました。 倒せるようにしたら、今度は怖くなくなった ところが直ったボスを遊んでみると、今度は拍子抜けしました。腹の下に潜れば絶対に刺されません。何も怖くないのです。 原因は、ボスを門をまたぐ高さに置いたことでした。フォークの高さがプレイヤーの到達上限より上へ出てしまい、安全地帯が広すぎたのです。「倒せない」を「怖くない」に付け替えただけでした。 そこで闘技場を中段へ降ろし、フォークの薙ぎがジャンプの弧と重なるようにしました。さらに突き上げの反動で横にも弾かれるようにして、一発ごとに潜り直す必要を作ります。ボットで測ると、攻略は成立したまま、歯とのニアミスが出るようになりました。倒せて、かつ危ない状態です。 配置は、数値では決まらなかった ここまでの修正はすべて、AIが座標を数値で置いては私が突き返す、の繰り返しでした。何度指示しても適格な場所に置かれず、この件だけで1〜2時間が溶けています。ここで方針を変えました。自分で置けるようにするしかありません。 PCの画面でステージ全体を俯瞰し、巨人をドラッグして置くエディタを作りました。置いた瞬間に、その板に立てるか、跳べば腹に届くか、門より下か、フォークが跳躍弧に重なるか(つまり怖いか)を判定し、OKとNGで出します。倒せない配置も置けます。禁止せず警告に留めました。道具の自由を奪えば、結局また数値の指示に戻るからです。 盤面ごと、左に寄っていた エディタで触ってみると、別の異常に気づきました。右にはいくらでも置けるのに、左には置けない。門も左に寄っている。 調べると、原因はレベルの側にありました。鍵盤は15レーンあり、横位置がそのまま音の高さです。ところがステージ1の和音はドミソで、使うのは15本中の0番、2番、4番。盤面ごと鍵盤の左3分の1に固まっていたのです。門は最上段の板の真上に立つ仕様だったので、門も一緒に左端へ寄っていました。右側の10本は、その島では一度も使わない死に幅です。 そこで、その島が実際に使うレーンの中心が画面中央へ来るよう鍵盤ごとずらし、門の中心は和音のまん中の音(ドミソなら「ミ」)の真上に変えました。左右に同じだけ余白ができ、巨人の入場も回り込みも、どちらの側でも成立します。 確認する道具も、確認しなければ壊れる 3D側では、11表情を横や斜めから見る確認動画を作りました。ところが視点を増やすと、カメラの狙いが外れて背景一色になり、次はキャラの内部へ入り、その次は床の下へ潜ります。表情を確かめる動画そのものが、表情を映していませんでした。目視で済ませず、全フレームにキャラの画素が十分あるかを数値で検査する手順を足しています。 ゲーム側の検証ボットも同じでした。最初のボットは操縦が下手で、板を外して落ちるたびに「ゲームが悪い」ように見えます。ボットの操縦ミスと、ゲームの不具合を切り分けられるようになるまで、何度も書き直しました。成果物を確かめる道具も成果物です。信用する前に、道具のほうを疑う必要があります。 AIが直したと報告した箇所ほど、私が触ると壊れているのも同じ構図でした。「向きを変えられるようにしました」と言うので探すと、ボタンのラベルは「入場: 自動」。これでは何のボタンか読めません。予告マークが出ないと指摘して調べさせると、出現の判定は新しい設定を見るよう直したのに、予告を消す判定だけ古いままで、毎フレーム消されていました。 GPUで速くなった話の訂正 前回の記事で、レンダリングをMacのGPUへ切り替えて速くなったと書きました。今回、新しいスクリプトがCPUで動いていたので調べ直すと、設定を各スクリプトへ手書きしていたため、追加のたびに漏れる作りでした。さらに、Metalを指定した既存スクリプトも、GPUとCPUの両方を有効にしていました。 実測すると、混在は57.9秒で終わる代わりに、CPU時間の合計は400秒を超えます。GPUだけなら87.3秒、CPU時間は68.8秒でした。待ち時間だけなら混ぜたほうが速い。しかしその間、CPUを食い潰します。「GPUにして速くなった」は、半分は本当で、半分は見ていませんでした。設定欄の METAL を確認したところで満足し、その下でCPUも働いているところを拡大していなかったわけです。 ...

公開: 2026年7月26日 · Toshihiko Arai
電話のキーパッドと、低群4×高群4のDTMF周波数マトリクス。ボタンを押すと2つの周波数の音が同時に鳴り、受信側は8つの周波数のエネルギーを測ってボタンを復元する図

「ピポパ」を解読する ── DTMFと、音でデータを送った時代

スマートフォンの電話アプリで番号を押すと、いまでも「ピ、ポ、パ」と鳴ります。あれは押した感触を出すための効果音ではありません。押したボタンそのものを音に変換した、れっきとしたデータ通信です。だからあの音を録音すれば、あとから何番を押したのか割り出せてしまう。テレビ番組で電話番号を入力する場面の音が伏せられることがあるのは、このためです。 この方式は DTMF(Dual-Tone Multi-Frequency、2つの音を同時に使う多周波信号)と呼ばれ、1963年にアメリカのベル・システムがプッシュホンとともに実用化しました。今回はこの「ピポパ」を材料に、音でデータを送るとはどういうことか、そして受け取った音をどう解読するのかを見ていきます。この連載では音の正体は数の列だ というところから始めて、楽器の音をプログラムで作る話を続けてきましたが、今回は楽器ではなく、音を「文字」として使う回です。 ボタンは音の「座標」でできている プッシュホンの前の世代、ダイヤルを回す黒電話は、まったく別の方法で番号を伝えていました。ダイヤルが戻るあいだに、回した数字の回数だけ回線を切ったりつないだりする。カチカチという断続そのものが合図で、これはパルス式と呼ばれます。機械的で確実ですが、遅く、そして交換機に向けた「番号選び」専用の合図なので、電話がつながった後の相手には何も伝えられません。 黒電話に触ったことがない世代のために補足すると、ダイヤルは指を穴に差し込んで、金具(指止め)まで回して離す道具です。回すときではなく、バネで戻るあいだに回線が断続します。「1」なら1回、「9」なら9回、「0」は10回。数字が大きいほど戻りが長く、ダイヤルするだけで時間がかかりました。市外局番から順に回していると、それだけで十数秒かかることも珍しくありません。 DTMFの発想は逆で、合図をただの「音」にしてしまいました。音でありさえすれば、電話線でも、空気中でも、録音テープの上でも通ります。つながった後の回線にも当然乗るので、通話の途中でボタン操作を送れる。音声ガイダンスの「〜の方は1を押してください」が今日でも成立しているのは、この性質のおかげです。 では、どんな音にするか。ここがDTMFの核心です。 用意するのは8つの音だけです。低めの4音(697・770・852・941ヘルツ)を「低群」、高めの4音(1209・1336・1477・1633ヘルツ)を「高群」とし、低群から1つ、高群から1つを選んで同時に鳴らす。低群がキーパッドの行を、高群が列を決めるので、2音の組はそのままボタンの座標になります。たとえば「5」は770ヘルツと1336ヘルツの同時再生。この組み合わせは「5」だけのもので、ほかのどのボタンとも重なりません。4×4で16通り、電話機に載っている12個のキーに、業務用などで使う拡張のA〜Dを足した16記号がこれで表せます。 なぜわざわざ2音同時なのでしょうか。1音だけでも「697ヘルツが鳴ったら1」と決めれば済みそうなものです。ところが電話回線には人の声が流れています。声にも口笛にもテレビの音にも、697ヘルツ付近の成分くらいいくらでも含まれるので、1音では「たまたま鳴っていた音」と区別がつきません。一方、離れた2つの決められた周波数が、同時に、それだけで鳴るという状況は、偶然にはまず起きません。しかも8つの周波数は、どれも他の音の整数倍(倍音の関係)にならないよう慎重に選ばれています。回線の歪みで倍音が生まれても、別の目標周波数に化けて誤検出を起こさないための用心です。電話回線が通せる帯域はおおむね300〜3400ヘルツと狭いのですが、8音はきちんとその中に収まっています。 この8つの数字は、ITU-T勧告Q.23として国際的に決められた値です。北米で開発されたTouch-Toneがそのまま国際規格になったので、日本のプッシュホンも、海外の電話機も、同じ周波数を使います。日本の携帯から海外の音声ガイダンスを操作できるのは、このおかげです。 ただし、規格どおりの2音をそのまま合成すると、記憶の中のプッシュ音とは少し違って聞こえます。本物には、決まった周波数のほかに2つの作法があるからです。ひとつはツイスト。電話線は高い音ほど減衰するので、送信側で高群を低群より2〜3デシベル強く鳴らしておきます。もうひとつは帯域。実際の音は300〜3400ヘルツしか通らない回線と、小さな受話器のスピーカーを経由して耳に届きます。純粋な正弦波をそのまま鳴らすと、澄みすぎて、あの少し詰まった感じになりません。下のデモは、この2つを模した状態で鳴らしています。 受ける側は、8ヶ所を聴診するだけ 送る側が「2音を足すだけ」なら、受ける側の仕事も驚くほど少なくて済みます。音に含まれるすべての周波数を調べる必要はありません。知りたいのは、決められた8つの周波数のそれぞれが「鳴っているか、いないか」だけです。 受信側は、届いた波形に対して8つの周波数それぞれのエネルギーを測ります。イメージとしては、8本の聴診器をそれぞれ決まった高さの音だけに当てて、どれが強く響いているかを聞き比べる感じです。低群の4本のうち1本だけ、高群の4本のうち1本だけが突出していれば、行と列が確定してボタンが分かる。どちらかの群で1本も立たない、あるいは2本立ってしまったら、それはDTMFではない(ただの声や雑音だ)として捨てる。判定が白黒はっきりしているのが、この設計の気持ちよさです。 この「特定の周波数だけを効率よく聴診する」計算には、ゲルツェル法(Goertzel algorithm、1958年にGerald Goertzelが発表)という定番のアルゴリズムがあります。周波数分析というとFFTのような大掛かりな変換を思い浮かべますが、知りたい周波数が8つと決まっているなら、その8ヶ所だけを漸化式ひとつで安く測れる。電話交換機のように何百回線も同時に監視する装置では、この安さが効きました。 Tip 漸化式という言葉が硬いのですが、要するに「前の答えを使って次の答えを出す式」のことです。プログラムで書けば、1つ前と2つ前の値を変数に持っておいて、ループを1周するたびに更新していくだけ。s[n] = 係数 * s[n-1] - s[n-2] + 入力 のような形になります。再帰と同じ考え方で、実装は素直なループです。 音の波形から必要な情報だけを抜き出すという意味では、マイクの音から音程を当てるピッチ検出 も同じ仲間です。あちらは「知らない高さを探す」問題で、こちらは「決まった高さがあるか確かめる」問題。探し物の種類が違うだけで、どちらも音を数の列として受け取り、計算で答えを取り出します。 触ってみる 言葉より押してみるのが早いので、デモを用意しました。キーパッドを押すと、そのキーの2音が実際に鳴ります。そして右上の解読欄に注目してください。ここに出る文字は、ボタンの信号を横流ししたものではなく、いま鳴った音の波形だけを毎フレーム受け取り、8つの周波数のエネルギーを測って復元したものです。エンコードとデコードが、スピーカーとプログラムのあいだで本当に往復しています。 うまく表示されないときは、デモを別タブで開く 。 「じゃま音を混ぜる」で試せること。 2音の組にした理由は、声や雑音と区別するためでした。それを自分で確かめられるように、回線に人の声や雑音が乗った状態を再現するボタンを付けました。押すと、8つのメーターは絶えず揺れ、スペクトラムにも山が立ちます。それでもキーは1つも確定しません。そのまま数字を押せば、じゃま音の上からでもきちんと解読されます。 実は、この機能を足したときに誤検出が出ました。声の代わりに純音を揺らして流していたのですが、たまたま低群と高群の1本ずつが強く出た瞬間に、デコーダが「キーが押された」と判定してしまったのです。これは実際の電話でも「トークオフ」と呼ばれる有名な誤動作で、通話中の声がボタン操作に化ける現象です。対策も実機と同じで、2本の山が8本ぶんのエネルギーの過半を占めていることを条件に加えました。声や雑音はエネルギーが広く散らばるので、この一行で弾けます。 真ん中の「8つの聴診器」で、押すたびに青(低群)と紫(高群)が1本ずつ立ち上がるのを確かめてください。その下のスペクトラム、つまりどの高さの音がどれだけ鳴っているかのグラフでは、どのキーを押しても山がきっかり2本だけ立ちます。音を周波数の軸で眺める見方は、周波数特性の記事 でも扱いました。キー列は「1234」でも「0000」でも、意味のない適当な並びで十分です。 いちばん下のおまけは、後で触れるカセットテープ方式の再現です。短い文字列を0/1のビット列にして、低い音と高い音の「ピーガガガ」で送り、受信側がそれを聴き取って文字に戻します。 どう実現するか 送る側は本当に足し算だけです。キーに対応する低群・高群の周波数でサイン波を2本作り、足して鳴らします。 // 「5」の音: 770 Hz + 1336 Hz function dtmfSample(n, fs){ const t = n / fs; return 0.5 * (Math.sin(2 * Math.PI * 770 * t) + Math.sin(2 * Math.PI * 1336 * t)); } 受ける側の「聴診」も、正体は素朴な掛け算と足し算です。調べたい周波数 $f$ のコサインとサインを波形に掛けて足し込むと、その周波数の成分だけが積み上がり、無関係な成分は打ち消し合ってゼロに近づきます。積み上がった量の2乗和が、その周波数のエネルギーです。 ...

公開: 2026年7月26日 · Toshihiko Arai
連載『手で動かすAI』第6回のカバー。3つの生スコアの棒が、指数で持ち上げられ、合計で割られて、足すと100%になる確率の棒に変わるイラスト

自信の大きさまで答えさせる ── 出力を確率に整えるソフトマックス

前回 、手で描いた数字を自作のネットワークに読ませました。出口には10本の棒が並び、いちばん長い棒の数字が答えでした。ただ、あの棒の高さは、10個の出力ニューロンがそれぞれ勝手に出した反応の強さで、足しても100%にはなりません。だから「答えは3」とは言えても、「どのくらいの自信で3なのか」「2番手の8とどれだけ差があるのか」は、あの棒のままでは読み取れませんでした。 今回は、その生の出力を確率のかたちに整える、小さな仕上げを一つ入れます。名前はソフトマックスといいます。仕組みはあっけないほど単純で、けれどこの先ずっと出てくる部品です。 生の反応は、そのままでは確率にできない やりたいことは、10個(今回は話を追いやすいよう、3・5・8の3個で考えます)の生スコアを、足すと100%になる確率に変えることです。素朴に考えると、全部を合計で割ればよさそうに思えます。3個のスコアを足して、各自をその合計で割れば、たしかに合計は1になります。 ところが、これはうまくいきません。ニューロンの出す生スコアには、マイナスの値がふつうに混じるからです。マイナスのスコアを合計で割ると、マイナスの確率という意味をなさない数字が出てしまう。合計そのものがゼロに近くなれば、割り算も破綻します。確率は0%から100%のあいだの正の数でなければならないのに、生スコアはその約束を守ってくれません。 そこで一手はさむ。合計で割る前に、すべてのスコアを指数関数に通します。指数関数というのは、$e^x$ ── ネイピア数$e$(約2.718)を、スコアの数だけ掛け合わせる関数です。難しく身構える必要はなくて、ここで効く性質はたった二つだけです。ひとつ、どんな入力(負の数でも)を入れても、出てくる値は必ずプラスになる。もうひとつ、入力が大きいほど、出力は急激に大きくなる ── つまりスコアの差を、より際立たせる。 指数で全部プラスに直してしまえば、あとは安心して合計で割れます。これでようやく、足すと100%になる確率が手に入ります。 図の左端、数字5の生スコアはマイナス0.5でした。このままでは確率にできませんが、指数に通すと0.61という小さなプラスの値になります。数字3のスコア2.0は指数で7.39まで持ち上がり、8の1.0は2.72になる。三つを合計すると10.72。あとはそれぞれを10.72で割れば、69%・6%・25%という、足してちょうど100%の確率が出そろいます。いちばんスコアの高かった3が、いちばん高い確率になる。順位は変わらないまま、「どれくらい自信があるか」という情報が新しく読めるようになりました。これがソフトマックスの全部です。 式で書けば、$i$番目の出力の確率は次のように決まります。分子が「そのスコアを指数に通したもの」、分母が「全員を指数に通して足したもの」で、割り算がまさに正規化にあたります。 $$ p_i = \frac{e^{z_i}}{\displaystyle\sum_j e^{z_j}} $$触って確かめる 言葉より、動かすのが早いです。下で3つの数字の生スコアをスライダーで動かすと、ソフトマックスが整えた確率が、その場で棒に組み替わります。 うまく表示されないときは、デモを別タブで開く 。 どんなふうにスコアを動かしても、3本の確率を足すと必ず100%になります。ここがソフトマックスの効き目です。「3と8が僅差」のボタンを押すと、二つがほぼ半々に割れて、ネットワークが迷っている様子がそのまま数字に出ます。「3が断然」なら、3が98%まで跳ね上がる。答えを一つ選ぶだけなら生スコアの大小を見れば済みますが、こうして確率にしておくと、その答えをどれだけ信用していいかまで一緒に読めるわけです。 温度で、自信の尖り方が変わる デモにはもう一つ、温度$T$というスライダーがあります。これは指数に通す前に、スコアをまるごと$T$で割っておく、という小さな細工です。式でいえば分子と分母の肩が$z_i/T$に変わるだけ。 $$ p_i = \frac{e^{z_i/T}}{\displaystyle\sum_j e^{z_j/T}} $$温度を下げると($T$を1より小さく)、スコアの差が拡大されて、確率は一点へ尖ります。勝者がほぼ100%を総取りして、自信満々の出力になる。逆に温度を上げると($T$を1より大きく)、差が薄められて、確率はなだらかに均されます。三つが横並びに近づいて、迷いの多い出力になる。デモの「温度を下げる/上げる」で、この尖りとなだらかさを行き来してみてください。 この温度という言葉は、ずっと先で言語モデルに次の単語を選ばせるときに、また出てきます。文章生成AIの設定項目として実在するもので、開発者向けの画面(GoogleのAI StudioやOpenAIのPlaygroundなど)を開くと、温度のスライダーが並んでいます。上げると突飛で多様な言葉が出やすくなり、下げると無難で堅い言葉に寄る ── あれは、次の単語の候補につけたソフトマックスの確率を、いま見たとおりに尖らせたり均したりしているだけなのです。普段のチャット画面には出てこない設定ですが、裏ではこの計算が動いています。 確率にしておくと、学習も素直になる 自信が読めるようになるのは、人間が結果を眺めるときに便利、というだけではありません。学習そのものにも効きます。この連載では第0回 から、学習とは「どれだけ外したか」を表す一本の数字(誤差、専門的には損失とも呼びます)を小さくしていくことだ、とくり返してきました。数字の分類では、正解のラベル(たとえば「これは3」)に対して、ネットワークが3にどれだけ高い確率を割り当てられたかで、この間違いの大きさを測ります。正解の確率が1に近ければ損失は小さく、0に近ければ損失は大きい。この測り方(交差エントロピーと呼びます)は、出力が確率になっていて初めて素直に使えます。ソフトマックスは、答えを読みやすくすると同時に、学習の土台もきれいに整えているわけです。 新しい部品としては、これで打ち止めです。ソフトマックスは、指数で持ち上げて合計で割るだけ。それでネットワークの生の反応が、足して100%の確率に変わり、答えと一緒に自信の大きさまで返せるようになりました。 前回のネットは、これで確率まで返せる一人前の分類器になりました。ただ、テスト正解率95.7%という数字には、まだ一つ問い返す余地があります。このネットは本当に数字の形を理解して読めているのか、それとも訓練で見た6万枚を、うまく丸暗記しているだけなのか。次回は、その「理解」と「暗記」の境目を見にいきます。 連載「手で動かすAI」 ← 前回 手で描いた数字を、自作のネットワークが読む 次回 → 覚えるのと分かるのは違う

公開: 2026年7月26日 · Toshihiko Arai
連載『手で動かすAI』第5回のカバー。手書きの数字3が、入力784ピクセル・出力10個のニューラルネットワークに入り、3の出力がいちばん強く光って答えになるイラスト

手で描いた数字を、自作のネットワークが読む ── ここまでの部品だけで

ここまで4回かけて、部品を一つずつ組み上げてきました。ニューロン1個(第1回 )、それを重ねたネットワーク(第2回 )、数字が鎖を流れる前向き計算(第3回 )、そして全つまみを一度に回す逆伝播(第4回 )。ただ、動かしてきたのはいつも、平面に散らばった点や、たった4つのXORといったおもちゃでした。今回はいよいよ、この同じ部品だけで、実物を動かします。あなたが手で描いた数字を、自作のネットワークに読ませてみましょう。約束しておくと、新しい仕組みは一つも足しません。 数字も、結局は数の列 サウンドプログラミングの連載では、音は数の列 だという話から始めました。機械にとって数なのは、音にかぎりません。手で描いた数字も例外ではありません。28×28のマス目に描いた絵は、それぞれのマスがどれだけ黒いかという、784個の数(0から1)の並びにすぎません。ネットワークからすれば、これは入力が784個あるというだけのことです。 前回 まで、入力は2つ(大きさと甘さ、あるいは点のx1とx2)でした。それを784個に増やす。出口のほうも、これまでは1つでしたが、今回は0から9までの10個用意します。10個の出力ニューロンが、それぞれ「この絵は0っぽいか」「1っぽいか」……と反応し、いちばん強く反応した出口を答えとする。仕組みとして新しいのは、この「入口を増やし、出口を10個にしていちばん強いものを選ぶ」ところだけで、部品そのものは第1回 のニューロンのままです。 学習のやり方も、新しくありません。第4回 の逆伝播を、そのまま使います。手書き数字を大量に集めたMNISTという定番の練習台(何者かはデモのあとで触れます)を用意し、その6万枚を1枚ずつネットワークに通して、出た答えと正解のズレから全部のつまみの勾配を求め、少しだけ回す。これを何万回とくり返すだけです。つまり、この回で本当に新しいものは、何一つありません。ただ入口と出口を広げて、たくさんの例で今までどおり学習させた。それだけで、次のデモが動きます。 描いて、読ませる 言葉より、試すのが早いです。下の黒い欄に、0から9の数字を1つ、大きめに描いてみてください。指でもマウスでもかまいません。 うまく表示されないときは、デモを別タブで開く 。 描き終えると、右の10本の棒が動きます。これがまさに10個の出力ニューロンの反応の強さで、いちばん長い棒の数字が、ネットワークの答えです。中身は、たった今説明したとおりのネットワーク(入力784・隠れ層48・出力10)で、MNISTの6万枚から前回の逆伝播で学習させたもの。ブラウザの中で動いているのは、その学習済みのつまみを使った前向き計算だけです。ひとつだけ舞台裏を明かすと、描いた絵はそのまま渡すのではなく、中央に寄せて大きさをそろえてから28×28にしています(小さな28×28の表示が、実際にネットワークへ渡している絵です)。学習に使ったMNISTの数字が中央ぞろえだったので、それに合わせているだけです。 太く・大きく・なるべく真ん中に描くと、よく当たります。逆に、隅に小さく描いたり、他の数字と紛らわしい崩し方をすると間違えます。95.7%というのは裏を返せば、20枚に1枚くらいは外すということでもあります。人間だって走り書きは読み違えるので、そこは似たようなものです。 ひとつだけ先に断っておくと、日本で習うとおりに旗をつけて「1」を書くと、このデモはほぼ確実に7と答えます。 崩し方の問題ではなく、学習に使った数字の書き手が原因です。理由は後の節 で書きます。 学習に使ったMNISTのこと さきほど後回しにしたMNISTに触れておきます。手書き数字を集めた画像のセットで、訓練用が6万枚、答え合わせ用が別に1万枚あります。1枚は28×28の白黒画像で、それぞれに「これは3」という正解が添えてあります。元になった数字を書いたのは、アメリカの国勢調査局の職員と高校生で、1990年代に機械学習用として整理されました。 このセットが長く使われてきたのは、みんなが同じ問題を解いているからです。新しい手法を思いついた人がまずこれで試し、「うちの方法は98%当たった」と言えば、他の手法と同じ土俵で比べられる。共通のものさしとして便利なので、機械学習を始める人が最初に触れる題材にもなりました。今回のネットワークが出した95.7%も、この土俵の上での数字です。 「1」がどうしても7になる、という報告 ここに、この連載でいちばん大事かもしれない落とし穴があります。日本で習うとおりに「1」を書くと、このデモはまず外します。 左上から斜めに入る、旗のついた1のことです。 手元で同じデモに描いて測りました。旗つきの1は7が64%、9が21%で、正解の1はわずか1%。同じ位置に旗のない素の縦棒を引くと、1が98%になります。ついでに本物の7を描くと7が94%。つまりネットワークから見て、旗つきの1と7はほとんど同じ形なのです。上に斜めの線があって、そこから下へ伸びる ── 言われてみれば、そのとおりです。 原因は仕組みではなく、学習に使った数字を書いた人にあります。MNISTを書いたのはアメリカの国勢調査局の職員と高校生で、アメリカ式の「1」はただの縦棒です。旗つきの1は、6万枚の中にほとんど入っていません。見たことのない形を出されたネットワークは、手持ちの知識でいちばん近いもの、つまり7と答えます。 95.7%という数字は、あくまでMNISTと同じ書き方の数字に対しての成績です。書き手が変わり、国が変わり、時代が変わると、同じネットワークがあっさり外す。学習データに何が入っていて、何が入っていないか。それが、仕組みの良し悪しと同じくらい結果を左右します。この連載でこの先どんな仕組みを足しても、入っていないものは読めないという事実だけは変わりません。 (デモで試すときは、旗をつけずに縦棒で「1」を書いてみてください。素直に当たります。) なお、このページが持ち歩いているのはMNISTそのものではありません。6万枚から学び終えたあとの重み、つまり数値が4万個弱の入ったファイルだけです。画像の山は学習が済んだ時点で役目を終えていて、あなたが数字を描いたとき動いているのは、その数値を使った掛け算と足し算だけです。 これが、画像認識の芯 ここで一度、立ち止まる価値があります。いま動いたものは、写真から猫を見つけたり、スキャンした文字を読み取ったりする画像認識の、まぎれもない芯です。使った道具は、この連載で手を動かして作ってきた三つ ── ニューロン、それを重ねること、そして勾配降下 ── だけ。それを入力784個・出力10個に広げ、6万枚で回しただけで、手書き数字が95%以上読めてしまう。世の中の巨大な画像認識も、つまみの数が何億に増え、層がずっと深くなっただけで、芯の考え方はいま触ったこれと同じです。 もちろん、このネットワークにはまだ素朴なところがあります。たとえば784個の入力を、ネットワークは順番のないただの数の袋として扱っていて、それが本当は縦横に並んだ一枚の絵だということを知りません。隣り合ったピクセルが関係しているという当たり前の事実を、まだ活かせていないのです。ここを作り込むと、認識はもう一段強くなります。 また、10本の棒の高さは、いまはそれぞれのニューロンが勝手に出した反応の強さで、合計しても100%になりません。「この絵は80%の自信で3」といった、確率らしい出力に整える一手も、まだ入れていません。 次回はまず、この出力を確率のかたちに整えるソフトマックスという小さな仕上げを見て、そのあとで、ピクセルが一枚の絵だという事実を活かす方法へ進んでいきます。土台の上に、実物のための工夫を一つずつ足していく段階に入ります。 連載「手で動かすAI」 ← 前回 100万個のつまみを、どうやって一度に回すのか 次回 → 自信の大きさまで答えさせる

公開: 2026年7月25日 · Toshihiko Arai
途切れたトーンの切れ目を無音のままにすると途切れて聞こえ、ノイズで塞ぐと破線のように音が続いて聞こえることを示した図

鳴っていない音が聞こえ続ける ── 連続性の錯覚

電話の向こうで工事の音がして、相手の声がところどころかき消される。それでも会話は途切れて聞こえず、声はずっと続いていたように感じる。誰でも身に覚えのあるこの日常は、実は耳の錯覚です。かき消された瞬間、声の証拠は本当に耳へ届いていません。それでも聞こえた気がするのは、脳がその区間を作って埋めているからです。 連続性の錯覚と呼ばれるこの現象は、この連載の「耳のバグ」の棚では差音 ・ミッシング・ファンダメンタル ・シェパードトーン ・リセ・リズム に続く5本目です。これまでの4本が音の高さやテンポの錯覚だったのに対し、今回は「鳴っていない音がまるごと聞こえる」という、いちばん大胆な捏造を耳がやってのけます。 穴は穴に聞こえる。では塞ぐと? まず錯覚が起きない側から見ます。サイン波のような単純な音を、鳴らして、止めて、また鳴らして、と繰り返すと、当然ながらプツプツと途切れた音に聞こえます。切れ目は100ミリ秒。短いようで、耳には隠しようのない長さです。 ここで、切れ目の区間だけに大きめのノイズをかぶせます。音そのものは1ミリ秒たりとも足していません。トーンは切れ目で完全に止まったまま、穴をノイズで塞いだだけです。ところが聞いてみると、トーンはノイズの向こうで鳴り続けている1本の音に化けます。物理的には存在しない区間の音を、耳がはっきり聞かせてくるのです。 種を明かすと、これは脳が行っている推論の副産物です。ポイントは、かぶせたノイズが「もしトーンが鳴り続けていたとしても、かき消してしまう」だけの大きさを持っていることです。このとき脳の立場からすると、ノイズの区間にトーンの証拠が無いのは当然で、「途切れた」証拠にはなりません。鳴っていても鳴っていなくても、届く音は同じだからです。そこで脳は、切れ目の前後がきれいにつながるという状況証拠から「鳴っていたはず」と判定し、その区間の音を自前で補って聞かせます。逆に言えば、ノイズが小さくて「鳴っていれば聞こえたはず」の状況では、脳は正しく「途切れた」と判定します。錯覚が起きるかどうかの分かれ目は、ノイズの音量が握っているわけです。 触ってみる 切り替えながら確かめられるデモを用意しました。音の高さがゆっくり上下する「うねる音」で、まず「無音のまま」のプツプツ途切れた状態を確認してから、「ノイズで埋める」に切り替えてみてください。それだけで、うねりがノイズの向こうで1本につながります。切れ目の間も音程が動き続けて聞こえたら、それは完全に脳の作った音です。イヤホンで聴くとよく効きます。 うまく表示されないときは、デモを別タブで開く 。 いちばんの見どころはノイズの音量スライダーです。つながって聞こえている状態から少しずつ下げていくと、どこかで錯覚が壊れて、突然「途切れた音+小さいノイズ」に聞こえ出します。先ほどの理屈どおり、「鳴っていれば聞こえたはずなのに聞こえない」と脳が判定できる音量まで下がった瞬間です。「一定の音」モードも用意しましたが、こちらは効き方の個人差がかなり大きい上級編です。動き続ける軌道という強い手がかりを持つうねる音に比べて、一定の音の補完は地味で、同じ音量でも途切れて聞こえる人がいます。錯覚は万人に同じ強さでは働かない、という実感も含めて試してみてください。 この錯覚は、単純な音だけでなく言葉でも起きます。文章の一部の音を咳の音で置き換えて聞かせると、聞き手は欠けた音素まで含めて文章を完全に聞き取り、どこが欠けていたかを言い当てられない。1970年に心理学者リチャード・ウォーレンが報告した音素修復と呼ばれる実験で、連続性の錯覚が日常の聞き取りをずっと下支えしていることを示しました。雑踏や電話越しで会話が成立するのは、耳が物理的な音をそのまま報告する装置ではなく、欠けを埋めながら聞かせる推論装置だからです。 どう実現するか デモの実装は、この連載でやってきたことの組み合わせで足ります。トーンは鳴らしっぱなしのオシレーターを、ゲイン(音量)の自動化で周期的にオン・オフするだけ。ノイズは2秒ぶんの乱数を詰めたバッファをループ再生して、切れ目の区間だけゲインを上げます。 const PERIOD = 0.53, TONE_ON = 0.43; // 0.43秒鳴らして0.1秒の切れ目 const OVERLAP = 0.04, RAMP = 0.012; // ノイズは切れ目より少し広く覆う // サイクル k のトーンとノイズの窓 toneGain.gain.setValueAtTime(0, on); toneGain.gain.linearRampToValueAtTime(TONE_GAIN, on + RAMP); toneGain.gain.setValueAtTime(TONE_GAIN, off - RAMP); toneGain.gain.linearRampToValueAtTime(0, off); noiseGain.gain.setValueAtTime(0, off - OVERLAP); // 切れ目の少し前から noiseGain.gain.linearRampToValueAtTime(g, off - OVERLAP + RAMP); ただし、この錯覚には成立条件があって、雑に作ると全く働きません。実は開発中の最初の版では、真っ白なノイズをそのまま被せていて、錯覚が起きませんでした。ノイズは十分うるさく聞こえるのに、トーンは途切れたまま。計算してみると原因は明快で、白色ノイズはエネルギーが全周波数に薄く広がるため、トーン周辺の帯域だけを見るとトーンのほうが18dBも大きく、まるでかき消せていなかったのです。かき消せていない以上、脳は正しく「途切れた」と聞き取ります。そこでノイズをバンドパスフィルターでトーンの帯域へ絞り込み、ゲインを掛けて、帯域内でノイズがトーンを6dB以上上回るよう設計し直しました。帯域はかなり細く(Q=7)絞っています。マスキングに効くのは帯域内の音圧だけで、帯域の外に広がるエネルギーは錯覚に寄与せず、ただうるさいだけだからです。絞るほど、同じマスキング力を小さな総音量で実現できます。錯覚を起こすのは「うるさいノイズ」ではなく「その音の居場所を静かに占拠するノイズ」です。 うねる音では、このバンドパスの中心周波数を音程の軌道に追従させています。ここにも一つ罠があって、バンドパスの帯域幅は中心周波数に比例して広がるため、そのままだと高い音程のときほどノイズの総量が増えて、ノイズ自体の音量がうねって聞こえてしまいます。中心周波数に応じてゲインを補正し、総音量を音程によらず一定に保っています。 細かい数字もふたつ効いています。ひとつは12ミリ秒のランプで、ゲインを瞬間的に切り替えるとプチッというクリックノイズが出て、そこが「切れ目の証拠」として耳に残ってしまいます。もうひとつはノイズの窓を切れ目の前後に40ミリ秒ずつ、合わせて80ミリ秒だけ広く取っている点です。トーンの端とノイズの端がぴったり同時だと、切り替わりの縁が聞き取れてしまう。ノイズが先に立ち上がってからトーンが消えるようにして、縁を完全に覆い隠します。錯覚の実験装置は、こういう縁の処理が生命線です。 ちなみに、この錯覚は音声技術の側でも実用されています。インターネット通話で音声データの一部が届かなかったとき、欠けた区間を前後から予測した音で埋めるパケットロス隠蔽という処理は、脳が勝手にやっている補完を機械側で肩代わりする発想です。埋め方が多少雑でも、聞き手の脳がさらに上から補正してくれるので、思いのほか気づかれません。 参考文献 R. M. Warren, “Perceptual Restoration of Missing Speech Sounds,” Science, vol. 167 (1970), pp. 392–393. DOI: 10.1126/science.167.3917.392 。咳で置き換えた音素が補完されて聞こえる音素修復の原論文。 連続性の錯覚の全体像は Wikipedia: Continuity illusion がまとまっています。 デモの実装には Web Audio API を使用。GainNode のオートメーションでトーンとノイズの窓を予約しています。 音が消えている100ミリ秒のあいだ、耳に聞こえているものの正体を、ぜひデモで確かめてみてください。 ...

公開: 2026年7月25日 · Toshihiko Arai
みかん色のパラシュートで空を降下するえびふりゃ。遠くに飛行機が小さく去っていく

輸送機から降ってくるマスコット ── ゲームの開幕ムービーを、AIとBlenderで作った

前回 、音感トレーニングのジャンプゲームをAIと作っている話を書きました。画面の横軸がピアノの鍵盤になっていて、和音の音の上だけに足場が出るあれです。あれからリリースに向けてあれこれ手を入れ続けているのですが、その試行錯誤の途中で思いついたのが、今回の到着ムービーです。ステージが島になっていて、新しい島に挑むたびに「飛行機で島へ運ばれて、パラシュートで降りて、砂浜に着く」というシーンが流れたら格好いいのではないか。 思いついたプロットはこうです。上空を俯瞰で飛ぶ飛行機。腹のドアが開いて、マスコットのえびふりゃが落ちる。落下の途中でパラシュートがバサッと開いて、ふわりと浮く。砂浜に着地して、勢い余って砂に埋まる。鉢巻きと尻尾だけ覗かせてブルブル震え、ポンッと飛び出して、さあ冒険だ。 先に、完成したものをお見せします。25秒・全8ショット・614フレーム。雲海の巡航からジャンプまでの通しです。 ここから先は、この25秒がすんなりできなかった、という話です。作り方は3D化のとき と同じで、Blenderを私は一切触らず、コードは全部AIに書かせます。舞台になる海辺は釣りの世界 で一度作ってあるので、今回は流用すればすぐ終わる──と思っていました。終わりませんでした。この記事は、その顛末の記録です。 また、海に負けかけた まず舞台のビーチです。私は最初に釘を刺しておきました。海を作るのはすごく大変だったのだから、釣りゲームで作った海を活用してほしい、と。あの海は、サイン波を全部捨ててノイズにたどり着くまで三度負けた、いわくつきの海です。 AIは「海を移植しました」と、それらしいビーチを出してきました。ところが見ると、全然違う。うねりがゴロゴロした、彩度の高い、どこかで見たようなCGの海。しかも波打ち際には泡の玉が置物のように並んでいる。置物の泡は、釣りの海で「チートがバレましたね」と白状させた、まさにその却下案です。同じAIが、同じ人間相手に、同じ手を二度打ってきたわけです。 問い詰めると、原因はあっけないものでした。AIは釣りの記事の「文章」は読んでいたのに、記事に載っている海の「画像」を一度も見ていなかった。文章から仕組みだけ拾って、見た目は自分の癖で作っていたのです。画像を並べて比較させてようやく、波はほぼ平らでいい、色は淡い岸から水平線の濃い帯への3段だ、主役は細かいきらめきの粒だ、と伝わりました。 ついでに技術的な収穫もひとつ。色がどうしても濃く沈む問題の犯人は、色空間の変換漏れでした。人間が指定する色(sRGB)とレンダラーが計算に使う色(リニア)は別物で、変換せずに渡すと「深い紺」のつもりが「中途半端な青」になる。分かってしまえば一行の変換関数の話ですが、これを踏むまで、私は何度も「記事の海と全然違う」と言い続けることになりました。 波打ち際は釣りの海の結論をそのまま使っています。水際線を描くのではなく、海へ下る砂の斜面と水面の交わる線から「生まれさせる」方式。おかげで泡の白い線は、置物ではなく水面の高さの等高線として、勝手に有機的な曲線になります。 頼んでいない島が、生えてきた 事件はビーチの沖で起きました。あるとき水平線の手前に、緑色の饅頭が2個浮かんでいたのです。言っておきますが、私は島を頼んでいません。このゲームはステージを島単位で渡っていく作りなので、海の向こうに次の島が見えたら気が利いているだろう、とAIが自分で判断して置いたようです。 気持ちは分かります。でも饅頭にしか見えない。100メートルほど先にぽっかり浮かんでいるようにしか見えないのです。遠くの島というのはもっと霞んでいるものなので、置くならもっと遠くにリアルに霞ませろ、と直しを頼みました。AIは霞の色に寄せる、稜線をギザギザにする、切り絵のシルエットにする、と手を替え品を替えてきましたが、多少ましになるだけで、どうやっても「近くの何か」から抜けない。距離感というのは物体の描き込みではなく空気の描き方で出るものらしく、それを本気でやるのは大工事です。 そこで判断しました。ステージ到着の数秒のムービーのために、遠景の空気遠近を作り込むのは割に合わない。「島を表現するな。消せ」。消してみると、水平線だけの海で何も困りませんでした。AIが気を利かせて足した背景ほど、リアリティの請求書は高くつくという話です。 輸送機を、デザインし直す キャラを運ぶ飛行機は、最初AIが小ぶりな単発のプロペラ機を出してきました。これが原案です。 可愛いのですが、これでは遊覧飛行です。私のイメージは、パラシュート部隊が飛び降りる、プロペラがいくつも付いた大型の輸送機。ただしミリタリー色に塗れという意味ではなく、色はパラシュートと同じ「みかん×生成り」のままで、シルエットだけ輸送機にしてほしい。 そう伝えて出てきたのが、この機体です。4発のプロペラ、太い胴体、高い位置の一枚翼、T字の尾翼。そして投下シーンの主役になる、腹の観音開きのドア。 作り直しの途中には珍事もありました。プロペラの羽根を回転軸の中心に置いた箱で作ったせいで、3枚羽根のつもりが中心から6本の腕が生えた風車になっていたのです。羽根は軸から一方向に伸びるものだと教えて、ようやくプロペラになりました。 世界の縁は、四角い 次の敵は世界の形でした。飛行機のシーンを作らせると、まず高度が低い。海面スレスレを飛ぶ輸送機を見せられて、これでは輸送機というより飛行艇です。 高度を上げさせると、今度はもっと根本的な問題が露出しました。カメラが高く上がった途端、海の四角い縁、つまりワールドの終端が画面に写り込んだのです。 3Dの世界は、実は板の上に作られています。地上すれすれのカメラなら板の縁は水平線の彼方ですが、上空からの俯瞰では板がただの板として見えてしまう。対策は身も蓋もなくて、海の板を巨大にするだけです。ただし芸のない巨大化はレンダリングが重くなるので、波の立つ詳細な海は岸の近くだけにして、その外側は起伏のない一枚板を敷く二層構えにしました。近くは波、遠くは色。人間の目は遠くの波など見ていないので、これで十分です。 高度のほうは、実際の高さの数値よりも記号が効きました。雲です。雲海を下に見て飛べば、それだけで「はるか上空」になる。クレイ調の平たい雲をいくつか浮かべ、輸送機はその上を飛ばすことにしました。 開傘は、カメラが落ち続ける 今回いちばん作りたかったのは、パラシュートが開く瞬間です。私の注文は「映画のスカイダイビング映像のリアル感」でした。落下するカメラがキャラと並走する。パラシュートが開いた瞬間、キャラだけが急減速する。カメラは速度を一切変えずに落ち続け、上を仰ぎながらキャラを見送る。するとキャラは、画面の中でぐんぐん上へ遠ざかって小さくなっていく。 実際に浮かび上がっているのではありません。減速しただけです。でも落ち続けるカメラから見れば、それは「急に浮いた」ように見える。相対運動だけで無重力感を作る、実写のスカイダイビング撮影がやっているのと同じ理屈です。 パラシュート自体も、最初から開いた状態を出すわけにはいきません。畳まれた束がまず細長いストリーマーになってはためき、それからバサッとドームに開く。開く瞬間には弾性の揺り戻しを入れて、布が空気を掴んだ感じを出します。 ここで表情の駄目出しをひとつ。開傘の喜びで口を開けた顔にさせたのはいいのですが、AIはその顔のまま延々と降下を続けさせました。いつまでも口を開けていたら不格好です。感情の表現は一瞬でいい。「すぐ元に戻せ」という指示で、口開きは開傘の0.5秒だけになりました。 緊張感がないんだよ 着地のシーンには、注文を重ねました。最初にAIが出してきた着地は、ふわふわとスローに降りてきて、そっと砂に埋まるものでした。可愛い。可愛いが、緊張感がない。勢い余って埋まるのだから、埋もれるくらい速くないと意味がない。 もうひとつ、細かいけれど許せなかったのが砂の土手です。突入でめくれた砂がクレーターの縁に盛り上がるのですが、AIはこの土手を着地する前から置いていました。埋まってから現れるなら分かる。まだ何も起きていない砂浜に、結果だけが先にある。ホラーです。 直した後の着地はこうなりました。0.5秒の急降下で砂に突入。衝撃でカメラが揺れ、土手はその瞬間に盛り上がって現れる。役目を終えたパラシュートは消えたりせず、空気が抜けてフニャーと萎み、横に流れて砂の上に横たわる。以降のシーンでも、萎んだ傘はずっと背景に残っています。 総計何時間かかったと思ってんの 制作の裏で、私はAIにこう聞きました。今回のレンダリング、総計何時間かかったと思ってるのか。AIは「1本25分」のような顔をしていましたが、実際に積み上げさせると約3時間。しかもその大半は、レンダラーが遅いからではなく、直すたびに全フレームを焼き直していたからでした。 ここから運用を変えさせました。まず、動画をショット単位の部品に分割する。巡航、投下、落下、開傘、降下、着地、飛び出し、歩き。修正が入ったら、そのショットのフレームだけレンダリングし直して、部品を差し替えて連結する。連結は再エンコードすらしないので一瞬です。確定したシーンは、二度とレンダリングしない。 もうひとつはGPUです。調べさせたら、スクリプトはGPU指定をしておらず、ずっとCPUだけで回っていました。Metal GPUを有効にし、さらにフレーム間でシーンの下準備を使い回す設定(persistent data)を入れて、1フレーム3.5秒が1.8秒に。仕上げの高解像度に至っては3倍速になりました。この2つで、「1ショット直すのに25分」が「2〜4分」になっています。 歩き出して、ジャンプで終わる 最後のシーンは、ゲームへの接続です。砂から飛び出したえびふりゃが、体を左右にくねらせながら、正面のカメラへ向かってペタペタ歩いてくる。目の前まで来たら、ぐっとためて、ジャンプ。画面いっぱいの笑顔で飛び上がったところでカットです。このジャンプがそのままゲームの1跳ね目につながる、という算段です。 ...

公開: 2026年7月24日 · Toshihiko Arai
サウンドプログラミング連載の目次。音の波形が数字の列に分解され、合成・エフェクト・分析へ枝分かれしていく図

サウンドプログラミング入門 ── ブラウザで鳴らして学ぶ、音の作り方と仕組み

音をプログラムで扱うと聞くと、専門の道具や難しい理論が要りそうに思えます。ところが中身は驚くほど単純で、音とは1秒間に数万個並んだ数字の列でしかありません。スピーカーはその数字のとおりに膜を前後させているだけです。だから音を作るのも、加工するのも、分析するのも、突き詰めればすべて数列の計算になります。 このページは、araisun.com で書いているサウンドプログラミング連載の目次です。オシレータやエンベロープといった音響合成の基本から、ディレイ・リバーブなどのエフェクト、声を作るフォルマント合成、FFTによる分析、そして耳が引っかかる錯覚まで。どの回にも、ブラウザで実際に音が鳴るデモを置いてあります。 Web Audio API で書いた素のJavaScriptなので、何もインストールせずにその場で聴けます。読んで分からなくても、つまみを動かせば分かる、という作りを目指しました。 目次のうち「準備中」と書いてあるものは、書き上がってはいるものの、まだ公開していない回です。それぞれの分野の中に混ぜてあるので、この連載がどこまでを扱うつもりなのかは、そこから読み取ってください。公開したらリンクになります。 数式は隠しません。ただし出しっぱなしにもせず、必ず「その式で何が鳴るのか」まで着地させます。C言語で音を書いていた時代の教科書的なアルゴリズムを土台にしているので、Web Audio に限らず、どの言語でも同じ考え方が使えます。 どこから読むか はじめてなら、音は数の列 から順に読むのが素直です。サンプル・倍音・エンベロープという語彙が最初の3本でそろい、以降がぐっと読みやすくなります。 作りたい音が決まっているなら、目次から直接どうぞ。ウォブルベースが作りたい、リバーブの中身が知りたい、といった動機で1本だけ読んでも成立するように書いています。 理屈より不思議な話が読みたいなら、耳の錯覚 の章から。無限に上がり続ける音階や、鳴っていないのに聞こえる低音など、聴いて驚く回を集めてあります。 音の正体 音・音色・音程が、それぞれ数の何にあたるのか。連載の土台になる4本と、音楽の側から見た1本です。 音は数の列 ── サイン波を数式から鳴らす 音色の正体は倍音の配合 ── 足し算だけでノコギリ波を作る 同じサイン波が「ピアノらしく」も「オルガンらしく」もなる ── ADSRエンベロープ 音色を変えるデジタルフィルター入門 ── ローパスとハイパスのカットオフ きれいな和音はなぜ「うなり」が消えるのか ── 平均律と純正律 楽器の音を合成する サンプリング音源を使わず、計算だけで楽器の音を作る回です。 sin 2つで金属もベルもエレピも ── FM合成 ノイズをひと吹き、輪に閉じ込めて回すだけで弦が鳴る ── カープラス・ストロング ノイズと sin だけでドラムセットを作る ── 打楽器の手続き合成 トロンボーンの音を「実測」で当てにいく ── 音色工房① 声を作る 母音、子音、そして機械が喋るようになるまでの歴史。 ノコギリ波が「あー」と歌う ── フォルマント合成 「あ」は作れたのに「さ」が作れない ── 子音の正体(前編・摩擦音) 「た」は音ではなく出来事 ── 子音の正体(後編・破裂音) 機械はどうやって喋ってきたか ── ボコーダーからAI音声まで 「ゆっくり」も初音ミクも同じ木の枝 ── 音声合成の系統樹(準備中) シンセサイザーの音づくり クラブミュージックでおなじみの音を、部品から組み立てます。 ...

公開: 2026年7月24日 · Toshihiko Arai