C 中的快速 2D 卷积

2024-03-15

我正在尝试用 Python 实现卷积神经网络。最初,我使用 scipy.signal 的 convolve2d 函数来进行卷积,但它有很多开销,而且用 C 实现我自己的算法并从 python 调用它会更快,因为我知道我的输入是什么样的。

我实现了2个功能:

  1. 将矩阵与不可分离核进行卷积
  2. 将矩阵与可分离的内核进行卷积(现在我假设 python 在将其传递到 C 之前进行排名检查和分割)

这些函数都没有填充,因为我需要降维。

不可分离的二维卷积

// a - 2D matrix (as a 1D array), w - kernel
double* conv2(double* a, double* w, double* result)
{
    register double acc;
    register int i; 
    register int j;
    register int k1, k2;
    register int l1, l2;
    register int t1, t2;

    for(i = 0; i < RESULT_DIM; i++) 
    {
        t1 = i * RESULT_DIM; // loop invariants
        for(j = 0; j < RESULT_DIM; j++) 
        {   
            acc = 0.0;
            for(k1 = FILTER_DIM - 1, k2 = 0; k1 >= 0; k1--, k2++)
            {
                t2 = k1 * FILTER_DIM;  // loop invariants
                for(l1 = FILTER_DIM - 1, l2 = 0; l1 >= 0; l1--, l2++)
                {
                    acc += w[t2 + l1] * a[(i + k2) * IMG_DIM + (j + l2)];
                }
            }
            result[t1 + j] = acc;
        }
    }

    return result;
}

可分离的二维卷积

// a - 2D matrix, w1, w2 - the separated 1D kernels
double* conv2sep(double* a, double* w1, double* w2, double* result)
{
    register double acc;
    register int i; 
    register int j;
    register int k1, k2;
    register int t;
    double* tmp = (double*)malloc(IMG_DIM * RESULT_DIM * sizeof(double));

    for(i = 0; i < RESULT_DIM; i++) // convolve with w1 
    {
        t = i * RESULT_DIM;
        for(j = 0; j < IMG_DIM; j++)
        {
            acc = 0.0;
            for(k1 = FILTER_DIM - 1, k2 = 0; k1 >= 0; k1--, k2++)
            {
                acc += w1[k1] * a[k2 * IMG_DIM + t + j];
            }
            tmp[t + j] = acc;
        }
    }

    for(i = 0; i < RESULT_DIM; i++) // convolve with w2
    {
        t = i * RESULT_DIM;
        for(j = 0; j < RESULT_DIM; j++)
        {
            acc = 0.0;
            for(k1 = FILTER_DIM - 1, k2 = 0; k1 >= 0; k1--, k2++)
            {
                acc += w2[k1] * tmp[t + (j + k2)];
            }

            result[t + j] = acc;
        }
    }

    free(tmp);
    return result;
}

使用 gcc -O3 标志进行编译并在 2.7GHz Intel i7 上进行测试,使用 4000x4000 矩阵和 5x5 内核,我分别得到(平均值为 5):

271.21900 ms
127.32000 ms

与 scipy.signal 的 convolve2d 相比,这仍然是一个相当大的改进,相同的操作大约需要 2 秒,但我需要更快的速度,因为我将调用这个函数数千次。目前无法将数据类型更改为浮点型,尽管这会带来相当大的加速。

有没有办法进一步优化这些算法?我可以应用任何缓存技巧或例程来加快速度吗?

任何建议,将不胜感激。


如果您仅在 x86 上运行,请考虑使用 SSE 或 AVX SIMD 优化。为了double数据吞吐量的提高将是适度的,但如果你可以切换到float那么使用 SSE 或许可以将性能提升 4 倍左右,而使用 AVX 则可以提升 8 倍左右。 StackOverflow 上已经有很多关于这个主题的问题和答案,您可以从中获得一些关于实现的想法。另外,还有许多可用的库,其中包括高性能 2D 卷积(过滤)例程,并且这些例程通常利用 SIMD 来提高性能,例如Intel 的 IPP(商业)或 OpenCV(免费)。

另一种可能性是利用多个核心 - 将图像分割成块并在其自己的线程中运行每个块。例如。如果您有 4 核 CPU,则将图像分成 4 个块。 (看pthreads http://linux.die.net/man/3/pthread_create).

如果您确实想完全优化此操作,您当然可以结合上述两种想法。


您可以将一些小的优化应用于当前的代码以及任何未来的实现(例如 SIMD):

  • 如果您的内核是对称(或奇对称)的,那么您可以通过添加(减去)对称输入值并执行一次乘法而不是两次乘法来减少运算数量

  • 对于可分离的情况,不要分配全帧临时缓冲区,而是考虑使用“条带挖掘”方法 - 分配一个较小的缓冲区,它是全宽的,但行数相对较少,然后在“条带”中处理图像,交替应用水平核和垂直核。这样做的优点是您拥有更加缓存友好的访问模式和更小的内存占用。


关于编码风格的一些评论:

  • the register关键字多年来一直是多余的,如果您尝试使用它,现代编译器会发出警告 - 放弃它可以节省一些噪音(和一些打字)

  • 铸造结果malloc在 C 中是不受欢迎的 - 它是多余且有潜在危险 https://stackoverflow.com/q/605845/253056.

  • 任意输入参数const(即只读)并使用restrict对于任何永远不能使用别名的参数(例如a and result) - 这不仅可以帮助避免编程错误(至少在以下情况下)const),但在某些情况下,它可以帮助编译器生成更好的优化代码(特别是在可能存在别名指针的情况下)。

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

C 中的快速 2D 卷积 的相关文章

  • 在 Python 中引发异常的正确方法是什么? [复制]

    这个问题在这里已经有答案了 这是简单的代码 import sys class EmptyArgs StandardError pass if name main The first way to raise an exception if
  • 在 C++ 中初始化指针

    可以在声明时将指针分配给值吗 像这样的东西 int p 1000 是的 您可以在声明时初始化指向值的指针 但是您不能这样做 int p 1000 是个地址运算符 并且您不能将其应用于常量 尽管如果可以 那会很有趣 尝试使用另一个变量 int
  • 如何在 tkinter 后台运行函数[重复]

    这个问题在这里已经有答案了 我是 GUI 编程新手 我想用 tkinter 编写一个 Python 程序 我想要它做的就是在后台运行一个可以通过 GUI 影响的简单函数 该函数从 0 计数到无穷大 直到按下按钮为止 至少这是我想要它做的 但
  • 使用 Popen 打开进程并获取 PID

    我正在开发一个漂亮的小功能 def startProcess name path Starts a process in the background and writes a PID file returns integer pid Ch
  • 如何在使用 Flask for Python 3 的同时使用 Bootstrap 4?

    我检查过 发现默认安装时 Flask Bootstrap 原生使用 Bootstrap 3 3 7 但实际上我想通过使用 Flask Bootstrap 包在我的项目中使用 Bootstrap 4 任何有关如何更新它或类似内容的帮助将不胜感
  • 使用 C# 和 .NET Core 在 AWS Cognito 用户池中进行用户管理

    如何使用 C 和 NET Core 3 x 管理 AWS Cognito 用户池中的用户 在文档中找不到有关它的任何内容 Attilio Gelosa 的原创文章 我写这篇文章是希望对其他人有帮助 我必须阅读一页又一页的文档 并从 AWS
  • Pandas 根据条件替换数据框值

    我有一个主数据框 df Colour Item Price Blue Car 40 Red Car 30 Green Truck 50 Green Bike 30 然后我有一个价格修正数据框 df pc Colour Item Price
  • 如何在Phone类库项目中添加ResourceDictionary并访问它

    我正在开发一个项目 其中我有一个引用图书馆项目的子项目 在我的库项目 电话类库 中 如何创建 ResourceDictionary xaml 其中我需要添加一些样式并在 xaml 文件和 cs 文件中使用它 我需要访问 xaml 文件中的
  • numpy 向量化而不是 for 循环

    我用 Python 写了一些代码 运行良好 但速度很慢 我认为是由于 for 循环 我希望可以使用 numpy 命令加速以下操作 让我定义目标 假设我有一个 2D numpy 数组all CMs尺寸row x col 例如考虑一个6x11数
  • 数据类和属性装饰器

    我一直在阅读 Python 3 7 的数据类 作为命名元组的替代品 我通常在必须将数据分组到结构中时使用它 我想知道数据类是否与属性装饰器兼容 以便为数据类的数据元素定义 getter 和 setter 函数 如果是这样 是否在某处进行了描
  • 从 SUDS 中的 SOAP 响应中提取 Cookie

    我必须使用具有多种服务的 API 所有这些都需要来自下面的身份验证的 JSESSION cookie 然而 当我调用下一个服务时 它不会保留 cookie 因此会拒绝它们 from suds client import Client url
  • model.predict() 返回类而不是概率

    Hello 我是第一次使用 Keras 我训练并保存了一个模型 作为 json 文件及其权重 该模型旨在将图像分为 3 个类别 我的编译方法 model compile loss categorical crossentropy optim
  • 将整数转换为特定格式的十六进制字符串

    我是 python 新手 有以下问题 我需要将整数转换为 6 个字节的十六进制字符串 例如 281473900746245 gt xFF xFF xBF xDE x16 x05 十六进制字符串的格式很重要 int 值的长度是可变的 格式 0
  • 如何通过 API Gateway 使用事件调用类型调用 Lambda 函数?

    文件说 默认情况下 Invoke API 采用 RequestResponse 调用类型 您可以选择通过将 Event 指定为 InitationType 来请求异步执行 因此 我可以发送到我的函数 python 的就是到处都是 Inspi
  • 如何正确地将十六进制转义添加到字符串文字中?

    当你有C语言的字符串时 你可以在里面直接添加十六进制代码 char str abcde a b c d e 0x00 char str2 abc x12 x34 a b c 0x12 0x34 0x00 这两个示例在内存中都有 6 个字节
  • 使texture2D在运行时/脚本Unity3D中可读[重复]

    这个问题在这里已经有答案了 我有一个插件 可以让我访问 Android 手机图库中的图片 这给了我一个Texture2D类型的纹理 然后我想使用 GetPixels 函数对其进行编辑 但默认情况下它未设置为可读 如何使纹理可读 以便我可以在
  • WPF DataGrid 选定项

    我有一个 DataGrid 用户可以通过在最后一行输入数据来添加项目 我还有一个按钮可以删除当前选定的项目 但是 当选择最后一行 空 用于添加新项目 时 最后选定的项目将保留在 SelectedItem 中 因此 如果我打开窗口 选择最后一
  • 如何在您的网站中连接两个人

    有一款名为 Verbosity 的游戏 这是一款有目的的游戏 位于此链接上www gwap com 在游戏中 他们随机连接两个玩家互相玩 游戏是玩家1应该向他的搭档 玩家2 描述一个单词 而玩家2应该猜测这个单词 我正在尝试建立一个网站来执
  • ASP.NET API:尚未为此 DbContext 配置数据库提供程序

    我正在尝试从我的 Net Core API 项目连接到 MySql 数据库 这是我的上下文类 public class MyContext DbContext public MyContext public MyContext DbCont
  • File.Move 的原子性

    我想将目录中的文件重命名为原子事务 该文件不会更改目录 该路径作为 NTFS 文件系统的 UNC 路径提供 可能位于服务器 03 或 08 上 File Move 对于这些目的来说是原子的吗 例如 它要么成功完成 要么失败 以使原始文件仍然

随机推荐

  • 即使其中一项承诺被拒绝,也不要让整个任务失败

    在 redux saga 中 如果我们想处理多个 Promise 我们可以使用all 这相当于Promise all yield all users map user gt call signUser user function signU
  • 使用 ProtoBuf-Net 反序列化嵌套动态类型时出现的问题

    我正在尝试使用 ProtoBuf Net r668 反序列化一个包含在 DynamicType true 的多层中的对象 使用旧版本的 ProtoBuf Net v1 它可以毫无问题地反序列化 但是 使用最新版本时 它会失败 ProtoBu
  • Android 启动画面图像尺寸适合所有设备

    我有一个全屏 PNG 我想在启动时显示 只有一个错误 我不知道 每个可绘制文件夹中放置的大小是多少 ldpi mdpi hdpi and xhdpi 我的应用程序应该在所有手机和平板电脑上运行良好且美观 我应该创建什么尺寸 以像素为单位 才
  • 从任务栏隐藏窗口

    我正在尝试开发自己的应用程序 用于在桌面上放置笔记 类似于 Windows 操作系统下的粘滞便笺 一切工作正常 但我仍然面临一个问题 因为我希望应用程序尽可能 最小 所以我希望它不要出现在任务栏中 这样就不会打扰用户 最终 我希望它出现在系
  • SQL XML 导入:XQuery [value()]:预期为“)”

    我正在尝试将数据从 XML 数据插入到 SQL 中的表中 XML 文件是从 Microsoft Excel 创建的 它具有以下标题
  • 用 C 语言制作一个没有框架的 GUI

    我正在学习 C 编程语言的 C 我刚刚完成第 2 章或第 2 单元 我浏览到最后发现没有任何关于如何创建 GUI 的内容 并且从我查找的内容来看 看来我必须使用一个框架 但我讨厌这个想法 在没有框架的情况下如何创建 GUI 这些框架到底是如
  • 随机图像显示[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 输出多个图像时最简单的代码或方法是什
  • python sax错误“文档元素后有垃圾”

    我使用 python sax 来解析 xml 文件 xml文件实际上是多个xml文件的组合 看起来如下
  • 如何使用 Ghostscript 删除 PDF 中的重复对象?

    使用命令行 Ghostscript 是否可以删除 PDF 中重复的嵌入对象 图像 并将其替换为单个实例 我有一个 200 多页的 PDF 每页上都有背景图像和一些较小的徽标 该文件非常大 因为完全相同的背景图像和徽标二进制文件嵌入在每个单独
  • 如何在 gulp 4 上将 gulpfile 任务分割成不同的文件,而无需任何像 gulp-hub 这样的包?

    我正在尝试将 gulpfile 任务拆分为不同的文件 我之前做过并将其添加到主 gulpfile 中 只需添加require path taskName 但这在 gulp 4 中不起作用 这是我的styles js file var gul
  • 是否可以在 Solidity 智能合约创建上预留一个地址用于收税?

    我正在使用 Solidity 编程语言 并尝试实现一个合约 即每笔交易都会扣除税费 并且该税费应该转移到正在创建的合约的某个特定地址 那可能吗 是的 这是可能的 所有以太坊代币标准 ERC 20 ERC 721 仅定义一个接口和很少的其他点
  • 如何在.net中将数字格式化为S9(5)V99 ascii

    我一直在寻找 s9 5 v99 但得到了不同的信息 而且不太清楚 有人可以展示如何转换或转换公式吗 谢谢 您在这里向我们展示的是 这PICTURECOBOL 数据声明的子句部分 COBOL 数据声明有点奇怪 需要一些时间来适应 这是一个介绍
  • Facebook API - 减少您请求的数据量,然后重试 1 行请求

    我的广告洞察请求的逻辑如下 如果 Facebook 要求我减少所请求的数据量 我会将日期范围减半 如果日期范围相同 我会减半limit 到了我发送此请求的地步 https graph facebook com v3 2 https grap
  • 使用 ccTouchesMoved 方法移动 CCCamera? (cocos2d、iPhone)

    所以我得到了这个工作 void ccTouchesMoved NSSet touches withEvent UIEvent event UITouch myTouch touches anyObject CGPoint location
  • 双向数据绑定不更新 UI

    我试图理解为什么设置值不会自动刷新用户界面 如果我调用 binding setItem UI 就会刷新 我知道绑定对象包含更新的值 但在设置 item name 和 item checked 后 UI 没有刷新 我究竟做错了什么 我需要每次
  • 如何在flutter中显示全屏图像

    有什么办法可以显示全屏图像吗 var imagejadwal new Image network https firebasestorage googleapis com v0 b c smp bruder appspot com o fo
  • yii:使用查询生成器选择总和

    我尝试执行一个简单的查询 如下所示 tot Yii app gt db gt createCommand gt select sum field gt from products gt where id id gt queryRow 但 t
  • Gradle 依赖项 - 最新快照

    我有一个 gradle 多项目构建 在一个项目中 我定义了对其他 JAR 的一些依赖项 并使用 始终依赖于 JAR 的最新版本 例如 runtime group com app name core version 这非常有效 每当我重新构建
  • jQuery:.ready() 和 .ajaxComplete

    我希望我的 JS 的某些部分在文档准备好或 ajax 查询完成时初始化像这样的东西 if document ready or document ajaxComplete do something 这样的条件可以写吗 我该如何做才正确呢 你可
  • C 中的快速 2D 卷积

    我正在尝试用 Python 实现卷积神经网络 最初 我使用 scipy signal 的 convolve2d 函数来进行卷积 但它有很多开销 而且用 C 实现我自己的算法并从 python 调用它会更快 因为我知道我的输入是什么样的 我实