1

コードを高速化するために、多次元 sumproduct 関数を Python から Theano に変換しています。私の Theano コードは同じ結果に達しますが、一度に 1 つの次元の結果しか計算しないため、Python の for ループを使用して最終結果を取得する必要があります。Theano は複数の関数呼び出し間で (gpu の) メモリ使用量と転送を最適化できないため、コードが遅くなると思います。それともこれは間違った仮定ですか?

では、sumprod が 1 回の関数呼び出しで計算されるように、Theano コードを変更するにはどうすればよいでしょうか?

元の Python 関数:

def sumprod(a1, a2):
    """Sum the element-wise products of the `a1` and `a2`."""
    result = numpy.zeros_like(a1[0])
    for i, j in zip(a1, a2):
        result += i*j
    return result

次の入力について

a1 = ([1, 2, 4], [5, 6, 7])
a2 = ([1, 2, 4], [5, 6, 7])

出力は次のようになります。[ 26. 40. 65.]つまり、1*1 + 5*5、2*2 + 6*6、および 4*4 + 7*7 です。

Theano バージョンのコード:

import theano
import theano.tensor as T
import numpy

a1 = ([1, 2, 4], [5, 6, 7])
a2 = ([1, 2, 4], [5, 6, 7])

# wanted result:  [ 26.  40.  65.]
# that is 1*1 + 5*5, 2*2 + 6*6 and 4*4 + 7*7

Tk = T.iscalar('Tk')
Ta1_shared = theano.shared(numpy.array(a1).T)
Ta2_shared = theano.shared(numpy.array(a2).T)

outputs_info = T.as_tensor_variable(numpy.asarray(0, 'float64'))

Tsumprod_result, updates = theano.scan(fn=lambda Ta1_shared, Ta2_shared, prior_value: 
                                       prior_value + Ta1_shared * Ta2_shared,
                                       outputs_info=outputs_info,
                                       sequences=[Ta1_shared[Tk], Ta2_shared[Tk]])
Tsumprod_result = Tsumprod_result[-1]

Tsumprod = theano.function([Tk], outputs=Tsumprod_result)

result = numpy.zeros_like(a1[0])
for i in range(len(a1[0])):
    result[i] = Tsumprod(i)
print result
4

1 に答える 1

7

まず、theano メーリング リストでは、stackoverflow よりも多くの人があなたの質問に答えてくれます。しかし、私はここにいます:)

まず、関数が GPU に適していません。すべてが十分に最適化されていたとしても、結果を加算して合計するためだけに入力を gpu に転送すると、Python バージョンよりも実行に時間がかかります。

あなたのpythonコードは遅いです。これはより高速なバージョンです:

def sumprod(a1, a2):
    """Sum the element-wise products of the `a1` and `a2`."""
    a1 = numpy.asarray(a1)
    a2 = numpy.asarray(a2)
    result (a1 * a2).sum(axis=0)
    return result

theano コードについては、このより高速な python バージョンと同等のものを次に示します (スキャンは不要です)。

m1 = theano.tensor.matrix()
m2 = theano.tensor.matrix()
f = theano.function([m1, m2], (m1 * m2).sum(axis=0))

ここから覚えておくべきことは、コードを「ベクトル化」する必要があるということです。「ベクトル化」は NumPy コンテキストで使用され、numpy.ndarray を使用し、一度に完全なテンソルで動作する関数を使用することを意味します。これは、ループ (python ループまたは theano スキャン) で実行するよりも常に高速です。また、Theano は、計算をスキャンの外に移動することでこれらのケースのいくつかを最適化しますが、常にそうするとは限りません。

于 2013-05-29T14:00:42.667 に答える