>我在 Keras 中构建了一个自动编码器,它接受多个输入和相同的输出,我想将其转换为变分自动编码器。我很难将输入和输出之间差值的损失与变分部分的损失结合起来。
我想要实现的目标:
自动编码器应用于包含数字和分类数据的数据集。为此,我对数字列进行规范化,并对分类列进行 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 和 yPredict 的函数,但在变分部分工作。for 循环应遍历所有输入和相应的输出,并使用适当的损失函数(数值的均方误差或分类特征的分类交叉熵(进行比较
但显然不允许 for 循环遍历输入向量集并将它们与输出向量集进行比较;我收到错误
Tensor objects are only iterable when eager execution is enabled. To iterate over this tensor use tf.map_fn.
我怎样才能获得Model.compile()
的方便行为,我可以告诉在不同的输入和输出上使用不同的损失函数,并结合变分损失?
我认为在处理VAE损失的网络中添加aKL发散层会更简单。你可以这样做,(其中β是vae损失的重量(:
import keras.backend as K
from keras.layers import Layer
class KLDivergenceLayer(Layer):
""" Identity transform layer that adds KL divergence
to the final model loss.
"""
def __init__(self, beta=.5, *args, **kwargs):
self.is_placeholder = True
self.beta = beta
super(KLDivergenceLayer, self).__init__(*args, **kwargs)
def call(self, inputs):
mu, log_var = inputs
kl_batch = - self.beta * K.sum(1 + log_var -
K.square(mu) -
K.exp(log_var), axis=-1)
self.add_loss(K.mean(kl_batch), inputs=inputs)
return inputs
然后,您可以在计算平均值和对数变量后,在代码中添加此行:
z_mean , z_log_var = KLDivergenceLayer()([z_mean , z_log_var])
该层是将KL损失添加到最终损失中的身份层。那么你的最终损失可能就是你在上面使用的那个。
我发现这是Luis C. Tiao的帖子:https://tiao.io/post/tutorial-on-variational-autoencoders-with-a-concise-keras-implementation/