30倍!使用Cython加速Python代码

在线wifi跑包 金刚包跑包 cap跑包 hccapx ewsa在线 就来 握手包跑包

各位好 又见面了 我是曹操 今天给大家带来一篇新的教程

希望各位细心学习 低调用网

专业跑包字典下载专业跑包字典下载

标星★公众号 爱你们♥ 作者:George Seif、Thomas Wolf、Lukas Frei 编译:1+1=6 | 公众号海外部 近期原创文章: ♥♥♥2万字干货: ♥♥♥♥♥♥♥♥♥♥♥♥♥♥ 前言 您可能经常听到有关Python运行速度慢的抱怨。与其他编程语言相比,Python确实较慢。有几种方法可以加速代码:如果您的代码是纯Python,如果您有一个大型的for循环,您只能使用它,而不能使用矩阵,因为数据必须按顺序处理。那么有没有办法加快Python本身的速度呢?让我们来看看Cython吧!

x = 0.5

文末下载Cython相关书籍 什么是Cython? Cython是Python和C / C++之间的一个中间步骤。它允许您编写纯Python代码,并进行一些小的修改,然后将其直接翻译成C代码。Cython语言是Python的一个超集,它包含两种类型的对象:您只需向每个变量添加类型信息。通常,我们可以在Python中声明一个变量,例如:

cdef float x = 0.5
pip install cython

使用Cython,我们为该变量添加了一个类型声明:

这告诉Cython,该变量是一个浮点数,就像我们在C中所做的一样。对于纯Python,变量的类型是动态确定的。Cython中的显式类型声明使其转换为C代码成为可能,因为显式类型声明需要+。有许多方法可以测试、编译和发布Cython代码。Cython甚至可以像Python一样直接在Jupyter Notebook中使用。安装Cython只需要一行pip:

%load_ext Cython

使用Cython需要安装C语言编译器,因此,安装过程因您当前的操作系统而异。对于Linux,通常使用GNU C编译器(gncc)。对于Mac OS,您可以下载Xcode以获取gncc。而在Windows桌面系统下安装C编译器会更复杂。使用%load_ext Cython指令在Jupyter notebook中加载Cython扩展。然后通过指令%%cython,我们就可以像Python一样在Jupyter notebook中使用Cython。如果在执行Cython代码时遇到编译错误,请检查Jupyter终端的完整输出信息。大多数情况下可能是因为在%%cython之后遗漏了-+标签(比如当您使用spaCy Cython接口时)。如果编译器报告有关NumPy的错误,则可能是遗漏了import numpy。如果您要在IPython中使用Cython,请首先介绍一下IPython Magic命令。Magic命令以百分号开头,通常有两种类型:首先运行以下语句引入Cython:

%%cython
def test(x):
    y = 1
    for i in range(x+1):
        y *= i
    return y

然后,在运行Cython代码时,我们需要添加以下Cython代码:

然后,您就可以愉快地使用Cython了。Cython中的类型 在Cython中,变量和函数有两组不同的类型。对于变量,我们有:请注意,所有这些类型都来自C / C++!我们可以方便地将结果传递给C代码,并返回结果,Cython会自动进行类型转换。了解了Cython类型之后,我们就可以直接实现加速了!如何使用Cython加速代码 我们首先需要设置Python代码的基准:一个用于计算阶乘的for循环。原始的Python代码如下:

import pyximport; pyximport.install()
import my_cython_module

Cython的实现过程看起来非常相似。首先,确保Cython代码文件具有.pyx扩展名。这些文件将由Cython编译器编译为C或C++文件,然后由C编译器进一步编译为字节码文件。您还可以使用pyximport将.pyx文件直接加载到Python程序中:

专业跑包字典下载

您还可以将自己的Cython代码构建为Python包,然后像正常的Python包一样导入或发布。但是,这种方法需要更多的时间,特别是如果您希望Cython包能够在所有平台上运行。如果您需要一个参考示例,可以查看spaCy的安装脚本:

cpdef int test(int x):
    cdef int y = 1
    cdef int i
    for i in range(x+1):
        y *= i
    return y
from distutils.core import setup
from Cython.Build import cythonize

setup(ext_modules = cythonize('run_cython.pyx'))

最终,Python解释器将能够调用这些字节码文件。对代码本身的唯一更改是我们已经为每个变量和函数声明了类型。请注意,函数具有cpdef以确保我们可以从Python调用它。另外,请注意我们的循环变量i如何具有类型。您需要为函数中的所有变量设置类型,以便C编译器知道使用哪种类型!接下来,创建一个setup.py文件,将Cython代码编译为C代码:

python setup.py build_ext --inplace
import run_python
import run_cython
import time

number = 10

start = time.time()
run_python.test(number)
end = time.time()

py_time = end - start
print("Python time = {}".format(py_time))

start = time.time()
run_cython.test(number)
end = time.time()

cy_time = end - start
print("Cython time = {}".format(cy_time))

print("Speedup = {}".format(py_time / cy_time))

然后执行编译:Boom!我们的C代码已经编译好,可以使用了!您将看到,在Cython代码所在的文件夹中,有所有运行C代码所需的文件,包括run_cython.c文件。如果您感兴趣,可以查看Cython生成的C代码!现在我们准备测试新的C代码!查看下面的代码,它将执行一个速度测试,将原始Python代码与Cython代码进行比较。现在我们准备测试我们新的超快速C代码了!查看下面的代码,它执行速度测试以将原始Python代码与Cython代码进行比较。

专业跑包字典下载专业跑包字典下载

Cython可以让您在几乎所有原始Python代码上获得良好的加速,而不需要太多额外的工作。需要注意的关键是,循环次数越多,处理的数据越多,Cython可以提供的帮助就越多。查看下表,该表显示了Cython为不同阶乘值提供的速度,我们使用Cython获得了超过36倍的加速!

专业跑包字典下载

Cython在NLP中的加速应用 当我们处理字符串时,如何在Cython中设计更高效的循环呢?spaCy是一个不错的选择!spaCy中的所有Unicode字符串(标记的文本、其小写文本、其词形形式、POS标签、解析树依赖标签、命名实体标签等)都存储在一个称为StringStore的数据结构中,它通过一个64位哈希码进行索引,例如C类型的uint64_t。

专业跑包字典下载

StringStore对象实现了Python Unicode字符串与64位哈希码之间的查找映射。它可以在spaCy的任何地方和任意对象中访问,例如npl.vocab.strings、doc.vocab.strings或span.doc.vocab.string。当某个模块需要在某些标记上获得更快的处理速度时,可以使用C语言类型的64位哈希码代替字符串来实现。调用StringStore查找表将返回与该哈希码相关联的Python Unicode字符串。但是,spaCy能做的不仅仅是这些,它还允许我们访问完全填充的C语言类型结构的文档和词汇表,我们可以在Cython循环中使用这些结构,而不必构建自己的结构。spaCy拓展:

import urllib.request
import spacy

with urllib.request.urlopen('https://raw.githubusercontent.com/pytorch/examples/master/word_language_model/data/wikitext-2/valid.txt') as response:
text = response.read()
nlp = spacy.load('en')
doc_list = list(nlp(text[:800000].decode('utf8')) for i in range(10))

建立一个脚本用于创建一个包含10份文档的列表,每份文档大约包含17万个单词,使用spaCy进行分析。当然,我们也可以对17万份文档(每份文档包含10个单词)进行分析,但这样做会导致创建过程非常慢,因此我们选择了10份文档。我们想要在这个数据集上执行某些自然语言处理任务。例如,我们可以统计数据集中作为名词出现的单词”run”的次数(例如,被spaCy标记为”NN”词性标签)。使用Python循环来实现上述分析过程非常简单和直观:

专业跑包字典下载

这段代码至少需要运行1.4秒才能获得答案。如果我们的数据集中包含数百万个文档,为了获得答案,我们可能需要花费超过一天的时间。我们也许可以使用多线程来加速,但在Python中这种做法并不明智,因为您还需要处理全局解释器锁(GIL)。在Cython中,可以无视GIL的存在而自由使用线程加速。但是不能再使用Python中的字典和列表,因为Python中的变量都自动带有锁(GIL)。幸运的是,Cython已经封装了C++标准库中的容器:deque、list、map、pair、queue、set、stack、vector。完全可以替代Python的dict、list、set等。我们使用Cython就可以解决这个问题,但不能再使用Python中的字典和列表,因为Python中的变量都自动带有锁(GIL)。幸运的是,Cython已经封装了C++标准库中的容器:deque、list、map、pair、queue、set、stack、vector。完全可以替代Python的dict、list、set等。另外,请注意,Cython也可以使用多线程!Cython在后台可以直接调用OpenMP。现在让我们尝试使用spaCy和Cython来加速Python代码。首先需要考虑好数据结构,我们需要一个C类型的数组来存储数据,需要指针来指向每个文档的TokenC数组。我们还需要将测试字符(”run”和”NN”)转换为64位哈希码。当所有需要处理的数据都变成了C类型对象,我们就可以以纯C语言的速度对数据集进行迭代。以下是转换为Cython和spaCy的实现:

%%cython
cdef extern from "math.h":
    cpdef double sin(double x)

在Jupyter notebook上,这段Cython代码运行了大约20毫秒,比之前的纯Python循环快了大约80倍。使用Jupyter notebook单元编写模块的速度很可观,它可以与其他Python模块和函数自然地连接:在20毫秒内扫描大约170万个单词,这意味着我们每秒能够处理高达8千万个单词。如果您已经了解C语言,Cython还允许访问C代码,而Cython的创建者还没有为这些代码添加现成的声明。例如,使用以下代码,可以为C函数生成Python包装器并将其添加到模块dict中。

专业跑包字典下载

Cython注意的陷阱 1、.pyx中用CDEF定义的内容,除类以外对的.py都是不可见的。 2、.c中不能操作C类型,如果想在.py中操作C类型,就要在.pyx中从Python对象转换为C类型,或者用含有set/get方法的C类型包装类。 3、虽然Cython可以自动进行Python的str和C的”char *”之间的类型转换,但对于固定长度的字符串”char a[n]”是无法自动转换的。需要使用Cython的libc.string.strcpy进行显式拷贝。 4、回调函数需要用函数包装,并通过C的”void *”强制转换后才能传入C函数。 Cython相关资料(下载) 0、其他:

专业跑包字典下载专业跑包字典下载专业跑包字典下载专业跑包字典下载

1、官方文档: 2、参考书籍(文末下载): 书籍下载 在后台输入(严格大小写) Cython资料 —End— 量化投资与机器学习微信公众号,是业内垂直于Quant、MFE、CST、AI等专业的主流量化自媒体。公众号拥有来自公募、私募、券商、银行、海外等众多圈内10W+关注者。每日发布行业前沿研究成果和最新量化资讯。

赞(0)