参考:

  • Cython 入门教程
  • Cython Documentation

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

Python 循环

from math import exp
import numpy as np
def 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 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/jupyter notebook中测算运行时间

%timeit rbf_network(X, beta, theta)

完整版:

# 打开IPython 或 jupyter notebook
from math import exp
import numpy as np
def 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 YD = 5
N = 1000
X = np.array([np.random.rand(D) for d in range(N)])
beta = np.random.rand(N)
theta = 10%timeit rbf_network(X, beta, theta)
4.21 s ± 145 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

scipy.interpolate.Rbf

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

from scipy.interpolate import Rbf
import numpy as np
D = 5
N = 1000
X = np.array([np.random.rand(D) for d in range(N)])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
264 ms ± 4.01 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

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

Cython

cython编译参考:Building Cython code
我们在文件 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 setup
from Cython.Build import cythonize
setup(name='fastloop', ext_modules=cythonize('fastloop.pyx'),)

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

python3 setup.py build_ext --inplace # 使用python3的编译

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

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

from fastloop import rbf_network
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
%timeit rbf_network(X, beta, theta) # 87.3 ms per loop

使用pyximport

使用pyximport 直接导入.pyx文件,不需编译

import pyximport; pyximport.install()
from fastloop import rbf_network
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%timeit rbf_network(X, beta, theta) # 87.3 ms per loop

IPython/jupyter notebook中编译

%load_ext cython%%cython
from math import exp
import numpy as np
import time
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 YD = 5
N = 1000
X = np.array([np.random.rand(D) for d in range(N)])
beta = np.random.rand(N)
theta = 10# %timeit rbf_network(X, beta, theta)
s=time.clock()
rbf_network(X, beta, theta)
print(time.clock()-s)

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

cython fastloop.pyx -a

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

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

from libc.math import exp

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

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

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

fastloop.pyx其内容如下

#cython: boundscheck=False, wraparound=False, nonecheck=False
# from math import exp
from libc.math cimport exp
import numpy as np
# cimport numpy as npcdef 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

接下来我们可以考虑修改编译器参数(这些属于 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)
# 编译
python3 setup.py build_ext --inplace

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

我们可以重新编译程序,并测速(打开Ipython/jupyter notebook

from fastloop import rbf
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
%timeit rbf(X, beta, theta) # 21.7 ms per loop

Cython基础使用相关推荐

  1. Cython基础--Cython的类型

    Cython的类型 1 类型定义 1.1 定义一个C变量: 1.1.1 在Cython里定义一个C变量和C语言类似,不同的地方就是在声明的最前面要加上cdef,另外,末尾不用加分号";&qu ...

  2. Cython基础--Cython的函数

    Cython的函数 1 函数定义: 1.1 在Cython里定义一个类C函数: 1.1.1 在这里之所以说是定义一个"类C"函数,而不是一个C函数,是因为它和纯C函数的定义还是有区 ...

  3. Cython的学习方法

    在认识Cython之前,我已经用swig写Python扩展好长一段时间了. 虽然用swig为写Python扩展提供了很大的方便,但是其易用性却仍然不是很好: 1.很多情况下要自己转换输入输出参数,如封 ...

  4. PyTorch 图像分类

    PyTorch 图像分类 如何定义神经网络,计算损失值和网络里权重的更新. 应该怎么处理数据? 通常来说,处理图像,文本,语音或者视频数据时,可以使用标准 python 包将数据加载成 numpy 数 ...

  5. python训练手势分类器_使用Pytorch训练分类器详解(附python演练)

    [前言]:你已经了解了如何定义神经网络,计算loss值和网络里权重的更新.现在你也许会想数据怎么样? 目录: 一.数据 二.训练一个图像分类器 使用torchvision加载并且归一化CIFAR10的 ...

  6. 第一学:pytorch入门60min

    目录 1.Tensor张量 2.自动微分 3.神经网络 4.pytorch图像分类器 5.数据并行处理 1.Tensor张量 #Tensors类似于NumPy的ndarrays,同时Tensors可以 ...

  7. Python的标量与矢量运算分析

    文章目录 技术背景 NumPy Pytorch TensorFlow Numba Cython 标量运算 矢量运算 经验总结 技术背景 Python 的官方解释器是用 C 实现的 CPython .其 ...

  8. cython大白话基础教程

    1. Overview Cython是个编程语言,Cython帮助你像写python一样写C的扩充代码,官方画大饼说想要把Cython变成python的增强版本.Cython能把c, c啪啪编译好当作 ...

  9. matlab在图像上画出来的矩形框如何变成可托动的_计算机基础系列:源代码如何被计算机执行...

    计算机芯片的物理特性决定了它只能接受二进制指令.不同计算机芯片的指令集不同.高级编程语言需要转化成二进制机器语言才能被计算机所执行.编译型语言需要使用编译器经过编译和连接生成可执行文件,解释型语言需要 ...

  10. Python_基础知识储备

    目录 目录 前言 初识Python 解析型与编译型 OOP与POP 相关概念1 Python的解释器 Python程序设计的思想 Python的编程风格 最后 前言 前面的博文从记录了如何Setup ...

最新文章

  1. 史上最强女游戏程序员
  2. Vue指令之v-on的缩写和事件修饰符||.stop 和 .self 的区别
  3. 数据挖掘之离群点检测
  4. Oracle数据库之数据处理
  5. 关于STRUCT优化的一个点
  6. python为text添加滚动条_Python GUI编程(Tkinter)7、带滚动条的Text
  7. 为何程序员上班时间总戴个耳机,看完恍然大悟...
  8. 项目进行JVM调优 Jconsole
  9. Leetcode每日一题:183.customers-who-never-order(从不订购的客户)
  10. TCP四次握手连接释放
  11. 电影下载、播放、制作、转换、各类问题全攻略
  12. bootstrop table api
  13. 巅峰之证!首位阿里云ACE认证专家产生
  14. python指数函数ks检验_python指数函数不正确的指数值
  15. xcode清理缓存_Mac 垃圾清理软件腾讯柠檬Lemon
  16. ajax英文翻译,Ajax[埃阿斯]英文名的中文翻译意思、发音、来源及流行趋势-千代英文名...
  17. python 绘图如何画螺旋圈_如何画出python螺旋线
  18. 微信广告+视频号,营销能力全面盘点,视频号是否能做新突破?
  19. thinkPHP基于php的枣院二手图书交易系统--php-计算机毕业设计
  20. 工控机主板与ARM工控机主板有什么不同呢?

热门文章

  1. hdp环境下ip更改
  2. 单片机c语言编写注解,单片机C语言程序注解
  3. Entry name ‘META-INF/androidx.vectordrawable_vectordrawable.version‘ collided
  4. 数学专业英语-微积分篇
  5. YAML Syntax Error Duplicated mapping key at line 62, column 24: description: 城市主键
  6. java启动后台进程_windows下java -jar 后台运行以及杀死后台进程的操作
  7. Windows11常用快捷键总结(包含触控板使用技巧)
  8. 群晖docker安装青龙面板自动狗东京豆领取
  9. uni-app在手机上背景图片不显示
  10. 高电平输入好还是rca输入好_汽车音响接高电平还是低电平是什么意思