用 Cython 加快 Python 循环速度

本文翻译自该博客
Cython 是 Python 语言到 C 语言的翻译器, 它能让你利用 Python 类似的语法达到接近 C 语言的运行速度。

本文介绍了如何用 Cython 来对单一包含紧凑循环(”tight loops”)的 Python 函数进行加速。在后续的文章中将会介绍关于 Cython 更复杂的应用,例如包含各种函数和类的情况。

什么时候该使用 Cython

你可以选择很多种方案来提升自己 Python 代码的运行速度,各种方案的具体对比请参考 quantecon。当然,你也可以选择另一种更快的语言来实现自己的项目,比如 Julia 或者干脆横下心来用 C 语言。

Cython 静态编译并不是什么前沿技术,这是一项很成熟而且有良好文档支持的技术,能够应付复杂的大型项目。很多 Python 科学计算库后台采用了 Cython 代码,例如 pandas 和 scikit-learn

例子

我们这里的例程实现了一种径向基函数的近似计算。

Python 循环

下面是对上述函数的一个最初版本的 Python 实现。

from math import expimport numpy as npdef rbf_network(X, beta, theta):N = X.shape[0]D = X.shape[1]Y = np.zeros(N)for i in range(N):for j in range(N):r = 0for d in range(D):r += (X[j,d]-X[i,d])**2r = r**0.5Y[i] += beta[j]*exp(-(r*theta)**2)return Yreturn Y

接下来生成一些数据:

import numpy as np
D = 5
N = 1000
X = np.array([np.random.rand(D) for d in range(N)])
beta = np.random.rand(N)
theta = 10

在 IPython 中测算运行时间

%timeit rbf_network(X, beta, theta) # 5.15 s per loop

果然这些 Python 循环很慢!

1 loop, best of 3: 5.46 s per loop

scipy.interpolate.Rbf

这种情况下,我们幸运地找到了基于 numpy 的 RBF 实现。

from scipy.interpolate import Rbf
rbf = Rbf(X[:,0],X[:,1],X[:,2],X[:,3],X[:,4], np.random.rand(N))
Xtuple = tuple([X[:,i] for i in range(D)])
%timeit rbf(Xtuple) #336 ms per loop

现在好多了!但是如果我们想把程序运行得快一点,但却找不到可用的函数库呢?

1 loop, best of 3: 342 ms per loop

Cython

我们在文件 fastloop.pyx 中实现 Cython 版本的代码,其内容如下

from math import exp
import numpy as np
def rbf_network(double[:, :] X, double[:] beta, double theta):cdef int N = X.shape[0]cdef int D = X.shape[1]cdef double[:] Y = np.zeros(N)cdef int i, j, dcdef double r = 0for i in range(N):for j in range(N):r = 0for d in range(D):r += (X[j, d]-X[i, d])**2r = r**0.5Y[i] += beta[j] * exp(-(r*theta)**2)return Y

目前为止我们做的工作仅仅是在变量名前面增加了一些类型声明。对局部变量,我们采用 cdef 关键字。对 array 数组,我们采用 ‘memoryviews’ 来接受 numpy 数组输入。

值得注意的是,在 *.pyx 文件中,你没有必要对变量进行声明,任何没有声明类型的变量都会留在 Python 中,而不会被翻译为 C 类型。

为了编译上面的 fastloop.pyx 文件,我们需要写一个 setup.py 脚本,内容如下所示

from distutils.core import setupfrom Cython.Build import cythonizesetup(name='fastloop', ext_modules=cythonize('fastloop.pyx'),)

然后,我们在 terminal 中对 fastloop.pyx 进行编译,命令如下:

python setup.py build_ext --inplace

这个命令会生成 C 代码文件 fastloop.c 和一个编译好的 Python 库文件 fastloop.so

然后我们对这个库文件进行测试

from fastloop import rbf_network
%timeit rbf_network(X, beta, theta) # 87.3 ms per loop
10 loops, best of 3: 84 ms per loop

果然快了很多,但是我们还有提升空间。Cython 中有很多提升性能的小技巧。下面将介绍第一个,如果我们在 terminal 中输入

cython fastloop.pyx -a

我们将生成一个 fastloop.html 文件,我们在浏览器中打开它。如下图所示

黄色高亮的语句仍然在使用 Python 运行,导致程序变慢。我们优化的目标是避免黄色高亮语句,尤其是在循环中。

我们的第一个问题是依旧在使用 Python 版本的指数函数,应该把它替换成 C 版本的。 math.h 中的大多数函数都包含在了 Cython 的 libc 库中,所以只需要用下面的语句替换 from math import exp

from libc.math import exp

接下来我们需要增加一些编译指令(compiler directives),最简单的方法是将下面的这行增加到 fastloop.pyx 文件头部

#cython: boundscheck=False, wraparound=False, nonecheck=False

通过把这些检测关掉,一旦程序出错,你只能得到段错误的提示,而不是像 python 中那种特别详细的信息,因此,最好是先把代码的错误排除干净,再添加该行。

接下来我们可以考虑修改编译器参数(这些属于 C 语言的技巧)。当我们用 gcc 时,最重要的编译选项是 -ffast-math。在我有限的经验中,这可以大大提高程序速度,而不损失可靠性。为了实现这个改变,我们需要修改 setup.py 文件。

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
ext_modules=[ Extension("fastloop",["fastloop.pyx"],libraries=["m"],extra_compile_args=["-ffast-math"])]setup(name='fastloop', cmdclass={"build_ext": build_ext},ext_modules=ext_modules)

现在再次运行 cython fastloop.pyx -a,我们看到循环中的语句已经不是用 Python 运行的了:

循环之外的黄色语句在这里对程序运行速度没有太大影响(如果需要在循环中多次调用这个函数,那么将会影响速度)。

我们可以重新编译程序,并测速

from fastloop import rbf_network%timeit rbf_network(X, beta, theta) # 21.7 ms per loop
10 loops, best of 3: 22.4 ms per loop

转载自:https://charlesnord.github.io/2017/03/11/cython-tuto/

Cython 入门教程相关推荐

  1. 【CV】Pytorch一小时入门教程-代码详解

    目录 一.关键部分代码分解 1.定义网络 2.损失函数(代价函数) 3.更新权值 二.训练完整的分类器 1.数据处理 2. 训练模型(代码详解) CPU训练 GPU训练 CPU版本与GPU版本代码区别 ...

  2. python 三分钟入门_Cython 三分钟入门教程

    作者:perrygeo 译者:赖勇浩(http://laiyonghao.com) 原文:http://www.perrygeo.net/wordpress/?p=116 我最喜欢的是Python,它 ...

  3. Kafka入门教程与详解

    1 Kafka入门教程 1.1 消息队列(Message Queue) Message Queue消息传送系统提供传送服务.消息传送依赖于大量支持组件,这些组件负责处理连接服务.消息的路由和传送.持久 ...

  4. python tornado教程_Tornado 简单入门教程(零)——准备工作

    前言: 这两天在学着用Python + Tornado +MongoDB来做Web开发(哈哈哈这个词好高端).学的过程中查阅了无数资料,也收获了一些经验,所以希望总结出一份简易入门教程供初学者参考.完 ...

  5. python向量计算库教程_NumPy库入门教程:基础知识总结

    原标题:NumPy库入门教程:基础知识总结 视学算法 | 作者 知乎专栏 | 来源 numpy可以说是 Python运用于人工智能和科学计算的一个重要基础,近段时间恰好学习了numpy,pandas, ...

  6. mysql query browswer_MySQL数据库新特性之存储过程入门教程

    MySQL数据库新特性之存储过程入门教程 在MySQL 5中,终于引入了存储过程这一新特性,这将大大增强MYSQL的数据库处理能力.在本文中将指导读者快速掌握MySQL 5的存储过程的基本知识,带领用 ...

  7. python tensorflow教程_TensorFlow入门教程TensorFlow 基本使用T

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 TensorFlow入门教程 TensorFlow 基本使用 TensorFlow官方中文教程 TensorFlow 的特点: 使用图 (graph) 来 ...

  8. air调用java,AIR2.0入门教程:与Java应用交互

    在之前的一篇文章中,我介绍了如何使用AIR2.0新增的NativeProcess类与本地进程进行交互和通讯,在那个例子里面我们使用了C++ 的代码,实际上只要是基于命令行的标准输入输出,AIR2.0的 ...

  9. 【Arduino】开发入门教程【一】什么是Arduino

    Arduino Arduino 是一款便捷灵活.方便上手的开源电子原型平台,包含硬件(各种型号的arduino板)和软件(arduino IDE).它适用于艺术家.设计师.爱好者和对于"互动 ...

最新文章

  1. 创建模板_UG中如何创建属于自己的编程模板界面?
  2. Nginx防盗链、访问控制、Nginx解析PHP相关配置、Nginx代理
  3. 【编程之美】3.5 最短摘要的生成
  4. VTK:IO之ReadImageData
  5. 力扣:12正数转罗马数字(python) 简单粗暴解决方法
  6. 琴岛学院计算机应用技术,我院计算机工程系成功晋级“中国高校计算机大赛-网络技术挑战赛”全国总决赛...
  7. sql语句变量定义和样例
  8. 【Elasticsearch】Elasticsearch:聚合 操作
  9. python 图片数据增强_数据增强之批量修改图像尺寸大小(附Python实现)
  10. Win7开机动画图片下载大全 修改攻略
  11. cocos creator 游戏源码_Cocos Creator 3D v1.0.2 正式发布,新增小游戏平台支持
  12. TBODY的使用方法和意义
  13. 【开源编码分享】Python古三式∶太乙神数丶奇门遁甲丶大六壬
  14. 迪士尼电影经过多年的
  15. 腾讯云快速增长背后 三大短板仍需补足
  16. 奋斗者——一个高级咨询师是怎样炼成的
  17. 常用字符,点,叉、、、
  18. Java开源 Web开发框架 (一)
  19. 瀑布开发模式和敏捷开发模式的区别和思考
  20. [2011-04-30]返现网排行榜

热门文章

  1. PageIndicatorView
  2. 电机的matlab仿真实例,电机控制Matlab仿真模型
  3. simulink电机仿真笔记一
  4. 中秋国庆旅游 App 市场竞争激烈!工具类 App 更易被苹果推荐!
  5. 中国银联正式推出在线支付和手机支付业务zt
  6. HTML-做一个网页的注册登记表单
  7. Java语言中的输入方法
  8. 外地人一年内直接落户上海
  9. Python 文件查找
  10. Linux计划任务介绍