二元交叉熵损失计算中np.dot和np.multiply与np.sum的区别
Difference between np.dot and np.multiply with np.sum in binary cross-entropy loss calculation
我尝试了下面的代码,但没有发现 np.dot 和 np.multiply 与 [=47= 之间的区别]
这里是np.dot代码
logprobs = np.dot(Y, (np.log(A2)).T) + np.dot((1.0-Y),(np.log(1 - A2)).T)
print(logprobs.shape)
print(logprobs)
cost = (-1/m) * logprobs
print(cost.shape)
print(type(cost))
print(cost)
它的输出是
(1, 1)
[[-2.07917628]]
(1, 1)
<class 'numpy.ndarray'>
[[ 0.693058761039 ]]
这是 np.multiply 和 np.sum
的代码
logprobs = np.sum(np.multiply(np.log(A2), Y) + np.multiply((1 - Y), np.log(1 - A2)))
print(logprobs.shape)
print(logprobs)
cost = - logprobs / m
print(cost.shape)
print(type(cost))
print(cost)
它的输出是
()
-2.07917628312
()
<class 'numpy.float64'>
0.693058761039
我无法理解类型和形状的差异,但两种情况下的结果值相同
即使在压缩前代码的情况下成本值与后面的相同但类型保持不变
cost = np.squeeze(cost)
print(type(cost))
print(cost)
输出是
<class 'numpy.ndarray'>
0.6930587610394646
np.dot
是两个矩阵的dot product。
|A B| . |E F| = |A*E+B*G A*F+B*H|
|C D| |G H| |C*E+D*G C*F+D*H|
而 np.multiply
执行两个矩阵的 element-wise multiplication。
|A B| ⊙ |E F| = |A*E B*F|
|C D| |G H| |C*G D*H|
与np.sum
一起使用时,结果相等纯属巧合。
>>> np.dot([[1,2], [3,4]], [[1,2], [2,3]])
array([[ 5, 8],
[11, 18]])
>>> np.multiply([[1,2], [3,4]], [[1,2], [2,3]])
array([[ 1, 4],
[ 6, 12]])
>>> np.sum(np.dot([[1,2], [3,4]], [[1,2], [2,3]]))
42
>>> np.sum(np.multiply([[1,2], [3,4]], [[1,2], [2,3]]))
23
如果 Y
和 A2
是 (1,N) 数组,那么 np.dot(Y,A.T)
将产生 (1,1) 结果。它正在进行 (1,N) 与 (N,1) 的矩阵乘法。 N's
求和,留下 (1,1).
与 multiply
结果是 (1,N)。对所有值求和,结果为标量。
如果 Y
和 A2
是 (N,) 形状的(相同数量的元素,但是 1d),np.dot(Y,A2)
(没有 .T
)也会产生一个标量。来自 np.dot
文档:
For 2-D arrays it is equivalent to matrix multiplication, and for 1-D arrays to inner product of vectors
Returns the dot product of a and b. If a and b are both scalars or both 1-D arrays then a scalar is returned; otherwise an array is returned.
squeeze
减少了所有大小为 1 的维度,但仍然 returns 一个数组。在 numpy
中,数组可以具有任意数量的维度(从 0 到 32)。所以 0d 数组是可能的。比较 np.array(3)
、np.array([3])
和 np.array([[3]])
.
的形状
您正在做的是计算 binary cross-entropy loss,它衡量模型的预测(此处:A2
)与真实输出(此处:Y
).
这是您的案例的可重现示例,它应该可以解释为什么您在第二种情况下使用 np.sum
获得标量
In [88]: Y = np.array([[1, 0, 1, 1, 0, 1, 0, 0]])
In [89]: A2 = np.array([[0.8, 0.2, 0.95, 0.92, 0.01, 0.93, 0.1, 0.02]])
In [90]: logprobs = np.dot(Y, (np.log(A2)).T) + np.dot((1.0-Y),(np.log(1 - A2)).T)
# `np.dot` returns 2D array since its arguments are 2D arrays
In [91]: logprobs
Out[91]: array([[-0.78914626]])
In [92]: cost = (-1/m) * logprobs
In [93]: cost
Out[93]: array([[ 0.09864328]])
In [94]: logprobs = np.sum(np.multiply(np.log(A2), Y) + np.multiply((1 - Y), np.log(1 - A2)))
# np.sum returns scalar since it sums everything in the 2D array
In [95]: logprobs
Out[95]: -0.78914625761870361
请注意,np.dot
沿 求和仅匹配此处 (1x8) and (8x1)
的内部维度 。因此,8
s 将在点积或矩阵乘法期间消失,产生的结果为 (1x1)
这只是一个 标量 但 returned作为形状 (1,1)
.
的二维数组
此外,最重要的是要注意这里 np.dot
is exactly same as doing np.matmul
因为输入是二维数组(即矩阵)
In [107]: logprobs = np.matmul(Y, (np.log(A2)).T) + np.matmul((1.0-Y),(np.log(1 - A2)).T)
In [108]: logprobs
Out[108]: array([[-0.78914626]])
In [109]: logprobs.shape
Out[109]: (1, 1)
Return 结果作为 标量 值
np.dot
或 np.matmul
returns 无论生成的数组形状如何,都基于输入数组。即使使用 out=
参数,如果输入是二维数组,也不可能 return 一个 标量 。但是,如果结果数组的形状为 (1,1)
(或更一般地 标量 值包装在 nD 数组中)
In [123]: np.asscalar(logprobs)
Out[123]: -0.7891462576187036
In [124]: type(np.asscalar(logprobs))
Out[124]: float
ndarray of size 1 to scalar value
In [127]: np.asscalar(np.array([[[23.2]]]))
Out[127]: 23.2
In [128]: np.asscalar(np.array([[[[23.2]]]]))
Out[128]: 23.2
In this example it just not a coincidence. Lets take an example we have two (1,3) and (1,3) matrices.
// Lets code
import numpy as np
x1=np.array([1, 2, 3]) // first array
x2=np.array([3, 4, 3]) // second array
//Then
X_Res=np.sum(np.multiply(x1,x2))
// will result 20 as it will be calculated as - (1*3)+(2*4)+(3*3) , i.e element wise
// multiplication followed by sum.
Y_Res=np.dot(x1,x2.T)
// in order to get (1,1) matrix) from a dot of (1,3) matrix and //(1,3) matrix we need to //transpose second one.
//Hence|1 2 3| * |3|
// |4| = |1*3+2*4+3*3| = |20|
// |3|
// will result 20 as it will be (1*3)+(2*4)+(3*3) , i.e. dot product of two matrices
print X_Res //20
print Y_Res //20
我尝试了下面的代码,但没有发现 np.dot 和 np.multiply 与 [=47= 之间的区别]
这里是np.dot代码
logprobs = np.dot(Y, (np.log(A2)).T) + np.dot((1.0-Y),(np.log(1 - A2)).T)
print(logprobs.shape)
print(logprobs)
cost = (-1/m) * logprobs
print(cost.shape)
print(type(cost))
print(cost)
它的输出是
(1, 1)
[[-2.07917628]]
(1, 1)
<class 'numpy.ndarray'>
[[ 0.693058761039 ]]
这是 np.multiply 和 np.sum
的代码logprobs = np.sum(np.multiply(np.log(A2), Y) + np.multiply((1 - Y), np.log(1 - A2)))
print(logprobs.shape)
print(logprobs)
cost = - logprobs / m
print(cost.shape)
print(type(cost))
print(cost)
它的输出是
()
-2.07917628312
()
<class 'numpy.float64'>
0.693058761039
我无法理解类型和形状的差异,但两种情况下的结果值相同
即使在压缩前代码的情况下成本值与后面的相同但类型保持不变
cost = np.squeeze(cost)
print(type(cost))
print(cost)
输出是
<class 'numpy.ndarray'>
0.6930587610394646
np.dot
是两个矩阵的dot product。
|A B| . |E F| = |A*E+B*G A*F+B*H|
|C D| |G H| |C*E+D*G C*F+D*H|
而 np.multiply
执行两个矩阵的 element-wise multiplication。
|A B| ⊙ |E F| = |A*E B*F|
|C D| |G H| |C*G D*H|
与np.sum
一起使用时,结果相等纯属巧合。
>>> np.dot([[1,2], [3,4]], [[1,2], [2,3]])
array([[ 5, 8],
[11, 18]])
>>> np.multiply([[1,2], [3,4]], [[1,2], [2,3]])
array([[ 1, 4],
[ 6, 12]])
>>> np.sum(np.dot([[1,2], [3,4]], [[1,2], [2,3]]))
42
>>> np.sum(np.multiply([[1,2], [3,4]], [[1,2], [2,3]]))
23
如果 Y
和 A2
是 (1,N) 数组,那么 np.dot(Y,A.T)
将产生 (1,1) 结果。它正在进行 (1,N) 与 (N,1) 的矩阵乘法。 N's
求和,留下 (1,1).
与 multiply
结果是 (1,N)。对所有值求和,结果为标量。
如果 Y
和 A2
是 (N,) 形状的(相同数量的元素,但是 1d),np.dot(Y,A2)
(没有 .T
)也会产生一个标量。来自 np.dot
文档:
For 2-D arrays it is equivalent to matrix multiplication, and for 1-D arrays to inner product of vectors
Returns the dot product of a and b. If a and b are both scalars or both 1-D arrays then a scalar is returned; otherwise an array is returned.
squeeze
减少了所有大小为 1 的维度,但仍然 returns 一个数组。在 numpy
中,数组可以具有任意数量的维度(从 0 到 32)。所以 0d 数组是可能的。比较 np.array(3)
、np.array([3])
和 np.array([[3]])
.
您正在做的是计算 binary cross-entropy loss,它衡量模型的预测(此处:A2
)与真实输出(此处:Y
).
这是您的案例的可重现示例,它应该可以解释为什么您在第二种情况下使用 np.sum
In [88]: Y = np.array([[1, 0, 1, 1, 0, 1, 0, 0]])
In [89]: A2 = np.array([[0.8, 0.2, 0.95, 0.92, 0.01, 0.93, 0.1, 0.02]])
In [90]: logprobs = np.dot(Y, (np.log(A2)).T) + np.dot((1.0-Y),(np.log(1 - A2)).T)
# `np.dot` returns 2D array since its arguments are 2D arrays
In [91]: logprobs
Out[91]: array([[-0.78914626]])
In [92]: cost = (-1/m) * logprobs
In [93]: cost
Out[93]: array([[ 0.09864328]])
In [94]: logprobs = np.sum(np.multiply(np.log(A2), Y) + np.multiply((1 - Y), np.log(1 - A2)))
# np.sum returns scalar since it sums everything in the 2D array
In [95]: logprobs
Out[95]: -0.78914625761870361
请注意,np.dot
沿 求和仅匹配此处 (1x8) and (8x1)
的内部维度 。因此,8
s 将在点积或矩阵乘法期间消失,产生的结果为 (1x1)
这只是一个 标量 但 returned作为形状 (1,1)
.
此外,最重要的是要注意这里 np.dot
is exactly same as doing np.matmul
因为输入是二维数组(即矩阵)
In [107]: logprobs = np.matmul(Y, (np.log(A2)).T) + np.matmul((1.0-Y),(np.log(1 - A2)).T)
In [108]: logprobs
Out[108]: array([[-0.78914626]])
In [109]: logprobs.shape
Out[109]: (1, 1)
Return 结果作为 标量 值
np.dot
或 np.matmul
returns 无论生成的数组形状如何,都基于输入数组。即使使用 out=
参数,如果输入是二维数组,也不可能 return 一个 标量 。但是,如果结果数组的形状为 (1,1)
(或更一般地 标量 值包装在 nD 数组中)
In [123]: np.asscalar(logprobs)
Out[123]: -0.7891462576187036
In [124]: type(np.asscalar(logprobs))
Out[124]: float
ndarray of size 1 to scalar value
In [127]: np.asscalar(np.array([[[23.2]]]))
Out[127]: 23.2
In [128]: np.asscalar(np.array([[[[23.2]]]]))
Out[128]: 23.2
In this example it just not a coincidence. Lets take an example we have two (1,3) and (1,3) matrices.
// Lets code
import numpy as np
x1=np.array([1, 2, 3]) // first array
x2=np.array([3, 4, 3]) // second array
//Then
X_Res=np.sum(np.multiply(x1,x2))
// will result 20 as it will be calculated as - (1*3)+(2*4)+(3*3) , i.e element wise
// multiplication followed by sum.
Y_Res=np.dot(x1,x2.T)
// in order to get (1,1) matrix) from a dot of (1,3) matrix and //(1,3) matrix we need to //transpose second one.
//Hence|1 2 3| * |3|
// |4| = |1*3+2*4+3*3| = |20|
// |3|
// will result 20 as it will be (1*3)+(2*4)+(3*3) , i.e. dot product of two matrices
print X_Res //20
print Y_Res //20