推荐书: Python开发最佳实践

keras基础-Dense的输入的秩大于2时的注意事项

微博@mlln-cn, 并附上文章url链接, 我就能回答你的问题奥!

文章目录
  1. 1. 问题描述
  2. 2. Dense的算法就是dot
  3. 3. 总结


本文代码运行环境:

  • windows10
  • python3.6
  • jupyter notebook
  • tensorflow 1.x
  • keras 2.x

问题描述

keras的Dense层的输入通常是一个二维的矩阵(batch_size, n_input), 但其实, 你的输入的秩可以是大于2的, 比如下面的代码是正确的:

1
2
3
4
5
6
7
from keras import layers

# 注意keras中, batch size是省略的
input1 = layers.Input((2,3))
dense = layers.Dense(4)
output = dense(input1)
output
输出(plain):

而权重的形状是这样的:

1
dense.kernel
输出(plain):

我们可以看到, 输出output的形状是(batch_size, 2, 4), 为什么会是这样的? 我查阅了keras中的文档, 文档中说:if the input to the layer has a rank greater than 2, then it is flattened prior to the initial dot product with kernel, 但是, 实际情况不是这样的, 如果被flatten以后, 输出应该是这样的:

1
2
3
4
5
input1 = layers.Input((2,3))
flat = layers.Flatten()(input1)
dense = layers.Dense(4)
output = dense(flat)
output
输出(plain):

而权重的形状是这样的:

1
dense.kernel
输出(plain):

Dense的算法就是dot

很显然, 文档说的有问题, 代码并不是这样的运行的。所以我查阅了Keras的源码, 我发现Dense前向传播的计算方法是在这里:

1
2
3
4
5
6
7
8
def call(self, inputs):
# 理解内部发生了什么, 关键要看这一行
output = K.dot(inputs, self.kernel)
if self.use_bias:
output = K.bias_add(output, self.bias, data_format='channels_last')
if self.activation is not None:
output = self.activation(output)
return output

所以, 我们要看一下keras中dot的行为:

1
2
3
4
5
6
from keras import backend as K

x = K.placeholder(shape=(2, 2, 3))
y = K.placeholder(shape=(3, 4))
xy = K.dot(x, y)
xy
输出(plain):
1
2
3
import tensorflow as tf

sess = tf.InteractiveSession()
1
2
3
4
5
6
7
8
import numpy as np
np.random.seed(123)
x_data = np.random.randint(1,10, (2,2,3))
y_data = np.random.randint(1,5, (3,4))
xy_data = xy.eval(feed_dict={x:x_data, y:y_data})
print('x:', x_data)
print('y:', y_data)
print('xy:', xy_data)
输出(stream):
x: [[[3 3 7]
[2 4 7]]

[[2 1 2]
[1 1 4]]]
y: [[3 2 1 1]
[1 1 2 4]
[4 3 1 4]]
xy: [[[40. 30. 16. 43.]
[38. 29. 17. 46.]]

[[15. 11. 6. 14.]
[20. 15. 7. 21.]]]

这个结果和我们直接用np.dot的方法结果是一样的。

1
np.dot(x_data, y_data)
输出(plain):
array([[[40, 30, 16, 43],
[38, 29, 17, 46]],

[[15, 11, 6, 14],
[20, 15, 7, 21]]])
1
np.dot(x_data, y_data[:, 1])
输出(plain):
array([[30, 29],
[11, 15]])

总结

其实两个tensor之间的点乘大家应该懂了, keras官方文档有问题导致对它的理解又产生了疑惑。如果三维的tensor不容易理解的话, 可以去掉batch_size这个维度来看:

1
2
3
4
5

x=np.random.randint(1,5,(2, 3))
y=np.random.randint(1,5,(3, 3))
print('正常情况下, x只是个向量:')
np.dot(x[0,:],y)
输出(stream):
正常情况下, x只是个向量:
输出(plain):
array([28, 26, 16])
1
2
print('特殊情况下, x只是个矩阵:')
np.dot(x,y)
输出(stream):
特殊情况下, x只是个矩阵:
输出(plain):
array([[28, 26, 16],
[40, 36, 23]])

一句话总结的话, Dense的输入为一个矩阵的时候, 相当于它的每一个行向量分别进入Dense层进行计算, 然后把计算得到的向量拼接成矩阵。有问题来我网站提问:mlln.cn , 转载请注明出处。

注意
本文由jupyter notebook转换而来, 您可以在这里下载notebook
有问题可以直接在下方留言
或者给我发邮件675495787[at]qq.com
请记住我的网址: mlln.cn 或者 jupyter.cn

赞助

运营本站花费了很多时间和精力, 并且本站坚持不放广告, 如果你觉得本站对你有帮助, 请资助我一杯咖啡: