次のテンソル実行があります。
np.einsum('k,pjqk,yzjqk,yzk,ipqt->it', A, B, C, D, E)
そして、'z' または 'q' の次元が拡張されると、実行時間が非常に長くなることに気付きました。私の直感では、おそらくそれほど悪くはないはずでした。手動のテンソル収縮によって最適化できたのは私の入力フォームだったのかもしれません。
少し掘り下げた後、最適化には「最適」と「貪欲」の2つのモードがあることがわかりました。両方のモードに対してパスを評価した場合、それぞれ次のようになります。
(['einsum_path', (0, 3), (1, 3), (0, 2), (0, 1)],
' Complete contraction: k,pjqk,yzjqk,yzk,ipqt->it\n'
' Naive scaling: 8\n'
' Optimized scaling: 5\n'
' Naive FLOP count: 5.530e+04\n'
' Optimized FLOP count: 7.930e+02\n'
' Theoretical speedup: 69.730\n'
' Largest intermediate: 2.400e+01 elements\n'
'--------------------------------------------------------------------------\n'
'scaling current remaining\n'
'--------------------------------------------------------------------------\n'
' 3 yzk,k->yzk pjqk,yzjqk,ipqt,yzk->it\n'
' 5 yzk,yzjqk->jqk pjqk,ipqt,jqk->it\n'
' 4 jqk,pjqk->qp ipqt,qp->it\n'
' 4 qp,ipqt->it it->it')
と
(['einsum_path', (2, 3), (1, 3), (1, 2), (0, 1)],
' Complete contraction: k,pjqk,yzjqk,yzk,ipqt->it\n'
' Naive scaling: 8\n'
' Optimized scaling: 5\n'
' Naive FLOP count: 5.530e+04\n'
' Optimized FLOP count: 1.729e+03\n'
' Theoretical speedup: 31.981\n'
' Largest intermediate: 4.800e+01 elements\n'
'--------------------------------------------------------------------------\n'
'scaling current remaining\n'
'--------------------------------------------------------------------------\n'
' 5 yzk,yzjqk->jqk k,pjqk,ipqt,jqk->it\n'
' 4 jqk,pjqk->qkp k,ipqt,qkp->it\n'
' 5 qkp,ipqt->tik k,tik->it\n'
' 3 tik,k->it it->it')
テストした結果は、示されているように、「最適」の方がはるかに高速であるということです。
質問
違いが何であり、「貪欲」がデフォルトに設定されている理由を簡単に説明できる人はいますか?
常に「最適」を使用することの欠点は何ですか?
私の einsum 計算が何千回も実行される場合 (これは最適化の反復の一部として実行されます)、実行を再構築して、再計算する必要なく (または「貪欲な」パス)毎回?