生成式神经网络:求替代Softmax的输出和为1的归一化层
解决方案:自定义总和归一化层替代连续Softmax
嘿,完全懂你的需求——既要靠ReLU拿到真实的零值稀疏性,又要让输出总和为1,还得避开连续用Softmax导致的输出极端化问题对吧?
先说说为什么你原来的做法会出问题:第一次Softmax已经把输出压缩到0-1区间且总和为1了,接着用ReLU其实不会改变任何值(因为Softmax输出本来就非负),再套一次Softmax的话,会把原本就小的数值进一步压到几乎为0,大数值则被放大到接近1,直接导致输出极端化,完全背离了你想要保留稀疏性同时温和归一化的目标。
那该怎么解决?其实你需要的就是一个简单的总和归一化层——直接让每个输出元素除以所有输出的总和,这样既保留ReLU带来的真实零值,又能让输出总和为1,而且不会引入Softmax的指数运算带来的极端化问题。
下面是在TensorFlow/Keras里实现这个自定义层的代码:
from tensorflow.keras.layers import Layer import tensorflow as tf class SumNormalization(Layer): def __init__(self, epsilon=1e-8, **kwargs): self.epsilon = epsilon # 防止总和为0时除零错误 super().__init__(**kwargs) def call(self, inputs): # 计算最后一维的总和(假设你的输出是(batch_size, 200)) sum_total = tf.reduce_sum(inputs, axis=-1, keepdims=True) + self.epsilon # 每个元素除以总和实现归一化 return inputs / sum_total def get_config(self): # 保存层的配置,方便模型序列化 config = super().get_config() config['epsilon'] = self.epsilon return config
然后把你原来的代码改成这样就可以了:
outputs = Dense(200, activation='softmax', activity_regularizer=l1(1e-5))(x) outputs = Activation('relu')(outputs) # 得到真实的零值稀疏性 outputs = SumNormalization()(outputs) # 归一化到总和为1,完美保留零值
这个层的优势很明显:
- 完全保留ReLU后的真实零值,不会像Softmax那样把接近0的值变成非零
- 只是线性的除法操作,不会放大输出之间的差异,避免极端化
- 简单易懂,没有复杂的运算,训练时数值稳定性更好
如果你的输出总和有可能为0(比如ReLU把所有元素都变成0了),可以调整epsilon参数的大小,默认的1e-8已经足够应对绝大多数情况啦。
内容的提问来源于stack exchange,提问作者user7867665
相关产品推荐
相关产品推荐

