可以使用Lambda图层来操纵输入的数据和形状吗?

时间:2017-04-11 13:12:05

标签: keras

我想使用具有张量流的Keras在两个现有网络(模型)A和B中创建一个新网络。新网络的架构就像这样

输入 - > A - > B - >输出

A的输出具有(15,500)的形状,B的输入具有(1000)的形状。我有一个转换方法,它接受形状(15,100)的输入并调用完全不同的网络(C)的预测,并返回形状为(1000)的输出。

我假设我必须引入一个Lambda图层,它将使用我的转换方法将A的输出转换为B所需的格式。但是,当我尝试这样做时,我收到错误

" TypeError:/:' Dimension'不支持的操作数类型并且'浮动' _"在转换方法中调用预测。

这是转换方法

def convert(x):
    C = load_model("path/to/the/network/C.h5")
    return C.predict(x)

我不确定这是否是正确的做法,如果是,那么为什么会出现这个错误。如果这不是正确的方式,那么,我的方法应该是什么。

Keras版本:2.0.1 Tensorflow版本:1.0.1

谢谢,

1 个答案:

答案 0 :(得分:2)

我将假设您不是在尝试将C作为新网络的一部分进行训练(我们称之为D)。这就是我想象你想要的

 A
 | 
(C) # transform step. a non-trainable keras model
 |
 B
 |
out

请注意,变量名称来自原始答案部分中的示例。

更新,是原始回答中的代码仅使用dense_2中的model_1图层。

这不是你想要的,所以我去挖掘。而且很漂亮,答案很简单。

  • 加载C及其重量,
  • 更新模型的输出,以便我们可以将任意图层设置为输出。
  • 使用layer.trainable = False将C的图层设置为无法训练。
  • 最后,调用转换模型,就像调用图层model_1(inp2)
  • 一样

以下是原始答案更新中的示例,为了证明C中的权重不可训练,我们将打印model_1.summary()

# let `model_1` be C in the diagram above.
from keras.models import Model
from keras.layers import (Lambda, Dense, Input)

inp = Input(shape=(5, ))
lam = Lambda(lambda x: x + 2, name='lamb')(inp)
den = Dense(1, name='dense')(lam) # this is the `model_1` output
model_1 = Model(inp, den)

# suppose we want an intermediate output from model_1
# (the `lam` layer for instance)
# we update the outputs and use that output in model2

model.outputs = [model.output,  model.get_layer(name='lamb').output]
print(model.outputs)

# [<tf.Tensor 'dense_11/BiasAdd:0' shape=(?, 1) dtype=float32>,
# <tf.Tensor 'lamb_9/add:0' shape=(?, 5) dtype=float32>]

# now build D, since we can treat a model like a layer( awesome!) 
# we can just let models A, B in the diagram above be layers 
# (for this exmple) - nothing changes.

# But first set the layers of `model_1` to not be trainable:

print(model_1.summary()) # Trainable params: 6.0 - before
for l in model_1.layers:
    l.trainable = False 
print(model_1.summary()) # Trainable params: 0.0  - after

# ...then D is:

inp2 = Input(shape=(5, ))     # imagine that this layer is model A
transform = model_1(inp2)[1]  # this is (C) the transform step. 
                              # Notice that we pulled out the lambda 
                              # output by using the index into the
                              # `model_1's` outputs.

# carry on as normal
den2 = Dense(1)(transform) # imagine that this is B
model_2 = Model(inp2, den2)
model_2.compile(loss='mse', optimizer='adam')
model_2.summary()

# simulate data
X = np.random.randn(10, 5)
y = np.random.randn(10, 1)

# fit D
model_2.fit(X, y)  # ... it trains!

一些注意事项:

  • 我们不打算调用编译,因为我们不需要 配置培训模型。查看compile()的文档字符串 或等同于keras docs

  • 但是,如果我们使用keras.models.load_model加载模型。 该模型已编译,但它不应该有任何影响,因为我们是 打算使用layer.trainable = False。请参阅save()

  • 的文档字符串

原始答案

不是使用数组返回预测,而是抓住输出C的最后一层。

def convert(x):
    # there is not need to load C in the lambda layer.
    # load it somewhere outside of the training op.
    # assuming you have C loaded...
    return C.get_layer('dense_2')(x)

以下是此方法的一个简单示例:请注意,您必须制作 确保图层形状兼容。

你可以想象这是模式C

from keras.models import Model
from keras.layers import (Lambda, Dense, Input)

inp = Input(shape=(5,))
lam = Lambda(lambda x: x + 2, name='lamb')(inp)
den = Dense(1, name='dense')(lam) # this is the `model_` output
model_1 = Model(inp, den)
model_1.compile(loss='mse', optimizer='adam')

我们将抓取lam图层的输出 并将其用作下面D中的转换步骤:

inp2 = Input(shape=(5, ))
# grab the 'dense' layer from `model_1` 
sums = Lambda(lambda x: model_1.get_layer(name='dense')(x))(inp2)
den2 = Dense(1)(sums)
model_2 = Model(inp2, sums)
model_2.compile(loss='mse', optimizer='adam')
model_2.summary()