【Tensorflow.jsバックエンド】機械学習の処理時間の短縮化の話〜SIMD処理とWebGLの比較


2022/05/08

去年の話題になりますが、
Google Chrome 89のx86版でもSSE3命令以前のCPUのサポートを廃止するという情報がありました。

デフォルトでブラウザ動作するTensorflow.jsとブラウザに対応したCPU命令には密接な関係があります。

これを理解して使わないと、Googlw Chromeでtensorflow.jsアプリを動かした際の演算パフォーマンスにも多大な影響を及ぼします。

前回の記事で、Node.jsのネイティブアプリとして呼び出したtensorflow.js(node)は古いCPUだと動かない、という内容を説明していました。

今回は
「ブラウザ駆動でも古いCPUほどSIMDとMultiThreadingの恩恵を受け取れなくなる」というそんなお話です。


Tensorflow.jsバックエンドとSIMD系ニーモニック

先に脇道に逸れて、少々SIMDの話をします。

SIMD系のCPU命令

隔年でGoogle Chromeで古いCPUへの互換性が切り捨てられています。

2020年9月に公開されたドラフトの内容においては、x86のGoogle Chrome 89以降でも、CPU命令でいうSSE3以上のニーモニックが必須となります。

SSE3以降非対応の古いCPUを搭載したマシーンでも、Chromeブラウザでtensorflow.jsライブラリを呼び出した途端クラッシュします。

SSE(Streaming SIMD Extensions;ストリーミングSIMD拡張命令)は、CPU命令を複数のデータへ同時に適用できるようか拡張指令です。

同時に単一データ/単一命令(SISD)しか扱えない対して、単一データ/マルチ指令(SIMD)に対応させることで、1回の演算処理のパフォーマンスが大幅に向上することができます。

このため、音声映像などリアルタイム性を求められるマルチメディア処理などに利用されています。

ストリーミングSIMD拡張命令は年を経るごとに変遷しており、Intel製品の場合、最初のSIMD拡張命令のMMXから順に

            
            SSE: 1999年〜
SSE2: 2000年〜
SSE3: 2004年〜
SSSE3: 2006年〜
SSE4.1: 2007年〜
SSE4.2: 2008年〜
AVX: 2011年〜
AVX2: 2013年〜
AVX-512: 2016年〜
        
という流れで発展しています。

Google Chromeでは、2014年以降からSSE2以上が必須となっていましたが、2021年よりSSE3以上が要求されます。

このスペック要求の節目のバージョンがGooogle Chrome 87ということで、それより以前のバージョンを使っている場合、「SSE3が検出できない」といった趣旨の警告が表示されるようです。

SIMDとは

折角なので、「SIMD」(Single Instruction, Multi Data)についても簡単に触れておきます。

その名の通り、CPUに単一の命令を複数のデータに並列に処理させる手法の一つです。

通常の処理では、SISD(Single Instruction, Single Data)で一回の演算で一回の処理を行うところを、SIMDで置き換えると、複数の演算を一回の処理でまとめて行うことが可能です。

いわゆるSIMDはベクトル演算の一種であり、繰り返し制御等を行わない変わりに、同時にデータ処理するだけ高速化が期待できます。

全てのプログラムが高速化できるとは限りませんが、多量のデータを一度に扱う必要のあるプログラムなどでは、SIMD系命令で飛躍的に動作速度がする可能性があり、画像処理プログラムなどはその一つです。

通常ベクトル演算はCPUのハードウェア構造に因る機能ですので、当然古いCPUアーキテクチャを持つCPU製品ではここ最近のSIMD系ニーモニックは利用できないという点は知っておきたいところです。

生のSIMDをレジスタから呼び出してバイナリ実装したい方は、
こちらのサイトなどが詳しく説明されていますので参考にしてみてください。

おらがクラシックCPUでtensorflow.jsの動作を検証

話を主題に戻します。

8年前に割と高値で購入したCPUでIntel製の第4世代Corei7プロセッサー(Intel i7-4770S)でTensorflow.jsの演算を少々やっていた時に、
nodeネイティブな「tfjs-node」で処理させるよりも、Chrome(ハードウエアアクセラレーションあり)上で素の「tfjs」のほうが明らかに処理が早い...ということに気づきました。

どうもChromeブラウザではWebGLで実装したソフトウェアレベルの高速な演算処理を行わせており、これがSIMD系命令で高速化したネイティブアプリのCPU処理よりも高速だ、というなんだか感覚に逆転してしまいました。

通常、node.jsネイティブのバックエンドであるtfjs-nodeの方が、ただのtfjsよりは速く処理できるというつもりだったので、ハードウェアアクセラレーション有りのブラウザ処理でこんなに速いのであれば、tfjs-nodeなんて不要なのでは...とも思いました。

結果として、tfjs-nodeが遅いのではなく、
「AVX-512以降を使えないCPUでないとtfjs-nodeの恩恵がない」という話のようです。

現在、Chromeブラウザが搭載しているWebGLハードウェアアクセラレーションは非常に有能で、古いSIMD命令では太刀打ちできないレベルにあります。

他方で、AVX-512以降を利用できるCPU製品では、WebGLをも凌ぐSIMD演算とマルチスレッド処理に対応しています。

そんな既にアンティークと化してしまいそうなこのCPUの命令セットを表示させてみると

            
            $ cat /proc/cpuinfo | grep flags
flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand lahf_lm abm cpuid_fault epb invpcid_single pti tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm xsaveopt dtherm ida arat pln pts
        
見ての通りで、まぁ...sse4_2やavxまではSIMD対応しているようです。

当然ながらAVX-512は使えないので、せめてここ5年以内に発売されたCPUでなければ、tfjs-nodeを使うより、通常のtfjsでブラウザのハードウェアアクセラレーションや、マルチスレッド処理できるWASM(webassembly)バックエンドを利用すべきです。


参照

Tensorflow.jsをNodejsで高速化しようとしたが、旧型CPUでは、WebGLの方が高速だった話

Supercharging the TensorFlow.js WebAssembly backend with SIMD and multi-threading

TensorFlow.js の WebAssemblyバックエンド の紹介

記事を書いた人

記事の担当:taconocat

ナンデモ系エンジニア

主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。