web-dev-qa-db-ja.com

numpy / scipyの二乗の差の合計(SSD)

PythonとNumpy/Scipyを使用して、画像処理アルゴリズムを実装しようとしています。プロファイラーは、次の関数(頻繁に呼び出される)に多くの時間が費やされていることを教えてくれます。 2つの画像間の二乗差の合計

def ssd(A,B):
    s = 0
    for i in range(3):
        s += sum(pow(A[:,:,i] - B[:,:,i],2))
    return s

どうすればこれをスピードアップできますか?ありがとう。

11
Internet man

ただ

_s = numpy.sum((A[:,:,0:3]-B[:,:,0:3])**2)
_

(形状が常に(、3)の場合、これはおそらくsum((A-B)**2)です)

合計メソッドを使用することもできます:_((A-B)**2).sum()_

正しい?

38
Andrew Jaffe

2つの否定的なマークを得たRitsaertHornstraの答えに加えて(確かに私はそれを元の形で見ていませんでした...)

これは実際には真実です。

反復回数が多い場合、「**」演算子またはpow(x、y)メソッドを使用する場合、ペアを手動で乗算する場合の2倍の時間がかかることがよくあります。必要に応じて、NaNを破棄する場合はmath.fabs()メソッドを使用します(これは、特にint16などを使用する場合に実行されることがあります)。それでも、指定された2つの関数の約半分の時間しかかかりません。

私が知っている元の質問にはそれほど重要ではありませんが、間違いなく知っておく価値があります。

1
Duncan Tait

パワー2のpow()関数が高速になるかどうかはわかりません。試してください:

def ssd(A,B):
    s = 0
    for i in  range(3):
        s += sum((A[:,:,i] - B[:,:,i])*A[:,:,i] - B[:,:,i])
    return s
1

なぜあなたがi in range(3)を取っているのか混乱しています。それはアレイ全体なのか、それとも一部なのか?

全体として、これのほとんどをnumpyで定義された操作に置き換えることができます。

def ssd(A,B):
    squares = (A[:,:,:3] - B[:,:,:3]) ** 2
    return numpy.sum(squares)

このようにして、3つではなく1つの操作を実行でき、numpy.sumを使用すると、組み込みのsumよりも追加を最適化できる場合があります。

1
Mike Graham

np.dot :を使用することもできます。

def ssd(A,B):
  dif = A.ravel() - B.ravel()
  return np.dot( dif, dif )

これは、np.sumおよび**2を使用する代替方法よりも少し高速で、おそらくより正確かもしれませんが、指定された軸に沿ってssdを計算する場合は機能しません。その場合、 np.einsum を使用した魔法の添え字式があるかもしれません。

1
Jonathan H

あなたはこれを試すことができます:

dist_sq = np.sum((A[:, np.newaxis, :] - B[np.newaxis, :, :]) ** 2, axis=-1)

詳細については、こちらをご覧ください(「k最近傍法」の例): https://jakevdp.github.io/PythonDataScienceHandbook/02.08-sorting.html

0
Xiaoyan Zhuo