2013-03-11 5 views
19

私はいくつかのテストを行い、奇妙な結果を得ました。Python Numpyデータ型パフォーマンス

コード:

import numpy as np 
import timeit 


setup = """ 
import numpy as np 
A = np.ones((1000,1000,3), dtype=datatype) 
""" 

datatypes = "np.uint8", "np.uint16", "np.uint32", "np.uint64", "np.float16", "np.float32", "np.float64" 

stmt1 = """ 
A = A * 255 
A = A/255 
A = A - 1 
A = A + 1 
""" 
#~ np.uint8 : 1.04969205993 
#~ np.uint16 : 1.19391073202 
#~ np.uint32 : 1.37279821351 
#~ np.uint64 : 2.99286961148 
#~ np.float16 : 9.62375889588 
#~ np.float32 : 0.884994368045 
#~ np.float64 : 0.920502625252 

stmt2 = """ 
A *= 255 
A /= 255 
A -= 1 
A += 1 
""" 
#~ np.uint8 : 0.959514497259 
#~ np.uint16 : 0.988570167659 
#~ np.uint32 : 0.963571471946 
#~ np.uint64 : 2.07768933333 
#~ np.float16 : 9.40085450056 
#~ np.float32 : 0.882363984225 
#~ np.float64 : 0.910147440048 

stmt3 = """ 
A = A * 255/255 - 1 + 1 
""" 
#~ np.uint8 : 1.05919667881 
#~ np.uint16 : 1.20249978404 
#~ np.uint32 : 1.58037744789 
#~ np.uint64 : 3.47520357571 
#~ np.float16 : 10.4792515701 
#~ np.float32 : 1.29654744484 
#~ np.float64 : 1.80735079168 

stmt4 = """ 
A[:,:,:2] *= A[:,:,:2] 
""" 
#~ np.uint8 : 1.23270964172 
#~ np.uint16 : 1.3260807837 
#~ np.uint32 : 1.32571002402 
#~ np.uint64 : 1.76836543305 
#~ np.float16 : 2.83364821535 
#~ np.float32 : 1.31282323872 
#~ np.float64 : 1.44151875479 

stmt5 = """ 
A[:,:,:2] = A[:,:,:2] * A[:,:,:2] 
""" 
#~ np.uint8 : 1.38166223494 
#~ np.uint16 : 1.49569114821 
#~ np.uint32 : 1.53105315419 
#~ np.uint64 : 2.03457943366 
#~ np.float16 : 3.01117795524 
#~ np.float32 : 1.51807271679 
#~ np.float64 : 1.7164808877 

stmt6 = """ 
A *= 4 
A /= 4 
""" 
#~ np.uint8 : 0.698176392658 
#~ np.uint16 : 0.709560468038 
#~ np.uint32 : 0.701653066443 
#~ np.uint64 : 1.64199069295 
#~ np.float16 : 4.86752675499 
#~ np.float32 : 0.421001675475 
#~ np.float64 : 0.433056710408 

stmt7 = """ 
np.left_shift(A, 2, A) 
np.right_shift(A, 2, A) 
""" 
#~ np.uint8 : 0.381521115341 
#~ np.uint16 : 0.383545967785 
#~ np.uint32 : 0.386147272415 
#~ np.uint64 : 0.665969478824 


for stmt in [stmt1, stmt2, stmt3, stmt4, stmt5, stmt6, stmt7]: 
    print stmt 
    for d in datatypes: 
     s = setup.replace("datatype", d) 
     T = timeit.Timer(stmt=stmt, setup=s) 
     print d,":", min(T.repeat(number=30)) 
    print 
print 

がなぜそんなに遅いfloat16されますか? なぜfloat32はとても速いのですか?整数演算よりも高速なことが多い。

関連するパフォーマンスに関するヒントがある場合は、聞いてうれしいです。

これは、Windows 8 64bit上のPython 2.6.6 32bitです。 Numpy 1.6、Numpy 1.7の数字も同様です。今MKL最適化されたバージョンをテストします:http://www.lfd.uci.edu/~gohlke/pythonlibs/#numpy

編集:いくつかの浮動小数点の場合、わずかに速いですMKLのバージョンが判明が、整数OPSのため、時には多くが遅く:

stmt2 = """ 
A *= 255 
A /= 255 
A -= 1 
A += 1 
""" 
#np1.6 
#~ np.uint8 : 0.959514497259 
#~ np.uint16 : 0.988570167659 
#~ np.uint32 : 0.963571471946 
#~ np.uint64 : 2.07768933333 
#~ np.float16 : 9.40085450056 
#~ np.float32 : 0.882363984225 
#~ np.float64 : 0.910147440048 

# np1.7 
#~ np.uint8 : 0.979 
#~ np.uint16 : 1.010 
#~ np.uint32 : 0.972 
#~ np.uint64 : 2.081 
#~ np.float16 : 9.362 
#~ np.float32 : 0.882 
#~ np.float64 : 0.918 

# np1.7 mkl 
#~ np.uint8 : 1.782 
#~ np.uint16 : 1.145 
#~ np.uint32 : 1.265 
#~ np.uint64 : 2.088 
#~ np.float16 : 9.029 
#~ np.float32 : 0.800 
#~ np.float64 : 0.866 
+1

https://en.wikipedia.org/wiki/Half-precision_floating-point_format "これは、記憶用であり、算術演算を実行するためのものではありません。" – endolith

答えて

17

ハーフ精度演算(float16)ものですがこれは基本的なC言語(および適切なプロセッサー命令)に対応する型がないので、numpyによって「エミュレート」されなければなりません。一方、ネイティブデータ型を使用すると、単精度(float32)および倍精度(float64)操作を非常に効率的に行うことができます。

単精度演算の優れた性能として、現代のプロセッサは、良好なマルチメディア性能のためにも必要とされるベクトル化された浮動小数点演算(AVXなど)のための効率的なユニットを有する。

8

16ビットの浮動小数点数は、ほとんどの一般的なCPUでは直接サポートされていません(ただし、グラフィックスカードのベンダーは明らかにこのデータタイプに関与しているため、GPUは最終的にサポートします)。私はそれらが比較的遅い方法でエミュレートされることを期待しています。 Googleはfloat16 was once hardware-dependentと言いますが、実際に起こったかどうかはわかりませんでしたが、サポートしていないハードウェアのためにエミュレートしたい人もいました。

32ビット浮動小数点はネイティブでサポートされているだけでなく、SIMD命令セット拡張を使用して多数の演算をベクトル化することもでき、ベンチマーク操作のオーバーヘッドを大幅に削減します。例外はデータをシャッフルしていますが、その場合float32はint32と同レベルであり、両方とも同じSIMD命令を使用してより大きなメモリブロックをロードして格納できます。

整数演算のSIMD命令もありますが、あまり一般的ではありません(たとえば、浮動小数点バージョンより後のバージョンでSEEが導入されました)。私の推測では、(あなたのビルド)NumPyはあなたのためのより遅い操作のSIMD実装を持っていません。あるいは、浮動小数点演算は、性能が重要な多くのベクトル化が容易なアプリケーション(例えば、画像/メディア/ビデオエンコードおよびデコード)で使用されるので、最適化される可能性があります。

関連する問題