我正在尝试实现一个自动编码器,我想要一个二进制序列作为瓶颈层的输出,因为我想分别使用编码器和解码器。
以下是我的自动编码器的架构代码:
inputs_encoder = keras.Input(shape = 2**k)
x = Dense(units=S*2**(k), activation=activation)(inputs_encoder)
x = BatchNormalization(axis=1)(x)
outputs_encoder = Dense(units=N, activation='sigmoid')(x)
model_enc = keras.Model(inputs=inputs_encoder, outputs=outputs_encoder, name = 'encoder_model')
inputs_decoder = keras.Input(shape = N)
x = Dense(units=S * 2 ** (k), activation=activation)(inputs_decoder)
x = BatchNormalization(axis=1)(x)
outputs_decoder = Dense(units=2 ** k, activation='softmax')(x)
model_dec = keras.Model(inputs=inputs_decoder, outputs=outputs_decoder, name = 'decoder_model')
inputs_meta = keras.Input(shape = 2**k)
encoded_bits = model_enc(inputs=inputs_meta) #This is the output I'd like to be binary
decoded_sequence = model_dec(inputs=encoded_bits)
meta_model = keras.Model(inputs=inputs_meta, outputs=decoded_sequence, name = 'meta_model')
我尝试在sigmoid层之后使用函数tf.math.round(x)
,这会导致错误,因为它是一个不可微的函数。
然后,我用了一个技巧放"tf.stop_gradient(tf.math.round(x(-x(+x``",解决了梯度问题,但网络的准确性不好。
有更好的方法吗?
这看起来像是一个量化问题(如果您需要查找有关该主题的更多信息(。
我通常看到的处理方式是,在训练中跳过round
,只将其应用于评估和推理。这也很好,因为当你比较有和没有舍入步骤的模型性能时,它可以告诉你舍入(量化(造成了多少额外的损失。
需要考虑的一件事是,sigmoid会给你一个介于0和1之间的值,所以round会破坏大部分信号。通过保留更多的位,您可能能够从模型中获得更多。比如说,每个值保留3位,将sigmoid的结果乘以2**3 -1
,然后四舍五入,得到0到7之间的值。在解码器上,在将其输入网络之前,您必须除以2**3 -1
。显然,这需要在解码器和编码器之间传输更多的比特。然而,您可以牺牲嵌入的维度来保持大小不变(只有1/(2**3(个维度,以补偿每个值的3个比特(。这样可能会使模型更容易获得良好的性能。和往常一样,要找到正确的值,您需要进行一些超参数调整。