NumPy'nin einsumunu anlama


190

Tam olarak nasıl einsumçalıştığını anlamak için uğraşıyorum . Belgelere ve birkaç örneğe baktım, ama öyle görünmüyor.

İşte sınıfta geçirdiğimiz bir örnek:

C = np.einsum("ij,jk->ki", A, B)

iki dizi için AveB

Sanırım bu sürecek A^T * B, ama emin değilim (bunlardan birinin devri doğru mu?). Biri bana tam olarak burada olanlardan (ve genel olarak kullanırken einsum) geçebilir mi?


7
Aslında öyle (A * B)^Tya da eşdeğer olacak B^T * A^T.
Tigran Saluev

23
einsum Burada temel bilgiler hakkında kısa bir blog yazısı yazdım . (En alakalı bitleri Yığın Taşması ile ilgili bir cevaba nakletmekten mutluyum).
Alex Riley

1
@ajcr - Güzel bağlantı. Teşekkürler. numpyAyrıntıları anlatırken dokümantasyon son derece yetersizdir.
rayryeng

Güven oyu için teşekkürler! Geç kaldım, aşağıda bir cevap yazdım .
Alex Riley

Python'da *bunun matris çarpımı değil, elementwise çarpımı olduğunu unutmayın. Dikkat et!
ComputerScientist

Yanıtlar:


371

(Not: Bu cevabı kısa dayanmaktadır blog post hakkında einsumbir süre önce yazmıştım.)

Ne yapar einsum?

İki çok boyutlu dizimiz olduğunu hayal edin Ave B. Şimdi varsayalım ki ...

  • çok-katlı A olan Bürünlerin yeni bir dizi oluşturmak için belirli bir şekilde; ve sonra belki
  • bu yeni diziyi belirli eksenler boyunca toplamak ; ve sonra belki
  • devrik belli bir düzen içinde yeni bir dizi eksenlerini.

einsumNumPy kombinasyonlarının izin vereceği ve izin vereceği multiply, bunu daha hızlı ve daha verimli bir şekilde yapmamıza yardımcı olacak iyi bir şans var .sumtranspose

Nasıl einsumçalışır?

İşte basit (ama tamamen önemsiz değil) bir örnek. Aşağıdaki iki diziyi alın:

A = np.array([0, 1, 2])

B = np.array([[ 0,  1,  2,  3],
              [ 4,  5,  6,  7],
              [ 8,  9, 10, 11]])

Çoğalır Ave Belement-wise oluruz ve sonra yeni dizinin satırları boyunca toplarız. "Normal" NumPy'de şunu yazardık:

>>> (A[:, np.newaxis] * B).sum(axis=1)
array([ 0, 22, 76])

Böylece, burada dizinleme işlemi Aiki dizinin ilk eksenlerini sıralar, böylece çarpma yayınlanabilir. Ardından ürün dizisinin satırları cevabı döndürmek için toplanır.

Şimdi einsumbunun yerine kullanmak istersek şunu yazabiliriz:

>>> np.einsum('i,ij->i', A, B)
array([ 0, 22, 76])

İmza dize 'i,ij->i'burada anahtar ve açıklayan biraz ihtiyacı var. Bunu iki yarıda düşünebilirsiniz. Sol tarafta (solunda ->) iki giriş dizisini etiketledik. Sağında ->, biz ile bitirmek istiyorum diziyi etiketli oldum.

Sırada ne var:

  • Abir ekseni vardır; etiketledik i. Ve Biki ekseni vardır; eksen 0 olarak ive eksen 1 olarak etiketledik j.

  • By tekrarlayarak etiketi ihem girdi dizilerde, biz söylüyoruz einsumBu iki eksenin gerektiğini çarpılır birlikte. Diğer bir deyişle, Adiziyi Btıpkı olduğu gibi dizinin her sütunu ile çarpıyoruz A[:, np.newaxis] * B.

  • jİstediğimiz çıktıda etiket olarak görünmediğine dikkat edin; Az önce kullandık i(1D dizisiyle sonuçlanmak istiyoruz). By ihmal etiketi, biz söylüyoruz einsumiçin özetlemek bu eksende. Başka bir deyişle, ürünlerin satırlarını, tıpkı yaptığımız gibi .sum(axis=1)topluyoruz.

Temel olarak kullanmak için bilmeniz gereken her şey budur einsum. Biraz oynamaya yardımcı olur; her iki etiketi de çıktıda bırakırsak 'i,ij->ij', 2D bir ürün dizisini geri alırız (aynı A[:, np.newaxis] * B). Çıktı etiketi yoksa, 'i,ij->tek bir sayı geri alırız (yapmakla aynı (A[:, np.newaxis] * B).sum()).

einsumBununla ilgili en iyi şey , öncelikle geçici bir ürün dizisi oluşturmamasıdır; sadece ürünleri olduğu gibi toplar. Bu, bellek kullanımında büyük tasarruflara neden olabilir.

Biraz daha büyük bir örnek

Nokta ürününü açıklamak için iki yeni dizi var:

A = array([[1, 1, 1],
           [2, 2, 2],
           [5, 5, 5]])

B = array([[0, 1, 0],
           [1, 1, 0],
           [1, 1, 1]])

Nokta ürününü kullanarak hesaplayacağız np.einsum('ij,jk->ik', A, B). İşte işaretlenmesini gösteren bir resim Ave Bbiz işlevinden almak çıkış dizisi:

resim açıklamasını buraya girin

O etiket görebilirsiniz jbu araçlar biz sıraları çarparak ediyoruz - tekrarlanır Asütunları ile B. Dahası, etiket jçıktıya dahil edilmiyor - bu ürünleri topluyoruz. Etiketler ive kçıkış için tutulur, böylece bir 2D dizi geri alırız.

Etiket dizisi ile bu sonucu karşılaştırmak daha net olabilir jedilir değil özetlenebilir. Aşağıda, solda, yazmanın sonucu olan 3D dizisini görebilirsiniz np.einsum('ij,jk->ijk', A, B)(yani etiketi sakladık j):

resim açıklamasını buraya girin

Toplama ekseni j, sağda gösterilen beklenen nokta ürününü verir.

Bazı alıştırmalar

Daha iyi hissetmek için einsum, alt simge gösterimini kullanarak tanıdık NumPy dizi işlemlerini uygulamak yararlı olabilir. Eksenleri çarpma ve toplama kombinasyonlarını içeren her şey kullanılarak yazılabilir einsum.

A ve B aynı uzunlukta iki 1D dizisi olsun. Örneğin, A = np.arange(10)ve B = np.arange(5, 15).

  • Toplamı Ayazılabilir:

    np.einsum('i->', A)
  • Eleman-bilge çarpma,, A * Byazılabilir:

    np.einsum('i,i->i', A, B)
  • İç ürün veya nokta ürün np.inner(A, B)veya np.dot(A, B)yazılabilir:

    np.einsum('i,i->', A, B) # or just use 'i,i'
  • Dış ürün, np.outer(A, B)yazılabilir:

    np.einsum('i,j->ij', A, B)

2D diziler için, Cve Deksen uyumlu uzunlukları (aynı uzunlukta veya bunlardan birinin uzunluğu 1 olan her ikisi için), burada birkaç örnek olması koşuluyla,:

  • İzi C(ana köşegen toplamı),, np.trace(C)yazılabilir:

    np.einsum('ii', C)
  • Eleman-bilge çoğalması Cve devrik D, C * D.T, yazılabilir:

    np.einsum('ij,ji->ij', C, D)
  • Her öğenin Cdiziye çarpılması D(4D dizisi yapmak için), C[:, :, None, None] * Dyazılabilir:

    np.einsum('ij,kl->ijkl', C, D)  

1
Çok güzel bir açıklama, teşekkürler. "İstediğimiz çıktıda etiket olarak görünmediğime dikkat edin" - değil mi?
Ian Hincks

Teşekkürler @IanHincks! Bir yazım hatası gibi görünüyor; Şimdi düzelttim.
Alex Riley

1
Çok iyi bir cevap. ij,jkMatris çarpımını oluşturmak için kendi başına (oklar olmadan) çalışabileceğini de belirtmek gerekir . Ancak netlik için, okları ve ardından çıktı boyutlarını koymak en iyisidir. Blog gönderisinde.
ComputerScientist

1
@ Barışçıl: Bu doğru kelimeyi seçmenin zor olduğu durumlardan biri! Ben "sütun" biraz daha iyi uyuyor hissediyorum çünkü Auzunluğu 3, sütunların uzunluğu ile aynı B(oysa satırları Buzunluğu 4 ve element-bilge ile çarpılamaz A).
Alex Riley

1
Not ihmal olduğunu ->semantiğini etkiler: "çıktı eksenleri alfabetik yeniden sıralanır beri örtük modunda, seçilen alt simgeler önemlidir Bu araçlar. np.einsum('ij', a)2D dizi etkilemez iken np.einsum('ji', a)onun devrik alır."
BallpointBen

40

numpy.einsum()Sezgisel olarak anlarsanız fikrini kavramak çok kolaydır. Örnek olarak, matris çarpımını içeren basit bir tanımla başlayalım .


Kullanmak için numpy.einsum()yapmanız gereken tek şey sözde abonelik dizesini argüman olarak, ardından da girdi dizilerinizi iletmektir .

Diyelim ki iki 2D diziler var, diyelim Ave Bve matris çarpma yapmak istiyorum. Yani, şunları yaparsınız:

np.einsum("ij, jk -> ik", A, B)

Burada alt simge dizisi ij diziye karşılık Agelirken, alt simge dizisi jk diziye karşılık gelir B. Ayrıca, burada dikkat edilmesi gereken en önemli şey , her bir alt simge dizesindeki karakter sayısının dizinin boyutlarıyla eşleşmesi gerektiğidir . (2B diziler için iki karakter, 3B diziler için üç karakter vb.) Ve alt simge dizeleri arasındaki karakterleri ( bizim durumumuzda) tekrarlarsanız , toplamın bu boyutlar boyunca olmasını istediğiniz anlamına gelir . Böylece, toplamlar azaltılacaktır. (yani bu boyut kaybolacaktır ) jein

Alt simge dize bundan sonra ->, bizim elde edilen dizi olacak. Boş bırakırsanız, her şey toplanır ve sonuç olarak bir skaler değer döndürülür. Aksi takdirde sonuç dizisinin alt simge dizesine göre boyutları olacaktır . Örneğimizde olacak ik. Biz matris çoğalması için dizideki sütun sayısı biliyoruz çünkü bu sezgisel Adizideki satır sayısını eşleşmesi gerekir Bburada neler olduğunu ise (kömürü tekrarlayarak bu bilgiyi kodlamak yani jiçinde alt simge dize )


Aşağıda, bazı np.einsum()yaygın tensör veya nd-dizi işlemlerinin uygulanmasının kullanımını / gücünü gösteren bazı örnekler verilmiştir .

Girdiler

# a vector
In [197]: vec
Out[197]: array([0, 1, 2, 3])

# an array
In [198]: A
Out[198]: 
array([[11, 12, 13, 14],
       [21, 22, 23, 24],
       [31, 32, 33, 34],
       [41, 42, 43, 44]])

# another array
In [199]: B
Out[199]: 
array([[1, 1, 1, 1],
       [2, 2, 2, 2],
       [3, 3, 3, 3],
       [4, 4, 4, 4]])

1) Matris çarpımı (benzeri np.matmul(arr1, arr2))

In [200]: np.einsum("ij, jk -> ik", A, B)
Out[200]: 
array([[130, 130, 130, 130],
       [230, 230, 230, 230],
       [330, 330, 330, 330],
       [430, 430, 430, 430]])

2) Ana diyagonal boyunca elemanları çıkarın (benzer np.diag(arr))

In [202]: np.einsum("ii -> i", A)
Out[202]: array([11, 22, 33, 44])

3) Hadamard ürünü (yani iki dizinin eleman-bazlı ürünü) (benzer arr1 * arr2)

In [203]: np.einsum("ij, ij -> ij", A, B)
Out[203]: 
array([[ 11,  12,  13,  14],
       [ 42,  44,  46,  48],
       [ 93,  96,  99, 102],
       [164, 168, 172, 176]])

4) Eleman-bazlı kareleme ( np.square(arr)veya benzeri arr ** 2)

In [210]: np.einsum("ij, ij -> ij", B, B)
Out[210]: 
array([[ 1,  1,  1,  1],
       [ 4,  4,  4,  4],
       [ 9,  9,  9,  9],
       [16, 16, 16, 16]])

5) İz (yani ana diyagonal elemanların toplamı) (benzer np.trace(arr))

In [217]: np.einsum("ii -> ", A)
Out[217]: 110

6) Matris devri (benzeri np.transpose(arr))

In [221]: np.einsum("ij -> ji", A)
Out[221]: 
array([[11, 21, 31, 41],
       [12, 22, 32, 42],
       [13, 23, 33, 43],
       [14, 24, 34, 44]])

7) Dış Ürün (vektörlerin) (benzeri np.outer(vec1, vec2))

In [255]: np.einsum("i, j -> ij", vec, vec)
Out[255]: 
array([[0, 0, 0, 0],
       [0, 1, 2, 3],
       [0, 2, 4, 6],
       [0, 3, 6, 9]])

8) İç Ürün (vektörlerin) (benzeri np.inner(vec1, vec2))

In [256]: np.einsum("i, i -> ", vec, vec)
Out[256]: 14

9) Eksen 0 boyunca toplam (benzer np.sum(arr, axis=0))

In [260]: np.einsum("ij -> j", B)
Out[260]: array([10, 10, 10, 10])

10) Eksen 1 boyunca toplam (benzer np.sum(arr, axis=1))

In [261]: np.einsum("ij -> i", B)
Out[261]: array([ 4,  8, 12, 16])

11) Parti Matrisi Çarpımı

In [287]: BM = np.stack((A, B), axis=0)

In [288]: BM
Out[288]: 
array([[[11, 12, 13, 14],
        [21, 22, 23, 24],
        [31, 32, 33, 34],
        [41, 42, 43, 44]],

       [[ 1,  1,  1,  1],
        [ 2,  2,  2,  2],
        [ 3,  3,  3,  3],
        [ 4,  4,  4,  4]]])

In [289]: BM.shape
Out[289]: (2, 4, 4)

# batch matrix multiply using einsum
In [292]: BMM = np.einsum("bij, bjk -> bik", BM, BM)

In [293]: BMM
Out[293]: 
array([[[1350, 1400, 1450, 1500],
        [2390, 2480, 2570, 2660],
        [3430, 3560, 3690, 3820],
        [4470, 4640, 4810, 4980]],

       [[  10,   10,   10,   10],
        [  20,   20,   20,   20],
        [  30,   30,   30,   30],
        [  40,   40,   40,   40]]])

In [294]: BMM.shape
Out[294]: (2, 4, 4)

12) Eksen 2 boyunca toplam (benzer np.sum(arr, axis=2))

In [330]: np.einsum("ijk -> ij", BM)
Out[330]: 
array([[ 50,  90, 130, 170],
       [  4,   8,  12,  16]])

13) Dizideki tüm elemanları toplar (şuna benzer np.sum(arr))

In [335]: np.einsum("ijk -> ", BM)
Out[335]: 480

14) Birden fazla eksen üzerinde toplam (marjinalleştirme)
(benzer np.sum(arr, axis=(axis0, axis1, axis2, axis3, axis4, axis6, axis7)))

# 8D array
In [354]: R = np.random.standard_normal((3,5,4,6,8,2,7,9))

# marginalize out axis 5 (i.e. "n" here)
In [363]: esum = np.einsum("ijklmnop -> n", R)

# marginalize out axis 5 (i.e. sum over rest of the axes)
In [364]: nsum = np.sum(R, axis=(0,1,2,3,4,6,7))

In [365]: np.allclose(esum, nsum)
Out[365]: True

15) Çift Nokta Ürünleri ( np.sum (hadamard-ürünü) benzeri krş 3 )

In [772]: A
Out[772]: 
array([[1, 2, 3],
       [4, 2, 2],
       [2, 3, 4]])

In [773]: B
Out[773]: 
array([[1, 4, 7],
       [2, 5, 8],
       [3, 6, 9]])

In [774]: np.einsum("ij, ij -> ", A, B)
Out[774]: 124

16) 2D ve 3D dizi çarpımı

Böyle bir çarpma sonucu doğrulamak istediğiniz doğrusal denklem sistemini ( Ax = b ) çözerken çok yararlı olabilir .

# inputs
In [115]: A = np.random.rand(3,3)
In [116]: b = np.random.rand(3, 4, 5)

# solve for x
In [117]: x = np.linalg.solve(A, b.reshape(b.shape[0], -1)).reshape(b.shape)

# 2D and 3D array multiplication :)
In [118]: Ax = np.einsum('ij, jkl', A, x)

# indeed the same!
In [119]: np.allclose(Ax, b)
Out[119]: True

Aksine, eğer np.matmul()bu doğrulama için kullanmak gerekiyorsa reshape, aynı sonucu elde etmek için birkaç işlem yapmalıyız :

# reshape 3D array `x` to 2D, perform matmul
# then reshape the resultant array to 3D
In [123]: Ax_matmul = np.matmul(A, x.reshape(x.shape[0], -1)).reshape(x.shape)

# indeed correct!
In [124]: np.allclose(Ax, Ax_matmul)
Out[124]: True

Bonus : Daha fazla matematik burada okuyun: Einstein-Summation ve kesinlikle burada: Tensor-Notasyonu


7

Etkileşimlerini vurgulamak için farklı ancak uyumlu boyutlara sahip 2 dizi yapalım

In [43]: A=np.arange(6).reshape(2,3)
Out[43]: 
array([[0, 1, 2],
       [3, 4, 5]])


In [44]: B=np.arange(12).reshape(3,4)
Out[44]: 
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

Hesaplamanız, (4,2) dizi oluşturmak için (3,4) ile (2,3) 'nokta' (ürün toplamı) alır. i1'inci loş A, sonuncusu C; ksonuncusu B, 1 C. jtoplam tarafından 'tüketilir'.

In [45]: C=np.einsum('ij,jk->ki',A,B)
Out[45]: 
array([[20, 56],
       [23, 68],
       [26, 80],
       [29, 92]])

Bu aynıdır np.dot(A,B).T- aktarılan son çıktıdır.

Ne olduğu hakkında daha fazla bilgi edinmek jiçin Cabonelikleri şu şekilde değiştirin ijk:

In [46]: np.einsum('ij,jk->ijk',A,B)
Out[46]: 
array([[[ 0,  0,  0,  0],
        [ 4,  5,  6,  7],
        [16, 18, 20, 22]],

       [[ 0,  3,  6,  9],
        [16, 20, 24, 28],
        [40, 45, 50, 55]]])

Bu ayrıca aşağıdakilerle de üretilebilir:

A[:,:,None]*B[None,:,:]

Yani, (2,3,4) dizisinin sonucunu kverecek şekilde sonuna Ave iönüne bir boyut ekleyin B.

0 + 4 + 16 = 20,, 9 + 28 + 55 = 92vb; Üzerinde Sum jve devrik erken sonuç almak için:

np.sum(A[:,:,None] * B[None,:,:], axis=1).T

# C[k,i] = sum(j) A[i,j (,k) ] * B[(i,)  j,k]

7

NumPy: Ticaretin püf noktalarını (Bölüm II) öğretici buldum

Çıkış dizisinin sırasını belirtmek için -> kullanıyoruz. Bu yüzden 'ij, i-> j' yi sol taraf (LHS) ve sağ taraf (RHS) olarak düşünün. LHS üzerindeki herhangi bir etiket tekrarı, ürün öğesini akıllıca hesaplar ve ardından toplar. RHS (çıkış) tarafındaki etiketi değiştirerek, girdi dizisine göre ilerlemek istediğimiz ekseni, yani 0, 1 ekseni boyunca toplamı tanımlayabiliriz.

import numpy as np

>>> a
array([[1, 1, 1],
       [2, 2, 2],
       [3, 3, 3]])
>>> b
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])
>>> d = np.einsum('ij, jk->ki', a, b)

Üç eksen olduğuna dikkat edin, i, j, k ve j tekrarlanır (sol tarafta). i,jiçin satır ve sütunları temsil eder a. j,kiçin b.

Ürünü hesaplamak ve jekseni hizalamak için bir eksen eklememiz gerekir a. ( bbirinci eksen (?) boyunca yayınlanacaktır)

a[i, j, k]
   b[j, k]

>>> c = a[:,:,np.newaxis] * b
>>> c
array([[[ 0,  1,  2],
        [ 3,  4,  5],
        [ 6,  7,  8]],

       [[ 0,  2,  4],
        [ 6,  8, 10],
        [12, 14, 16]],

       [[ 0,  3,  6],
        [ 9, 12, 15],
        [18, 21, 24]]])

jsağ tarafta bulunmadığından j, 3x3x3 dizisinin ikinci ekseni üzerinden

>>> c = c.sum(1)
>>> c
array([[ 9, 12, 15],
       [18, 24, 30],
       [27, 36, 45]])

Son olarak, endeksler (alfabetik olarak) sağ tarafta tersine çevrilmiştir, bu yüzden biz devrediyoruz.

>>> c.T
array([[ 9, 18, 27],
       [12, 24, 36],
       [15, 30, 45]])

>>> np.einsum('ij, jk->ki', a, b)
array([[ 9, 18, 27],
       [12, 24, 36],
       [15, 30, 45]])
>>>

NumPy: Ticaretin püf noktaları (Bölüm II) , site sahibinin yanı sıra bir Wordpress hesabı için davet gerektiriyor gibi görünüyor
Tejas Shetty

... güncellenmiş bağlantı, neyse ki bir arama ile buldum. - Teşekkürler.
İkinci Dünya Savaşı

@TejasShetty Şimdi burada çok daha iyi cevaplar - belki de bunu silmeliyim.
İkinci Dünya Savaşı

2
Lütfen cevabınızı silmeyin.
Tejas Shetty

5

Einsum denklemlerini okurken, onları zihinsel olarak zorunlu sürümlerine kadar kaynatmanın en yararlı olduğunu buldum.

Aşağıdaki (heybetli) ifadeyle başlayalım:

C = np.einsum('bhwi,bhwj->bij', A, B)

Önce noktalama işaretleriyle çalışırken, virgülle ayrılmış iki adet 4 harfli bloğumuz olduğunu bhwive oktan bhwjönce ve 3 harfli tek bir blobumuz olduğunu görüyoruz bij. Bu nedenle, denklem iki sıra-4 tensör girişinden bir sıra-3 tensör sonucu üretir.

Şimdi, her blobdaki her harf bir aralık değişkeninin adı olsun. Mektubun blobda göründüğü konum, bu tensörde üzerinde bulunduğu eksenin dizinidir. Bu nedenle, C'nin her bir elemanını üreten zorunlu toplam, döngüler için iç içe üç, her C indeksi için bir tane ile başlamalıdır.

for b in range(...):
    for i in range(...):
        for j in range(...):
            # the variables b, i and j index C in the order of their appearance in the equation
            C[b, i, j] = ...

Yani, aslında, forC'nin her çıktı endeksi için bir döngünüz var. Aralıkları şimdilik belirsiz bırakacağız.

Herhangi aralık değişkenleri orada var - biz sol tarafında bakmak Sonraki yok görünen sağ tarafında? Bizim durumumuzda - evet hve w. Bu fortür her değişken için bir iç yuvalanmış döngü ekleyin :

for b in range(...):
    for i in range(...):
        for j in range(...):
            C[b, i, j] = 0
            for h in range(...):
                for w in range(...):
                    ...

En içteki döngüde artık tüm indeksler tanımlanmıştır, böylece gerçek toplamı yazabiliriz ve çeviri tamamlanır:

# three nested for-loops that index the elements of C
for b in range(...):
    for i in range(...):
        for j in range(...):

            # prepare to sum
            C[b, i, j] = 0

            # two nested for-loops for the two indexes that don't appear on the right-hand side
            for h in range(...):
                for w in range(...):
                    # Sum! Compare the statement below with the original einsum formula
                    # 'bhwi,bhwj->bij'

                    C[b, i, j] += A[b, h, w, i] * B[b, h, w, j]

Kodu şu ana kadar takip edebildiyseniz, tebrikler! Einsum denklemlerini okuyabilmek için tek ihtiyacınız olan bu. Özellikle orijinal einsum formülünün yukarıdaki snippet'teki son toplama deyimiyle nasıl eşleştiğine dikkat edin. Döngüler ve menzil sınırları sadece kabartır ve neler olduğunu anlamak için ihtiyacınız olan tek şey son ifadedir.

Tamlık uğruna, her aralık değişkeni için aralıkları nasıl belirleyeceğimizi görelim. Her değişkenin aralığı basitçe indekslediği boyut (lar) ın uzunluğudur. Bir değişken, bir veya daha fazla tensörde birden fazla boyutu endeksliyorsa, bu boyutların her birinin uzunluklarının eşit olması gerekir. Yukarıdaki kodların tamamını içeren kodu aşağıda bulabilirsiniz:

# C's shape is determined by the shapes of the inputs
# b indexes both A and B, so its range can come from either A.shape or B.shape
# i indexes only A, so its range can only come from A.shape, the same is true for j and B
assert A.shape[0] == B.shape[0]
assert A.shape[1] == B.shape[1]
assert A.shape[2] == B.shape[2]
C = np.zeros((A.shape[0], A.shape[3], B.shape[3]))
for b in range(A.shape[0]): # b indexes both A and B, or B.shape[0], which must be the same
    for i in range(A.shape[3]):
        for j in range(B.shape[3]):
            # h and w can come from either A or B
            for h in range(A.shape[1]):
                for w in range(A.shape[2]):
                    C[b, i, j] += A[b, h, w, i] * B[b, h, w, j]

0

Bence en basit örnek tensorflow dokümanlarında

Denkleminizi einsum notasyonuna dönüştürmek için dört adım vardır. Bu denklemi örnek olarak ele alalımC[i,k] = sum_j A[i,j] * B[j,k]

  1. Önce değişken isimlerini bırakıyoruz. Biz olsunik = sum_j ij * jk
  2. sum_jTerimi örtük olduğu gibi bırakıyoruz . Biz olsunik = ij * jk
  3. Biz yerini *ile ,. Biz olsunik = ij, jk
  4. Çıktı RHS üzerindedir ve ->işaretiyle ayrılmıştır . Biz olsunij, jk -> ik

Einsum yorumlayıcısı bu 4 adımı tersine çevirir. Sonuçta eksik olan tüm indeksler toplanır.

İşte dokümanlardan bazı örnekler

# Matrix multiplication
einsum('ij,jk->ik', m0, m1)  # output[i,k] = sum_j m0[i,j] * m1[j, k]

# Dot product
einsum('i,i->', u, v)  # output = sum_i u[i]*v[i]

# Outer product
einsum('i,j->ij', u, v)  # output[i,j] = u[i]*v[j]

# Transpose
einsum('ij->ji', m)  # output[j,i] = m[i,j]

# Trace
einsum('ii', m)  # output[j,i] = trace(m) = sum_i m[i, i]

# Batch matrix multiplication
einsum('aij,ajk->aik', s, t)  # out[a,i,k] = sum_j s[a,i,j] * t[a, j, k]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.