alf*_*lfa 20 c++ math neural-network softmax
我在神经网络的最后一层使用Softmax激活函数.但我在安全实现此功能时遇到问题.
一个天真的实现将是这个:
Vector y = mlp(x); // output of the neural network without softmax activation function
for(int f = 0; f < y.rows(); f++)
y(f) = exp(y(f));
y /= y.sum();
Run Code Online (Sandbox Code Playgroud)
对于> 100个隐藏节点,这不能很好地工作,因为y NaN在很多情况下(如果y(f)> 709,exp(y(f))将返回inf).我想出了这个版本:
Vector y = mlp(x); // output of the neural network without softmax activation function
for(int f = 0; f < y.rows(); f++)
y(f) = safeExp(y(f), y.rows());
y /= y.sum();
Run Code Online (Sandbox Code Playgroud)
在哪里safeExp定义为
double safeExp(double x, int div)
{
static const double maxX = std::log(std::numeric_limits<double>::max());
const double max = maxX / (double) div;
if(x > max)
x = max;
return std::exp(x);
}
Run Code Online (Sandbox Code Playgroud)
此函数限制exp的输入.在大多数情况下,这可以工作,但并非在所有情况下,我没有真正设法找出它在哪些情况下不起作用.当我在前一层中有800个隐藏的神经元时,它根本不起作用.
然而,即使这有效,我也会以某种方式"扭曲"人工神经网络的结果.您能想出任何其他方法来计算正确的解决方案吗?我可以使用任何C++库或技巧来计算此ANN的确切输出吗?
编辑: Itamar Katz提供的解决方案是:
Vector y = mlp(x); // output of the neural network without softmax activation function
double ymax = maximal component of y
for(int f = 0; f < y.rows(); f++)
y(f) = exp(y(f) - ymax);
y /= y.sum();
Run Code Online (Sandbox Code Playgroud)
它在数学上确实是一样的.然而,在实践中,由于浮点精度,一些小值变为0.我想知道为什么没有人在教科书中写下这些实现细节.
Ita*_*atz 13
首先去记录比例,即计算log(y)而不是y.分子的日志是微不足道的.为了计算分母的日志,您可以使用以下"技巧":http://lingpipe-blog.com/2009/06/25/log-sum-of-exponentials/
我知道它已经回答了,但无论如何我会在这里逐步发布.
把日志:
zj = wj . x + bj
oj = exp(zj)/sum_i{ exp(zi) }
log oj = zj - log sum_i{ exp(zi) }
Run Code Online (Sandbox Code Playgroud)
设m为max_i {zi}使用log-sum-exp技巧:
log oj = zj - log {sum_i { exp(zi + m - m)}}
= zj - log {sum_i { exp(m) exp(zi - m) }},
= zj - log {exp(m) sum_i {exp(zi - m)}}
= zj - m - log {sum_i { exp(zi - m)}}
Run Code Online (Sandbox Code Playgroud)
如果m远大于其他z_i,则术语exp(zi-m)可能遭受下溢,但这没关系,因为这意味着z_i与归一化后的softmax输出无关.最终结果是:
oj = exp (zj - m - log{sum_i{exp(zi-m)}})
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
12936 次 |
| 最近记录: |