官方的定义为
keras.layers.Dot(axes, normalize=False)
它处于Merge模块
中,查看源代码发现它的merge方式是这样的,如下
PS:原链接
def _merge_function(self, inputs):
if len(inputs) != 2:
raise ValueError('A `Dot` layer should be called '
'on exactly 2 inputs')
x1 = inputs[0]
x2 = inputs[1]
if isinstance(self.axes, int):
if self.axes < 0:
axes = [self.axes % K.ndim(x1), self.axes % K.ndim(x2)]
else:
axes = [self.axes] * 2
else:
axes = []
for i in range(len(self.axes)):
if self.axes[i] < 0:
axes.append(self.axes[i] % K.ndim(inputs[i]))
else:
axes.append(self.axes[i])
if self.normalize:
x1 = K.l2_normalize(x1, axis=axes[0])
x2 = K.l2_normalize(x2, axis=axes[1])
output = K.batch_dot(x1, x2, axes)
return output
主要讨论axes
参数,通过上面的代码分析,它的作用体现在倒数第二行,output = K.batch_dot(x1, x2, axes)
,本来到这里应该也差不多了,但是它最后的计算结果让我有些迷惑,故写了一个测试代码如下
import tensorflow as tf
from keras.layers import Dot
from keras import backend as K
import numpy as np
a = np.arange(24).reshape(2,3,4) # a和b的维度有些讲究,具体查看Dot类的build方法
b = np.arange(48).reshape(2,3,8)
output = K.batch_dot(K.constant(a), K.constant(b), axes=1)
with tf.Session() as sess:
output_array = sess.run(output)
print( output_array )
print( output_array.shape )
输出结果
最后的结果和其shape是让我迷惑的地方,虽然代码没错,可以得到结果,但是这两种形状是怎么能够进行运算的?这是怎么算出来的这种形状?
来看看a和b的值,左边为a,右边为b,下面为结果
看了很久,恍然大悟
在a和b的第一维相同的情况下,取a的axis为1的那一列,取b的aixs为1的那一列点乘。由于a在前,故a的每一列都要和b的所有列进行点乘
如结果的第一个160的计算方式为
0
×
0
+
4
×
8
+
8
×
16
=
160
0\times0+4\times8+8\times16=160
0×0+4×8+8×16=160
第二个172的计算方式为
0
×
1
+
4
×
9
+
8
×
17
=
172
0\times1+4\times9+8\times17=172
0×1+4×9+8×17=172
至于结果的第二行就要选取a的第二列[1, 5, 9]了,后面的计算方式还是一样的
补充知识
np.dot(a, b, output)
- 其他情况不讨论
- a为多维数据,b为多维数据时,需要保证a的最后一维和b的倒数第二维维度一样
以下选自官方原文
If a
is an N-D array and b
is an M-D array (where M>=2
), it is a
sum product over the last axis of a
and the second-to-last axis of b
::
dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m])
上面官方的这个例子中a的维度和b的维度都是3,且两个3维的array通过dot操作后,维度会变成4。
example
下面这个例子中维度除了a的最后一维以及b的倒数第二维,其余顺序随便写的。