softplus的逆的数值稳定计算方法

参考内容: Add softplus inverse #72759

什么是softplus函数?

根据Softplus的pytorch实现1 ,Softplus是ReLU函数2的近似,用于保证输出总是为正。其公式和图像如下:

Softplus ⁡ ( x ) = 1 β ∗ log ⁡ ( 1 + exp ⁡ ( β ∗ x ) ) \operatorname{Softplus}(x)=\frac{1}{\beta} * \log (1+\exp (\beta * x)) Softplus(x)=β1log(1+exp(βx))

在这里插入图片描述

softplus函数的逆

我们很容易知道,对于 β = 1 \beta=1 β=1的softplus函数逆是:
y = log ⁡ ( e x − 1 ) y=\log (e^x-1) y=log(ex

<think>我们讨论的是适合整数离散数值的激活函数。在深度学习中,激活函数通常用于神经网络的隐藏层或输出层,引入非线性。但是,当处理离散整数输出(如分类问题中的类别标签)时,我们通常会在输出层使用特定的激活函数,并将网络的输出转换为离散值。 对于整数离散数值,常见的场景包括: 1. 分类问题:输出是离散的类别标签(如0,1,2,...)。此时,对于二分类,我们常用sigmoid激活函数(输出在0到1之间)然后通过阈值(如0.5)转换为0或1;对于多分类,我们使用softmax激活函数得到每个类别的概率,然后取最大概率的类别作为预测的离散标签。 2. 回归问题但目标是整数:例如预测某个物品的数量(非负整数)。此时,我们可以使用线性激活函数(即无激活函数)然后四舍五入到最近的整数,但这样可能不够好。另一种方法是使用ReLU(因为数量非负)然后取整,但ReLU的输出是连续的,取整会带来不可导的问题。所以,对于计数问题,有更合适的方法,比如使用泊松分布(输出层用指数激活函数)或者负二项分布等。 然而,问题中并没有明确是分类还是回归,所以我们需要区分。 常见的激活函数及其适用场景: 1. Sigmoid: 将实数映射到(0,1)区间,适用于二分类问题(输出一个概率)。然后通过阈值转换为0或1。 2. Softmax: 将实数向量映射为概率分布(每个元素在0到1之间,且和为1),适用于多分类问题。然后取argmax得到离散类别。 3. ReLU: 常用于隐藏层,输出为非负实数。对于整数离散输出,如果目标是非负整数,可以在输出层使用ReLU然后四舍五入,但这不是标准的做法,因为四舍五入操作不可导,无法训练。因此,对于回归到非负整数,通常使用其他损失函数(如泊松损失)和对应的输出激活函数(如指数函数,因为泊松分布的参数是正的)。 4. 线性激活函数:即无激活函数,输出可以是任意实数。如果目标是整数,可以在输出后取整,但同样有不可导的问题,且可能效果不佳。 对于整数离散数值的回归问题(比如预测计数),一种常见做法是使用泊松回归。在神经网络中,我们可以在输出层使用指数激活函数(因为泊松分布的参数λ必须为正),然后使用泊松损失函数(即负对数似然)。这样,模型输出的预测值是一个正数,然后我们取整(或者直接使用连续值作为λ参数,在预测时取整或取期望)得到离散的整数。 另一种方法是使用softmax来预测每个整数值的概率(但整数值范围很大时,这种方法不可行,因为类别太多)。 因此,根据问题类型,我们可以选择: 分类问题(类别有限): - 二分类:sigmoid + 阈值 - 多分类:softmax + argmax 回归问题(输出为整数,特别是计数): - 使用指数激活函数(确保输出为正)并配合泊松损失函数(或者负二项分布损失函数等)。 - 或者,将问题视为分类问题,如果整数的范围是有限且不太大的话。 下面给出两个例子: 1. 二分类问题(输出0或1)的神经网络输出层: 激活函数:sigmoid 预测:如果输出>=0.5则预测为1,否则为0。 2. 计数问题(非负整数)的神经网络输出层: 激活函数:指数函数(exponential)或softplus(保证为正,但指数更符合泊松分布参数的意义) 损失函数:泊松损失(Poisson loss) 示例代码(使用Keras): 二分类: ```python from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense model = Sequential() model.add(Dense(32, activation='relu', input_dim=100)) model.add(Dense(1, activation='sigmoid')) # 输出层使用sigmoid model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['accuracy']) ``` 计数回归(泊松): ```python from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense model = Sequential() model.add(Dense(32, activation='relu', input_dim=100)) model.add(Dense(1, activation='exponential')) # 输出层使用指数激活函数,确保输出为正 model.compile(optimizer='rmsprop', loss='poisson') # 使用泊松损失 ``` 注意:泊松损失在Keras中为'poisson',它计算的是: loss = y_true * log(y_pred) - y_pred # 注意这是负对数似然的一部分,但Keras会最小化损失,所以使用负对数似然的相反数?实际上Keras的poisson损失定义为:y_pred - y_true * log(y_pred),然后对所有元素求和。但根据文档,它是Poisson分布的负对数似然。 预测时,我们可以使用: predictions = model.predict(x_test) # 因为泊松分布的输出是连续的(表示λ),我们可以四舍五入取整 integer_predictions = np.round(predictions).astype(int) 但是,泊松分布假设数据符合泊松分布(即方差等于均值),如果数据存在过离散(方差大于均值),则负二项分布更合适。不过Keras没有内置负二项损失,需要自定义。 另一种方法:将整数回归视为分类问题(当整数范围较小时)。例如,预测0到9的整数,我们可以构建10个类别的多分类模型。 总结: - 分类问题:使用sigmoid(二分类)或softmax(多分类)将网络输出转换为概率,再通过阈值或argmax得到离散整数标签。 - 回归问题(整数):使用指数激活函数(或其他保证输出为正的激活函数)配合泊松损失,预测时取整。或者,如果整数范围小,可以当作分类问题。 注意:在隐藏层,我们通常使用ReLU、tanh等激活函数,但输出层需要根据具体任务选择。 因此,回答“适合整数离散数值的激活函数”需要根据具体任务来定。 如果问题中的整数离散数值是分类标签,那么输出层的激活函数就是sigmoid(二分类)或softmax(多分类)。如果问题中的整数离散数值是回归目标(如计数),那么输出层的激活函数可以是exponential(指数)或softplus(但泊松回归常用指数)。 下面给出一个自定义的softplus激活函数(因为Keras没有内置exponential,但我们可以用tf.exp实现指数激活函数,或者使用softplus作为替代,因为softplus也可以保证输出为正,且更平滑)?实际上,Keras有exponential激活函数,即`tf.keras.activations.exponential`。 在Keras中,我们可以这样使用指数激活函数: 在Dense层中指定`activation=tf.exp` 或者 `activation='exponential'`(如果Keras版本支持的话)或者自定义。 自定义指数激活函数: ```python import tensorflow as tf def exponential_activation(x): return tf.exp(x) # 然后在输出层使用 model.add(Dense(1, activation=exponential_activation)) ``` 但注意:指数激活函数可能导致数值稳定(当输入很大时,输出会非常大),因此需要确保网络输出不会太大。另一种选择是使用softplus:`activation='softplus'`,因为softplus是ReLU的平滑版本,且输出为正,而且增长比指数慢,数值稳定。 所以,对于计数问题,也可以使用softplus激活函数。 结论: 根据任务类型选择输出层的激活函数: - 二分类:sigmoid - 多分类:softmax - 计数回归:exponential 或 softplus 注意:这些激活函数用于输出层,隐藏层通常使用ReLU等。 最后,我们给出一个使用softplus激活函数处理计数问题的例子(因为数值稳定性更好): ```python model = Sequential() model.add(Dense(32, activation='relu', input_dim=100)) model.add(Dense(1, activation='softplus')) # 输出层使用softplus model.compile(optimizer='rmsprop', loss='poisson') ``` 预测时同样取整。 因此,回答用户的问题:适合整数离散数值的激活函数取决于任务,常见的有sigmoid(二分类)、softmax(多分类)和exponential/softplus(计数回归)。 注意:在分类问题中,我们得到的离散值是通过激活函数输出的概率再经过阈值或argmax得到的,而激活函数本身输出连续值(概率)。在回归问题中,激活函数输出连续值,我们通过取整得到离散值。 所以,严格来说,激活函数输出的是连续值,但我们可以通过后处理得到离散整数。 如果问题要求激活函数直接输出整数,那是不可能的,因为激活函数通常是连续的(除了阶跃函数,但阶跃函数不可导,不用于神经网络训练)。我们只能通过后处理(如阈值、取整)得到整数。 因此,我们通常说的“适合整数离散数值的激活函数”实际上是指:该激活函数的输出可以方便地转换为离散整数值,并且其数学性质适合该任务(如二分类使用sigmoid配合交叉熵损失)。 下面,我们给出一个使用softmax处理多分类问题的代码示例(假设有5个类别,标签为0,1,2,3,4): ```python model = Sequential() model.add(Dense(32, activation='relu', input_dim=100)) model.add(Dense(5, activation='softmax')) # 输出5个类别的概率 model.compile(optimizer='rmsprop', loss='categorical_crossentropy', # 如果标签是one-hot编码 metrics=['accuracy']) ``` 训练时,标签需要是one-hot编码,或者使用稀疏交叉熵(sparse_categorical_crossentropy)如果标签是整数形式(0到4): ```python model.compile(optimizer='rmsprop', loss='sparse_categorical_crossentropy', metrics=['accuracy']) ``` 预测时,使用: proba = model.predict(x_test) y_pred = np.argmax(proba, axis=1) # 得到0,1,2,3,4的整数预测 所以,对于多分类问题,输出层使用softmax激活函数,然后通过argmax得到离散整数(类别标签)。 综上所述,我们根据任务类型选择激活函数。 §§相关问题§§: 1. 在二分类问题中,除了sigmoid激活函数,还有哪些激活函数可以用在输出层? 2. 对于多分类问题,为什么使用softmax激活函数? 3. 在计数问题中,使用指数激活函数和softplus激活函数有什么区别? 4. 在输出为整数的回归问题中,除了泊松回归,还有哪些方法?</think>### 适合整数离散数值的激活函数 在神经网络中,处理整数离散数值(如分类标签、计数数据等)时,输出层需要特殊的激活函数将连续输出映射到离散空间。以下是几种常用方案: --- #### 1. **Softmax 激活函数(多分类问题)** 适用于多分类任务,将输出转换为概率分布,通过 `argmax` 获取离散整数标签。 ```python import torch import torch.nn as nn # 模型定义(输出层使用Softmax) class Classifier(nn.Module): def __init__(self, input_dim, num_classes): super().__init__() self.fc = nn.Linear(input_dim, num_classes) def forward(self, x): x = self.fc(x) return nn.functional.softmax(x, dim=1) # 输出概率分布 # 示例:预测离散标签 model = Classifier(input_dim=10, num_classes=3) inputs = torch.randn(2, 10) # 2个样本,10维特征 probs = model(inputs) # 输出概率分布 [0.2, 0.3, 0.5] pred_labels = torch.argmax(probs, dim=1) # 获取离散标签(如 [2]) ``` **关键点**: - 输出层维度 = 离散类别数量(如 3 类) - `argmax` 将概率分布转为离散整数(0, 1, 2...) - 损失函数:交叉熵损失 `nn.CrossEntropyLoss()` --- #### 2. **Sigmoid 激活函数(二分类/多标签)** 适用于二分类或多标签任务,通过阈值(如 0.5)将连续输出转为 0/1。 ```python # 二分类场景 model = nn.Sequential( nn.Linear(10, 1), nn.Sigmoid() # 输出范围 [0, 1] ) output = model(inputs) # 连续值(如 0.7) binary_pred = (output > 0.5).float() # 离散化为 0 或 1 # 多标签场景(如 5 个标签) model = nn.Sequential( nn.Linear(10, 5), nn.Sigmoid() # 每个输出独立激活 ) probs = model(inputs) # 5个独立概率 [0.1, 0.9, 0.4, ...] multi_label_pred = (probs > 0.5).int() # 离散化 [0,1,0,...] ``` **关键点**: - 二分类:单节点输出 + Sigmoid - 多标签:多节点输出 + Sigmoid(每个节点独立判断) --- #### 3. **直接整数化(计数问题)** 适用于回归到整数值(如物品计数),使用无界激活函数后取整。 ```python # 预测计数值(如商品库存) model = nn.Sequential( nn.Linear(10, 1), nn.ReLU() # 确保输出非负 ) output = model(inputs) # 连续值(如 7.3) int_pred = torch.round(output).int() # 四舍五入为整数 ``` **替代方案**: - **泊松损失**:配合指数激活函数,直接建模计数分布 ```python output = nn.Linear(10, 1)(inputs) poisson_loss = torch.exp(output) - targets * output # 泊松负对数似然 ``` --- #### 4. **Gumbel-Softmax(可微离散化)** 在训练中生成离散样本,同时保持梯度可传播。 ```python def gumbel_softmax(logits, tau=1.0, hard=False): gumbels = -torch.empty_like(logits).exponential_().log() # Gumbel噪声 y = logits + gumbels y = nn.functional.softmax(y / tau, dim=-1) if hard: y_hard = torch.zeros_like(y).scatter_(-1, y.argmax(dim=-1, keepdim=True), 1.0) y = (y_hard - y).detach() + y # 直通估计器 return y # 使用示例 logits = torch.tensor([[1.0, 2.0, 3.0]]) discrete_sample = gumbel_softmax(logits, tau=0.5, hard=True) # 输出 one-hot 向量 ``` **关键点**: - `tau`(温度参数)控制离散程度 - `hard=True` 时输出真实 one-hot,但梯度通过直通估计器传播 --- ### 选择建议 | 场景 | 激活函数 | 输出处理 | 损失函数 | |---------------------|---------------|------------------|----------------------| | 多分类(单标签) | Softmax | `argmax` | 交叉熵损失 | | 多标签分类 | Sigmoid | 阈值比较(如0.5)| 二元交叉熵损失 | | 计数/整数回归 | ReLU/指数函数 | 四舍五入 | MSE/泊松损失 | | 可微离散采样 | Gumbel-Softmax| 直接输出离散值 | 自定义损失 | ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值