はじめに
第一章 プログラムできるハードウェア
第二章 開発環境の整備
第三章 ハードウェア・プログラミング (スタートアップ編)
第四章 機械学習ソフトウェア
第五章ハードウェア・プログラミング(組み込み編)
第六章 ハードウェア・プログラミング(チューニング編)
あとがき
著者紹介
ソフトウェアからFPGAやASICなどのハードウェアを開発する手法は古くからあり、ハードウェア業界では一般的に高位合成と呼ばれます。
近年、AIやディープラーニングの勉強会やFPGA関連のコミュニティベースでの勉強会などで、ソフトウェアから高位合成でもFPGAを開発する発表などが多くなってきました。高位合成が目立つようになってきたのは高位合成ツール本体の価格が下がってきていること、また、本書のようなC言語からの高位合成だけではなく、Java・Python・rubyといった言語からも高位合成できるツールなども登場し、FPGAを使うためにわざわざ専用の言語を使う必要性が無くなりつつあるところにあります。
ソフトウェア・エンジニアの中には、「ハードウェア」というだけで毛嫌いされる方もいますが、このように様々がツールが登場したおかげで高位合成自体の敷居も徐々に下がり、その出番が多くなってくることでしょう。これからはますます、FPGAを扱えるソフトウェア・エンジニアが増えてくると考えられます。
筆者は普段、FPGA側のハードウェア・エンジニアとして観点からFPGA関連の記事や同人誌などを執筆しています。本書では逆に、ソフトウェア・エンジニアの目線からFPGAの特性を見る、という観点で機械学習の一つであるCNNをFPGAに適用していくチュートリアル形式で高位合成を行いました。
本書を出版するにあたってご尽力して頂いたインプレスR&D山城様に厚くお礼を申し上げつつ、本書を読んで頂いた皆様にはソフトウェアでのFPGA開発の可能性を感じ取って、FPGA開発を活用したソフトウェア開発にチャレンジして頂ければ幸いです。
この本に掲載されているURL、商品価格、入手先などは2017年9月時点のものです。
本書に記載されている会社名、製品名などは、一般に各社の登録商標または商標、商品名です。会社名、製品名については、本文中では©、®、™マークなどは表示していません。
近年、FPGAを使用したハードウェア・アクセラレーションの中でもソフトウェアと連携したハードウェア・アクセラレーションが注目されています。Microsoft1や百度2などの検索エンジンで使用されたり、画像認識などの機械学習や深層学習3などに使用されるケースが多くなってきました。また、開発ツールや評価ボードといったハードウェアの入手もしやすくなり、気軽にFPGAを使用したプログラムのハードウェア・アクセラレーションを行うことが可能になってきました。
さて、一昔前のFPGAは、カスタム・インターフェースの処理、ネットワークや映像・放送送信の通信処理や画像処理などで多く使用されてきました。そのような現場ではFPGAのハードウェア開発とソフトウェア開発を切り離して行うことが多く、FPGA開発においてはVerilog HDLやVHDLなどのハードウェア記述言語を使用して開発するケースが多くありました。現在でもそのような分野のFPGA開発ではハードウェア言語を用いた開発が主流となっています。
では、FPGAを開発・利用するためにはハードウェア言語を使用しなければいけないかというと、必ずしもそうではありません。現在ではC言語などで開発を行う「高位合成」という手法でもFPGAを開発することが可能になっており、ソフトウェア・エンジニアでもFPGAを容易に扱うことが可能になってきました。
本書ではC言語で開発された機械学習の1つであるCNN(Convolutional Neural Network:畳み込みニューラルネットワーク)のアプリケーションを題材に、Xilinx社のSDSoCを用いてFPGAでハードウェア・アクセラレーションを実現する方法についての開発例を、実例を交えて解説します。
FPGAとはField Programmable Gate Arrayの略で、再構成可能なハードウェア4です。FPGAの中身は回路を構成するためのロジック、DSP、RAMや専用のハードウェア・マクロなどがあり、これらを組み合わせて専用の回路を作ります。現在のFPGA業界はXilinx社とIntel社(旧Altera社。2015年にIntel社が買収)の二社のデバイスが市場の大半を占めています。
例えば、「ビデオカメラの映像を白黒変換してモニターに映す」というシステムを作る場合、図1-2のようにFPGAで画像フィルター回路を作成し、システムの一部又は単独のシステムとして使用されます。
FPGAを使用してハードウェア・プログラミングを行うためには、FPGAが得意とするところ、そして、FPGAをどのように使用するとメリットが発生するのかを理解してプログラミングする必要があります。
FPGAは自由に回路を構成し設計できることから、何らかの目的専用の処理を行う独自回路を開発することができます。例えば、「独自開発の汎用的ではない通信方式」や「特殊な映像効果を与える画像処理」などをFPGA上で独自に回路を開発して実現することが可能です。この時「汎用的な処理を行う回路」とは、CPUの周辺ペリフェラル(UARTやSATA、PCIeなどのインターフェース)などを指します。多くのコンピュータはこれら汎用の回路をハードウェア・コントローラ(ハードウェア・マクロ)として実装しています。そして、汎用のハードウェア・コントローラが実現できないことをFPGAでは実現可能です。
FPGAでは処理を並列して行うことができます。CPUではプログラミングされた命令を逐次実行していきますが、FPGAでは同時にいくつでも並列して処理する回路を設計することができます。
例えば、リスト1-1のようにforループ文で100回の乗算をするようなソースコードの場合、一般的にCPUでは100回の乗算を繰り返し行いますが、FPGAではリスト1-2のように100個の乗算器を並べて配置し一度の時間軸に並列に演算することも可能です。
for( I = 0; i < 100; ++i){
z[i] = x[i] * y[i];
}
リスト1-2:並列に並べられた演算
z[0] = x[0] * y[0];
z[1] = x[1] * y[1];
z[2] = x[2] * y[2];
...
z[98] = x[98] * y[98];
z[99] = x[99] * y[99];
FPGAを用いたハードウェア・プログラミングを行うためにCPUとFPGAの処理方法の違いを理解しておきましょう。
CPUでは、ソフトウェアの実行をプログラムで記述されている順番に、CPUコアに用意されている命令処理回路で処理を行います。図1-3のように、プログラミングされた命令はメモリから読み出され、デコード、実行、メモリに書き戻す一連の動作を繰り返します。
一方FPGAは、内蔵されたロジック、乗算器、RAMなどを組み合わせて専用の回路を構成、処理の順番にそって各専用回路を構成し、接続して動作させます。各専用回路は同じ時間軸で動作し、入力される信号がくるとすぐに動作します。
例えば、図1-4のようにFPGA上で入力信号を処理する回路を2つ作成するとこの2つの回路が同時(並列)に処理することが可能です。
また、CPUでは図1-5のように乗算命令を実行するときは除算や加算、減算回路は使用しないのに動作させたままになります。一方、FPGAは使用しない回路を実装する必要がないので、CPUコアのように無駄な回路を動作させておく必要が無くなります。無駄な回路を動作させないということはそれだけ電力を消費しないということにつながります。つながります。
CPUとFPGAで同じ処理を実現した場合にどちらの方が処理性能が良いかというのはこれについては一概に比べることができません。次のようにCPUとFPGAの動作周波数が大きく違うからです。
・一般的に汎用的なCPUは数100MHz〜2GHz程度で動作します
・FPGAで設計した回路は一般的に数10MHz〜数100MHzで動作します
FPGAとCPU処理の違いは既に述べているようにFPGAが並列処理、CPUが逐次処理である点にあり、同じ動作周波数であれば、並列処理が行えるFPGAのほうが処理能力(スループット)が高くなります。例えば、リスト1-3のような演算式の処理をもとにCPUとFPGAでの処理の違いを見てみましょう。
y = ( a * b ) + ( c * d ) + ( e * f ) + ( g * h )
CPUの処理はリスト1-4のようにCPUコアにあるレジスタ(リスト1-4ではr0〜r2がCPUのレジスタ)にメモリから読み込んだ値を代入して演算回路で逐次実行します。
r0 = a
r1 = b
r2 = r0 * r1
r0 = c
r1 = d
r0 = r0 * r1
r2 = r2 + r1
r0 = e
r1 = f
r0 = r0 * r1
r2 = r2 + r1
r0 = g
r1 = h
r0 = r0 * r1
r2 = r2 + r1
y = r2
FPGAでは図1-6のような回路構成にすると一度に演算を完了させることが可能です。
また図1-7のように、演算回路毎に分割し、クロックで同期させる回路を構成することも可能です。この場合は、乗算器及び加算器は同じ時間軸で処理され、結果はそれぞれの演算器を順番に伝達されます。例えば、演算回路の時間軸をクロックで表現した場合は3クロック後に結果がyに出力されます。
FPGAに限らず、処理回路が多いほど結果が出力されるまでに時間がかかるため、一概にどの回路構成が良いかはシステムの設計思想で変わってきます。FPGAでの開発では絶えずこのような並列性の処理を考えながら論理設計を行っていきます。
しかし、リストのような回路を実際にFPGAで設計した場合、最高動作周波数は100MHz(=1つの演算回路の伝達に10ns)程度になります。例えば、1GHz(=1命令を1nsで実行)で動作するCPUと比較してみましょう。
CPUは16回の命令を実行するので16nsで演算が完了します。一方、FPGAは3回の信号伝達で演算が完了するので、30nsの時間が必要になります。もし、FPGAの動作周波数が1GHzであれば、当然、FPGAの方が処理が早く完了します。
このように、局所的に見ると命令の実行数が多くてもCPUのほうが処理性能が高いと言えます。
よくFPGAのメリットの1つとして取り上げられるパイプラインがあります。パイプラインはCPUとFPGAで意味合いが違います。
すでに同じようなことを述べていますがCPUのパイプラインは図1-10のように「命令実行のパイプライン」です。
FPGAのパイプラインは図1-11のように「処理のパイプライン」を構成することが可能です。
では、FPGAのパイプラインではどのようなメリットがあるのでしょうか。リスト1-1の演算式のyを算出するまでの時間に注目してみましょう。CPUの動作周波数が1GHz、FPGAの動作周波数が100MHzとします。この環境においてCPUでリスト 1-2を実行、FPGAでリスト1-4を動作させたとします。1回あたりの演算時間はCPUで16ns、FPGAで30nsと前項で述べました。この点だけを捉えればCPUの方が演算速度が速いことになります。
しかし、図1-12のようにこの演算について10,000回ループ演算を行った場合、CPUでは16ns×10,000回=約160μs、FPGAでは10ns×10,000回=100μsとなりFPGAの方が処理速度が速くなります。
このように、FPGAでは処理のパイプラインによってCPUよりも速く演算できるメリットが生まれます。
つまり、FPGAを使ったハードウェア・プログラミングで、CPU処理よりも満足な処理性能を得るためには、いかに演算を含めた処理がパイプラインにできるかが非常に大きな要素になります。
CPUでは様々な機能をリアルタイムに制御するために、割り込み処理が使用されます。割り込みの度に現在実行している処理を中断して処理を行います。
FPGAでは並列処理が可能なため、割り込みの必要がないため割り込みによる遅延が発生しません。このことからリアルタイム処理に向いています。
CPUは32bit CPU、64bit CPUといったぐあいに基本的にレジスタの長さが決まっています。32bit CPUで64bit同士の演算を行う場合は、CPUのレジスタ長に合わせて各桁を分解して演算する必要があり、1命令で演算を完了することができません。
例えば、32bit CPUで64bit変数aと64bit変数bの乗算を行う場合は、次のように式を分解して計算を行うことになります。
(( aの上位32bit * 2^32 ) + aの下位32bit ) * (( bの上位32bit * 2^32 ) + bの下位32bit )
FPGAでは64bitでも1,024bitでも演算回路を用意して処理することが可能です。32bit CPUで4bit同士の演算を行う場合は32bitのレジスタを使用しなければいけないため、28bitの無駄なレジスタも使用しなければなりません。FPGAの場合は4bitの演算回路を用意すれば良いので、無駄な回路を作成する必要がありません。CPUでは使用していないbitでも電力が消費されますが、不要なbitを削減できればそれだけ消費電力を下げることが可能です。
このように同じ演算でもFPGAでは不要な回路が無くなり消費電力を下がります。消費電力の低下もFPGAのもうひとつのメリットです。
ソフトウェアをFPGA化するうえで、無闇にFPGA化を行っても性能を向上するどころか何のメリットも生まれません。CPUとFPGAの得意分野は全く違う方向を向いているので、ソフトウェアをFPGA化するにはここまでに述べたCPUとFPGAの違いをよく理解し、CPUで実行すべきなのか、それともFPGAで実行すれば何らかのメリットが得られるのかを判断する必要があります。
CPUは命令を逐次処理することを一次元と捉えれば、FPGAは図1-13のように三次元的な要素であると思い浮かべてください。ハードウェア・プログラミングにおいては、処理をしている部分が一次元で済む話なのか、三次元に展開したほうにメリットがあるのかを考えながらソフトウェアを構築するようにしましょう。
また、ソフトウェアの処理をFPGAに展開して処理性能を向上させるということは、処理をパイプライン化してレイテンシ(処理の遅延時間)を短くして、処理の並列化によってスループット(単位時間あたりの処理能力)を向上させる点も意識したプログラミングが必要です。