Ryuz's tech blog

FPGAなどの技術ブログ

なぜGPUはリアルタイム処理に向かないのか

はじめに

久しく CUDA プログラミングもしていないなと思いつつ、久々に Wiki で RTX5090 などのスペック眺めてたら、凄いことになっているなと思ったので自分への備忘録も兼ねて記事にしておきます。

あと、あくまで当サイトがメインとするFPGAと比べて、GPUがリアルタイム処理に向かないというお話で、FPGAがGPUよりリアルタイムに強いと言われる話を裏返して考えてみようというものです。 用途によってリアルタイムの定義も変わってきますし、GPUがデータセンターなどでの大量のデータプロセッシングで十分な応答性で高いパフォーマンスを出しているのもその通りです。

先日書いた「続・FPGAに対する誤解」や「なぜGPUは高性能なのか」を少し補完するものにもなるかと思います。

最近の NVIDIA RTX のスペック

RTX4090 と RTX5090 のざっくりと重要な数字だけ拾って換算してみました。

下記のような感じでしょうか。

RTX 4090 RTX 5090
SM数 128 170
CUDAコア数 16,384 21,760
レジスタ数 8,388,608 11,141,120
最大スレッド数 262,144 348,160

1 つの SM に最大で 2048個のアクティブスレッド(64 WARP)を収容することができるようです。 またこの世代では 1 つの SM に 128個の物理コアが入っているようです。

GPGPUではその性能を最大限に出すためには、物理コア数以上にコア数以上のスレッドを割り当てる必要があります。 これは、実際のコアの実行でメモリアクセス待ちなどのタイミングで、別WARPを実行してパイプラインを埋めることで性能を出す仕組みになっているためです。

また、GPGPU ではスレッドの数に合わせて大量のレジスタは持っているものの、インストラクションデコーダは1つであり、基本的には「同じ演算を大量に並列で行う」ことを前提にしています。

従って最新のGPGPUで性能を出そうとすると、348,160スレッド などで並列演算できるだけのデータを用意する必要があります。

GPGU がリアルタイム演算が苦手な理由

ここがそのまま GPGPU がリアルタイム演算が苦手な本質的な部分に繋がります。

例えば SSD や YOLO などの画像認識では 512x512 などの画像サイズを処理しますが、512x512=262,144ピクセル でやっと RTX4090 の 262,144スレッドが埋まります。なんと RTX 5090 だとこの程度の画像だと、ピクセル数よりもスレッド収納数の方が多いことになります。

そうすると、この規模の信号処理だと、1フレーム分以上データをメモリに溜めて(バッファリングして)から計算を開始しないとパイプラインが埋まらない などといった事が平気で起こり始めてしまいます。

ここで注意点はスループット(処理性能)とレイテンシ(遅延)は異なるという事です。GPUの全演算器がフル稼働して高スループットで大量のデータを処理していたからと言ってレイテンシが小さくなるかと言うとそんなことはありません。 並列処理を行う為に一度メモリへのバッファリングした分はそのまま信号遅延(レイテンシ)になります。60fps のカメラを使うと、露光に 16.6ms、読み込んでメモリに溜めるので 16.6ms かかるので、33.3ms 経ってからやっと計算を始める という事になります。

ここから計算と出力があるので、すぐに 50~100ミリ秒ぐらいの遅れが起こるのですが、こちらの動画 を見るまでもなく、用途によってはこれは致命的です(製造分野とかドローンみたいなものとかの画像処理だともっと早く計算したいケースがあります)。

しばし、遅延の解消は非常に大きなユーザー体験の向上をもたらすのですが、この事実はあまり一般に知られていないため、ユーザーは知らない間に遅延のある状態を当たり前として慣らされてしまっている面があったりもします。

FPGA との比較

大雑把に比較すると

  • 並列演算に必要なデータ数が揃うまで溜めて、一気に並列演算するのがGPU
  • データが届いた端から順にパイプライン並列で演算していくのがFPGA

と言うような言い方ができます。

当然一度、データをメモリに溜めている分、遅延とコストが増加するのが GPU です。

そして残念ながらレイテンシに関しては 今後並列度が向上すればするほど悪化する可能性がある というアーキテクチャ上の特性を持っていると言えると思います。

ただしデバッグも含めたプログラミングの難易度は圧倒的に GPU が楽ですし、遅延以外の項目でも長所/短所がお互いにあるのは過去にいろいろ書いてきた通りです。

おわりに

久しぶりに GPU のスペックをちゃんと見てみて、コアの増えっぷりに改めて驚きました。普段 16nm プロセスとかの FPGA でのほほんと遊んでる身からすると、最先端半導体プロセス恐るべし です。

GPUの発祥であるゲーム用途で、プログラミングシェーダーが出始めたころには、「ピクセルの数だけ並列化できるから、実質無限に並列化が捗る」ぐらいの勢いだったのですが、そろそろ「ピクセル数じゃ足りなくなる日が来るんじゃないか?」という予感さえしてしまいました。

いずれにせよ、GPUで性能を出そうとすれば、データを溜めれるだけ溜めて、なるべく大きなバッチで大量のスレッドを回す という方向に全力で振るべきなので、今後、コア数が増えて並列度が上がれば上がるほど、遅延(レイテンシ)と言う観点では不利になっていく可能性があるかと思います(特に産業用途とかのエッジ環境では)。ますます FPGA などとの住みわけも広がっていくのではないかと感じました。

もちろん、GPUでもデータを小分けにしてパイプライン化するなど、遅延を減らす工夫はいろいろできるのですが、それをやりだすとプログラミングの難易度が FPGA と同じになってしまいますし、本質的なところであくまで「並列処理で性能を上げる」事しかできないのが SIMT の宿命かと思います。

今後の進化の中で、GPUの特性が、ますますGPUらしく出てきたときに、他のアーキテクチャとの住みわけが再度議論されてきても面白いかなと思った次第です。

当サイトがFPGAを駆使して、ミリ秒遅延であれこれ画像処理しているのは、そういったお話に繋がってくるわけです。

OPS(Operations per second)とは何なのか?

はじめに

今日は OPS(Operations per second) って何だろうという個人的疑問からの駄文です。

スーパーコンピューターやパソコンなどの性能を示す指標として FLOPS(Floating-point Operations Per Second) は昔からよく使われていたかと思いますし、多くの場合それは倍精度浮動小数点演算の能力を示していたかと思います。 また演算能力に対するメモリ帯域の性能指標である B/F (Byte per Flop) を語る際のベースとしても FLOP は重要な指標でした。

一方で、OPS(Operations per second) という単位もあり、これも昔からあるのですが、一般には FLOPS ほどは見かけない指標で、私のような組み込み分野で、浮動小数点演算器を持たないマイコンを使う 人々が良く使うものだった気がします。整数演算のみで性能を語る際に、「このマイコンはXX OPS あるから、このオーディオコーデック移植できそうだな」とかそんな用途で使われることが多かった気がします。

FLOPSに関しては x86なパソコンを例にとっても 8087 をはじめ、486DXで標準搭載されて以降、当たり前に浮動小数点演算ができるので、スパコンからパソコンまで一貫して性能比較に使える標準的な指標として長らく君臨していたように思います。

一方で、深層学習(ディープラーニング)の出現によって、これらの用語が一般の人にも認知されるようになり、さらに使われ方も深層学習の実行時性能を測るのに適した形に大きく姿を変えたものが一般に広まってきているように思います。

深層学習の出現による使われ方の変化

まず FLOPS がいつのまにやら FP64(倍精度浮動小数点) 以外を指すケースの方が見かけることが多くなってきました。

FP32での FLOPS、BF16 での FLOPS、 はては FP8 とか FP4 とかいろいろ現れています。

特に、深層学習の推論で、FP64 などまず使われませんので、GPUやNPU などの性能で謡われる FLOPS は特に何も語られていなければ FP32以下を指すことが多くなった気がします。 当然ですが、FP64 の FLOPS 値と、FP8 の FLOPS値では、計算機の総能力としては全然違うものになります。

加えて、 深層学習の推論では、浮動小数点演算を使わずに整数演算だけでやってしまおうというものを増えています。そうすると FLOPS という単位が使えなくなります。そこで OPS(Operations per second) という単位が急速に市民権を得たように思います。

そして実際 INT64/32/16 などもありますが、量子化技術により INT8/4/3/2/1 などの小さな単位の整数や、果ては b1.58 や バイナリなども現れています。

当然ですが、 INT4 の OPS値と INT8 の OPS 値でも、計算機の総能力は全然違うものになります。

また、深層学習 では、演算の多くは行列乗算の為の積和演算です。これは乗算と加算の組み合わせですが、FLOPS や OPS に換算する場合はこれを個別にカウントします。FMA命令のような複合演算命令もちゃんと2演算として数えます。 まあ深層学習向けにはあまりないと思いますが、乗算命令がなくて加算だけ沢山出来るCPUでも OPS は OPS なので、このあたりも OPS や FLOPS の中身はよく理解してカタログスペックを読み解く必要はあると思います。

もう少し踏み込むと、積和演算時、しばし、乗算よりも和の部分で、Accumulation や Reduction 演算するときは一時的に大きな桁数が必要だったりもしますので、この辺りも少し注意点だったりします(とくに SIMDなど)。

どのように性能を読み解けばいいのか

ここで、「計算効率のいい学習モデルを作ろう」、「効率よく計算機に実装しよう」と言った時に、どのような計算機を調達してきて、どのようなモデルを開発して、どのように実装するのかと言うのは非常に重要です。

FP32 で計算しないと精度が出ないモデルを作ってしまったら、「INT8 で 何十TOPS もある NPU を用意したはずなのに、全然性能が出ない」なんてこともあり得るわけです。

また、逆もしかりで、INT4 で十分な精度が出るのに、INT8 しか計算できない計算機を持ってきた場合、下手すると、「演算器の 3/4 と、メモリバス幅の 1/2 は、調達時の無意味な部品コストと、運用時の無駄な電力消費でしかない」なんてことになりかねません。

ちなみに、乗算器は、私が調べた範囲では深層学習に使う範囲程度なら、おむね桁数の二乗に比例する程度に思っておいて大きな誤差は無さそうです(筆算で掛け算を計算する回路を想像してみてください)。つまり桁数が倍になると4倍程度のトランジスタを使ってしまう可能性があるわけです。

ここでまた、別の罠もあって、深層学習においては、この層は BF16 が欲しいが、この層は INT4 でも十分、などといった事が起こったりもします。

このようなケースでは、「BF16 も計算できるが、モードを切り替えると4倍量の INT4 も計算できる計算機」みたいなものを良く調べて見つけてくる必要があります。

そのうえで、「私の作ったモデルは、この計算機を使えば XXX token/s 出せそうだ」とか見積もっていかないといけないことになるわけです。

逆もしかりで、計算機が先に指定されるケースもあり、「この計算機で要件の XX fps を出すには、INT8 なら XX GOPS、 INT4 なら XXX GOPS まで行ける」とか見定めて、パラメータ数や層数を逆算して学習モデルを作らないといけないケースもあるでしょう。

ようするに、ちゃんと性能を読まないと、モデル設計前に見積もれないということなのですが、正しく見積もらずに設計してる事例って結構あるあるではないかとも思ってしまうわけです。

オレオレ型とオレオレ演算でも OPS を定義できるのでは?

ここで再び OPS の話に戻しますが、実はこれ FLOPS と違って かなりあいまいな表現じゃないかと個人的に思っています。

FLOPS における IEEE 754 のようなある程度同一の基準で比較できるものと比べて、「演算(Operation)」という、とても曖昧なものを扱っているため、物は言いよう といった事も出来てしまします。

FPGA などを活用すれば、オレオレ型おれおれ演算 なんかを定義することが可能ですが、それに対しても、「〇〇 OPS です」と言えちゃうわけです。

ここで仮に オレオレ型として MY3 という 3bit の型を作って、思いつくまま適当に「-1.1, 0, +0.1, +0.7, +1.2, 1.5+0.3i, +π, +∞」 の8種類の値を表します、みたいな好き勝手な定義をしても何も構わないわけです。MY3 と MY3 の間に四則演算以外の演算子を定義することも自由です。

ここで FPGA の 6入力 LUT を考えると、 MY3 を 2つ入力して、1つの MY3 を出力する回路は LUT が 3 個あればどんな演算でも行えますし、一部を複合演算だと言い張ることも自由です。

要するに OPS値盛り放題 と言えなくもありません(笑)。

まあ、冗談は話半分としても、作ろうとしている学習モデルに対して、もっとも最適な型を独自定義 して、それに対する もっとも効率のいい演算を独自定義 して、「それに対するモデルの精度と演算量を OPS値としてカタログスペックにする」などという事も理屈上は可能なわけです。

現在、$100 程度の FPGA でも LUT は 数十k 個は入る時代になっています。 LUT単位の演算であれば 500MHz ぐらいで動かすことも可能ですので、「数万円で 10TOPS のNPUを自作したぞ~」などという事も出来ちゃうという事です。

おわりに

先日ふと、RISC-V などのカスタム命令で馬鹿みたいにOPS値だけ謡えるSIMD命令って追加できないかなみたいなこと考えておりましたら、「そういえば OPS って単位謎だよな? ハックすれば幾らでも盛れるんじゃないのか?」みたいな疑問を抱いて、ちょっとした駄文にしてみました。

もっとも多くの場合は、既存の GPGPU などで使える型と演算をベースに正しく議論されるのだとは思います。

一方で、「今はまだ存在しないデータ型や演算子を定義して、もっと効率よく高精度な学習モデルが作れないか?」というのもまた一つ興味深いテーマな気はしております。

そういったものを、手軽に実験してみるのにもまた FPGA は面白いデバイスなのではないでしょうか?

また普段 FPGA お使いの方も、DSP の数だけで深層学習の性能を決めてしまわずに、オレオレモデルに手を出すことで、もっとLUTでしかできない特殊な演算モデルを考えるのも楽しいと思います。

システムアーキテクチャ設計とは何なのか

はじめに

業種や分野を問わず「全体を見てシステムアーキテクチャ設計できる人が少ない」というような話はよく聞きます。

私も決してそういう設計の上級者でも何でもないのですが、長いエンジニア人生の中で、平均的な人よりはちょっとだけ多くそういう設計をする機会には恵まれてきたように思いますし、何よりお仕事とは関係なく趣味でオレオレアーキテクチャは沢山作ってきましたので、一体全体システム設計だとかアーキテクチャ設計だのを学ぶのの何が難しいのかというのを勝手気ままに考察してみたいと思います。

世の中には、シンプルで美しいアーキテクチャもあれば、複雑怪奇な継ぎはぎだらけで二度と触りたくないシステムまで様々です。後者をに関しては、設計した人を「システムアーキテクチャ設計できる人」と呼んではまずいケースも多々あるので、まあそういうのも含めて考察してみようと思います。

システムアーキテクチャ設計できる人が少ない理由

能力的な問題

まず人それぞれ得意不得意は必ずあります。私がいくら勉強しても英語が話せないとか、人の顔と名前覚えられないとか、絵心がさっぱりでダサいプレゼンしか作れないとか、まさにそれだと思ってます。個人的には、向かないことをわざわざ労力掛けても仕方ないので適材適所で分担すればいい話だとは思っています。

で、私の経験上、世の中には 全体はよくわからないけど部品なら作れるよ と言う人がそれなりの数いらっしゃいます。

でそういう方々にうまいこと得意分野を割り当てていって、ゴールを目指すスキルに長けている人をプロジェクトマネージャーと呼ぶわけです。

が、ここにちょっとだけ罠があって、「部品は作れるよ」という方々の中には 100点満点近い部品を作れる人もいれば、指摘や指導を繰り返してやっと60点のギリギリ及第点の部品を作れる人まで様々です。 少なくともソフトウェア開発の現場でのソフトウェア部品の個人差による品質バラツキは顕著にあるかと思います。

人間が一度に把握できるスコープは人それぞれですので、どうしても部分しか見れない人はここで壁にぶつかりがちな気がします。

一方でシステム設計できるように育っていく人は、部品がどう使われるのか、その外側の要件も視野に入れているので、部品に求められる要件の意味や行間まで考えて100点近い部品を作ってくる人が多いように思います。

スキル習得機会の問題

もう一点は、折角能力があっても、スキルを伸ばす機会がなかなか手に入らない事です。開発に携わる人間で ゴールを決める 工程に携われる機会は決して多くはありません。多くの場合は、誰かの決めたゴールを達成するための部品 を任される機会しかないのが実情でしょう。

そして私の知る範囲で、よくある2つの課題があります。

  • 全体像を教えてもらえることなく、ただ部品を作ることだけを指示されるケース
  • そもそもスキル習得にならない悪い見本のようなシステムの部品開発を指示されるケース

でしょうか。

特に前者は聞けば教えてもらえることもありますが、 NDA だったり組織の縦割り行政だったり、政治的理由で情報を教えてもらえないケースもあり、何に使うのかわからないまま部品を作らされるというケースがあります。

また後者も、これをそのまま受け入れてしまう人も多いのですが、それだとそれ以上成長できなくなってしまいますので、まだ、システムのダメさ加減を愚痴りながら仕事してるエンジニアの方が、全体の事を考えてる分マシなのかもしれません(まあ、愚痴るだけで終われば同じことなんですが)。

あとは最近だと、「AI が作っちゃうのでよくわからないままスキル習得にならないまま終わってしまうケース」なんてのもあるのかもしれません。

どうあれ「個々の技術を磨きながら、全体を設計する能力も磨く」という事が阻害されるケースはいろいろあるという事です。

ダメな設計はなぜ生まれてしまうのか

どこかの銀行のシステムの例を挙げるまでもなく、ダメなシステム開発と言うのは大小いっぱいあります。FPGA用の回路設計だって例外ではありませんし、ソフトウェア以外にも、機械だったり、組織の運用マニュアルだったり、いろんなシステムが世の中にあります。

多くのダメなシステムは、正しい最終イメージがアーキテクトの中で出来上がっていないとか、細部を知らない人間が間違った理解の土台の上に物理的にありえない形態をイメージしてしまったりしたまま、部分から作っていって破綻するようなケースが多い気がします。

全体を見せてもらえない/全体を見る能力がない/土台となる基礎力が無い、などの制約下で、とにかく部品を作ってくっつければなんか出来上がるだろう(というか闇雲でもなんでも前に進む以外にやれることがない)、ぐらいのノリでどんどん作ってしまったんじゃないかと言うぐらい行き当たりばったりでカオスなシステムと言うのは、まあ残念ながら世の中にあります。

要するにグランドデザインがちゃんと出来ておらず、ゴールがどこにあるかあいまいなまま作っているので、ゴールまでにあと何を作れいいのか、どちらに向かえばいいのか、あとゴールまでどれぐらいかかるんか、などがわからないまま、目の前にある課題だけが課題として上がっていく状態です。

で、作った部品の数だけで進捗管理してるから、100個作ったのにくっつけても動かない状態になった後は、進捗率が 99% のまま工数がどんどん伸びていくというあの状態ですね。納期を過ぎた後、ひたすら疲弊しながら人海戦術デバッグして、ぎりぎり60点の合格ラインで納品するわけです。

逆に、正しい最終イメージが頭に描けるだけのスキルのアーキテクトが居る場合、あとゴールまで何が足りていないのかちゃんと把握できますし、仮にゴールが見えていない場合も ゴールが見えていないというリスク を正しく認識できるので、ゴールの位置を確認するための作業 なども正しく計画に組み入れていけるわけです。優秀なアーキテクトの居る組織ではおおむね 80点ぐらいのシステムを毎回きっちり約束通り仕上げていきますし、そのような組織の中で適正のある若者の中からは次のアーキテクトも育っていくわけです。

美しい設計はなぜ生まれるのか

ここで、経済的合理性は一旦おいておいて、100点に近い設計を考えてみます。

建築にせよ、機械にせよ、ソフトウェアにせよ、半導体プロセッサにせよ、美しいと思える設計 というのは少なからずこの世に沢山あります。美しいものはシンプルです。美しいものは機能性が高いです。美しいものは長持ちします。美しいものは時代を超えて美しいです。

もはや、お金の為に作るというよりは、匠がある種の芸術の領域に片足突っ込んで、自己満足の為に作らないと作れないような領域なのかもしれませんが、まあ確かにそういうものはあるように思います。

そして経験上、美しい設計を作っているアーキテクトは、驚くほどなんでも知ってるし何でも良く見て ます。例えばプロセッサアーキテクチャ設計で巨匠と言われるような人たちは、トランジスタレベルのロジック構造から、演算器やキャッシュの構成、メモリの特性まで熟知して、それらも極めてタイトでピーキーな部品として設計できる能力まで有した上で、最新のAIの学習モデルから半導体製造工程まで熟知してて神業みたいなアーキテクチャを設計しています。

私なんかは見ていてポーカンとなるだけなのですが、ほんと凄い人たちは凄いのです。

ここでおもむろにハッカーと画家ミケランジェロがシスティーナ礼拝堂の天井画の全ての像を自分自身で描くと 主張した話なんかをふと思い出したので、私見交じりに書くと、きっとミケランジェロの描く100点満点の作品には、100点満点の部品が揃っている必要があったのではないかなと想像してみます。

ここで言う100点満点の部品とは、例えばプロセッサを作る場合、そのプロセッサアーキテクチャ用に専用部品を作れと言ってるんじゃなくて、拘りたい部分に関してちゃんとトランジスタレベルで無駄のない綺麗な設計になってる汎用部品たれという話です。

で、冒頭の話に戻りますが、芸術観点で拘ったシステムが作りたくても、商業として部品開発者の中には 60点の部品しか作れない人がどうしても含まれてしまいますので、ミケランジェロは一切合切そういう要因を排除して拘りたかったのかな、なんて考えてみたりもするわけです。

どうすればシステム設計力が身につくのか

小さなゴールを自分で置く

一番の王道はこれじゃないかと思います。大きなゴールは初めから置かれているケースがほとんどと思いますので、自分の裁量の範囲で自分の小さなゴールを置く事です。

特にソフトウェアでは、要望された仕様を満たす部品の設計や実装方法、アルゴリズム選択は無数にある場合が多いですので、自分なりのゴールを置いてより自己満足度の高い部品を作ることを心がけることだと思います。

何よりも自分でゴールを置くという事は、完成形をイメージするという事であり、なぜそれを選択したのか一つ一つに自分なりの理由を見つけ、開発中もあと何が足りていないのか考え、不足を埋めながらゴールを目指すことができます。

そして少しづつ、大きなゴールを任されるようにポジション取りをしていくという事が重要に思います。

趣味で設計する

で、実はこっちが個人的にはメインだった気もしていて、なかなか「王道でアーキテクトが育っていくような環境をずっと維持できてる職場」と言うのは決して多くはないです。

となると仕事と言う枠を気にせずに自分でオレオレアーキテクチャを設計してみるというのが実はとても重要な気がしています。いくらでも大きなゴールを置いて挑戦することができますし、失敗しても誰も困りませんし、面白いものが出来ればOSSで公開したり、ブログ記事を書いたりすればいいわけです(笑)。

なんでもかんでも自己責任と言われてしまうこのご時世、ある程度は職場に頼らずに自分のスキルには自分で責任を持たないといけないのかもしれません。 まあ、さすがに「この先この職場環境だと能力を活かす環境が来そうにないな」とあれば転職なども選択になったりもするのかもしれませんが。

研究開発の場合どうなのか

研究の場合、「まだ誰もやってない未知のことを確認する」というのがメインタスクになります。要するに「やってみないとわからない」ので「ゴールも分からないし、進捗管理何てできるわけないじゃないか」というのもまあ、一理ある意見かとは思います。が、一方で、だからこそアーキテクト的な能力が問われることも多い気がします。

研究を行う場合、必ず何らかの仮説をもって実験を行う事になります。実験の結果仮説があっていることもあれば間違っていることもあります。

一方で、仮説を立てた以上は、正しかった場合のゴールイメージは立つはずです。そして仮説が正しいことを証明するための美しいシステムとは何か、どうすればそこにたどり着けるかを考える事は、仮説が間違っていた場合の証明もまた最短で行う事になります。

研究を一連のシステムとして、研究計画を立てて進めていく際にもシステム設計力やアーキテクト力みたいなものは同様に問われてくるように思う次第です。

おわりに

今回もかなり抽象的な駄文にはなってしまいましたが、新しいものを作るときに「そのゴールを想像してグランドデザインができる能力」と言うのは、大小問わず、研究するにも開発するにも重要な事ではないかと思います。

一方でそれらの能力は 意識的に取りにいかないと身につかない し、悪い環境にいても身につかない ので、そうなりたいと思った人がそれなりに自分で自分を育てるという事をやらないと身につかない能力なんだと思います。

「馬を水辺に連れて行くことはできても、水を飲ませることはできない」ということわざがありますが、組織も簡単に育てられる人材じゃない気がしていますし、昨今の組織は自分で育てるよりも、即戦力を中途採用したがる時代になっています。逆に言えばアーキテクトを目指す人にはリターンの大きい時代ではあるかと思いますので、是非頑張っていただければと思う次第です。

(コーヒーブレイク) AIにSF小説書かせてみた

個人事業主になって間もなく1年ですが、初めてやってくる青色申告を前に必死に勉強しながら準備しております(まあ大半は 会計ソフトがやってくれるんですが、仕組みがわからないと安心できないのがエンジニアのサガでして)。

今、大学様と一緒に研究連携させて頂いて、論文の連名にして頂いたりとか、ぼちぼちそういう赤字の活動もしているのですが、商品にならないようなものもいろいろ試作したりしているわけで、こちらの制度 に該当するのではないかと思い、いろいろ調べたり、計算したりしていたのですが、結局1日費やしてしまいました。

freee会計を使っているのですが個人事業主向けの安いプランだとこの申告は未対応で、やるなら自分でやる必要がありそうです。 法律系の条文を読み解いて計算するというのは、エンジニアにはなかなか難易度が高いですね。

幸い今はAIがあるのと、私の父が役人だったのである程度こういう条文作ってる方々の裏側の苦労とかも多少の見聞きはしており興味は持っていたので、いい勉強にはなりましたが、金額が小さすぎて申請をためらうレベルだなとか思いつつも、正しく税金計算して納税するコストってて案外大きいな と改めて。

そして、もうちょっと理系向けの数式で表現したり、機械的に最適化したら、少しぐらいマシになったりしないものなの? なにより もう全自動で徴税してほしい というフラストレーションを感じてみたりもしつつ。

ということで、今日、いっそお金のない世界で全部アルゴリズムに支配してもらえないの?、といったホモ・デウス に出てくるような話を AI に愚痴っておりましたら、何やらSF小説が出来てしまったので張っておきます。

いろいろ注文つけて、星新一さん風に仕上げてもらいましたが、いやはや生成AI に、コード以外にちゃんとなにか生成させたのはじめてかもです。

戯れに置いておきます。


タイトル:『完璧な収支』

 エヌ氏は、窓辺に届いたリンゴを手に取り、その艶やかな皮を眺めた。  この世界には、「お金」という言葉も「金額」という概念もない。あるのは、膨大な計算機網が編み上げる、巨大で精密な「あみだくじ」だけだ。

 エヌ氏が一篇の詩を書く。その所有権が網に吸い込まれた瞬間、彼は夕食のリンゴと、冬を越すための軽油を手に入れる。  詩を欲した誰かのニーズが、リンゴを余らせていた誰かのニーズと、一瞬で、物理的に直結したのだ。そこには、情報の不透明さを利用して、見えないコストを上乗せする仲介者の入り込む余地などなかった。

 「実に気分がいい。昔の人は、不自由だったらしいな」

 エヌ氏は、古びた資料で読んだ「税金」という奇妙な制度を思い出した。  かつての人類は、リンゴを買うためにまず「円」という名の数字を集め、さらにその中からいくらかを「納税」として差し出していたという。役所という建物に人々が集まり、「確定申告」なるパズルに頭を悩ませる。払いすぎた、足りない、計算が違う……。そうして集められた数字が、本当に目の前の道路に使われたのか、誰にも分からなかったのだ。

 しかし、今のアルゴリズムは冷徹に、そして誠実に働く。  エヌ氏が散歩に出れば、一歩ごとに「道路の摩耗代」や「街灯の明かりの代金」が、彼がこれまでに提供した価値の「貯蔵分」から、一滴の無駄もなく、リアルタイムで差し引かれていく。  申告も、徴収も、着服もない。世界は完璧な「等価交換」だけでメンテナンスされているのだ。

 「さて、残りの分を確認しておこうか」

 エヌ氏が端末を操作すると、彼がこれまで積み上げてきた「貯蔵リスト」が表示された。  そこには「米一トン」「石油五百リットル」「最新の治療薬へのアクセス権」、そして「純金十グラム」といった、実体のある価値が並んでいる。  これらはアルゴリズムが、世界中の倉庫や工場で常に「エヌ氏の取り分」として確保している権利だ。たとえ明日、何らかのシステムトラブルが起きても、この「実物」へのアクセス権が消えることはない。

 「これで老後も安心だ。私が若いうちに提供した価値は、こうして腐らない形で世界にストックされている。何しろ、『仲介』という名目で複雑な手数料を差し引く、得体の知れない管理者を介さずに済むのだからね」

 散歩の途中、エヌ氏は資料にあったもう一つの、最も理解しがたい記述を思い出した。  『金利』と『インフレ』という現象だ。  昔の人々は、何も生み出さず、何も提供していないのに、銀行に預けておくだけで数字が増えることを期待したという。その一方で、誰かがどこかで数字を刷り増やすと、昨日までリンゴ一個と交換できた数字が、今日は半分しか交換できなくなる……。

 エヌ氏は思わず足を止めた。  「何もしていないのに数字が増えたり、何も使っていないのに価値が減ったりするなんて。それはまるで、物理法則を無視した幽霊の仕業じゃないか」

 実体のない数字に魔法をかけ、人々の労働を吸い取る。そんな、論理が崩壊した呪術のような世界で、彼らは正気を保てていたのだろうか。

 エヌ氏は、リンゴを最後の一口まで味わった。  ふと見ると、足元の舗装路が、ほんの少しだけ輝きを増した。  エヌ氏が今朝書いたコードが、どこか遠くの道路補修システムの効率を向上させたらしい。その「お返し」として、彼のリストに、新たな「高級肥料の優先権」が一つ付け加えられた。

 「なんて素晴らしい、合理的な世界だ」

エヌ氏は満足して歩き出した。  そこには、銀行も、税務署も、証券会社もない。  ただ、人々が互いに差し出した「価値」と「感謝」が、目に見えない網となって、どこまでも美しく、公平に広がっているだけだった。



(感想とか)

AI面白いこと書くな、と思いつつ、昨今の米価格の騒動とか見てると「適正な価格って何」なんてことは考えさせられてしまいます。

おにぎりが一個あったときに、それは間違いなく「おにぎり美味しい」という体験とともに「おにぎり一個分お腹が膨れる」という価値を提供してくれるわけで、安く買えても、テンバイヤーから倍の値段で買ったとしても、そのモノ自体の価値は変らないわけです。

小説の世界は、ニクソンショック前の金本位制の時代とか、加賀百万石とか言ってた江戸時代とかの価値観に近いのかもしれません。

たぶん真逆の世界観としては、すべての価値をお金で支配する世界 で、例えば政府が紙幣発行をやめて、アクセスコントロール付きのトークンとしてデジタルマネーだけを発行し

  • 発行量を自在に調節してお金の価値を上げ下げする
  • 消費を加速するためにお金に消費期限を付ける
  • 一日の利用額を制限する/犯罪者の資産を凍結する

などなど、お金を支配することで世界を支配する世界でしょうか。

最近でも、現金で買うよりローンにしてその分NISAに入れた方が得、みたいな、モノに目が行かずお金で損得を考えてしまうパターンは増えているのですが、「いい車に乗りたい」とか「美味しいもの食べたい」とかモノや体験そのもの価値と、「今日も一日頑張って働いた」という達成感を、もう少しダイレクトに結び付けられる思考方法もあっていいのかなと思って見た次第です。

リアルタイムAIで考える事

はじめに

当サイトでは、応答時間がミリ秒以下になるような、高リアルタイム性のコンピューターシステムを検討対象としており、AI(というか機械学習)もその対象範囲です。

このようなリアルタイム性の条件下でAIを考える場合、通常の AI のように単に高精度な結果を出せる学習モデルを設計するだけではだめで、時間経過の中で今出力できる最善の解に更新を繰り返していくモデルを設計し、 実世界のダイナミクスに追従する適応性 を持たせることが必要になります。

ですので今日はあまり一般的な話ではなく、この分野に閉じて、少し考察をしてみようと思います。

メモリ階層とモデルの矛盾

一般的な計算機のメモリは階層的になっており、CPUなどでも1次キャッシュから3次キャッシュ、外部SDRAMなどの階層で、容量が小さく高速なものから順に、大容量で低速なものになっていきます。

FPGAなど、自由に計算機アーキテクチャを設計できるデバイスにおいてもこれは同様で、利用できる演算資源としては、階層的になっており、例えば以前に下記のような絵を描いたことがあります。

リアルタイムコンピューティングのメモリ階層

一方で、リアルタイムコンピューティングでは、新しい入力から出力更新までの制約時間の中で読み出せる量のデータしか使えません。 例えば サンプリングレート 1kHz (1000fps) で1ms (1ミリ秒は 1000分の1秒) で応答する処理を行う場合、メモリがどんなに大容量であっても 1ms で読み出せる量のデータやパラメータしか演算に投入することができません。

そうすると、大容量メモリほど少しのデータとパラメータしか使えない という一見矛盾したことが起こり始めます。

容量と速度の逆相関

しかしこれはとても重要なことで、同じくリアルタイム処理であるグラフィックスレンダリングの処理などでは、例えば 60fps でゲーム画像をレンダリングしたい場合、16.6ms で読み出せるデータ(テクスチャやポリゴン頂点など)しか描画に使えません。 そうなると容量よりもデータ帯域が重要となり、GPUには GDDRメモリなど容量は少ないが高速なメモリが採用されてきた歴史があります。

高リアルタイムシステムほど、これのもっと極端なことが起こっていきます。

ではそのような制約下でどのようにAIモデルを考えていくかと言うのが本記事の考察です。

階層メモリのリアルタイムでの活用方法

それではパターン別に大容量メモリをうまく使う方法を考えていきます。大きくはデータの履歴(状態変数も含む)の保持に使うパターンと、学習パラメータを置いておくのに使うパターンとがあると思います。

データ履歴の活用の工夫

最初に過去のデータを利用する観点で考察します。今入力されたデータだけでなく、過去に入力されたデータを使う事で、空間的な広がりや、時間的な変化を認識できるようになります。

データの古さで置き分ける

もっともオーソドックスな使い方がこれでしょうか。例えば画像処理においては

のようにすると、空間と時間の3次元方向の周辺情報を使ってそのピクセルを処理することができます。 画像のようのものは1フレーム自体が巨大ですし、場合によっては何フレームも過去の情報を使いたい場合は容量の多い外部メモリを活用できます。 内蔵メモリにフレーム全部が収まらないにもかかわらず、カメラデータ入力の数倍程度のメモリ帯域があれば、演算対象のピクセル周辺のデータは常にオンメモリに持ってこれる構成が作れます。

状態空間モデルで、各ピクセル位置に状態を持たせる場合でも、状態変数をフレームと一緒に外部SDRAMに記憶して、次にそのフレーム位置が来た時に状態を復元して、次の時刻の計算を行うのも合理的な使い方と言えるでしょう。

特に周期性を持った時系列処理においてこの考え方は非常に重要で、例えばお店の売り上げのような時系列データでも、曜日や季節に影響を受けるため、昨日の同じ時間、先週の同じ曜日、先月の同じ日、昨年の同じ日、などとはしばし比較評価を行います。 大容量メモリが大量の容量を持っていることを利用して、ピンポイントで古い情報を利用するのに利用するわけです。

お店の売り上げの例だとあまりにも長いですが、我々の身の回りや、産業応用などでは、エンジンの回転周期ぐらいの周期性を持った時系列は沢山あります。特に人間には感知できないぐらい高い周波数でも計算機なら感知できるというのは重要なことだと思います。

選択的に履歴を選ぶ

履歴はそのままフラットに記録しておき、どこを読み出すかを選択的に選ぶことで読み出しデータ帯域を抑えることもできます。

以前に、ハイフレームレートでは動き補償の計算が激減できるという話をしたことがありますが、該当するピクセルに写っていた物体が、過去のフレームのどこにあるか追跡しながらそこだけピンポイントで取り出してくることもできます。

例えばバイクに乗って手を振っている移動している人から、「手を振っている」という時間変化成分を加えてた認識が、限られたメモリ帯域の中でできる可能性など出てくるわけです。

動き補償は極めて強力な武器で、60fps で 16ピクセル移動する物体でも、1000fps なら1ピクセルしか移動せず、CNN の3x3の畳み込みフィルタに収まってくれます。

また ViT などの応用で、画像の中の注目すべきポジションを計算して、次のフレームでそのあたりを重点的に読み出すのも手です。

これもリアルタイムシステムであれば、1ミリ秒の間に最大で何ピクセル移動するかは、物理的に制約できる事が多いですので、対象のダイナミクスにあわせてマージンを設定すればよく、効果的に過去のデータを限られた帯域の中で活用できます。

過去の情報を要約(圧縮)して使う

これには時間方向の要約と空間方向の要約の2つの軸があると思いますが、読み出し時ではなく書き込む際にデータ量を圧縮してしまう方法です。

いずれも要らなくなった情報から順に削除したり圧縮したりしていきます。 例えば古いものを 1/2 に出来れば、 1/2 + 1/4 + 1/8 + ・・・ = 1 ですので、決まったメモリ帯域の中で履歴にアクセスし続けられる計算になります。

例えば以前に単純に画像を縮小していくというMIPMAP方式を提案したことがあります。 Attention 的に有用なものだけ残す手もありますし、また、認識まで行ってもっとメタ情報として圧縮する方法もあるでしょう。

縮小を行うと1つのピクセルの処理において、より広い範囲を俯瞰して判断することが可能になり認識精度が上がります。

画像処理では認識したい画像特徴に対してスケール普遍性がある場合が多く、画像ピラミッドを作って認識することは多いです。 CNNなどでも特徴量の世界でもこれは同じであり同じ認識器をマルチ解像度に適用していくのは合理性があります。

また動き補償と縮小とを組み合わせると、把握できる範囲が 6x6、12x12、24x24 ・・・ と倍々で広がりますので、多少の移動速度であれば簡単にスコープに捕らえます。過去の動きは大雑把に追跡して、最新位置を最新の最大解像度の画像で正確に認識し、さらにその情報を次のフレームに状態として引き継げるわけです。

パラメータ利用の工夫

昨今のAIでは 入力データよりもパラメータの方がはるかに巨大 ということがしばしあります。

すべてのパラメータがFPGA内などにオンメモリにもてれば何の苦労もないわけですが、残念ながら外部SDRAMなどにパラメータを置いておいて動的に入れ替えなければ、極めて小パラメータのモデルしか使えないことになってしまします。

パラメータを動的に変更する

例えば、高速に応答したい物体Xの認識パラメータセットと、その他の認識対象セットがA、B、C、D・・・ と何セットかあった場合

X → A → X → B → X → C → X → D → X →

のようにタイムスロット(画像なら1フレーム毎とか)ごとにパラメータセットを入れ替える手が考えられます。

1つのタイムスロットで読み込めるパラメータ数は決まっていますので、時間ごとに切り替えることで、見逃せない X を頻繁に調べつつ、他のものも探索するようなことは十分にあり得ます。

100クラス認識できるものを 10 回入れ替えて 1000クラス分類に近づけていくようなアプローチでしょうか。

選択的にパラメータ使う(MoEなど)

MoE(Mixture of Experts) も最近よく耳にする技術になってきました。これはもちろんリアルタイムAIでも重要な要素だと思います。

画像認識も、街中や森の中、夜間や霧、顕微鏡画像やMRI画像など、環境の違いもあれば、認識したいものが人間だっり、自動車だったり、交通標識だったり、部品のひび割れだったり、病気の腫瘍だったり様々です。

これらをパラメータセットを沢山持っておいて、適応的に切り替えながらあらゆるシーンで活用することを考えるのも、限られたメモリ帯域を有効に使う上でとても重要です。

例えば、人間が前を向いた時、横を向いたとき、後ろを向いたとき、などそれぞれを学習させた認識器を使って、今どういう運動をしているかを認識しておけば、次のフレームでロードすべき認識パラメータはおのずと決まってきますし、変化や状況を見て適応的に次にロードするパラメータを選ぶことで、一度に使うパラメータ数を抑えながら幅広い認識を応答性良く行える可能性が出てきます。

ハイブリッドに使う

ここまで挙げたようなテクニックをハイブリッドに組み合わせることももちろんありだと思います。

特に、センサーの値を特徴量として汎用的にとらえる部位と、特徴量から目的に合わせた認識を行う部位はしばし分けて考えられます。

特徴量を作る部分では、例えば昼用と夜用などシーン変化に応じてパラメータを切り替えて常に高品質な特徴量を得られるようにして、後半は認識対象に応じてパラメータを切り替えるような手もあります。

100クラスのうち50クラスだけは常に同じものを認識するようにして、残りの50だけを変えたパラメータを入れ替えるなどもありでしょう。

用途にに応じた組み合わせこそが重要だと思います。

おわりに

アルゴリズム開発をしている多くの人にとって、0.1 秒で以下で終わるものと言うのは、どれも大差ないように思えるかもしれません。

一方で我々の生活するリアルな空間では、その 1/100 である 1ミリ秒(0.001秒)であっても、案外大きな変化をします。 人間は 100mを10秒 (1m を 0.1 秒)で走ってしまう生き物で、時速何百キロのボールを投げることもできます。 一般人がその半分の速度で動いても 1ミリ秒に何cm も移動するのです。

また、人間は応答に 0.1秒以上かかると言われています。ですので人間をアシストする計算機まで 0.1秒遅れてしまうと遅延が倍になります。計算機がアラートを出してから人間が回避行動をとるシステムにしたら 2倍鈍感な動作しか出来なくなった では悲しいわけです。

近年では フィジカルAI とか エンボディドAI と言われている領域の中には、これらが課題になる分野が間違いなくあります。

そしてこれらの分野にむけて学習モデルを作る場合、単に総演算量だけ考えればいいものではなくなります。

アルゴリズムを1ミリ秒などのタイムスロットで細切れにして、どこにどのようにデータを置いて、タイムスロット間では何を渡して、システム全体としてどう振舞うようにするか、を考える必要が出てきます。

考える事が一気に増えて複雑なパズルを解くことになりますが、これは好きな人にはとても楽しい話ですし、新規性のある独自の工夫や、他の方式との差別化がとてもやりやすい領域になります。

昨今の FPGA は、学生が研究用に研究室で買ってもらえるぐらいの価格帯のFPGAで、 ResNet18 を 60fps で動かせる程度の演算リソースは内蔵するようになってきました。これを 60fps の 16.6ms で計算するのではなく、 1/16 の演算量の計算を 16回に分けて行うことで、定常的には従来相当の認識率を保ちつつ、変化に対して 1 ms などの応答性を持たせることが出来れば大変興味深い研究になってきます。 最初の認識に 16ms (16フレーム)かかっても、それは従来と同じですので、そこから先に 1ms の応答性が手に入るなら大きな進歩を手に入れたことになります。

もしこういった分野に興味のある方、是非、いろいろ考えてみて頂けると面白いのではないかと思います。

フィジカルAIについて考えてみる

はじめに

昨今、フィジカルAIや、エンボディドAI などの単語をよく聞くようになってきました。

当サイトのリアルタイム性に対するこだわりが発揮しやすそうな領域であり、FPGA 応用の生きてくる分野でもありますので、少し考察してみたいと思います。

昔からあった領域に新しい名前が付いただけと言う部分も大いにあろうかとは思っておりますが、分かりやすい言葉で一般の人に周知されるという事は非常に重要な事ですので、大変喜ばしい方向に進んでいるように思います。

何より、数千億円規模の大規模GPU環境で学習した LLM が群雄割拠している中で、弱小企業や研究機関や個人が太刀打ちしようとすると勝負の土俵を変えるしかない部分はあり、そういった中で、日本にある、まだ学習につかわれていないデータや、データ化すらされていない技能などをターゲットにしていくのは、戦略としてはありだと思うわけです。

FPGAによるフィジカルAI考察

リアルタイム性での分類

フィジカルAIの類は、基本的には IoT でありエッジコンピュータの存在が前提になると思います。エッジコンピュータはリアルタイム性以外にもセキュリティーの問題だったり電力の問題だったりいろいろな観点で分類がありますが、当サイト的には、リアルタイム性の観点に絞って考えます。

そうすると大雑把に

  • AI をクラウドに投げても良いケース [ノンリアルタイム]
  • ノンリアルタイムOS上で動くGPUでよいケース(Jetsonなど) [数十ミリ秒の応答+ミリ秒単位ーのジッタ]
  • リアルタイムOS+NPU などで頑張るケース [サブミリ秒オーダーの応答+マイクロ秒単位のジッタ]
  • FPGA を使うケース [マイクロ秒オーダーの応答+ナノ秒単位のジッタ]

ぐらいの区分を思いつくわけです。

正直、9割ぐらいは「Jetson で十分」という領域かとは思っておりますが、1割ぐらいは FPGA でこそ開拓できる分野があるのではないかと思っています。

FPGAでしかできない低遅延AI計算

例えば産業用のサーボモーターは 1k~100kHz ぐらいの周期で電流量を変化させているわけですが、たとえばこれを「強化学習によってAIで制御してみよう」なんてことは発想としてはすぐ出てくるわけです。

センサーとしてもIMUとか圧力センサとか一エンコーダとか色々なものが利用可能ですが、例えば当サイトがやっているカメラ画像処理での1ミリ秒でのAI認識とか、1ミリ秒後に視界の変化捉えるオプティカルフロー演算の結果を出すみたいなものも応用範囲に入ってくるかと思います。

こちらなどでも書きましたが、GPUは同じ計算の並列実行を行わないと性能が出ませんので、コア数に応じて何千とか万とかのオーダーでデータを溜めてから演算を開始しないと性能が出ません。 従って原理的にどうやってもメモリに溜める遅延時間を許容しない限りAI演算性能を発揮できない宿命にあります。さらに GPU の多くは Linux などのノンリアルタイムOS上で動くことを前提としています。最近は Linux のリアルタイム機能も充実しては来ていますが、GPUへのデータ転送やキャッシュヒットのバラツキなどでどうしても計算時間に大きなジッタが出てきます。

そうすると、ある程度の大容量のAI計算をリアルタイムにやろうとするとFPGAに利が出てきますし、FPGAにあったパイプライン計算での演算や、データフローを乱さず低遅延で出力できる学習モデルの開発が重要になってきます。

まず試作しないとデータすら取れない領域

そして何よりここからが重要なのですが、低遅延でリアルな対象を相手にすると、FPGAなどで試作しないとデータすら取れない という事が起こります。

ロボットなどは専門ではないのですがわかりやすいので、例えば「風の中でカメラ画像を見ながらバランスをとってキャッチボールをするドローン」みたいなものを考えてみます。

そうすると、非常に乱暴に言うと、姿勢制御をしながら飛んでくるボールに向かうように、「次の瞬間の各モーターの電流値を決めるAI」を開発したいという話になります。

この際にとても厄介なのが、出力如何で次のセンサー値も変わってしまう という事です。モーターの動き如何で視点となるカメラも移動してしまいますから。

近代のAIのほとんどは、取得済みのデータセットを固定された入力として用いて学習していますが、フィジカルAI分野では AI の学習次第で入力も変化する という事が起こるわけです。

CGなどのシミュレーション(ある種のデジタルツイン)でもある程度補完できるケースもあるかとは思いますが、そのシミュレーションを作るための基礎データは、「実機でリアルにフィードバックして何が起こるか」というデータを集めない事には何もできないわけです。

そしてそのデータ自体も、「マイクロ秒単位でフィードバックを掛けて初めて起こる事象」のデータなわけですから、低遅延計算をまず試作しないと何の実験も出来ないわけです。

逆に言うと、そのようにして作られた学習データや学習モデルはまだ世の中にない唯一無二なものですので、十分に、世界初/世界一を目指して研究開発できる魅力的な分野になってくるわけです。

フィジカルだからだからこそのリカバリの効く領域

もう一点、フィジカルAI 分野で、特に、kHz 以上の高サンプリングレートで起こりがちな面白い事象として、リカバリが効く というのがあります。

人間が1本足でバランスを取って立っているようなときに、ふらふらしながらバランスを取りますよね。 ロボットなども同じで、あるマイクロ秒時間で予測を間違えて電流を止めてしまったり流しすぎたりしても、次の瞬間にそれを打ち消すだけ電流を流すとごまかせるなんてことは普通にあります。確率的にON/OFFを繰り返して結果をフィードバックしながら微妙な制御をするというのはルールベースでもいろんなところで行っていることです。

モーターに限らず、PWMで作る光の階調や、D級アンプの音声などでも、そもそも人間の感度より高い周波数でON/OFFを繰り返してますので、最終的に人間が感じる積分値が同じになるように後から多少のリカバリが出来たりもします。

要するにシステムにもとからある程度のマージンがあり、実行時にマージン範囲内で試行錯誤ができるという事です。 これは、学習モデルを考えるうえで、間違った答えを出すと一発アウトな従来AIと大きく違うところだと思っております。

また、このマージンを使って、実働中に「微かな試行錯誤」を行い、実働中に賢くなるAI(いわゆるオンライン学習)のようなものを入れ込む余地なども出てくるのではないかと思います。

製造分野などでも不良品にならない適正値の範囲では当然どんな製品にも微小なバラツキはあるわけで、要は最後にばらつきを規定範囲に収めることが目的なわけです。

おわりに

当サイトでは、計算機科学の観点、特に FPGA を起点に、フィジカルAIを眺めております。

AI の良いところは、ルールベースで手に負えなかった部分を扱えるようになった点だと思います。

我が国においては、すでにこの分野は非常に高いレベルで制御工学が発達しており、ルールベースのシステムが多数稼動していると思います。それらの中にAIを入れ込むというのは容易でない部分もありますが、うまく共存しながら拡張としてAIを足しこめれば大きな変化をする分野もあるのではないかと思います。

先のサーボモーターの例を挙げましたが、他にも高速回転するエンジンの点火タイミング制御とか、人間の四肢や視覚/聴覚などの拡張であったり、医療、宇宙までいろいろな研究対象がありそうに思います。

ビジネスの観点でも、製造装置のようなドメイン固有の技能のAI化であったり、汎用ロボットとか人間の拡張(パワードスーツとか電脳メガネとか)のような多目的に使えるAIまで、まだまだ未開拓な領域が広がっているように思います。

AI を研究テーマにしたいという若者の方も増えているかと思います。一方で、パソコン上で Python 使ってできる範囲で論文書いて学位取ろうとすると、やってる人が多すぎてテーマ選びから苦戦するという方も多いと思います。

幸い今フィジカルAIというワードがちょっとしたバスワードになっていて、昔なら「単にFPGA化しただけでしょ」としか見られなかった分野が再注目されているわけですから、FPGAやってみたいなと言う方に興味を持っていただけると嬉しく思う次第です。

もちろん「リアルタイムに動くシステムを試作する」と言うのはそれ自体結構大変ですし、「自分で作ったシステムに適した学習モデル」を考えたり、「実際に学習させたり」はとても大変なことではあるのですが、苦労に見合った楽しさや見返りはある分野だと思っております。

VLIWとスーパースカラについて考えてみる

はじめに

少し前に SIMT であるGPUの話 とか SIMDを持ったCPUの話 とか書いてきました。

MIMD についても考察しないといけないなと思いつつ、先だって頭の中で VLIW について気になり始めたので、引き続き個人的な見解を書いてみたいと思います。

また、命令実行方式の違いはあれど、データフローは VLIW と スーパースカラは良く似ているので合わせて考えてみたいと思います。

VLIW(Very Long Instruction Word)

VLIW というと、IA-64 (Itanium) を思い出す方も多いかもしれませんし、トランスメタ社の Cursor を思い出す方もいるかもしれません。最近だと Qualcomm Hexagon が割と成功しているようです(触ったことないですが)。

また 筆者が知っている範囲ですと、AMD の Versal や Ryzen で利用されている XDNAVLIW だったと思います。

VLIW はその名の通り、複数の命令を束ねて1つの長い命令を実行できるようにしたものです。 身も蓋もない言い方をすると、近代のCPUがスーパースカラによる並列実行を行う際に性能を出すためのアウトオブオーダー実行機構などを、CPUがハードウェアで実行時に行うのではなく、プログランのコンパイル時に静的に行おうというものです。

必然的にプロセッサの内部構造が生々しく命令セットに反映されがちですので、バイナリ互換性をどう保つか が一つの重要なファクターであり、互換性を無視して使うケースでの VLIW は普通に実用的だと思います(都度都度コンパイラ作る人はたまったもんじゃないのかもしれませんが)。

一方で、「バイナリ互換性を保ったまま、将来並列性を拡張したい」となると途端に難易度が上がり、「プロセッサの並列数が変わっても互換性のある、並列命令ってどうするの?」という素人目に難しい話になるように思います。

たしか Itanium では命令の並列数を固定せずに、並列実行できる区切りだけを与える命令フォーマットにしていたと思いますし、Cursor では、コードモーフィングによって x86 命令から変換する事で次の Efficeon に拡張しようとしました。

が、結果的に、ハードウェアで変換する今の x86-64 が一番柔軟性があって性能が出て生き残ってしまったという歴史になっているように思います。

一方で、おそらく今の x86 の内部で μOPS を実行する部分は VLIW みたいなものにはなっている気はします。

ソフトウェアパイプライニング

さて、命令セットの問題を置いておくと VLIW にせよ スーパースカラにせよ、異なる命令を同時に実行する と言う点では同じです。 SIMDやSIMTでは同じ命令を同時に実行することしかできませんでした。

しばし当サイトではFPGAの得意な処理として、データ並列の対局としてパイプライン並列の話をしてきましたが、まさにそれが可能でして、ソフトウェアパイプライニングなどと呼ばれます。

これはコンパイラで自動的に行われたり、実行時にアウトオブオーダー機構がいい感じにしてくれたりすることもありますが、明示的に書くなら下記のような感じです。

// prologue
a0 = x[0];

// pipelining
for (i = 1; i < N; i++) {
    a1 = x[i];
    b0 = a0 * 3 + 1;
    y[i-1] = b0;
    a0 = a1;
}

// epilogue
y[N-1] = a0 * 3 + 1;

で、どういう事が起こるかと言うと、下記のような事が起こることを狙っていくことになります。

ソフトウェアパイプラインの狙い

ここでは、あるデータを Store Unit で書いているときに、加算器で次のデータを加算しつつ、その次のデータを乗算器で乗算しつつ、さらにそのまた次のデータを Load Unit で読んでくるという、パイプラインができます。

規模こそ限定的ですが、以前 こちら で発表させて頂いたような動きが CPU でも出来てしまう事になります。

複数の異なる動作ができる実行ユニットを並列実行できるVLIWやスーパースカラ計算機だから出来る事で、特筆すべきことだと思っています。

もっとも、ほとんどの実行ユニットは1サイクルでは処理が終わりませんので、実際にはもう少したくさんのデータで各実行ユニット内のパイプラインの深さを埋めることになります。

1命令で4つずつデータを処理する MN-Core は、非常に合理的に出来ている VLIW の一つだと言えるのではないかと思います。

おわりに

SIMD や SIMT ほど長い話にはならなかったですが、異なる命令を並列実行できる と言う点は、並列化の難しい多くの複雑な問題に対して非常に有効に機能すると思われます。

一方で並列化の規模や粒度の点で、アウトオブオーダーのスーパースカラは命令デコードの負荷から限界があると思います。

しかしながら、「バイナリ互換性を求めないVLIW」であればまだまだ発展の余地がありそうにも思います。

いずれにせよ、同時に異なる演算を実行できる という利点を最も持っているのは FPGA だと思っておりまして、以前、「FPGAは1命令を繰り返すVLIWプロセッサ?」という記事を書かせて頂いた話に繋がるわけです。

世の中で何か面白いアイデアが生まれてくることを祈りつつ、筆をおきます。