SORU
10 ŞUBAT 2011, PERŞEMBE


NumPy ile hızlı tensör dönüş

Bir uygulama (Python ile yazılmış ve NumPy kullanarak) merkezinde 4. mertebe bir tensör döndürmek istiyorum. Aslında, tensör birçok kez döndürmek istiyorum ve bu benim performans sorunu var. Saf benim uygulama (aşağıda) sekiz iç içe döngüler içeren oldukça yavaş gibi görünüyor, ama kaldıraç NumPy matris işlemleri için bir çıkış yolu görüyor ve, umarım, işler daha hızlı olamaz. np.tensordot kullanarak olmam gerektiğini hissediyorum ama nasıl olacağını bilmiyorum.

Matematiksel olarak, bu unsurları tensör, T döndürülmüş', tarafından verilmiştir:'. T ^alt>ıjkl= Σ gıagjbgkcgldTatoplam sağ tarafta tekrarlanan endeksleri üzerinde olmak. T ve Tprime diziler ve dönme matrisi g 3*3 NumPy bir dizidir 3

Your original code: 19.471129179
Sven's code: 0.718412876129
My first code: 0.118047952652
My second code: 0.0690279006958
3*3 NumPy. Benim yavaş uygulama (çağrı başına ~0.04 saniye alıyordu altındadır.

#!/usr/bin/env python

import numpy as np

def rotT(T, g):
    Tprime = np.zeros((3,3,3,3))
    for i in range(3):
        for j in range(3):
            for k in range(3):
                for l in range(3):
                    for ii in range(3):
                        for jj in range(3):
                            for kk in range(3):
                                for ll in range(3):
                                    gg = g[ii,i]*g[jj,j]*g[kk,k]*g[ll,l]
                                    Tprime[i,j,k,l] = Tprime[i,j,k,l]   \
                                         gg*T[ii,jj,kk,ll]
    return Tprime

if __name__ == "__main__":

    T = np.array([[[[  4.66533067e 01,  5.84985000e-02, -5.37671310e-01],
                    [  5.84985000e-02,  1.56722231e 01,  2.32831900e-02],
                    [ -5.37671310e-01,  2.32831900e-02,  1.33399259e 01]],
                   [[  4.60051700e-02,  1.54658176e 01,  2.19568200e-02],
                    [  1.54658176e 01, -5.18223500e-02, -1.52814920e-01],
                    [  2.19568200e-02, -1.52814920e-01, -2.43874100e-02]],
                   [[ -5.35577630e-01,  1.95558600e-02,  1.31108757e 01],
                    [  1.95558600e-02, -1.51342210e-01, -6.67615000e-03],
                    [  1.31108757e 01, -6.67615000e-03,  6.90486240e-01]]],
                  [[[  4.60051700e-02,  1.54658176e 01,  2.19568200e-02],
                    [  1.54658176e 01, -5.18223500e-02, -1.52814920e-01],
                    [  2.19568200e-02, -1.52814920e-01, -2.43874100e-02]],
                   [[  1.57414726e 01, -3.86167500e-02, -1.55971950e-01],
                    [ -3.86167500e-02,  4.65601977e 01, -3.57741000e-02],
                    [ -1.55971950e-01, -3.57741000e-02,  1.34215636e 01]],
                   [[  2.58256300e-02, -1.49072770e-01, -7.38843000e-03],
                    [ -1.49072770e-01, -3.63410500e-02,  1.32039847e 01],
                    [ -7.38843000e-03,  1.32039847e 01,  1.38172700e-02]]],
                  [[[ -5.35577630e-01,  1.95558600e-02,  1.31108757e 01],
                    [  1.95558600e-02, -1.51342210e-01, -6.67615000e-03],
                    [  1.31108757e 01, -6.67615000e-03,  6.90486240e-01]],
                   [[  2.58256300e-02, -1.49072770e-01, -7.38843000e-03],
                    [ -1.49072770e-01, -3.63410500e-02,  1.32039847e 01],
                    [ -7.38843000e-03,  1.32039847e 01,  1.38172700e-02]],
                   [[  1.33639532e 01, -1.26331100e-02,  6.84650400e-01],
                    [ -1.26331100e-02,  1.34222177e 01,  1.67851800e-02],
                    [  6.84650400e-01,  1.67851800e-02,  4.89151396e 01]]]])

    g = np.array([[ 0.79389393,  0.54184237,  0.27593346],
                  [-0.59925749,  0.62028664,  0.50609776],
                  [ 0.10306737, -0.56714313,  0.8171449 ]])

    for i in range(100):
        Tprime = rotT(T,g)

Bir şekilde bunu daha hızlı gitmek yapmak için var mı? Kodu tensör diğer dereceler için genelleme yapmak yararlı olabilir, ama daha az önemli.

CEVAP
10 ŞUBAT 2011, PERŞEMBE


tensordot hesaplama g tansör dış ürünü kullanmak için:

def rotT(T, g):
    gg = np.outer(g, g)
    gggg = np.outer(gg, gg).reshape(4 * g.shape)
    axes = ((0, 2, 4, 6), (0, 1, 2, 3))
    return np.tensordot(gggg, T, axes)

Benim sistemde, bu Sven çözümü daha yaklaşık yedi kat daha hızlı. Eğer g tensör sık değişmiyorsa eğer değil, aynı zamanda gggg tensör önbelleğe alabilir. Bunu ve mikro-optimizasyon (tensordot bu kod, hiçbir kontrolleri, genel şekiller satır içi uygulaması) açın, hala iki kat daha hızlı yapabilirsiniz:

def rotT(T, gggg):
    return np.dot(gggg.transpose((1, 3, 5, 7, 0, 2, 4, 6)).reshape((81, 81)),
                  T.reshape(81, 1)).reshape((3, 3, 3, 3))

Ev benim laptop (500 yineleme) timeit sonuçları:

Your original code: 19.471129179
Sven's code: 0.718412876129
My first code: 0.118047952652
My second code: 0.0690279006958

Benim iş makine üzerindeki numaraları:

Your original code: 9.77922987938
Sven's code: 0.137110948563
My first code: 0.0569641590118
My second code: 0.0308079719543

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Matus Slovak

    Matus Slovak

    5 Temmuz 2007
  • Mega64

    Mega64

    24 ŞUBAT 2006
  • UKF Dubstep

    UKF Dubstep

    29 NİSAN 2009