2017-12-23 20 views
2

cs231n assignment1のベクトル化されたsvm勾配を実装するときにこの問題が発生します。ここ は一例です:numpy配列の複数の行を変更するためのベクトル化された方法(行を繰り返すことができます)

ary = np.array([[1,-9,0], 
       [1,2,3], 
       [0,0,0]]) 
ary[[0,1]] += np.ones((2,2),dtype='int') 

、それは出力:

ary[[0,1,1]] += np.ones((3,3),dtype='int') 

それは、エラーをスローしなかったが:行が一意でなくなるまで

array([[ 2, -8, 1], 
     [ 2, 3, 4], 
     [ 0, 0, 0]]) 

すべてがうまくあります出力は本当に奇妙でした:

array([[ 2, -8, 1], 
     [ 2, 3, 4], 
     [ 0, 0, 0]]) 

及びIは、第二行はなければならない私はこの問題を解決するために使用される[3,4,5]よりもむしろ[2,3,4]、 素朴な方法は、このようなループに使用している期待:

ary = np.array([[ 2, -8, 1], 
       [ 2, 3, 4], 
       [ 0, 0, 0]]) 
# the rows I want to change 
rows = [0,1,2,1,0,1] 
# the change matrix 
change = np.random.randn((6,3)) 
for i,row in enumerate(rows): 
    ary[row] += change[i] 

私は本当にこのループをベクトル化する方法を知らないので、NumPyでこれを行うより良い方法はありますか? 、なぜこれが

ary[rows] += change 

を?:ように、それは私がそうしたい理由を誰もが好奇心旺盛である場合は、ここでsvm_loss_vectorized機能の私の実装がある何かをする間違っている、私はラベルに基づいて重みの勾配を計算する必要がありますY:使用

def svm_loss_vectorized(W, X, y, reg): 
    """ 
    Structured SVM loss function, vectorized implementation. 

    Inputs and outputs are the same as svm_loss_naive. 
    """ 
    loss = 0.0 
    dW = np.zeros(W.shape) # initialize the gradient as zero 

    # transpose X and W 
    # D means input dimensions, N means number of train example 
    # C means number of classes 
    # X.shape will be (D,N) 
    # W.shape will be (C,D) 
    X = X.T 
    W = W.T 
    dW = dW.T 
    num_train = X.shape[1] 
    # transpose W_y shape to (D,N) 
    W_y = W[y].T 
    S_y = np.sum(W_y*X ,axis=0) 
    margins = np.dot(W,X) + 1 - S_y 
    mask = np.array(margins>0) 

    # get the impact of num_train examples made on W's gradient 
    # that is,only when the mask is positive 
    # the train example has impact on W's gradient 
    dW_j = np.dot(mask, X.T) 
    dW += dW_j 
    mul_mask = np.sum(mask, axis=0, keepdims=True).T 

    # dW[y] -= mul_mask * X.T 
    dW_y = mul_mask * X.T 
    for i,label in enumerate(y): 
     dW[label] -= dW_y[i] 

    loss = np.sum(margins*mask) - num_train 
    loss /= num_train 
    dW /= num_train 
    # add regularization term 
    loss += reg * np.sum(W*W) 
    dW += reg * 2 * W 
    dW = dW.T 

    return loss, dW 

答えて

3

内蔵np.add.at

ビルトインは、このようなタスク、I、Eのnp.add.atです。私たちは最もパフォーマンスの1ではないかもしれません2D配列、作業しているので、

np.add.at(ary, rows, change) 

しかし、。結局のところ、我々は同様に、このような場合のために非常に効率的なmatrix-multplicationを活用し、合計のために繰り返される行の十分な数を与えることができ、高速matrix-multiplication

を活用

は、本当に良いかもしれません。ここでは、我々はそれを使用する方法です -

In [681]: ary = np.random.rand(1000,1000) 

In [682]: rows = np.random.randint(0,len(ary),(10000)) 

In [683]: change = np.random.rand(10000,1000) 

In [684]: %timeit np.add.at(ary, rows, change) 
1 loop, best of 3: 604 ms per loop 

In [687]: def matmul_addat(ary, row, change): 
    ...:  mask = rows == np.arange(len(ary))[:,None] 
    ...:  ary += mask.dot(change) 

In [688]: %timeit matmul_addat(ary, rows, change) 
10 loops, best of 3: 158 ms per loop 
+0

新機能add.atある - matrix-multiplicationに対する

mask = rows == np.arange(len(ary))[:,None] ary += mask.dot(change) 

ベンチマーク

レッツ・時間np.add.at方法は大きな配列のための1つをベースと?私は今日それを2回見ました – Dark

+1

@ダーク年齢はここにあります。しかし、ちょうど今日、かなり役に立ちます:) – Divakar

+1

@Divakar、ええ、 'ufunc.at()'を思い出してくれてありがとう! – MaxU

関連する問題