IPPのCPU SIMDの相違による演算精度差について | インテル ツール フォーラム | フォーラム

iSUS に投稿されている記事の内容や、IA プラットフォーム上でのソフトウェア開発に関するトピックを開発者同士でディスカッションできる場としてフォーラムを公開しています。

運営ルールはフォーラムの利用案内をご覧ください。
フォーラムの使い方はこちら

 
フォーラムに投稿するにはログインが必要ですログイン

IPPのCPU SIMDの相違による演算精度差について

メンバー投稿

1:31 PM
2015年10月13日


yoshihingis

投稿数 54

1

 Ippは自身が動作しているCPUのSIMD構造をディスパッチャーが見分けて、搭載されているSIMDアーキテクチャーの最高機能を使用するように最適DLLが選択されると思います。
 この時、DLLの相違によって、演算の結果が異なるといったことは生じないように保証されているものなのでしょうか?

 例えばippiの画像フィルタ関数で、flot(Ipp32f)の画像イメージをフィルタリングするとき、Ivy BridgeのCPUだと、AVXのDLLが使用されると思いますが、Haswell世代以降だとAVX2のDLLが選択されると思います。 このときAVX/AVX2のDLLの差によって、演算結果が異なるような事はあるのでしょうか? もしご存知でしたら教えて頂ければ幸いです。

11:34 PM
2015年10月13日


iSUS編集部 – 菅原

投稿数 206

2

yoshihingis 様

お問い合わせの件ですが AVX と AVX2 に関していえば、AVX2 では FMA 命令が利用可能であるため C += A * B のような操作では、AVX と AVX2 では中間結果の丸めによる結果の差が出る可能性があります。

しかし、AVX 以上の命令セットをサポートする CPU でも常に AVX 命令セットを利用するという制御が、ippInitCpu() や ippSetCpuFeatures 関数で可能です。

IDZの以下の記事参照ください:
"https://software.intel.com/en-us/forums/intel-integrated-performance-primitives/topic/507004"
"https://software.intel.com/en-us/articles/ipp-dispatcher-control-functions-ippinit-functions"

4:08 PM
2015年10月14日


yoshihingis

投稿数 54

3

菅原様、ご回答ありがとうございます。
 結論からいう、float演算で同一データを入力した場合1LSBの差がでるのはやはりSIMDが原因でしたが、AVXとAVX2の差ではなく、AVXとSSE4.2の差でした。
 実際に使用している関数は、ippiFilterBilateralBorder_32f_C1Rですが、
 Core i3 3220(Ivy Bridge)と Core i5 4460(Haswell)とでは、
 ippInitCpu(ippCpuAVX)で、AVXまでに制限をかけても結果が1LSB異なる結果が出ました。Ivy BridgeとHaswellでは同じAVXでもCPU内部のベクトル演算になにか違いがあるようです。
 Dependency Walkerで、AVXのDLLがIvy,Haswellで呼び出されている事は確認しました。

 ippInitCpu(ippCpuSSE42)で、SIMDをSSE4.2までに制限すると、Ivy,Haswellとも同じ演算結果となりましたので、AVXが起因で、演算結果に1LSBの差が出ていると思われます。
 float演算では、Ippを使用した場合、演算結果の一致性が求められる場合、AVX以上の命令は使用するときは注意が必要なようです。

2:01 PM
2015年10月17日


iSUS編集部 – 菅原

投稿数 206

4

yoshihingis 様

Sandy/Ivy の AVX は、256ビットの上位128ビットと下位128ビットを2回に分けて演算するので、Haswellと実装が異なりますね。この辺の精度への影響に関する資料が見つからないのですが、実際に試してみるとすると、128ビット AVX の機能を使って片方のレーンだけで計算して比較してみるしかないですか。

お役に立てず申し訳ないです。

4:24 PM
2015年10月17日


yoshihingis

投稿数 54

5

菅原様

 ご検討ありがとうございます。
 ippCpuInit()を使って、SIMD設定をいろいろ変えて、演算結果を調べた結果 同一CPUでもAVX2/AVX/SSE4.2で全て異なった演算結果を出します。 ただHaswellのcore i7とCore i5ではSIMDの設定を同じにすれば、その結果は同一でした。

 Sandy/Ivyでも、同じ結果です。SIMD設定ごとに違った値を吐き出します。ただし、SIMD設定が同じであればSandy/Ivyでは結果は同じになりますが、AVX2/AVXに関しては、Haswellと異なった値になります。
 SIMDをSSE4.2に設定すれば、Haswell,Ivy,Sandyで全て同一演算結果でした。

 Ippの問題なのか、またはIppバイラテラル関数だけの問題なのか、または、コンパイラで最適化でAVX2/AVXまでオプションで設定してビルドした時、演算式がベクトル化された時も起こるのか? この辺は、検証も相当難しいので、実はインテルサポート様の方へ質問をしてみました。 回答が頂けたら、情報は共有させていただきたいと思います。

3:35 PM
2015年10月20日


yoshihingis

投稿数 54

6

浮動小数点演算などの、SIMD設定による演算結果の差は、Ippに限らず、コンパイラのバージョンの差異などによっても生じるなど、詳細なご説明をサポート様からいただきましたので、情報共有させて頂きます。
 まだ、同じSIMDのAVX設定で、HaswellとIvy/Sandyで異なる結果が出るのは、FMA命令はHaswellの方が、精度を増した構成になっているようです。
 丁寧なご説明をいただきまして、サポートの方にはこの場を借りて、御礼を申しあげます。
 なお、私が確認した限りは、SIMDによる演算差は、32bitで1LSBの差であり、実際は問題になることは少ないと思います。

 以下にサポート様からの回答を記述いたします。 

==================================================================
インテル コンパイラーの最適化 / ベクトル化 / 並列化において
浮動小数点演算内容は異なる場合があります。
コンパイラーに限らず、異なる SIMD 命令を使うのであれば
異なった順序で計算を行うため、浮動小数点値と
その演算の特性により、異なる結果が得られることがあります。

インテル IPP では、特にビット単位での一致にまで
配慮した実装は提供されておりません。
※ インテル MKL では、そのようなモードで計算を行う機能があります。
(条件付数値再現性 : CBWR) ただし、パフォーマンスは低下します。

以下はあるお客様の、演算結果が
異なることのご指摘に対する Intel 社の回答です。

—-
(原文)
Please refer the customer to the article at:
https://software.intel.com/en-us/articles/consistency-of-floating-point-results-using-the-intel-compiler

In general, compiler optimizations can cause differences in rounding leading to tiny variations in floating-point results for all sorts of reasons. Different compilers may optimize differently.
To get the same results on the same system (or microarchitecture) for compiler-generated code, (not library code), compile with -fp-model precise. If working on Haswell or later, add also -no-fma.
These switches disable certain optimizations, so may have some cost in performance. If you need consistent results across different microarchitectures, add also -fimf-arch-consistency=true.

This said, there is no official standard for the results of math functions (apart from square root). Math library functions might return very slightly different values between one compiler version and another – usually, the result from a more recent compiler would be more accurate. An obvious example is that the availability of fused multiply-add (FMA) instructions on Haswell might lead to more accurate math function results than on Sandy Bridge.

The differences we are talking about are very tiny, typically in the last bit of the mantissa. But they can get magnified if the user application contains cancellations. They are typically less than the numerical uncertainty inherent in floating-point computations.

Differences due to MPI versions are possible, though perhaps unlikely.
This assumes that you always run the same number of MPI ranks. If the number of ranks changes, then lots of other things change, and you should expect variations in results. Reductions (such as summations) are particularly sensitive. Even with a fixed number of ranks, if you do reductions, you need to select a reduction algorithm that is deterministic and always operates on data in the same order.

I'd like to emphasize that we are talking about reproducibility, not precision or accuracy.
Results can be different, even when they are both within the expected uncertainty (accuracy) of floating-point calculations. And customers quite often complain that a result (e.g. from a new compiler or with additional optimization) is different from the one they are used to, which they consider "correct", even though the new result is actually more accurate.

Of course, it's also possible for bugs to cause differences between different compiler versions. But such differences are usually much larger than the small variations due rounding effects that we are talking about here.

(参考 – 上記原文もご参照ください)

下記の資料をご参照ください。
https://software.intel.com/en-us/articles/consistency-of-floating-point-results-using-the-intel-compiler

一般に、コンパイラーによる最適化では、浮動小数値のまるめ処理により
微小な差分の差異が生ずることがあり、これがさまざまな原因となって
おります。コンパイラーが異なれば、違った最適化となります。
同じシステム(マイクロアーキテクチャー)にて、コンパイラーが生成する
コードが同じとなる結果を得るには、-fp-model precise を付加して
コンパイルするようにしてください。Haswell 以降をお使いの場合、
-no-fma も付加するようにしてください。これらのオプションは、
いくつか最適化を無効化しますので、パフォーマンスがいくらか犠牲に
なってしまうかと存じます。マイクロアーキテクチャが変わっても
結果の一貫性(consistent results)を維持したいような場合には、
-fimf-arch-consistency=true も付加するようにしてください。

数学関数において、正式な規格はございません(平方根については
別ですが)。数学関数ライブラリーにおいては、あるコンパイラーと
そのまた別のコンパイラーを比べた場合、僅かに異なる値を返すことが
よくあります。新しいコンパイラーでの計算は、より精密になってきて
おります。よい例として、Haswell の掛け算と足し算の融合(FMA)命令は
Sandy Bridge の数学関数よりも精密になっております。

我々が話題にしております差異に関しては、非常に微小で、通常、
仮数の最下位ビット程度かと存じます。ですが、拡大すると、
お客様のアプリケーションを止めなくてはならない場合もあるかと存じます。
大概は浮動小数点演算に固有な数値的な不確実性によるものかと存じます。

MPI のバージョンによっても差異が生ずるかもしれません。好ましく
ありませんが。これは、常に同じランク数で走らせていたとしても、
起こります。ランク数を変更した場合には、他にもいろいろと変更が
ありますので、結果も様々になります。(足し算などの) Reduction に
おいては、非常に顕著です。いつも同じランク数であるとしても、
Reduction を使用する場合は、Reduction アルゴリズムを選択する
必要がございます。これでいつも同じ順序で計算させるようにすることが
できます。

正確さや精度(precision or accuracy)についてではなく、
再現性について話をさせていただきたく存じます。
計算結果には、差異が生じるものです。浮動小数点演算の
正確性や不正確性に関わらずです。よくお客様に、新しいコンパイラーや
新しく加わったオプションを使用した場合、過去に使用していた
時と結果が異なるとのご指摘をいただきますが、"correct" に
ついて考えると、新しい結果については、精度が上がっているはずです。

もちろん、コンパイラーのバージョンによってはバグにより差異が生ずる
可能性もございます。丸めの影響なら小さいのですが、バグ場合は、
大概大きく差異が出ます。