昨日に続き、今度は積算について考えて見ます。
Xilinxは Vivado になってから IPコアに浮動小数点の Accumulator が追加されています。
中を見ると LSB-MSB の指定が必要であり、設定次第で Maximum Latency が20以上にもなるようです。
整数積算においては通常クリティカルパスはキャリーの処理であって、タイミング収束する範囲に桁を区切って一旦その範囲で個別に積算しておいて、桁あふれ分の足し込みを次ステージに持ち越してパイプラインを組めば基本的に長bitの積算であっても高周波数で構成可能です。おそらく内部で指数部分のシフトを行った後は、固定小数点でそのような足しこみの作りになっていると思われます。
FPGAにかかわらず、浮動小数点を使った演算一般において一般に足しこみを行う場合、通常は加算順序が精度の観点で非常に重要です。浮動小数点加算においては指数の大きいほうに桁合わせして加算が行われるので、小さい方の値が大きく精度落ちするケースがあります。 何百万個とかのデータの合計値を得る場合、下記のようなことをすると後半桁揃えで大いに精度を損なっていたなんてことが大いにありえます。
float sum = 0;
for ( i = 0; i <num; i++) {
sum += data[i];
}
sumが段々大きな値になっていき、dataの各要素に対して仮数部の桁数が変わってくるとその分、data側の精度が落ちてきて、遂には何も足されなくなったりします。
ですので対象とするデータの特性に合わせて、小さい順にソートして足したりとか、トーナメント戦のようにバランスよく足したりとか、いろいろな工夫が必要となります。
そういった中で、Xilinx のIPコアは内部が固定小数点という点でこの心配が無いのは、FPGAならではの素晴らしい特性だと思います。
一方で話をGPU検討に戻します。
GPUでは4×4の行列演算において、4個の要素の足し込みが発生します。
add/sub コアだと 6~7Latency 用意しないと十分な周波数で動くコアが出てこないので、こちらで積算を行うと、結果が出るのを待って次の加算に進まないといけないので、その間の空き時間を、依存関係の無い別の演算で埋めるのは少し難しそうです。
ちなみにIntel CPUなどではこういった単スレッドで埋めきれない空きの有効利用としてハイパースレッディング(一般名でいうところのスーパースレッディング技術)を搭載しているわけです。
一方で、Accumulatorを使うことを考えると、Latency の長さが、単純 add/sub の 2~3倍あるので、今度は足し込み要素が4個と少ないことが災いして、やはりあまり短縮にならず、同様にパイプラインを埋めきれずに無駄が発生することが予想されます。
結論から言うと、「どうせ4個しか足さないのだから4入力加算器自作すればいいのでは?」という方向に思いが傾いています。
加算器の場合、4個の入力のうち指数部が最大のものにそろえて加算すれば良いだけなので、4加算の2bit分の繰り上がりも考慮して纏めてやったほうが、個別に加算するより精度も効率も良くなりそうな気がします。
そして加減算器の宿命として加算結果が0に近いときの桁落ち対策で、指数部の再正規化でバレルシフタが必要になりますが、これが1個に統合できるのもメリットです。
とかやっていると、Xilinx の IP コアで使おうとしているのが乗算だけになってしまっており、いっそ乗算器も自分で作ろうかな? という気になってきます。
Zynq のようにARMとか抱いていると、IEEE754形式にフォーマット揃えるメリットがいろいろとありそうで、そのように進めているわけですが、それでもFPGAならではの最適化がいろいろありそうだなと思う今日この頃です。
コメント