美文网首页大数据 爬虫Python AI Sql
如何让自己的Python快100倍?spaCy和Cython实现

如何让自己的Python快100倍?spaCy和Cython实现

作者: 919b0c54458f | 来源:发表于2018-07-17 14:36 被阅读5次

    所以我在这里有点作弊,因为我们会谈论 Python,但也谈论一些 Cython 的神奇作用。但是,你知道吗?Cython 是 Python 的超集,所以不要让它吓跑你!

    你现在的 Python 程序已经是 Cython 程序。

    有几种情况下你可能需要加速,例如:

    你正在使用 Python 开发一个 NLP 的生产模块;

    你正在使用 Python 计算分析大型 NLP 数据集;

    你正在为深度学习框架,如 PyTorch /TensorFlow,预处理大型训练集,或者你的深度学习批处理加载器中的处理逻辑过于繁重,这会降低训练速度。

    让我们用一个简单的例子来分析这个问题。假设我们有一大堆矩形,并将它们存储进一个 Python 对象列表,例如 Rectangle 类的实例。我们的模块的主要工作是迭代这个列表,以便计算有多少矩形的面积大于特定的阈值。

    我们的 Python 模块非常简单,如下所示:

    我们在这里使用了原生 C 指针数组,但你也可以选择其他选项,特别是 C ++ 结构,如向量、对、队列等。在这个片段中,我还使用了 cymem 的便利的 Pool()内存管理对象,以避免必须手动释放分配的 C 数组。当 Pool 由 Python 当做垃圾回收时,它会自动释放我们使用它分配的内存。

    在 Jupyter 的第一次测试

    使用 %load_ext Cython 将 Cython 插件加载到 Jupyter notebook 中。

    现在,你可以使用黑魔术命令 %% cython 编写像 Python 代码一样的 Cython 代码。

    如果在执行 Cython 单元时遇到编译错误,请务必检查 Jupyter 终端输出以查看完整的信息。

    大多数情况下,在 %% cython 编译为 C ++(例如,如果你使用 spaCy Cython API)或者 import numpy(如果编译器不支持 NumPy)之后,你会丢失 - + 标记。

    Python 函数,用常用的关键字 def 定义。它们可作为输入和输出的 Python 对象。也可以在内部同时使用 Python 和 C / C ++ 对象,并可以调用 Cython 和 Python 函数。

    用 cdef 关键字定义的 Cython 函数。它们可以作为输入,在内部使用并输出 Python 和 C / C ++对象。这些函数不能从 Python 空间访问(即 Python 解释器和其他可导入 Cython 模块的纯 Python 模块),但可以由其他 Cython 模块导入。

    用 cpdef 关键字定义的 Cython 函数就像 cdef 定义的 Cython 函数一样,但它们也提供了一个 Python封装器,因此可以从 Python 空间(以 Python 对象作为输入和输出)以及其他 Cython 模块(以 C / C ++ 或 Python 对象作为输入)中调用它们。

    它可以通过 spaCy 任意处及任意对象访问(请参阅上图),例如 nlp.vocab.strings、doc.vocab.strings 或 span.doc.vocab.string。

    当某个模块需要对某些 token 执行快速处理时,仅使用 C 级别的 64 位哈希码而不是字符串。调用 StringStore 查找表将返回与哈希码相关联的 Python unicode 字符串。

    6我在左边写了一个脚本,它生成用于 spaCy 解析的 10 份文档的列表,每个文档大约 170k 字。我们也可以生成每个文档 10 个单词的 170k 份文档(比如对话数据集),但创建速度较慢,因此我们坚持使用 10 份文档。

    我们想要在这个数据集上执行一些 NLP 任务。例如,我们想要统计数据集中单词「run」作为名词的次数(即用 spaCy 标记为「NN」词性)。

    一个简单明了的 Python 循环就可以做到:

    但它也很慢!在我的笔记本电脑上,这段代码需要大约 1.4 秒才能得到结果。如果我们有一百万份文件,则需要一天以上才能给出结果。

    我们可以使用多线程,但在 Python 中通常不是很好的解决方案,因为你必须处理 GIL。另外,请注意,Cython 也可以使用多线程!而且这实际上可能是 Cython 最棒的部分,因为 GIL 被释放,我们可以全速运行。Cython 基本上直接调用 OpenMP。

    代码有点长,因为我们必须在调用 Cython 函数之前在 main_nlp_fast 中声明并填充 C 结构。(如果你在代码中多次使用低级结构,使用 C 结构包装的 Cython 扩展类型来设计我们的 Python 代码是比每次填充 C 结构更优雅的选择。这就是大多数 spaCy 的结构,它是一种结合了快速,低内存以及与外部 Python 库和函数接口的简便性的非常优雅的方法。)

    但它也快很多!在我的 Jupyter Notebook 中,这个 Cython 代码的运行时间大约为 20 毫秒,比我们的纯 Python 循环快大约 80 倍。

    进群:125240963   即可获取数十套PDF哦!

    相关文章

      网友评论

        本文标题:如何让自己的Python快100倍?spaCy和Cython实现

        本文链接:https://www.haomeiwen.com/subject/uoowpftx.html