内部Keras模型中具有多个嵌入层的问题

我正在尝试构建一个Keras模型model_B,该模型输出另一个Keras模型model_A的输出。现在,model_A的输出是根据来自多个Keras embedding层且具有不同词汇量的几个张量的级联来计算的。模型model_Amodel_B基本相同。

问题:我训练model_A时,一切正常。但是,当我在同一数据集上训练model_B时,出现以下错误:

  

tensorflow.python.framework.errors_impl.InvalidArgumentError:   index [1] = 3不在[0,2)[[{{node model_1 / embedding_1 / embedding_lookup}}]]

从本质上讲,该错误是说一个单词的索引超出了预期的词汇范围,但事实并非如此。有人可以弄清楚为什么会这样吗?


以下是该问题的可复制示例:

from keras.layers import Input,Dense,Lambda,concatenate,Embedding
from keras.models import Model
import numpy as np


# Constants
A = 2
vocab_sizes = [2,4]

# Architecture
X = Input(shape=(A,))
embeddings = []
for a in range(A):
    X_a = Lambda(lambda x: x[:,a])(X)
    embedding = Embedding(input_dim=vocab_sizes[a],output_dim=1)(X_a)
    embeddings.append(embedding)
h = concatenate()(embeddings)
h = Dense(1)(h)

# Model A
model_A = Model(inputs=X,outputs=h)
model_A.compile('sgd','mse')

# Model B
Y = Input(shape=(A,))
model_B = Model(inputs=Y,outputs=model_A(Y))
model_B.compile('sgd','mse')

# Dummy dataset
x = np.array([[vocab_sizes[0] - 1,vocab_sizes[1] - 1]])
y = np.array([1])

# Train models
model_A.fit(x,y,epochs=10)  # Works well
model_B.fit(x,epochs=10)  # Fails

根据上述错误,似乎输入x[:,1]被错误地馈送到词汇量为2的第一嵌入层,而不是第二词汇层。有趣的是,当我交换词汇量(例如设置vocab_sizes = [4,2])时,它可以工作,并支持先前的假设。

wintin98 回答:内部Keras模型中具有多个嵌入层的问题

出于某些奇怪的原因,张量循环导致此错误。 您可以用tf.split代替切片,使用必要的调整,效果会很好:

额外进口:

import tensorflow as tf
from keras.layers import Flatten
# Architecture
X = Input(shape=(A,))
X_as = Lambda(lambda x: tf.split(x,A,axis=1))(X)

embeddings = []
for a,x in enumerate(X_as):
    embedding = Embedding(input_dim=vocab_sizes[a],output_dim=1)(x)
    embeddings.append(embedding)
h = Concatenate(axis=1)(embeddings)
h = Flatten()(h)
h = Dense(1)(h)

为什么会这样?

好吧,很难猜测。我的假设是系统正在尝试使用实际变量a而不是您之前提供的值来应用lambda层(我想这应该不会发生,但是在加载模型时,我曾有过一次这个问题:加载模型时,其中一个变量保留了最后一个值,而不是具有循环值)

支持此解释的一件事是尝试使用常量而不是a

#Architecture
X = Input(shape=(A,))
embeddings = []

X_a1 = Lambda(lambda x: x[:,0],name = 'lamb_'+str(0))(X)
X_a2 = Lambda(lambda x: x[:,1],name = 'lamb_'+str(1))(X)
xs = [X_a1,X_a2]

for a,X_a in enumerate(xs):
    embedding = Embedding(input_dim=vocab_sizes[a],output_dim=1)(X_a)
    embeddings.append(embedding)
h = Concatenate()(embeddings)
h = Dense(1)(h)

要避免使用tf.split

的解决方案

另一种有效的方法(并支持Lambda可能在代码中将a的最后一个值model_B使用Lambda的原因)使整个循环在a层内,这样#Architecture X = Input(shape=(A,)) X_as = Lambda(lambda x: [x[:,a] for a in range(A)])(X) embeddings = [] for a,X_a in enumerate(X_as): embedding = Embedding(input_dim=vocab_sizes[a],output_dim=1)(X_a) embeddings.append(embedding) h = Concatenate()(embeddings) h = Dense(1)(h) 不会得到任何意外的值:

class MyApplicationLoader extends GuiceApplicationLoader() {
  override def builder(context: ApplicationLoader.Context): 
    GuiceApplicationBuilder = {
    val builder = super.builder(context)
    Global.Injector = builder.injector()
    builder
  }
}
,

我相信正在发生以下事情:

(1)在Lambda函数上执行初始“ for循环”时,您正在初始化常量张量,该张量将馈入“ strided_slice”运算符中,该运算符可正确提取[:,0]或[:,1] 。在Lambda函数中使用全局变量“ a”可能是“风险”,但在这种情况下可以正常工作。此外,我相信该函数将以“ lambda x:x [:,a]”的形式存储在字节码中,因此它将尝试在求值时查找“ a”的值。 “ a”可能是任何东西,因此在某些情况下可能会引起问题。

(2)构建第一个模型(model_A)时,常数张量不会重新初始化,因此lambda函数(strided_slice运算符)具有已初始化的正确值(0和1)在“ for循环”中。

(3)建立第二个模型(model_B)时,常数张量 被重新初始化。但是,此时,“ a”的值现在为1(如其他注释中所述),因为这是原始“ for循环”之后的最终值。实际上,您可以在定义model_B之前将a = 0设置为0,并且实际上您将获得与Lambda提取[:,0]并将其馈送到嵌入层相对应的行为。我对这种行为差异的推测可能与这种情况下调用Model_A(X)类初始化有关(而在第一个模型中,您仅将输出层指定为“ h”,而没有将Model_A()类称为输出-我认为其他评论也暗示了这种差异。

我要说的是,我在操作员初始化步骤中通过在文件“ frameworks / constant_op.py”中放入一些打印语句来验证了这种状况,并获得了调试语句,其值和序列与我上面所述的一致。

我希望这会有所帮助。

本文链接:https://www.f2er.com/3157282.html

大家都在问