我在Keras中建立了一个自动编码器,它接受多个输入和相同数量的输出,我想将其转换为可变自动编码器。我很难将输入和输出之间差异的损失与可变部分的损失结合起来。
自动编码器应用于包含数值和分类数据的数据集。为此,我将数字列归一化,并对分类列进行1-热编码。由于所得的分类向量和数值向量需要不同的损失函数(数值的均方误差和分类列的分类交叉熵),与1相比,非常大的1-hot编码向量将主导损失。小数字列,我决定将每一列作为其自己的输入向量。因此,我的自动编码器接受一组输入向量,生成相同数量和形状的输出向量。
这是两个数字输入和两个分类输入的设置,分别具有20和30宽的1-hot编码:
encWidth = 3
## Encoder
x = Concatenate(axis=1)([ Input(1,),Input(1,),Input(20,),Input(30,) ]) #<-configurable
x = Dense( 32, activation="relu")(x)
layEncOut = Dense( encWidth, activation="linear")(x)
layDecIn = Input( encWidth, name="In_Encoder" )
x = Dense( 32, activation="relu")(layDecIn)
layDecOut = [ outLayer(x) for outLayer in C.layOutputs ]
encoder = Model(C.layInputs, layEncOut, name="encoder")
decoder = Model( layDecIn, layDecOut, name="decoder" )
AE = Model(C.layInputs, decoder(encoder(C.layInputs)), name="autoencoder")
AE.compile(optimizer="adam",
loss=['mean_squared_error', 'mean_squared_error',
'categorical_crossentropy', 'categorical_crossentropy',], #<-configurable
loss_weights=[1.0, 1.0, 1.0, 1.0] #<-configurable
)
此示例是静态的,但是在我的实现中,数字字段和类别字段是可配置的,因此输入,损失函数的类型和损失权重应该可以从存储数据集中原始列的对象中进行配置。
....
## Encoder
x = Concatenate(axis=1)( C.layInputs )
...
AE.compile(optimizer="adam",
loss=C.losses
loss_weights=C.lossWeights
)
这里C是类的实例,它具有输入层和损失函数/权重,具体取决于我要在自动编码器中具有的列。
我现在将设置扩展到一个变分自动编码器,其潜在层具有均值和标准差。
encWidth = 2
## Encoder
x = Concatenate(axis=1)(C.layInputs)
x = Dense( 32, activation="relu")(x)
### variational part
z_mean = Dense(encWidth, name='z_mean', activation=lrelu)(x)
z_log_var = Dense(encWidth, name='z_log_var', activation=lrelu)(x)
z = Lambda(sampling, name='z')([z_mean, z_log_var])
## Decoder
layDecodeInput = Input( encWidth, name="In_Encoder" )
x = Dense( 32, activation="relu")(layDecodeInput)
layOutDecoder = [ outLayer(x) for outLayer in C.layOutputs ]
### build the encoder model
vEncoder = Model(C.layInputs, [z_mean, z_log_var, z], name='v_encoder')
### build the decoder model
vDecoder = Model( layDecodeInput, layOutDecoder, name="v_decoder" )
## Autoencoder
vAE = Model(C.layInputs, vDecoder(vEncoder(C.layInputs)[2]))
vae_loss = variational_loss(z_mean, z_log_var)
vAE.compile(optimizer="adam",
loss=vae_loss)
现在,我需要一个自定义错误函数,该函数将输入和输出之间的差值的损失(如上例所示)与变量部分的损失相结合;到目前为止,这是我想出的:
def variational_loss(z_mean, z_log_var, varLossWeight=1.):
def lossFct(yTrue, yPred):
var_loss = -0.5 * K.mean(1 + z_log_var - K.square(z_mean) - K.exp(z_log_var))
lossFunctions = [getattr(losses, "mean_squared_error") for losses in C.losses]
ac_loss = [
lossFkt(yTrue, yPred) * lossWeigt for
yt, yp, lossFkt, lossWeigt in zip(yTrue, yPred, lossFunctions, C.lossWeights) ]
loss = K.mean( ac_loss + [ kl_loss * varLossWeight ] )
return loss
return lossFct
所以它是一个生成器函数,它返回一个接受yTrue和yPredicted的函数,但在可变部分起作用。 for循环应遍历所有输入和相应的输出,并使用适当的损失函数(对于数值而言是均方误差,对于分类特征而言是类交叉熵)进行比较。
但是显然,for循环不允许遍历输入向量集并将它们与输出向量集进行比较;我收到一个错误
Tensor objects are only iterable when eager execution is enabled. To iterate over this tensor use tf.map_fn.
如何获得
Model.compile()
端点的便捷行为,在其中我可以告诉我在不同的输入和输入和输出上使用不同的损失函数,并结合变化损失?
我在Keras中建立了一个自动编码器,它接受多个输入和相同数量的输出,我想将其转换为可变自动编码器。我无法合并损失...
我认为在网络中添加一个KLA发散层来解决VAE丢失会更简单。您可以这样进行操作(其中beta是vae损失的权重):