FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

Google Voice Kitを使ってみる(2. サンプルプログラムの実行)

Google Voice Kitを使ってみる、続き。 前回、組み立てが完了したので次にソフトウェアをダウンロードして実行する。

まず、MagPiのウェブサイトからISOファイルをダウンロードする。 MicroSDカード(4GB以上?)を用意し、EtcherでISOファイルを書き込む。

aiyprojects.withgoogle.com

f:id:msyksphinz:20171223223403p:plain

SDカードをRaspberry-Pi3に差し込み、ブートすると、ディスプレイにデスクトップ画面が現れる。

f:id:msyksphinz:20171223230907p:plain

ワイヤレスLANを接続する。

f:id:msyksphinz:20171223235114p:plain

Voice / Microphone テストを実行しよう。"Check Audio"プログラムをクリックする。

f:id:msyksphinz:20171223235428p:plain

マイクから、"Front, Centre"と聞こえる。次に、"Testing 1,2,3..." とスピーカーに喋りかけると、その声がリピートされる。

成功だ!ちゃんと動作していることを確認できた。

関連記事

Google Voice Kitを使ってみる(1. 組み立て)

Google Voice Kit、前から欲しかったのだが、ついにAIY Projectsから発送され、自宅に到着した。 実際には先週には到着していたのだが、RISC-V Dayなど忙しさが重なり、試行できなかった。 土日でようやくトライできるようになったので、早速やってみよう。

ホーム - Raspberry Pi Shop by KSY

これが内容物一覧。

f:id:msyksphinz:20171223223702p:plain

Raspberry-Pi3が必要。

f:id:msyksphinz:20171223223815p:plain

Raspberry-Pi3に接続することでくみ上げる。

f:id:msyksphinz:20171223223857p:plain

ちなみに、組み立てるためには、マニュアルには書かれていない細目のスクリュードライバーが必要なので注意。

f:id:msyksphinz:20171223224833p:plain

あと、マイクの接続には両面テープが必要と書いてある。別に両面テープでなくてもいいのだが、普通のテープだと少し格好悪い。 はんだ付けの角が出っ張ってしまい、マイクが浮いているのが少し残念。

f:id:msyksphinz:20171223232114p:plain

完成形は以下のようになる。

f:id:msyksphinz:20171223224027p:plain

関連記事

「スターウォーズ エピソード8 最後のジェダイ」を見てきた

スターウォーズ大好きなんです。。。

starwars.disney.co.jp

本当は公開当日に行きたかったけど、忙しかったので一週間遅れ。レイトショーで見てきた。2時間30分って長いよ!

ストーリーはエピソード7ほど大きくは動かなかったような気がする。いろんな人が死んだけど。 事前情報は相変わらず何もないので、結構ドキドキハラハラしながら見ていた。 なんか旧三部作よりも、ファースト・オーダーとレジスタンスの戦力差が大きく見えて、ファースト・オーダー強すぎ!って感じがするね。

そんな中、どうやってエピソード9につなげていくのか、気になるところ。 今回はそんな、繋ぎの回って感じだった。

サントラ出たら買おうかなあ。DVDもまた買おうかな。エピソード7、ローグワン両方買っちゃったんだよね。

7th RISC-V Workshop の Vector Extension Proposal 概要

RISC-V 7th Workshopでは、Vector Extensionの説明がなされている。

https://content.riscv.org/wp-content/uploads/2017/12/Wed-1330-RISCVRogerEspasaVEXT-v4.pdf

f:id:msyksphinz:20171222012224p:plain

資料を読みながらまとめてみる。追記の可能性あり。


RISC-V Vector Extensionの特徴としては、

  • なるべくコンパクトにすること。
  • ベクトルレジスタの処理にマスクを加え、任意の要素のみ演算が適用されるようにする。
  • スカラー、ベクトル、行列の形式などをサポートする(ただし行列形式はオプションであり、ベースの仕様には追加されない)。
  • 型を混在させることが出来る。
  • (自称)これまでのベクトル命令の中で最高の出来である。

ベクトルレジスタ

ベクトルレジスタはV0からV31までの32本が定義されている。

  • 各ベクトルレジスタには"Type"とよばれるレジスタが付与される。これは16bit長のベクトルレジスタである。
  • 各ベクトルレジスタには"Type"が付けられ、ベクトルレジスタ毎に異なる"Type"を設定することが出来る。
  • "Type"はvdcfgレジスタにより設定することが出来る。16bit×32本で512bitあるのだが、これをどのように設定することが出来るのかは詳細が語られていない。
  • おそらくvdcfgレジスタが複数作られ、csrrw命令により設定されていくものと思われる。

ベクトル算術演算の実行

  • 実装されているベクトルレジスタの長さはMVLで定義する。一方で実行中の演算が適用されるベクトルの要素の長さはVLで定義する。
  • MVLの長さは全てのベクトルレジスタにおいて同一である。
  • ベクトルレジスタの長さと、演算のレイテンシは別物として考える。vadd命令を実行した場合その命令を1サイクルで実行する必要はない。何サイクル化に分けて実行して構わない。

f:id:msyksphinz:20171221011520p:plain

  • 4サイクルで実行する場合

f:id:msyksphinz:20171221011615p:plain

  • 2サイクルで実行する場合

f:id:msyksphinz:20171221011634p:plain

マスク付きの実行

ベクトル命令は、マスクを使ってエレメント毎に演算の有効無効を指定できる。例えば、vadd v5, v3, v4, v1.tとする場合、以下のようにv1.tで指定されるレジスタの値に依存してマスクがかけられる。

f:id:msyksphinz:20171221012156p:plain

メモリアクセス

ロード命令・ストライド付きロード命令

ロード命令は非常にシンプルなロード命令。Unalignedも許可するが、非常に低速なことが前提。

ストライド付きロード命令は、いわゆるGather命令。RISC-Vの仕様であるGather命令はさらにえげつない。 f:id:msyksphinz:20171221013344p:plain

Gather命令

Gather命令は、各ベクトルエレメントで、ロードするメモリアドレスのオフセットを自由に設定できる。 結構実装が大変になる気がするが。。。

f:id:msyksphinz:20171221014131p:plain

ベクトルレジスタの型、型変換

  • 異なる"Type"が設定されたレジスタ同士の演算でも、ある程度ルールの中ならば演算を適用させることが出来る。
vcvt v1(F32) --> v0(F16)
vcvt v1(u8) --> v0(F32)
vcvct v1(F32) --> v0(I32)

この場合のベクトルレジスタのサイズが非常にややこしいことになる。 各ベクトルレジスタは異なる型を持つことが出来るが、MVL(ベクトルレジスタ当たりのエレメントの数)は常に同一である。 したがって、以下のようなことが出来るようになる。

  • プログラムコードが2つのF16ベクトルレジスタおよび2つのF32ベクトルレジスタを必要としている場合、
    • F16(=2byte)×2 + F32(=4byte)×2 = 12byteが必要となる。

このとき、ベクトルレジスタのハードウェアとしては  4\text{byte}\times 4\text{element}\times 32\text{本}=512\text{byte} 保持しているとすると、 \text{MVL}=512\text{byte} / (12\text{byte} + 4\text{byte(使用しないレジスタ)}) = 32となり、1ベクトルレジスタ当たり32エレメントを持つことが出来るようになる。

これをどのようにベクトルレジスタに当てはめるかは実装に任されている。例えば、以下のような構成が可能となる。

上位の 4\text{byte}\times 4\text{element}\times 4\text{本}\times 2\text{レジスタ}(=128\text{byte}) をF16のベクトルレジスタとして使い、 次の4\text{byte}\times 4\text{element}\times 8\text{本}\times 2\text{レジスタ}(=256\text{byte}) をF32のベクトルレジスタとして使う。

f:id:msyksphinz:20171222012123p:plain

以上のように、ベクトルレジスタのハードウェアを実際のアーキテクチャ的などのレジスタに割り当てるかは非常に柔軟に持つことが出来るようになる。 その分、かなり制限を加えないと実装が大変そうだが... (検証も大変そうだ)。

と思ったら、命令コード表には入っていた。師匠に指摘していただきました。ありがとうございます。

f:id:msyksphinz:20171226010836p:plain

RISC-VのCompression命令仕様の理解とISSの実装

RISC-Vのハードウェア仕様の中で、RV64GCとか、RV32IMACとか出てくるが、その中で"C"というのは"Compressed"命令ということで、命令長が16bitの短縮命令のことを指す。

サポートしているアーキテクチャの中で"C"が入っていれば、このCompressed 命令を動かすことが出来るということで、命令コードサイズの短縮につながる。 ARMのThumb命令、MIPSのMIPS16eに近いものだ。

似て非なる"C"命令と"E"命令

時々混乱するのだが、Compressed命令群と雰囲気が似ている命令で"E"命令群が存在する。これはRV32Eと呼ばれ、RV32I(32bit整数命令)のハードウェア的な縮退版を指す。

主な変更点としては、RV32Iでは32本ある整数レジスタを16本に減らしている。使用できる命令自体はRV32Iと同一で、ただしx16-x31までの搭載していない汎用レジスタにアクセスすると例外を発生させる。 また、カウンタレジスタ(rdcycle[h],rdtime[h], rdinstret[h])は無理に実装しなくても良いという制限がある。

というわけでRV32Eは、命令長自体を短縮させるわけではなく、ハードウェア量を減らすための実装なので、そこは注意。

Compressed命令の概要

まず命令フォーマットとして、16bit長命令であることを示すのに、下位の2bitを使う。下位の2bitが2'b11であれば、32ビット長命令以上になるが、それ以外では16bit長命令となる。 非常にリッチである。

f:id:msyksphinz:20171220020108p:plain
(RISC-V User Instruction Manulより引用)

注意すべきは、RISC-Vのサポートしているモードによって実行される命令の意味が異なるということだ。例えば、RV32/RV64ではC.FLDであり、RV128ではC.LQ として解釈されて実行される。

命令フォーマットは以下に示すようになっている。レジスタ本数は基本モードと同様に32本利用できるが、32本をフルにアクセスできるのはCR(レジスタ間演算)、CI(レジスタ、即値)、CSS(スタック操作命令)のみとなる。

f:id:msyksphinz:20171220020226p:plain

それ以外の命令は、以下の表に従ってアクセスできるレジスタが制限される。 ロードストアに関しても同様だが、スタック相対のアクセスの場合のみ、CSS(Stack-relative Store)により専用命令が用意されている。この場合は任意のレジスタのデータをスタックに積むことが出来る。

f:id:msyksphinz:20171220020347p:plain

大きく分けてCompressed命令の仕様は以下のように分類される。

  • CR : レジスタ間演算命令。2オペランドを取り、1オペランドを上書きする形の命令が用意されている。
  • CI : レジスタ、即値演算命令。即値とレジスタの演算、または即値を代入する演算。
  • CSS : スタック相対メモリアクセス命令。スタックポインタをベースとしてメモリアクセスを行う。ロードとストアがあり、整数レジスタ用と浮動小数レジスタ用が用意されている。
  • CIW : 即値が広くとることが出来るレジスタアクセス命令。スタックポインタの更新などに使用される。
  • CL : ロード命令。
  • CS : ストア命令。
  • CB : 分岐命令。レジスタ比較を行うが、比較対象のレジスタはゼロレジスタに限定される。PC相対分岐を行う。
  • CJ : ジャンプ命令。PC相対ジャンプを行う。JumpとJump And Linkが用意されている。

RISC-V の命令セットシミュレータへのCompressed 命令実装の検討

自作命令セットシミュレータにRISC-Vを実装する検討をしているのだが、いくつか問題があった。まず、命令のモード毎に有効な命令が異なるということだ。 たとえば、下記の命令リストにおいて、C.FLWC.LDは命令コード的に全く同じなので、RISC-Vのサポートしている命令形態によって意味が異なる。

f:id:msyksphinz:20180603234957p:plain

したがって、とりあえずは命令デコードテーブルは重複している命令の片方を無効化して生成を行った。

  • 自作RISC-Vシミュレータの命令デコードテーブルの一部
$arch_table.push(Array['c.addi4spn', 16, 'XXXXX', 'XX',     'XXXXX', 'XXXX0', '00X', 'XXXXX', 'XXXXX00', 'COMPRESS', "", ""])
$arch_table.push(Array['c.fld     ', 16, 'XXXXX', 'XX',     'XXXXX', 'XXXX0', '01X', 'XXXXX', 'XXXXX00', 'COMPRESS', "", ""])
# $arch_table.push(Array['c.lq      ', 16, 'XXXXX', 'XX',     'XXXXX', 'XXXX0', '01X', 'XXXXX', 'XXXXX00', 'COMPRESS', "", ""])   # RV128
$arch_table.push(Array['c.lw      ', 16, 'XXXXX', 'XX',     'XXXXX', 'XXXX0', '10X', 'XXXXX', 'XXXXX00', 'COMPRESS', "", ""])
$arch_table.push(Array['c.flw     ', 16, 'XXXXX', 'XX',     'XXXXX', 'XXXX0', '11X', 'XXXXX', 'XXXXX00', 'COMPRESS', "", ""])
# $arch_table.push(Array['c.ld      ', 16, 'XXXXX', 'XX',     'XXXXX', 'XXXX0', '11X', 'XXXXX', 'XXXXX00', 'COMPRESS', "", ""])   # RV64/RV128
$arch_table.push(Array['c.fsd     ', 16, 'XXXXX', 'XX',     'XXXXX', 'XXXX1', '01X', 'XXXXX', 'XXXXX00', 'COMPRESS', "", ""])
# $arch_table.push(Array['c.sq      ', 16, 'XXXXX', 'XX',     'XXXXX', 'XXXX1', '01X', 'XXXXX', 'XXXXX00', 'COMPRESS', "", ""])
$arch_table.push(Array['c.sw      ', 16, 'XXXXX', 'XX',     'XXXXX', 'XXXX1', '10X', 'XXXXX', 'XXXXX00', 'COMPRESS', "", ""])
$arch_table.push(Array['c.fsw     ', 16, 'XXXXX', 'XX',     'XXXXX', 'XXXX1', '11X', 'XXXXX', 'XXXXX00', 'COMPRESS', "", ""])
# $arch_table.push(Array['c.sd      ', 16, 'XXXXX', 'XX',     'XXXXX', 'XXXX1', '11X', 'XXXXX', 'XXXXX00', 'COMPRESS', "", ""])   # RV64/RV128
  • Compressed命令のテストパタンの解析

Compressed命令のテストパタンを流してみると、どうも4-byteアラインではなく2-byteアラインに命令が配置されていてもジャンプできなければならないらしい!?

RISC-Vの例外仕様では、Instruction Address Misaligned例外は4-byteにアラインされていないことが条件かと思っていたけど、RVCに関してはそうではないらしい。

RISC-Vのメーリングリストを探していると見つけた。

An instruction address misaligned exception is generated on a taken branch or unconditional jump if the target address is not four-byte aligned. No instruction fetch misaligned exception is generated for a conditional branch that is not taken.

with a commentary note:

Instruction fetch misaligned exceptions are not possible on
machines that support extensions with 16-bit-aligned
instructions, such as the compressed instruction set extension,
C.

なるほどー、つまりCompressed命令をサポートしている実装では、Instruction Fetch Misaligned 例外は発生しないということか。これはびっくり。

というわけで例外的に命令フェッチアライン例外を無効にして自作ISSでRVC命令を流すようにすると、とりあえずデコードは出来たようだ。

f:id:msyksphinz:20180605001433p:plain

あとは中身の実装をしていかなければ。

RISC-Vオープンソースコア Rocket-Chip, BOOMv1, BOOMv2 のサイクル性能比較

RISC-V Day Tokyo 2017お疲れさまでした。 私は午前中から適当なことを喋って、特にお金をもらっているわけでもないのにRISC-V Foundationとか、SiFiveのIPについてべた褒めをしてしまったのだった。

あとで何人かには聞かれたのだが、講演で使った資料にはバックアップスライドがあって、各種オープンソースコアのサイクル数ベンチマークを取った資料がある。 これは独自に取得したベンチマーク結果で、その正しさは未知数なのだが、参考までに公開してみよう。

比較したのは、

使用したのはriscv-testsのbenchmarksテストセットで、ログに表示される命令数とサイクル数を取得して一覧にしている。

Inst-Count Rocket-Cycle Inst-Count(BOOM) BOOM v1-Cycle BOOM v2-Cycle
dhrystone.riscv 198654 250623 200129 200129 154647
median.riscv 4159 5758 4259 7637 9956
mm.riscv 25199 29396 25287 17482 17044
mt-matmul - 42520 - 15948 16295
mt-vvadd.riscv - 23836 - 8846 7049
mt-vvadd.riscv - 21482 - 7637 6049
multiply.riscv 24298 28567 21003 18371 20044
qsort.riscv 125723 204247 124233 205474 254778
rsort.riscv 173305 227307 171284 112700 101057
spmv.riscv 33924 59877 32535 27991 28583
towers.riscv 6170 6338 6623 4607 5415
vvadd.riscv 2420 2496 2519 2040 2014

グラフにしてみるとこんな感じ。Rocket-Chipを1.0にして、そのサイクル数の比率を測定している。縦軸が大きいほど性能が良い。

f:id:msyksphinz:20171219232449p:plain

BOOMはRocket-Chipに比べて、それなりに性能が出ている。ただし、BOOMv1はBOOMv2よりもサイクル性能が良さそうな気がする。

vaddのような単純なパタンではBOOMは性能が出ているが、これはBOOMが、faddの単純ループのレイテンシを隠蔽できるからであり、それ以外ではそこまで大きな差が現れる訳ではない。

  • riscv-tests/benchmarks/mt-vvadd/vvadd.c
//--------------------------------------------------------------------------
// vvadd function

void __attribute__((noinline)) vvadd(int coreid, int ncores, size_t n, const data_t* x, const data_t* y, data_t* z)
{
   size_t i;

   // interleave accesses
   for (i = coreid; i < n; i+=ncores)
   {
      z[i] = x[i] + y[i];
   }
}

ただし、qsortとmedianでは、BOOMv2はBOOMv1よりも遅いどころか、Rocket-Chipよりも遅いんだよなあ。このへんはアプリケーションの特性によるかもしれない。

Computer Architecture 6th Editionの7章"Domain-Specific Architecture" を読む (7.3章の用語集)

ヘネパタ第6版こと、"Computer Architecture 6th Edition" では、第7章でドメイン固有アーキテクチャの章が新設された。 これを機会に、しっかり読んでいこう。

Computer Architecture, Sixth Edition: A Quantitative Approach (The Morgan Kaufmann Series in Computer Architecture and Design)

Computer Architecture, Sixth Edition: A Quantitative Approach (The Morgan Kaufmann Series in Computer Architecture and Design)

7.3章はがっつりディープニューラルネットワークの内容だ。用語集も入っている。これを機にしっかり勉強しよう。

目次

これは著者が読んだ内容をまとめているだけなので、誤訳、理解不足により誤っている可能性があります!鵜呑みにしないようにお願いします。


  • 一般用語
用語 略語 簡単な説明
Domain-specific architectures DSA 特定のドメイン用に設計された専用プロセッサ。ドメイン外の処理は、他のプロセッサにより処理されることが期待されている。
Intellectual property block IP SOCにインテグレートすることのできるポータブルデザインブロック。
System on a chip SOC コンピュータのすべてのコンポーネントを含んだチップ; PMDなどで使われる。
用語 略語 簡単な説明
Activation - 人工ニューロンが「活性化」した結果; 非線形関数の出力である。
Batch - フェッチ処理の負荷を減らすために、一緒に処理するデータセットのまとまり。
Convolutional neural network CNN 前のレイヤからの出力の、空間的に近くの領域の非線形関数の集合を入力として受け取り、それに重みを乗算するDNN。
Deep neural network DNN 人工ニューロンを多数レイヤとして並べたもの。各レイヤは、前段のレイヤからの出力に、重みを掛け合わせて非線形関数を適用する。
Inference - DNNの生産フェーズ、Prediction(推論)とも呼ばれる。
Long short-term memory LSTM 時系列の分類、処理、推論に適しているRNN。これは「セル:cells」と呼ばれるモジュールの階層構造により構成されている。
MultiLayer perceptron MLP 前のレイヤで、重みを掛け合わせた結果に対して非線形関数出力を適用したものを入力とするDNNのことを示す。これらのレイヤは全て結合されている。
Rectified Linear Unit ReLU f(x)=max(x,0)で表現される非線形関数。有名な他の非線形関数としては、Sigmoid関数やHyperbolic Tangent(tanh)関数などがある。
Recurrent neural network RNN 入力が、前のレイヤの出力と、前の状態であるDNNのこと。
Training - DNNの学習フェーズ。学習(learning)とも呼ばれる。
Weights - Trainingフェーズ中に学習される値; パラメータ(parameter)とも呼ばれる。
  • TPU用語
用語 略語 簡単な説明
Accumulators - 4096個の256×32-bit(=4MB)のレジスタ群で、MMUの出力を格納し、Activation Unitの入力値として使用する。
Activation Unit - 非線形関数(ReLU, sigmod, hyperbolic tangent, max pool, average pool)として動作する。Accumulatorから入力を受け取り、Unified Bufferに計算結果を出力する。
Matrix multiply Unit MMU 256×256個のシストリックアレイ状の8-bit算術演算ユニットで、積和演算を実行する。演算器の入力はWeight MemoryおよびUnified Bufferで、出力はAccumulatorに格納される。
Systoric Array - 処理ユニットのアレイで、近傍のデータを上位から受け取り、部分計算結果を計算し、同じ入力値とその計算結果を次の近傍の演算器に渡す。
Unified Buffer UB 25MBのオンチップメモリで、Activationを保持する。DNNの実行時には、Activationの結果をDRAMにすピルアウトしないようにサイズを調整する。
Weight memory - 8MBの外部DRAMチップで、MMUに渡す重み情報を保持する。重み情報はMMUに渡される前にWeight FIFOに転送される。