PythonとJupyter NotebookでFPGAベース設計の構築とプログラミングを迅速化
DigiKeyの北米担当編集者の提供
2019-04-03
コンピュータビジョン、通信、産業用組み込みシステム、さらには増加しつつあるIoT(モノのインターネット)など、計算負荷の高いアプリケーション向けのハードウェア設計における効率を高めるため、設計者は以前からFPGA(Field Programmable Gate Array)を採用してきました。とはいえ、従来のFPGAプログラミングに含まれる詳細な手順が障壁となり、設計者は代わりとなる処理ソリューションを求めるようになりました。
Jupyter NotebookをベースにしたPYNQ(Python Productivity for Zynq)開発環境の登場によって、FPGAのプログラミングに新しい道が開かれました。特にPYNQをサポートするように設計された開発ボードを使うと、FPGA経験のほとんどない開発者でもFPGAの性能を十分に活用して計算負荷の高いアプリケーションを高速化できる設計を迅速に実装できます。
この記事では、通常のFPGAによるアプローチを説明した後、それに代わってFPGAベースのシステムの開発を迅速化する強力なオープンソースの手段を提供するDigilentの開発ボードを紹介し、そのボードを使い始める方法を示します。
FPGAを使う理由
複雑で計算負荷の高いアルゴリズムを採用する必要のあるエンジニアは、多くの場合FPGAに依存して厳しいパワーバジェットを損なわずに処理実行を高速化します。実際、FPGAはエッジコンピューティングシステムにおける人工知能アルゴリズムを高速処理するための支配的なプラットフォームとして台頭してきました(「Use FPGAs to Build High-Performance Embedded Vision Applications with Machine Learning(FPGAを使用した機械学習高性能組み込みビジョンアプリケーションの構築)」を参照)。
組み込みアプリケーション専用に設計された、より先進的なFPGA SoC(System-on-Chip)デバイスはプログラマブルロジック(PL)ファブリックをマイクロコントローラと統合したものです。たとえば、Xilinx Zynq-7000 SoCではデュアルコアのArm® Cortex®-A9プロセッサシステムを内蔵プログラマブルロジック(PL)ファブリック内の最大444,000個のロジックセルと結合しています(図1)。Zynq SoCは、内蔵プロセッサおよび広範な周辺回路と共に、最大2,020個のデジタルシグナルプロセッシング(DSP)ブロック(またはスライス)を備えています。開発者はこれらのリソースを使用して、複雑で計算負荷の高いアルゴリズムのスループットを高めるために必要な専用処理チェーンにPLファブリックを構成することができます。

図1:Xilinx Zynq-7000 SoCは、デュアルコアのArm Cortex-A9プロセッサ、プログラマブルロジックファブリック、および多くの組み込みアプリケーションに必要とされる広範な一連の周辺回路とインターフェースを組み合わせている。(画像提供:Xilinx)
プロセッサとPLファブリックの統合により、部品点数の削減に加えて、チップ外へのアクセスではなく内部バスを介して処理を行うことができます。この統合により、電源投入およびリセットのシーケンス実行時にPLファブリックをロードする重要なタスクが簡略化されます。
FPGAを使用して構築された一般的なマイクロコントローラベースのシステムの場合、開発者はFPGAをプログラムするビットストリームのロードのためのシーケンスとセキュリティを管理する必要があります。Zynq SoCでは、内蔵プロセッサがPLファブリックや他のオンチップ周辺モジュールの管理などの従来のマイクロコントローラのタスクを実行します。結果として、FPGAのロードプロセスは従来のFPGAのビットストリームの初期化よりも従来のマイクロコントローラのブートプロセスに類似したものになりました。
このブートプロセスは、Zynqのいずれかのプロセッサが管理するステップの短いシーケンスとして実行されます(図2)。電源投入時またはリセット時に、Zynqプロセッサが読み出し専用BootROMから短いコードを実行するときにブートプロセスが開始され、ブートデバイスから実際のブートコードがロードされます。ブートコードには、プロセッサのシステムコンポーネントを設定するコードと共に、PLビットストリームとユーザーアプリケーションが含まれています。ブートコードのロードが完了すると、プロセッサはその中のビットストリームを使用してPLを構成します。設定とPL構成の完了後、このデバイスはブートコードに含まれているアプリケーションの実行を開始します。

図2:従来のマイクロコントローラに似たブートシーケンスで、Xilinx Zynq-7000 SoCはブートローダをロードおよび実行するコードをBoot ROMから実行し、ブートローダが、ブートコード内に含まれているビットストリームによるプログラマブルロジックファブリックの構成などの以降の段階を処理する。(画像提供:Xilinx)
PLのロード処理が簡略化されても、従来は必要なビットストリームを生成するために求められる複雑なFPGA開発プロセスを扱うことが開発者に課題として残されていました。FPGAの性能を活用することを望む開発者にとって、従来のFPGA開発プロセスは実装のための大きな障壁であり続けています。Xilinxは、PYNQ環境によってこの障壁を効果的に排除しました。
PYNQ環境
PYNQでは、オーバレイと呼ばれるプリビルドされたライブラリ内にPLビットストリームがカプセル化されており、オーバレイは開発プロセスと実行環境におけるソフトウェアライブラリと似た役割を果たします。ブートロードプロセス実行時に、必要なオーバレイに関連付けられたビットストリームがPLファブリックを構成します。しかしこのプロセスは、各オーバレイに関連付けられたPythonアプリケーションプログラミングインターフェース(API)を通してオーバレイの機能を利用する開発者に対して透過的なままです。開発中、エンジニアは必要に応じてソフトウェアライブラリとオーバレイを組み合わせることができ、その各APIを通してアプリケーションを実装することが可能です。プロセッサシステムがソフトウェアライブラリのコードを通常通り実行するときに、PLファブリックがオーバレイ内で提供されている機能を実装します。その結果、パフォーマンスが加速化されるため、ますます要求が厳しくなりつつあるアプリケーションにFPGAベースの設計を採用することへの関心が高まり続けています。
PYNQはその名が示すように、プログラミング言語Pythonに関連する開発生産性の利点を活用します。Pythonは相対的にシンプルであることと、その巨大なエコシステムが拡大し続けていることからトップクラスの言語の1つとして台頭してきました。開発者は多くの場合、サポートサービスに必要なソフトウェアライブラリや専門的アルゴリズムをオープンソースPythonモジュールのリポジトリで見つけます。と同時に、C言語の重要な機能を実装することができます。これはPYNQがPythonインタプリタのC言語による一般的な実装を使用しているためです。この実装により、既存の数千ものCライブラリに容易にアクセスでき、開発者が提供するC言語ライブラリを簡単に使用できます。経験豊かな開発者は専用ハードウェアオーバレイとC言語ソフトウェアライブラリによってPYNQを拡張できますが、PYNQの強みはPythonプログラムを作成できるあらゆる開発者に生産性の高い開発環境を提供できる点にあります。
それ自体がオープンソースプロジェクトであるPYNQは、別のオープンソースプロジェクトであるJupyte Notebookをベースとして構築されています。Jupyter notebookは対話的にアルゴリズムを探究し、Pythonなど現在では40を超える他のサポート対象言語で複雑なアプリケーションのプロトタイピングを行うのに特に効果的な環境を提供します。Project Jupyterの下、コミュニティの総意に基づいて開発されたJupyter Notebookは実行可能コードの行と説明用テキストおよびグラフィックを組み合わせます。この機能により個々の開発者が、他の開発環境に移動することなく開発進捗内容を効率的に文書化できます。たとえば、ノートブックを使うと、データを表示するのに必要な数行のコードを、そのコードによって生成されるグラフィックと組み合わせることができます(3図)。

図3:XilinxサンプルレジストリのJupyter Notebookは、説明用テキスト、実行可能コード、アプリケーションに関連した出力を組み合わせたもの。(画像提供:Xilinx)
Jupyter Notebookはサーバが提供する対話型開発環境内で維持されるライブドキュメントであるため、コード、出力、説明用テキストを含めることができます(図4)。Jupyterセッション内では、サーバがHTTPを使用して通常のWebブラウザにノートブックファイルをレンダリングし、レンダリング済みドキュメントの静的および動的コンテンツに対してはHTTPとWebsocketを組み合わせて使用します。バックエンドではサーバがオープンソースのメッセージングプロトコルであるZeroMQ(ØMQ)を使用してコード実行カーネルと通信します。

図4:Jupyterセッション内では、サーバがコードを実行するバックエンドサーバとやりとりしながら、ノートブックファイルの内容をWebブラウザにレンダリングする。(画像提供:Project Jupyter)
編集モードではテキストとコードを編集できます。それに対して、対応するノートブックファイルをサーバが更新します。ノートブックファイルはJSON形式のキーと値の一連のペアで構成されるテキストファイルです。これらのペアはJupyter環境ではセルと呼ばれます。たとえば、上に示したJupyter NotebookのWebブラウザ表示はコードとマークダウンテキストのセルで構成されています(リスト1)。
Copy
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Error plot with Matplotlib\n",
"This example shows plots in notebook (rather than in separate window)." ]
}, {
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAA[truncated]",
"text/plain": [
"<matplotlib.figure.Figure at 0x2f85ef50>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"%matplotlib inline\n",
" \n",
"X = np.arange(len(values))\n",
"plt.bar(X + 0.0, values, facecolor='blue', \n",
" edgecolor='white', width=0.5, label=\"Written_to_DAC\")\n",
"plt.bar(X + 0.25, samples, facecolor='red', \n",
" edgecolor='white', width=0.5, label=\"Read_from_ADC\")\n",
"\n",
"plt.title('DAC-ADC Linearity')\n",
"plt.xlabel('Sample_number')\n",
"plt.ylabel('Volts')\n",
"plt.legend(loc='upper left', frameon=False)\n",
"\n",
"plt.show()"
]
},
リスト1:Jupyter Notebookは、このようなコードセクション、マークアップ、出力内容を含んだ一連のJSON形式によるキーと値のペアで構成されるテキストファイルであり、これが図3に示すレンダリングされたページに対応する。その図の.png画像に対応する文字列はここでは表示する目的のため途中で切れていることに注意。(コード提供:Xilinx)
文書化機能とは別のJupyter環境の威力は対話的にコードセルを実行できる点にあります。開発者はブラウザ内で目的のセルを選択し(図3の青線部)、ブラウザウィンドウ上部のJupyterメニューの[Run]ボタンをクリックするだけです。すると、対応するコードセルがJupyter Notebookサーバによってコード実行カーネルに渡されます。このカーネルはPYNQ環境の対話型Python(IPython)カーネルです。コード実行後、サーバがカーネルによって生成された出力を使用して、レンダリング対象のウェブページとノートブックファイルの両方を非同期的に更新します。
PYNQはこれと同じアプローチを、IPythonカーネルとノートブックWebサーバを含むJupyterフレームワークをZynq SoCのArmプロセッサ上に組み込むことによって、FPGAベースの開発へと拡張します。この環境に含まれているPythonモジュールであるpynqは、Pythonプログラム内でPYNQサービスにアクセスするために必要なPython APIをプログラマに提供します。
FPGA開発環境
特にPYNQをサポートするように設計された、DigilentのPYNQ-Z1開発キットを使うと、用意されているPYNQブート可能Linuxイメージを読み込むだけでFPGA加速化アプリケーションの開発をすぐに始めることができます。PYNQ-Z1ボードは、XilinxのXC7Z020 Zynq SoCに512メガバイト(MB)RAM、16MBフラッシュ、外付けフラッシュ追加用microSDスロットを組み合わせたものです。このボードは、スイッチ、ボタン、LED、複数の入出力ポートと共に、拡張のためDigilent Pmod(周辺モジュール)インターフェースとArduino シールドおよびDigilent chipKITシールドを介してサードパーティのハードウェアに接続するコネクタも備えています。このボードには、XADCと呼ばれるZynq SoCのA/Dコンバータ(ADC)が6つのシングルエンド アナログ入力ポートまたは4つの差動アナログ入力ポートとして搭載されています。Digilentは別売りで、電源、マイクロUSBケーブル、PYNQイメージ記録済みmicroSDカード、Pythonモジュールの更新/追加用Ethernetケーブルを含むPYNQ-Z1生産性向上キットも用意しています。
これらSoCおよびボードの全機能はJupyter Notebookを通じてすぐに利用できます。たとえば、ループバックテストでこのボードのPmodインターフェースにアクセスしてADCの値を読み取り、D/Aコンバータ(DAC)に書き込むには、わずか数行のコードのみが必要です(図5)。必要なPythonモジュールをインポートした後、「ベース」オーバレイを使用してSoC PLが初期化されます(図5のセル2)。従来のボードサポートパッケージと同様、このベースオーバレイがボードの周辺モジュールへのアクセスを提供します。

図5:Xilinxサンプルリポジトリに含まれているJupyter Notebookにはシンプルな入出力トランザクションのためのハードウェアサービス利用に関するデザインパターンの実例が示されています。(画像提供:Xilinx)
インポートしたモジュールを呼び出すだけで値の読み書きができます(図のセル3)。サンプルとして示したノートブックでは、ノートブックサーバがシーケンス内の各セルを発行し、生成した結果でノートブックを更新します。この場合は唯一の出力値が0.3418ですが、実行エラーがあればすべて通常のPythonトレースバックスタックとしてそれぞれのコードセルといっしょに表示されます。
複雑なアプリケーションの構築
用意されている広範なPythonモジュールとの組み合わせにより、このシンプルに見える組み込みアプリケーション開発に対するアプローチは、複雑な計算負荷の高いアプリケーションを迅速に実装するための強力なプラットフォームを隠れた存在にしています。たとえば、PYNQ-Z1 HDMI入力と人気の高いOpenCVコンピュータビジョンライブラリを使えば、迅速に顔認識ウェブカメラを実装できます。ベースオーバレイとウェブカメラインターフェースを読み込ませた後、OpenCVカメラオブジェクトvideoInを初期化します(図6)。ビデオ画像の読み込みは、videoIn.read()を呼び出すだけで行えるほどシンプルで、この例のようにframe_vgaが返されます。

図6:Xilinxサンプルリポジトリに含まれているJupyter Notebookには、PYNQ-Z1開発ボードのハードウェアリソースとOpenCVライブラリ(cv2)に用意されている強力な画像処理関数を組み合わせることでウェブカメラ顔認識システムを素早く構築する方法が示されている。(画像提供:Xilinx)
ノートブック内の個別のセルとして管理されている以降のステップでは、プリセット条件を使ってOpenCV(cv2)分類器オブジェクトを作成して目鼻などを識別する境界ボックスを付加します(この例では、目が緑、顔が青)。別のセルのペアで、このアプリケーションはボードのHDMI出力を使用して出力を表示した後、終了します(図7)。

図7:Xilinxウェブカメラ顔認識ノートブックの最後のセルは、OpenCV分類器の使い方を示しており、その結果を使用して元画像に境界ボックスを付加し、PYNQ-Z1開発ボードのHDMI出力ポートを使用して表示する。(画像提供:Xilinx)
複雑なソフトウェアを対話的に構築、テストし、議論を共有できるため、Jupyter Notebookは人工知能アプリケーションのアルゴリズムの最適化に取り組んでいるサイエンティストやエンジニアの間で好評です。作業が進むにつれ、ノートブックはコードとその出力だけでなく、結果についての開発者の解析も表示し、チームメンバーや同僚間で共有できる一種のコンピューティング記録になります。
ただし、開発者はノートブックが、より生産指向の高い取り組みではリポジトリとしてふさわしくない場合があることを理解する必要があります。たとえば、画像データの大きな16進コード化文字列(リスト1の途切れた部分参照)を含めると、ドキュメントのサイズが大きくなるだけでなく、一般的なソースバージョンコントロールシステムで使われている差分法が複雑になる可能性があります。コードと非機能的なテキストを織り交ぜることは、初期の解析段階で作成されたコードの実運用レベルの開発プロセスへの移行をさらに複雑化する可能性があります。しかし、コードの研究開発と迅速なプロトタイピングでは、Jupyter Notebookが強力な開発環境になります。
まとめ
FPGAは、IoT、コンピュータビジョン、産業用オートメーション、車載用製品などのアプリケーション向けに設計された組み込みシステムの増大する需要に応えるための性能の飛躍的向上を実現します。従来のFPGA開発手法には、多くの開発者にとって障壁が残されていましたが、Pythonを使用し、Jupyter NotebookをベースにしたPYNQ開発環境の登場は、効果的な代替手法になります。特にPYNQをサポートするように設計された開発ボードを使うと、FPGA経験のほとんどない開発者でもFPGAの性能を十分に活用して計算負荷の高いアプリケーションを高速化できる設計を迅速に実装できます。
免責条項:このウェブサイト上で、さまざまな著者および/またはフォーラム参加者によって表明された意見、信念や視点は、DigiKeyの意見、信念および視点またはDigiKeyの公式な方針を必ずしも反映するものではありません。


