为什么 tanh 在我的机器上比 exp 快?

2023-12-24

这个问题源于一个单独的问题 https://stackoverflow.com/questions/43033593/why-is-using-tanh-definition-of-logistic-sigmoid-faster-than-scipys-expit,结果证明它有一些明显的机器特定的怪癖。当我运行下面列出的 C++ 代码来记录之间的计时差异时tanh and exp,我看到以下结果:

tanh: 5.22203
exp: 14.9393

tanh运行速度约为 3 倍exp。考虑到数学定义,这有点令人惊讶tanh(并且不了解所实现的算法定义)。

更重要的是,这种情况发生在我的笔记本电脑上(Ubuntu 16.04,Intel Core i7-3517U CPU @ 1.90GHz × 4),但不会发生在我的台式机上(相同的操作系统,目前不确定CPU规格)。

我编译了下面的代码g++。上述时间没有编译器优化,尽管如果我使用的话趋势仍然存在-On对于每个n。我也摆弄过a and b值来查看正在评估的值范围是否产生影响。这似乎并不重要。

什么会导致tanhexp在不同的机器上?

#include <iostream>
#include <cmath>
#include <ctime>

using namespace std;

int main() {
    double a = -5;
    double b =  5;
    int N =  10001;
    double x[10001];
    double y[10001];
    double h = (b-a) / (N-1);

    clock_t begin, end;

    for(int i=0; i < N; i++)
        x[i] = a + i*h;

    begin = clock();

    for(int i=0; i < N; i++)
        for(int j=0; j < N; j++)
            y[i] = tanh(x[i]);

    end = clock();

    cout << "tanh: " << double(end - begin) / CLOCKS_PER_SEC << "\n";

    begin = clock();

    for(int i=0; i < N; i++)
        for(int j=0; j < N; j++)
            y[i] = exp(x[i]);

    end = clock();

    cout << "exp: " << double(end - begin) / CLOCKS_PER_SEC << "\n";


    return 0;
}

编辑:一些汇编输出

这是输出 https://pastebin.com/6BD7nzsk当我编译下面的简化代码时g++ -g -O -Wa,-aslh nothing2.cpp > stuff.txt.

#include <cmath>

int main() {
    double x = 0.0;
    double y,z;
    y = tanh(x);
    z = exp(x);
    return 0;
}

编辑:另一个更新

Assume nothing2.cpp包含先前编辑中的简化代码。我跑:

g++ -o nothing2.so -shared -fPIC nothing2.cpp
objdump -d nothing2.so > stuff.txt

这是内容stuff.txt https://pastebin.com/DvEqrNn0


有多种可能的解释,适用于您的情况的解释取决于您使用的平台或具体使用的数学库。但一种可能的解释是:

首先计算tanh不依赖于标准定义tanh相反,人们用以下方式表达它:exp(-2*x) or expm1(2*x)这意味着只需计算一个指数,这可能是一项繁重的操作(此外还有除法和一些加法)。

第二个可能是技巧是,对于较大的值x这将减少到(exp(2*x)-1)/(exp(2*x)+1) = 1 - 2/(expm1(2*x)+2)。这里的优点是,由于第二项很小,因此不必计算到相同的相对精度即可获得相同的最终精度。这意味着不需要的expm1这里和一般情况一样。

也适用于较小的值x有一个类似的技巧将其重写为(1-exp(-2*x))/(1+exp(-2*x)) = - 1/ (1 + 2/(expm1(-2*x)+2)这再次意味着我们可以利用这个因素exp(-2*x)很大并且不必以相同的精度进行计算。但是,您不必以这种方式实际计算它,您可以使用表达式expm1(-2*x)/(2+expm1(-2*x))相反,具有相同的精度要求expm1.

此外,还有其他优化可用于更大的值x这是不可能的exp基本同源。与大x因素expm1(2*x)将变得如此之大,以至于我们可以简单地完全丢弃它,而对于exp我们仍然需要计算它(即使是大的负数也是如此)x)。对于这些值tanh将立即决定1 while exp必须计算。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 tanh 在我的机器上比 exp 快? 的相关文章

随机推荐

  • iOS10 UNNotificationServiceExtension 未调用

    我正在实施新的 iOS10 扩展以使用丰富的通知 我试图在推送通知上测试它 但不起作用 我只是收到一个简单的通知 并且没有经历扩展 我做了官方网站和其他一些地方指定的所有操作 我的应用程序已启动并运行 并带有推送通知和正确的配置文件 我向我
  • 同步 Mercurial 存储库集合

    我在网络共享上有一组 Mercurial 存储库 为了启用离线工作 我需要在我的笔记本电脑上保存该集合的本地副本 以及在在线时同步这两个集合的简单方法 为此 我编写了一个快速脚本 自动将每个本地存储库与相应的远程存储库同步 推和拉 但它缺少
  • 清理本机反应项目

    如何清理反应本机项目 有什么方法可以像清理 xcode 项目一样清理 React Native 项目吗 任何帮助将不胜感激 一个反应原生项目是关于一个Xcode项目和一个安卓项目 对于纯js代码 不需要clean 所以 你需要的是 清理 X
  • 使用 Javascript 在帧之间传递数据

    我已经设置了一个简单的例子http ryanmalin co uk frames http ryanmalin co uk frames 如果您按 添加 它将把左侧框架中的表单数据粘贴到右侧框架中 当我将正确的框架 URL 更改为另一个域的
  • 在 JAX-RS Provider 中使用 @Context 向 CDI bean 提供上下文信息

    我有一些网络服务 JAX RS WildFly 9 Resteasy RequestScoped public class SomeService operations 现在我想提取上下文信息 例如用户代理 这可以使用 Context pr
  • jQuery - 从所选选项获取自定义属性

    鉴于以下情况
  • 使用批处理脚本附加文件夹名称并加 1

    我对批处理脚本的这一部分有点陌生 但我想做的是附加一堆文件夹名称并递增 1 同时尊重时间戳 即最新的文件夹在前 最旧的文件夹在最后 我看过其他脚本没有效果 Before Folder 1 Folder 2 Folder 3 Folder 4
  • 仅在时间序列中填充有限数量的 NA

    有什么办法可以让我们填补NAs in a zoo or xts数量有限的对象NA向前 换句话说就像填充NA最多连续 3 个NAs 然后保留NA从第 4 个值开始直到有效数字 像这样的东西 library zoo x lt zoo 1 20
  • 自动布局 UILabels

    我有三个UILabels按照我的习惯UITableViewCell 这可能是一些UILabels将是空的 label text UITableViewCell tableView UITableView tableView cellForR
  • 在 R 中为逻辑回归模型绘制多条 ROC 曲线

    我有一个逻辑回归模型 使用 R 作为 fit6 lt glm formula survived ascore gini failed data records family binomial summary fit6 我在用着pROC用于绘
  • Javascript通知解决方案库:桌面、声音、弹出、标题栏闪烁等

    是否有任何 Javascript 库支持在长时间运行的操作 例如上传 结束时发出通知 通知最好是通用的 这样即使某些技术不起作用 例如桌面通知 浏览器仍然能够引起注意 声音铃声 桌面通知 Chrome Stackoverflow com 风
  • 在Python中解析JSON时出现各种错误

    尝试从需要登录的 url 解析 json 在这里包括我的所有代码 因为我不确定错误在哪里 try import simplejson as json except ImportError import json import urllib2
  • 使用 .after() 添加 html 关闭和打开标签

    我试图通过找到列表的中间点并添加将无序列表分成两列 ul 在那之后 这可能是完全错误的方法 但这是我的想法 我的js看起来像这样 container ul each function var total this children leng
  • 有没有办法在 Racket 中查看 lambda 的主体?

    假设我有这段代码 lang racket define a x x y y z w w z 我凭直觉知道这个 lambda 表达式 扩展地 等于 z z 我的问题是是否有办法打印出正文a如果我想看看 Racket 在内部简化了多少功能 更多
  • 如何从数组元素中删除字符?

    我有一个像这样的数组 ee 3 4 22 22 我想删除逗号 或将其替换为 34使数组看起来像这样 ee 3 4 22 22 or this ee 3 4 34 22 34 22 34 原因是我试图将该数组从 Ruby 传递到 JavaSc
  • Asp Core 发布时错误的程序集重定向

    使用 Visual Studio 发布我的 ASP Core 项目时 config文件与我的可执行文件一起创建 The config包括几个bindingRedirect像这样
  • NIO SocketChannel 读取超时? [复制]

    这个问题在这里已经有答案了 如果连接建立后一段时间内没有收到数据 设置超时关闭 NIO SocketChannel 的最佳方法是什么 Either 您正在使用一个Selector 在这种情况下 您可以选择一个可以使用的超时 如果超时 sel
  • 如何手动创建 Apache Windows 服务

    我在尝试安装另一个 Apache Web 服务器时不小心删除了 Apache Windows 服务 有谁知道如何从 cmd 创建另一个 Apache Windows 服务 我尝试了 sc create 但最后缺少一个脚本 例如 k star
  • @PreAuthorize 和 hasPermission() 执行代码两次

    我想使用 PreAuthorize Spring 注释来控制应用程序中的访问 问题是 我有很多条件不取决于请求参数 而是取决于数据库实体 概述 我有一个Route实体 具有User owner场地 您可以删除Route仅当您是所有者时 我已
  • 为什么 tanh 在我的机器上比 exp 快?

    这个问题源于一个单独的问题 https stackoverflow com questions 43033593 why is using tanh definition of logistic sigmoid faster than sc