我在Keras中设置了一个自动编码器。我希望能够根据预定的“精度”向量加权输入向量的特征。此连续值向量的长度与输入的长度相同,并且每个元素都位于[0, 1]
范围内,对应于相应输入元素的置信度,其中1是完全置信度,0是无置信度。
每个示例都有一个精确向量。
我定义了一种损失,其中考虑了该精度向量。在这里,低置信度特征的重构权重降低了。
def MAEpw_wrapper(y_prec):
def MAEpw(y_true, y_pred):
return K.mean(K.square(y_prec * (y_pred - y_true)))
return MAEpw
我的问题是精度张量y_prec
取决于批次。我希望能够根据当前批次更新y_prec
,以便每个精度向量都与其观察值正确关联。
我已完成以下操作:
global y_prec
y_prec = K.variable(P[:32])
这里P
是一个numpy数组,其中包含所有精度矢量,其索引对应于示例。我将y_prec
初始化为批次大小为32的正确形状。然后定义以下DataGenerator
:
class DataGenerator(Sequence):
def __init__(self, batch_size, y, shuffle=True):
self.batch_size = batch_size
self.y = y
self.shuffle = shuffle
self.on_epoch_end()
def on_epoch_end(self):
self.indexes = np.arange(len(self.y))
if self.shuffle == True:
np.random.shuffle(self.indexes)
def __len__(self):
return int(np.floor(len(self.y) / self.batch_size))
def __getitem__(self, index):
indexes = self.indexes[index * self.batch_size: (index+1) * self.batch_size]
# Set precision vector.
global y_prec
new_y_prec = K.variable(P[indexes])
y_prec = K.update(y_prec, new_y_prec)
# Get training examples.
y = self.y[indexes]
return y, y
在这里,我旨在以生成批处理的相同功能更新y_prec
。这似乎正在按预期更新y_prec
。然后定义模型架构:
dims = [40, 20, 2]
model2 = Sequential()
model2.add(Dense(dims[0], input_dim=64, activation='relu'))
model2.add(Dense(dims[1], input_dim=dims[0], activation='relu'))
model2.add(Dense(dims[2], input_dim=dims[1], activation='relu', name='bottleneck'))
model2.add(Dense(dims[1], input_dim=dims[2], activation='relu'))
model2.add(Dense(dims[0], input_dim=dims[1], activation='relu'))
model2.add(Dense(64, input_dim=dims[0], activation='linear'))
最后,我编译并运行:
model2.compile(optimizer='adam', loss=MAEpw_wrapper(y_prec))
model2.fit_generator(DataGenerator(32, digits.data), epochs=100)
digits.data
是观察到的数个数组。
但是,这最终定义了单独的图形:
StopIteration: Tensor("Variable:0", shape=(32, 64), dtype=float32_ref) must be from the same graph as Tensor("Variable_4:0", shape=(32, 64), dtype=float32_ref).
我一直在寻找SO解决问题的方法,但没有发现任何可行的方法。感谢您提供有关如何正确执行此操作的帮助。
答案 0 :(得分:1)
可以使用Keras functional API轻松实现此自动编码器。这将允许有一个附加的输入占位符y_prec_input
,该占位符将与“精度”矢量一起馈入。完整的源代码可以在here中找到。
数据生成器
首先,让我们重新实现数据生成器,如下所示:
class DataGenerator(Sequence):
def __init__(self, batch_size, y, prec, shuffle=True):
self.batch_size = batch_size
self.y = y
self.shuffle = shuffle
self.prec = prec
self.on_epoch_end()
def on_epoch_end(self):
self.indexes = np.arange(len(self.y))
if self.shuffle:
np.random.shuffle(self.indexes)
def __len__(self):
return int(np.floor(len(self.y) / self.batch_size))
def __getitem__(self, index):
indexes = self.indexes[index * self.batch_size: (index + 1) * self.batch_size]
y = self.y[indexes]
y_prec = self.prec[indexes]
return [y, y_prec], y
请注意,我摆脱了全局变量。现在,改为提供精度向量P
作为输入参数(prec
),并且生成器会产生一个附加输入,该输入将被馈送到精度占位符y_prec_input
(请参阅模型定义)
模型
最后,可以按照以下方式定义和训练模型:
y_input = Input(shape=(input_dim,))
y_prec_input = Input(shape=(1,))
h_enc = Dense(dims[0], activation='relu')(y_input)
h_enc = Dense(dims[1], activation='relu')(h_enc)
h_enc = Dense(dims[2], activation='relu', name='bottleneck')(h_enc)
h_dec = Dense(dims[1], activation='relu')(h_enc)
h_dec = Dense(input_dim, activation='relu')(h_dec)
model2 = Model(inputs=[y_input, y_prec_input], outputs=h_dec)
model2.compile(optimizer='adam', loss=MAEpw_wrapper(y_prec_input))
# Train model
model2.fit_generator(DataGenerator(32, digits.data, P), epochs=100)
其中input_dim = digits.data.shape[1]
。请注意,我还将解码器的输出尺寸更改为input_dim
,因为它必须与输入尺寸匹配。
答案 1 :(得分:0)
当您调用fit_generator时,尝试使用worker = 0来测试您的代码,如果该代码正常工作,那么线程化就是您的问题。
如果原因是穿线,请尝试以下操作:
# In the code that executes on the main thread
graph = tf.get_default_graph()
# In code that executes in other threads(e.g. your generator)
with graph.as_default():
...
...
new_y_prec = K.variable(P[indexes])
y_prec = K.update(y_prec, new_y_prec)