仅仅重塑与重塑和转置之间的区别?

Hak*_*gün 6 python numpy machine-learning

我目前正在学习 CS231 作业,我发现一些令人困惑的事情。在计算梯度时,当我首先重塑 x 然后进行转置时,我得到了正确的结果。

x_r=x.reshape(x.shape[0],-1)
dw= x_r.T.dot(dout)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

但是,当我直接将形状重塑为 XT 形状时,它不会返回正确的结果。

dw = x.reshape(-1,x.shape[0]).dot(dout)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

有人可以解释以下问题吗?

使用 np.reshape() 获取元素的顺序如何改变?将 (N,d1,d2..dn) 形状数组重塑为 N,D 数组与通过转置获得 (D,N) 形状数组有何不同。

afs*_*rov 7

虽然两种方法都会产生相同形状的数组,但由于 numpy 读取/写入元素的方式,元素的顺序会有所不同。默认情况下,reshape使用类似 C 的索引顺序,这意味着读取/写入元素时最后一个轴索引变化最快,回到第一个轴索引变化最慢(取自文档

这是一个在实践中意味着什么的例子。我们假设有以下数组x

x = np.asarray([[[1, 2], [3, 4], [5, 6]], [[7, 8], [9, 10], [11, 12]]])

print(x.shape) # (2, 3, 2)

print(x)
# output
[[[ 1  2]
  [ 3  4]
  [ 5  6]]

 [[ 7  8]
  [ 9 10]
  [11 12]]]
Run Code Online (Sandbox Code Playgroud)

现在让我们通过以下两种方式重塑该数组:

opt1 = x.reshape(x.shape[0], -1)
opt2 = x.reshape(-1, x.shape[0])

print(opt1.shape) # outptu: (2, 6)
print(opt2.shape) # output: (6, 2)

print(opt1)
# output:
[[ 1  2  3  4  5  6]
 [ 7  8  9 10 11 12]]

print(opt2)
# output:
[[ 1  2]
 [ 3  4]
 [ 5  6]
 [ 7  8]
 [ 9 10]
 [11 12]]
Run Code Online (Sandbox Code Playgroud)

reshape首先推断新数组的形状,然后返回一个视图,在该视图中以类似于 C 的索引顺序读取元素。

举个例子opt1:由于原始数组x有 12 个元素,因此推断新数组的opt1形状必须为(2, 6)(因为 2*6=12)。现在,reshape返回一个视图,其中:

opt1[0][0] == x[0][0][0] 
opt1[0][1] == x[0][0][1]
opt1[0][2] == x[0][1][0]
opt1[0][3] == x[0][1][1]
opt1[0][4] == x[0][2][0]
opt1[0][5] == x[0][2][1]
opt1[1][0] == x[1][0][0]
...
opt1[1][5] == x[1][2][1]
Run Code Online (Sandbox Code Playgroud)

因此,如上所述,最后一个轴索引变化最快,第一个轴索引变化最慢。以同样的方式,输出为opt2将计算 的输出。

您现在可以验证转置第一个选项是否会产生相同的形状但元素的顺序不同:

opt1 = opt1.T

print(opt1.shape) # output: (6, 2)

print(opt1)
# output: 
[[ 1  7]
 [ 2  8]
 [ 3  9]
 [ 4 10]
 [ 5 11]
 [ 6 12]]
Run Code Online (Sandbox Code Playgroud)

显然,由于元素排序,这两种方法不会产生相同的数组,即使它们具有相同的形状。

  • @HakanAkgün 我编辑了答案,以展示如何知道以类似 C 的索引顺序重塑后哪个元素最终会出现在哪里。如果您想了解更多关于这些事情的一般信息,我建议您阅读 [NumPy 内部原理](https://numpy.org/doc/stable/reference/internals.html#numpy-internals)。 (2认同)