Kronecker-product
を実装している間教育的理由(明白ですぐに利用できるnp.kron()
を使用せずに)、私は中間結果として4次元配列を取得しました。最終結果を取得するために形状を変更する必要があります。
しかし、私はまだこれらの高次元配列の再形成に頭を包むことはできません。私はこの4D
配列を持っています:
array([[[[ 0, 0],
[ 0, 0]],
[[ 5, 10],
[15, 20]]],
[[[ 6, 12],
[18, 24]],
[[ 7, 14],
[21, 28]]]])
これは(2, 2, 2, 2)
の形状です。(4,4)
に再形成したいと思います。これは明らかなことだと思うかもしれません
np.reshape(my4darr, (4,4))
しかし、上記の変形は行いませんは期待される結果を与えます:
array([[ 0, 5, 0, 10],
[ 6, 7, 12, 14],
[ 0, 15, 0, 20],
[18, 21, 24, 28]])
ご覧のとおり、期待される結果のすべての要素が4D
配列に存在しています。 reshapeを必要に応じて正しく行うことのコツがわからないだけです。答えに加えて、そのような高次元の配列に対してreshape
を実行する方法のいくつかの説明は、本当に役に立ちます。ありがとう!
nd
からnd
への変換の一般的なアイデアそのようなnd
からnd
への変換に関するアイデアは、2つのことだけを使用しています-
軸を並べ替える( numpy.transpose
または numpy.moveaxis
または numpy.rollaxis
を使用して、必要な並べ替え順序がロールされている場合1つまたは numpy.swapaxes
2つの軸だけを交換する必要がある場合)および
形を変える。
軸を並べ替える:平坦化されたバージョンが出力の平坦化されたバージョンに対応するような順序を取得します。したがって、どうにかしてそれを2回使用してしまった場合は、再利用しないでください。
Reshape:軸を分割するか、最終出力を目的の形状にします。軸の分割は、ほとんどの場合、最初に必要です。入力が低調で、ブロックに分割する必要がある場合です。繰り返しますが、これは2回以上必要ありません。
したがって、通常は3つのステップがあります。
[ Reshape ] ---> [ Permute axes ] ---> [ Reshape ]
Create more axes Bring axes Merge axes
into correct order
バックトラッキング方式
入力と出力が与えられた場合の最も安全な解決方法は、バックトラッキングメソッドとして呼び出すことができるもの、つまり入力の軸を分割する(小さなnd
から大きなnd
に移動する場合)または出力の軸を分割することです。大きいnd
から小さいnd
に変更する場合)。分割のアイデアは、小さいnd
の寸法の数を大きいnd
の寸法と同じにすることです。次に、出力のストライドを調べ、入力と照合して、必要な置換順序を取得します。最後に、最後の軸がnd
の方が小さい場合、軸をマージするために、最後に形状変更(デフォルトの方法またはC順)が必要になる場合があります。
入力と出力の両方が同じ数のDIMである場合、両方を分割してブロックに分割し、それらのストライドを互いに比較する必要があります。そのような場合、ブロックサイズの追加の入力パラメーターが必要ですが、それはおそらくトピック外です。
これらの戦略を適用する方法を示すために、この特定のケースを使用してみましょう。ここでは、入力は4D
、出力は2D
です。したがって、おそらく、分割するために形状を変更する必要はありません。したがって、軸を並べ替えることから始める必要があります。最終出力は4D
ではなく、2D
なので、最後に再形成する必要があります。
ここでの入力は次のとおりです。
In [270]: a
Out[270]:
array([[[[ 0, 0],
[ 0, 0]],
[[ 5, 10],
[15, 20]]],
[[[ 6, 12],
[18, 24]],
[[ 7, 14],
[21, 28]]]])
予想される出力は次のとおりです。
In [271]: out
Out[271]:
array([[ 0, 5, 0, 10],
[ 6, 7, 12, 14],
[ 0, 15, 0, 20],
[18, 21, 24, 28]])
また、これはより大きなnd
から小さなnd
への変換であるため、バックトラッキング方法では、出力を分割してその strides を調べ、入力内の対応する値と照合します。
axis = 3
--- -->
axis = 1
------>
axis=2| axis=0| [ 0, 5, 0, 10],
| [ 6, 7, 12, 14],
v
| [ 0, 15, 0, 20],
v
[18, 21, 24, 28]])
したがって、必要な置換された順序は(2,0,3,1)
です。
In [275]: a.transpose((2, 0, 3, 1))
Out[275]:
array([[[[ 0, 5],
[ 0, 10]],
[[ 6, 7],
[12, 14]]],
[[[ 0, 15],
[ 0, 20]],
[[18, 21],
[24, 28]]]])
次に、単純に予想される形状に再形成します。
In [276]: a.transpose((2, 0, 3, 1)).reshape(4,4)
Out[276]:
array([[ 0, 5, 0, 10],
[ 6, 7, 12, 14],
[ 0, 15, 0, 20],
[18, 21, 24, 28]])
その他の例
履歴を調べたところ、nd
からnd
への変換に基づくQ&As
はほとんど見つかりませんでした。これらは、ほとんど説明がありませんが、他の事例として使用できます。前述のように、最大2つのreshapes
と最大1つのswapaxes
/transpose
があらゆる場所で仕事をしました。それらは次のとおりです。
transpose
に続いて reshape
を探しているようです。
x.transpose((2, 0, 3, 1)).reshape(np.prod(x.shape[:2]), -1)
array([[ 0, 5, 0, 10],
[ 6, 7, 12, 14],
[ 0, 15, 0, 20],
[18, 21, 24, 28]])
転置が必要な理由を理解するのに役立つように、誤った形状の出力(単一のreshape
呼び出しによって取得された)を分析して、なぜそれがunderstandであるかを理解します。
この結果の単純な2D変形バージョン(転置なし)は次のようになります-
x.reshape(4, 4)
array([[ 0, 0, 0, 0],
[ 5, 10, 15, 20],
[ 6, 12, 18, 24],
[ 7, 14, 21, 28]])
次に、予想される出力に関してこの出力を検討します-
array([[ 0, 5, 0, 10],
[ 6, 7, 12, 14],
[ 0, 15, 0, 20],
[18, 21, 24, 28]])
実際の結果は、誤って形作られた出力をZのようにたどることによって得られることに気づくでしょう-
start
| /| /| /|
|/ | / |/ |
/ / /
/ / /
| /| / | /|
|/ |/ |/ |
end
これは、actual結果を得るために、さまざまなストライドで配列を移動する必要があることを意味します。結論として、単純な形状変更では不十分です。元の配列をtransposeして、これらのZのような要素が互いに隣接するようにして、後続の再形成呼び出しができるようにする必要があります。必要な出力を提供します。
正しく転置する方法を理解するには、入力に沿って要素をトレースし、出力の各軸に到達するためにジャンプする必要がある軸を把握する必要があります。それに応じて転置が続きます。 Divakarの答え は、これを説明するスターリングジョブを実行します。
Divarkarの答えは素晴らしい ですが、transpose
とreshape
がカバーするすべての可能なケースをチェックする方が簡単な場合もあります。
たとえば、次のコード
n, m = 4, 2
arr = np.arange(n*n*m*m).reshape(n,n,m,m)
for permut in itertools.permutations(range(4)):
arr2 = (arr.transpose(permut)).reshape(n*m, n*m)
print(permut, arr2[0])
transpose
+ reshape
を使用して4次元配列から取得できるすべてのものが得られます。出力がどのように表示されるかはわかっているので、正しい答えを示した順列を選択するだけです。希望どおりの結果が得られなかった場合、transpose
+ reshape
は私のケースをカバーするには一般的ではなく、もっと複雑なことをする必要があります。