才权的博客


  • 首页

  • 归档

  • 标签

  • 关于

《从零开始学习自然语言处理(NLP)》-BERT推理加速实践(6)

发表于 2019-11-09

BERT推理加速的理论可以参考之前的博客《从零开始学习自然语言处理(NLP)》-BERT模型推理加速总结(5)。这里主要介绍基于Nvidia开源的Fast Transformer,并结合半精度模型量化加速,进行实践,并解决了TensorFlow Estimator预测阶段重复加载模型的问题。主要包括:

  • 环境搭建

  • Pre-train模型获取

  • 结合自身业务Fine-tuning

  • 模型单精度(FP32)转半精度(FP16)

  • Fast-transformer编译

  • Fast-transformer集成

  • TensorFlow estimator线上推理

下面逐个进行介绍。

环境搭建

BERT的Fine-tuning需要GPU环境(CPU训练估计要慢到天长地久),而GPU的环境配置又相对麻烦。除了显卡驱动外,还需要对应版本的安装CUDA、CUDNN、Python、TensorFlow-GPU。版本不匹配很容易出问题。简单的环境搭建,推荐直接使用Nvidia的NGC镜像。针对BERTFine-tuning(Pre-train同样适用),本文中使用Docker镜像:nvcr.io/nvidia/tensorflow:19.10-py3(镜像说明:https://ngc.nvidia.com/catalog/containers/nvidia:tensorflow)。

镜像主要包括:

  • Python 3.6.8
  • Tensorflow-estimator 1.14.0
  • Tensorflow-gpu 1.14.0+nv
  • TensorRT 6.0.1(Fast transformer基于TensorRT实现,需要依赖TensorRT)

Pre-train模型获取

中文的BERT预训练模型直接从google-research/bert获得即可,具体地址:https://github.com/google-research/bert
中文BERT模型

结合自身业务Fine-tuning

Fine-tuning主要是根据自己的使用场景,修改训练的数据读取逻辑,这里以文本分类(多分类、单标签)为例进行展开。文本分类的入口是run_classifier.py文件,主要增加一个自定义的数据获取类,比如,
自定义数据读取类
其中,
自定义数据读取类
自定义数据读取类
需要注意的是,如果训练样本提前没有进行shuffle操作,可以将代码中的shuffle值修改的大一些,否则,训练结果会很差,比如,
shuffle修改
Fine-tuning的代码可以使用Google官方的代码(代码地址:https://github.com/google-research/bert),也可以使用Nvidia提供的BERT代码(代码地址:https://github.com/NVIDIA/DeepLearningExamples/tree/master/TensorFlow/LanguageModeling/BERT)。
Nvidia代码的优点是方便配置,比如:
混合精度:加快训练速度
XLA优化:后面使用Fast Transformer加速,不建议打开这个选项,担心XLA的网络优化,会导致Fast Transformer参数初始化失败。(没有通过实验验证,不确定真实的结果)。
Fine-tuning后的模型会发现变大很多,比如BERT的中文预训练模型大小为393M,Fine-tuning后居然变成了1.2G。这么大的变化,主要由于训练过程中的checkpoints由于包含了每个权重变量对应的Adam momentum和variance变量。具体可以参考《BERT-TensorFlow版微调后模型过大解决方案》。

模型单精度(FP32)转半精度(FP16)

Fine-tuning后的模型默认是FP32保存的,在服务上线进行推理阶段,要先转换成半精度(FP16),从而加快推理速度。
TensorFlow提供了半精度转换的API,具体参考《TensorFlow 模型优化工具 — float16 量化将模型体积减半》。
这里没有使用TensorFlow的API,而是,使用了Nvidia Fast transformer提供的方法(ckpt_type_convert.py):
ckpt_type_convert.py
解释地址:https://github.com/NVIDIA/DeepLearningExamples/blob/master/FasterTransformer/sample/tensorflow_bert/sample.md
ckpt_type_convert.py地址:https://github.com/NVIDIA/DeepLearningExamples/tree/master/FasterTransformer/sample/tensorflow_bert

Fast-transformer编译

Fast-transformer由C++编写实现,使用前需要先进行编译。
编译环境之间使用当前的Docker环境即可,需要注意的是要先下载TensorRT的压缩包。虽然环境中已经有了TensorRT,但为了方便起见,还是直接下载一个(直接编译会出错)。注意对齐环境中的TensorRT版本(环境中使用的是TenorRT6.0版本)。
TensorRT下载地址:https://developer.nvidia.com/tensorrt
编译命令:
编译命令
命令地址:https://github.com/NVIDIA/DeepLearningExamples/tree/master/FasterTransformer
要正常使用Fast transformer还需要gemm_config.in文件,这个文件通过命令生成:
gemm_config.in文件生成
命令地址:https://github.com/NVIDIA/DeepLearningExamples/tree/master/FasterTransformer

Fast-transformer集成

Fast transformer的集成相对简单,直接将DeepLearningExamples/FasterTransformer/sample/tensorflow_bert/目录中的内容,拷贝到BERT源码目录即可。这里需要注意的是拷贝到google-research/bert的官方源码目录,而不是NVIDIA/DeepLearningExamples的BERT源码目录。
拷贝到后者中,会运行出错(Fast transformer Demo应该是基于Google官方BERT源码实践的)。
同时,需要注意的是上一个步骤中生成的C++层Fast transformer动态链接库,以及gemm_config.in文件的位置。
C++层Fast transformer动态链接库引用:
动态链接库引用
gemm_config.in文件放在源码目录下即可(执行命令的根目录)。
最后,设置

FLAGS.floatx = 'float16'

从而开启半精能力。
总结下Fast transformer集成需要的注意点:

  • 1 Fast transformer example代码拷贝到Google的BERT官方源码中;
  • 2 包含libtf_fastertransformer.so的build文件放置在正确位置;
  • 3 http://gemm_config.in文件放置在执行命令的目录;
  • 4 设置FLAGS.floatx = ‘float16’,开启半精推理能力;

TensorFlow estimator线上推理

Google官方的BERT是基于Estimator实现的,但Estimator的模型训练、评估、预测,每次都要重新加载模型。这对于实时的线上预测任务是不能接受的。需要将Estimator的预测部分进行修改,每次推理预测时不重新加载模型。具体的实现可以参考《TensorFlow关于怎样解决Estimater.predict总是重新加载模型的问题》。实际上,这篇博客的实现主要是参考了一个很棒的gitlab开源项目hanxiao/bert-as-service。
基于Fast transformer推理速度:
推理速度对比
数据来源:https://github.com/NVIDIA/DeepLearningExamples/blob/master/FasterTransformer/sample/tensorflow_bert/sample.md

小结

本文基于Nvidia的Fast transformer,详细介绍了BERT推理加速优化的完整步骤,包括环境搭建、Pre-train模型获取、结合自身业务Fine-tuning、模型单精度(FP32)转半精度(FP16)、Fast-transformer编译、Fast-transformer集成、TensorFlow estimator线上推理等步骤,以及其中需要注意的问题,为BERT推理服务上线提供参考。

参考资料

《BERT-TensorFlow版微调后模型过大解决方案》:https://blog.csdn.net/ljp1919/article/details/100652794
《TensorFlow 模型优化工具 — float16 量化将模型体积减半》:https://mp.weixin.qq.com/s?__biz=MzU1OTMyNDcxMQ==&mid=2247486633&idx=1&sn=18d8541781f48d4d845c93473cd27bcb&chksm=fc1847e1cb6fcef7617832b538751ed7731755d2bcb052f0005c8736c866b2153c87484a680d&scene=0&xtrack=1&key=6ccb298b02eeb1eb594dec195455c03b8590cecdfa74d520f2ac3ffa3045a6a68fecf770f1ffe514191634410c0b511057cf428acc0d07c8686e77b626052a5a076801f3e0dbed26e3c7f9ed9fc270f1&ascene=1&uin=MTU2Nzk1MDIyMA%3D%3D&devicetype=Windows+10&version=62070152&lang=zh_CN&pass_ticket=%2BEHBIFHwjhPmTTiowh%2FkWmCf9eVl%2BAYiX2jsbCe13wDg%2FyRzwrFbvFs7zf4i3icO
《TensorFlow关于怎样解决Estimater.predict总是重新加载模型的问题》:https://blog.csdn.net/hezhefly/article/details/98877796

《从零开始学习自然语言处理(NLP)》-BERT模型推理加速总结(5)

发表于 2019-11-01

1 BERT模型介绍

BERT是NLP任务的集大成者。 发布时,在GLUE 上的效果排名第一。
在语义表征方面
将基于浅层语义表征的词向量,加强为深层语义特征向量。同时,引入上下文特征,解决了词向量一词多义的问题。
在知识迁移方面
能够在海量的无监督文本训练语料中,有效的抽取语义特征。Pre-Train+Fine-Turning的模式下,非常实用。
在计算效率方面
BERT基于Transformer实现,采用self-attention机制,采用并行的矩阵运算,替代RNN的串行执行,有效提升模型计算效率。
在任务设计方面
BERT提供了分类、相似度计算(也是一种分类)、序列标注等NLP任务模板,基本覆盖了NLP任务的大多数模型应用场景。
具体的BERT介绍可以参考Google的论文:《BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding》
在学习BERT之前,建议先熟悉Transformer,具体可以参考Google论文:《Attention Is All You Need》
直接看论文可能不好理解,建议先参考网上的Blog:
图解Transformer:《The Illustrated Transformer》
图解BERT:《The Illustrated BERT, ELMo, and co. (How NLP Cracked Transfer Learning)》
很多国内的博客都是上面两篇博客的翻译或者引用。
BERT在NLP预训练领域确实有里程碑的意义,这篇博客做了不错的总结:《从Word Embedding到Bert模型—自然语言处理中的预训练技术发展史》

2 BERT模型的困境

虽然BERT有各种优点,在项目落地上却存在缺陷:计算复杂度过高。通过BERT模型的参数量,感受下:
BERT参数量
数据来源:https://github.com/NVIDIA/DeepLearningExamples/tree/master/TensorFlow/LanguageModeling/BERT
针对BERT模型,我们从预训练(Pre-train)、Fine-tuning、推理三个维度来看模型的计算耗时。
模型训练(Pre-train)时间:
Pre-train时间
数据来源:https://github.com/NVIDIA/DeepLearningExamples/tree/master/TensorFlow/LanguageModeling/BERT
Fine-tuning时间:
Fine-tuning时间
数据来源:https://github.com/NVIDIA/DeepLearningExamples/tree/master/TensorFlow/LanguageModeling/BERT
模型推理时间:
模型推理时间
模型推理时间
数据来源:https://github.com/NVIDIA/DeepLearningExamples/tree/master/TensorFlow/LanguageModeling/BERT
从上面的数据来看,预训练(Pre-train)要求的计算资源最大,耗时最长。自己做预训练相对较难。还好Google提供预训练模型(包括中文的预训练模型),git地址:https://github.com/google-research/bert
如果,计算资源充裕,可以使用自己的语料进行预训练,从实际的项目经验反馈来看,用自己的业务相关语料进行预训练,对模型的最终效果,相对于使用Google通用的预训练模型,有小幅提升。
Fine-tuning的计算在实际项目应用中基本可以接受,这里不做特别的深入。
最后需要关注的就是模型推理,而这也是服务上线最需要关注的。后面我们的分析重点,也集中在如何提升BERT模型的推理效率。

3 BERT模型推理加速方案汇总

BERT的模型优化方案,大概有下面几个方面:

3.1 编译优化

这里的编译优化主要指计算框架自身的编译优化,以TensorFlow的XLA为例,
xla编译优化
数据来源:https://www.tensorflow.org/xla
从实际的数据来看,TensorFlow的XLA优化能力有限,>1.15倍。

3.2 知识蒸馏

知识蒸馏是一个不错的模型压缩方案,通过小模型(student)来学习大模型(teacher)的能力。但一般来说,通过蒸馏获得小模型,相对于原来的小模型有算法效果提升,但不能保证能完全达到大模型(teacher)的效果。
TinyBERT就是使用了这种思路,具体可以参考paper《TinyBERT: Distilling BERT for Natural Language Understanding》

3.3 混合精度(Nvidia-TensorCore)

一般模型的参数使用FP32(单精度)进行保存和计算。特定的计算平台,比如英伟达的P100,可以使用单个的FP32寄存器,缓存两个FP16(半精度)变量,并进行并行计算,参考《Nvidia GPU的浮点计算能力》。

同时,英伟达的瓦特架构(Tesla V100)和图灵架构(Tesla T4)有TensorCore计算单元,可以同时完成混合精度矩阵的乘加运算。具体可以参考《Video Series: Mixed-Precision Training Techniques Using Tensor Cores for Deep Learning》。

将模型中的FP32变量替换成FP16,可以有效的压缩模型大小,同时,可以提升模型的训练及推理速度。但对模型效果会不会有影响呢?答案,肯定是不会的。具体原因可以参考这篇paper《Mixed Precision Training》。
文章主要提了三个方法:
1 FP32 MASTER COPY OF WEIGHTS
FP32 MASTER COPY OF WEIGHTS
简单的说就是把FP32的变量先拷贝一份,然后把所有的变量都量化成FP16。在前向和反向计算时都使用FP16,只是在最后更新参数时转化为FP32。
这样做也很好理解,更新参数时,一方面,会进行整个batch参数相加(然后取均值),转化成FP32避免向上溢出;另一方面,非常小的梯度会乘以学习率(一般<1),转化成FP32避免向下溢出。
2 LOSS SCALING
就是计算梯度时,梯度一般都会非常小,这里将梯度先乘以一个较大的系数进行放大,避免反向传播发生下溢出,最终再除以一个相同系数进行缩小,恢复正常值,从而在FP16精度的情况下,完成计算。
3 ARITHMETIC PRECISION
这里其实就是介绍了下英伟达的专用硬件模块TensorCore,可以同时完成混合精度的矩阵乘加运算。
ps:这篇paper的作者来自百度和英伟达。
在Nvidia平台上,使用混合精度也非常方便,TensorFlow直接集成了Nvidia的混合精度特性,具体操作如下:
混精操作
参考《Automatic Mixed Precision for Deep Learning》

3.4 Nvidia-编译优化(TensorRT)

除了TensorFlow自己的XLA优化编译之外,Nvidia推出了自己的模型编译优化方案TensorRT。XLA完成的是通用平台的模型压缩和剪枝优化编译,TensorRT更侧重跟自家平台的结合。
在Nvidia的GPU平台上TensorRT应该比XLA有更好的优化效果。TensorRT其实是一个较大的工具体系,混合精度、模型优化编译、自定义Plugin、TensorRT Serving都是它的组成部分。所以,不要单纯的理解TensorRT只是用来做编译优化的。

3.5 Nvidia-Batch合并(TensorRT Inference Serving)

Batch合并操作充分利用了计算平台并行计算的能力。假设有8个请求,一种方式是每个请求顺序发给模型,然后,串行获取结果;另一种是8个请求合并成一个batch请求模型,然后,并行获取结果。在GPU这样的并行计算平台,后者的计算效率更高。
TensorRT Inference Serving就是利用这个特点,在可容忍的时间相应时间内,尽量合并请求,进行batch处理,从而,提升服务的吞吐量。这是BERT模型在TensorRT Inference Serving的表现:
Inference Serving的表现
数据来源:https://github.com/NVIDIA/DeepLearningExamples/tree/master/TensorFlow/LanguageModeling/BERT
使用TensorRT Inference Serving后,服务的吞吐量有明显的提升。

3.6 Nvidia-自定义Plugin(TensorRT)

Plugin的意思是指模型中的特定计算操作。可以是重写TensorFlow中的算子(如softmax操作),也可以是自定义的矩阵乘加运算。TensorRT提供了C++和Python层的接口,可以进行自定义Plugin的编写。
这些自定义的操作,一方面,可以充分利用Nvidia GPU的计算特性;另一方面,在网络编译优化阶段也会有更好的效果。TensorRT的具体使用可以参考《TensorRT Developer Guide》。
这部分会是BERT性能优化最大的地方,后面的内容会围绕这一点重点展开。

4 BERT模型推理加速优化实践

Nvidia对BERT加速做了专门的工作,也获得不不错的效果,先看结果感受下:
BERT模型推理加速优化实践
数据来源:https://devblogs.nvidia.com/nlu-with-tensorrt-bert/

4.1 基于TensorRT API实现

在阅读理解任务上的响应时间压缩到了2.2ms,可见优化效果是非常明显的。英伟达开源了整个实验的数据和代码,具体可以参考《Real-Time Natural Language Understanding with BERT Using TensorRT》
基本思路是:
1 Fine-tuning获得的TensorFlow的ckpt模型(如果需要开启混合精度能力,需要在Fine-tuning步骤完成,建议直接使用英伟达修改过的BERT模型,参考《DeepLearningExamples/TensorFlow/LanguageModeling/BERT》)
2 使用TensorRT重新实现BERT,主要是Transformer部分(可以理解自定义了很多Plugin),同时,也包含任务相关的部分代码(如分类任务和阅读理解任务的实现是不同的)
3 使用TensorRT接口加载ckpt模型文件并获取参数
4 将参数输入给重新实现的BERT网络
5 优化编译并输出优化后的模型文件(TensorRT-engine文件)
6 加载TensorRT-engine文件,并进行推理
文中的示例只提供了阅读理解的实现,如果是分类问题,需要自己使用TensorRT API编写Transformer输出后,任务相关的代码,并对其参数。这里需要熟悉TensorRT的API,操作起来比较麻烦。

4.2 基于Fast Transformer实现

如果先看了《Real-Time Natural Language Understanding with BERT Using TensorRT》这篇文章,并尝试文中的方法进行分类分类任务。再看到基于Fast Transformer的方案,肯定觉得自己走了弯路(PS,我就是这样,汗~)。
BERT的核心是Transformer,Nvidia很贴心的把Transformer(主要是Encoder)以组件的形式进行了加速优化,并作为单独的开源项目发布(实现原理和上面一致)。项目参考《Faster Transformer》
简单来说,就是编写推理服务时,还是继续使用TensorFlow,只是其中的Google默认实现的Transformer被Nvidia换成了自己的定制实现模块。Transformer之外的部分原封不动。这样就既实现了BERT的计算加速,又保证了使用的灵活性。效果还是蛮不错的:
fast-transformer优化效果
数据来源:https://github.com/NVIDIA/DeepLearningExamples/blob/master/FasterTransformer/sample/tensorflow_bert/sample.md
这里多说一句,后面Nvidia会开源Fast Transformer 2.0,核心就是实现了Transformer的Decoder。
另外,TensorRT和Fast Transformer Nvidia有专门的在线研讨会(虽然过期了,但可以回看),这里推荐两个,《利用 TensorRT 自由搭建高性能推理模型》,《Faster Transformer 介绍》

总结

本文介绍了BERT的基本情况,面临的上线问题,以及加速优化的各种方案及原理。最后提出了基于Fast Transformer的通用加速方案。

资料参考

《BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding》:https://arxiv.org/abs/1810.04805

《Attention Is All You Need》:https://arxiv.org/abs/1706.03762

《The Illustrated Transformer》:https://jalammar.github.io/illustrated-transformer/

《The Illustrated BERT, ELMo, and co. (How NLP Cracked Transfer Learning)》:https://jalammar.github.io/illustrated-bert/

《从Word Embedding到Bert模型—自然语言处理中的预训练技术发展史》:https://zhuanlan.zhihu.com/p/49271699

《TinyBERT: Distilling BERT for Natural Language Understanding》:https://arxiv.org/abs/1909.10351

《Nvidia GPU的浮点计算能力》:https://weibo.com/ttarticle/p/show?id=2309403987017473113077

《Video Series: Mixed-Precision Training Techniques Using Tensor Cores for Deep Learning》:https://devblogs.nvidia.com/video-mixed-precision-techniques-tensor-cores-deep-learning/?ncid=so-twi-dplgdrd3-73821

《Mixed Precision Training》:https://arxiv.org/abs/1710.03740

《Automatic Mixed Precision for Deep Learning》:https://developer.nvidia.com/automatic-mixed-precision

《TensorRT Developer Guide》:https://docs.nvidia.com/deeplearning/sdk/tensorrt-developer-guide/index.html#extending

《NVIDIA/tensorrt-inference-server》:https://github.com/NVIDIA/tensorrt-inference-server

《Real-Time Natural Language Understanding with BERT Using TensorRT》:https://devblogs.nvidia.com/nlu-with-tensorrt-bert/

《Faster Transformer》:https://github.com/NVIDIA/DeepLearningExamples/tree/master/FasterTransformer

《利用 TensorRT 自由搭建高性能推理模型》:https://info.nvidia.com/223020-ondemand.html

《Faster Transformer 介绍》:https://mudu.tv/watch/3737641?key=502dfd75f66e66a8d5e4621c0887f617&expire=600

《DeepLearningExamples/TensorFlow/LanguageModeling/BERT》:https://github.com/NVIDIA/DeepLearningExamples/tree/master/TensorFlow/LanguageModeling/BERT

混合精度对模型训练和推理的影响

发表于 2019-10-13

单精度/双精度/半精度/混合精度

计算机使用0/1来标识信息,每个0或每个1代表一个bit。信息一般会以下面的三种形式表示:

1 字符串

字符串的最小单元是char,每个char占8个bit,也就是1个byte。比如字符串“abc”这三个字符组成的串占用的存储空间:

存储空间=1x3=3(bytes)=24(bits)

2 整数

整数包括INT4、INT8、INT16、INT32、INT64,INT后面的数值表示该整数类型占用的byte个数。

3 浮点数

浮点数包括Float16、Float32、Float64,同样,Float后面的数字表示该浮点型占用byte的个数。而这三种浮点数又有个不同的名字:

  • 半精度浮点数:Float16
  • 单精度浮点数:Float32
  • 双精度浮点数:Float64

有了上面单精度、双精度、混合精度三种形式的解释,混合精度就很好理解了。就是计算中存在不同精度的浮点数,比如:

Float16+Float32

混合精度的优点

先说结论:

压缩模型大小

我们一般模型训练使用的是Float32,那换成混合精度有什么好处呢?为了更好理解,我们将Float32的模型参数都换成Float16. 在参数数目不变的情况下,将Float32的参数都更换成Float16后,模型占用的内存就变成了之前的一半。所以,混合精度最直观的优点就是能够压缩模型的大小。

前面为了好理解,将Float32全都转成了Float16,但在实际的模型训练中,Float16因为能表示的精度有限,会导致数据溢出(超出能表示的范围),所以,只能部分操作用Float16,部分操作用Float32.最终导致混合精度的提出。

混合精度比较经典的论文是这篇:

《Mixed Precision Training》

论文介绍了混合精度在模型训练中的方法,并在多个训练场景中证实,混合精度相对于完全Float32的模型的参数训练,最终的算法效果影响不大。

混合精度对模型训练和推理速度的影响

先说结论:

理论上没有提升,反而会下降。但在结合计算平台特性,训练和推理速度会有提升

理论上混合精度只能压缩模型的大小,在训练阶段和推理阶段,都能能大大缓解CPU内存或GPU显存限制对模型训练压力。

因为模型结构和参数数量没有发生显著的变化(忽略混合精度对模型训练,参数更新的影响),理论上训练和推理速度应该不会有大的改变。而且,因为不同的精度需要进行对齐再运算(计算时,先将不同的精度转变成统一的精度后,再进行计算),返回导致计算效率降低,从而会导致训练和推理的速度降低。

但实际上计算平台对这种特殊的计算场景一般都有专门的硬件计算加速,比如:

1 具备专用的半精度计算单元

GPU针对Float16、Float32运算,都有专门的计算单元。

2 单精度支持两个半精度计算同时进行

比如,英伟达的GPU Tesla P100支持在一个Float32里同时进行2次Float16的半精度浮点计算,所以对于半精度的理论峰值可以达到单精度浮点数计算能力的两倍。

3 TensorCore

英伟达的瓦特(如Tesla V100)和图灵架构(如Tesla T4)都具备TensorCore单元,能完成单指令的混合精度矩阵乘加运算。

混合精度的实际表现

我们以英伟达开源的BERT评测对比下:

模型训练:
BERT模型训练

模型推理:
BERT模型推理

总结

混合精度可以明显的对模型的大小进行压缩(内存占用),同时,针对优化的计算平台,在模型训练和推理的速度方面也都有提升。

参考文档:

《Nvidia GPU的浮点计算能力》

《Nvidia BERT评测》

TensorFlow GPU开发环境搭建

发表于 2019-03-29

由于图片外链被禁止了,图片不能显示,完整文章看这里吧:https://zhuanlan.zhihu.com/p/60924644

TensorFlow有CPU版本和GPU版本之分,CPU版本安装相对简单,按着TensorFlow的官方文档进行安装即可。但CPU版本只能使用CPU进行计算,计算效率低。对于简单的模型计算可以使用CPU模式,但对于复杂的模型训练就需要GPU的支持了。

GPU版本安装方式

TensorFlow的GPU版本有两种安装方式:
源码编译安装
这种方式灵活性最强,但这种方式不但会涉及TensorFlow GPU版本计算框架的依赖,还会牵扯到源码编译的工具依赖和库依赖。如果不是有特别的需要,不建议采用这种安装方式。
二进制安装包安装
针对大多数的使用场景,直接使用编译好的二进制安装包进行安装即可,操作相对简单,依赖也比较少。本文主要针对二进制安装包的方式进行安装。

二进制安装包安装方式选择

参考TensorFlow官方文档
TensorFlow官方文档提供了基于命令方式的安装模式。但实际上,文档提供的安装命令更多是一种参考,而不是针对所有显卡和硬件环境都可以适用的,傻瓜式解决方案。或者说,直接按照TensorFlow的官网提供命令进行安装,多半会出现问题。
自定义安装
TensorFlow CPU版本和GPU版本最大的不同在于它们依赖的硬件平台,CPU版本的硬件依赖比较低,甚至可以粗糙的认为对硬件没有特别的要求(桌面或工作站处理器,大多是基于X86计算架构的)。GPU则不同,即便大家目前使用的GPU卡大多是Nvidia的,但Nvidia不同的显卡系列的计算能力和对TensorFlow的支持也是不一样的。所以有必要针对自己实际的GPU显卡,配置与之相对应的运行环境,最终满足TensorFlow GPU版本的运行要求。

TensorFlow GPU版本的运行依赖

GPU版本的TensorFlow运行依赖并不复杂,从底层到上层,依赖关系如下图所示:
运行依赖

显卡
目前深度学习使用的主流GPU大多是Nvidia的显卡。而大家常用的是GeForce系列和Tesla系列。从Nvidia的角度,GeForce系列定位在游戏市场,Tesla系列定位在数据中心。但实际上从经济考虑,很多公司都使用GeForce做模型训练,然后使用Tesla做线上服务(Nvidia禁止公司使用Tesla系列之外的显卡作为数据中心)。
驱动
驱动运行在系统的内核态,是操作系统的一部分,直接跟显卡硬件打交道,是应用层和硬件打交道的门户。不同的显卡需要不同的驱动。
CUDA
CUDA运行在系统的应用层,对通用GPU计算操作做了封装,方便其他组件调用。
cuDNN
cuDNN依赖CUDA库,封装了常用的深度学习方法,供更上层的组件调用。
TensorFlow GPU版本要求
不同版本的TensorFlow,对运行环境是有不同的要求。驱动版本的选择,主要依赖于显卡型号。而CUDA、cuDNN、Python版本的选择,则需要依赖TensorFlow GPU版本的选择:
依赖版本
参考:https://www.tensorflow.org/install/source

在有了显卡之后,后面需要做的,就是从下到上,安装对应版本的驱动、CUDA库、cuDNN库、Python和TensorFlow了。

具体环境搭建步骤

下面我们以超微的GPU工作站为例,逐步搭建TensorFlow GPU开发环境。
系统环境

  • GTX 1080TI 四卡
  • Ubuntu 16.04
  • 目标:TensorFlow GPU 1.10.0版本

(一)驱动安装
驱动选择地址:https://www.nvidia.com/Download/index.aspx?lang=en-us
驱动选择
最终,会下载得到xxx.run的安装文件,直接使用shell安装,

# sudo sh xxx.run

(二)CUDA安装
下载地址:https://developer.nvidia.com/cuda-zone
最新CUDA
我们需要安装的TensorFlow GPU版本为1.10.0,所以CUDA的版本是9。但直接打开是最新版本的CUDA。可以选择上面的“Legacy Releases”,然后,选择需要的版本,
对应版本CUDA
最终,会下载得到xxx.run的安装文件,直接使用shell命令进行安装,

# sudo sh xxx.run

(三)CUDNN安装
下载地址(需要注册):https://developer.nvidia.com/cudnn
cuDNN主要和CUDA版本对齐,
cuDNN
cuDNN主要下载两个文件,
两个文件
下载的两个xxx.deb文件,通过dpkg -i命令进行安装,

# dpkg -i xxx.deb

(四)Python安装
Python可以采用Anaconda环境,具体的安装步骤就不详细展开了,工作中选择了Python3.6版本。只提两点:
全局环境变量设置
Anaconda默认会将环境变量设置到~/.bashrc文件中。如果想全局可见,可以手动在/etc/profile文件中添加环境变量。
使用清华的下载链接
Anaconda的官方下载,国内下载速度很慢,可以直接使用清华的源。
地址:https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/
(五)TensorFlow GPU安装
TensorFlow安装先对简单,直接使用pip命令进行安装即可,但低于1.13.0版本的TensorFlow GPU版本,不能直接使用“pip install tensorflow-gup===xxx”来安装。需要手动下载安装文件,然后进行安装。
TensorFlow GPU历史版本下载地址:https://pypi.org/project/tensorflow-gpu/
历史版本
TensorFlow GPU也可以使用清华的源,但源更新的可能不够及时:
清华TensorFlow GPU地址:https://mirrors.tuna.tsinghua.edu.cn/help/tensorflow/
清华地址

小结

TensorFlow的GPU版本安装,本身并不复杂。关键是要梳理清楚不同组件的依赖关系。不同组件之间没有特别的强依赖,如果发现其中的某个组件有问题,单独卸载和重装即可。

《从零开始学习自然语言处理(NLP)》-DeepPavlov框架解析(4)

发表于 2019-03-02

由于图片外链被禁止了,图片不能显示,完整文章看这里吧:https://zhuanlan.zhihu.com/p/58133705

写在最前面

在这个日新月异的信息时代,海量数据的积累,计算能力的不断提升,机器学习尤其是深度学习的蓬勃发展,使得人工智能技术在不同领域焕发出蓬勃的活力。自己经历了嵌入式开发,移动互联网开发,目前从事自然语言处理算法开发工作。从工程软件开发到自然语言处理算法开发,希望通过这个系列的文章,能够由浅入深,通俗易懂的介绍自然语言处理的领域知识,分享自己的成长,同大家一起进步。

问题描述

在上一篇《从零开始学习自然语言处理(NLP)-NLP Framework开源方案梳理(3)》中梳理了目前流行的NLP开源框架,这里重点介绍下DeepPavlov框架。DeepPavlov框架的模型实用性很强,对实际的生产开发有很大的借鉴意义。

框架组成

DeepPavlov是一个基于TensorFlow和Keras的,专门针对对话系统研究和实验部署的自然语言处理框架。
项目地址:http://docs.deeppavlov.ai/en/master/#
框架主要包括:
常用的NLP模型(包括Pre-train模型)
如词向量训练、分类、命名实体识别(NER)、相似度计算等;
针对对话系统实现和评测的实验框架(Framework)
基于Json文件进行开发流程和数据流pipeline配置;
提供同第三方应用进行集成的工具
如与Amazon Alexa和Microsoft Bot Framework的集成;
为对话模型的评测提供Benchmark环境
DeepPavlov的默认Pre-train模型和测评数据集主要基于英文和俄文,对于中文场景需要做适当的调整。

框架使用对象

新模型开发者
方便同已有Benchmark模型进行对比评测
普通NLP任务处理者
如针对内容审核任务,敏感信息增加掩码等任务,可以直接使用框架提供的分类和序列标注模型,完成业务服务的快速开发和测评;
对话系统开发者
DeepPavlov是为对话系统场景量身定制的。对话系统开发者,可以直接参考使用;
对话系统应用开发者
DeepPavlov框架为应用集成提供了专门的工具,可以直接与Amazon Alexa,Microsoft Bot Framework等平台进行对接。

框架使用

规范开发流程
框架将数据模型服务的开发和验证流程(如数据清洗、模型设计、模型训练、模型选优、模型评测),使用Json配置文件串联成pipeline。能够很好的规范开发流程;
新模型对比评测
为对话模型的评测提供Benchmark环境,方便新模型的对比评测。但环境主要基于英文和俄文,对于中文任务,需要重新训练对比;
常用NLP模型使用
框架内置了很多常用模型(以分类为例,就包含了cnn_model,bilstm_model,bilstm_attention_model,transformer_model等12种模型实现),在项目中可以直接使用;
同时框架提供了Pre-train模型,但主要是基于英文和俄文的,对于中文场景需要自己进行重新训练;
对话系统开发
DeepPavlov是为对话系统场景量身定制的,对话系统开发者,可以直接参考使用;

DeepPavlov框架层次

DeepPavlov从整体到局部,可分为如下三个层次:
DeepPavlov框架层次
下面我们从外层到内层,逐层介绍DeepPavlov的框架设计。

DeepPavlov顶层框架

DeepPavlov框架
Agent
同用户直接交互的代理,直接接收用户输入的纯文本信息(raw text)
Skill
领域技能,如基于意图-词槽的任务型技能,基于Seq2Seq的闲聊技能,基于知识图谱的知识问答技能;
Skill Manager
确定用户query,选择使用哪些skill,并确定将哪一个skill的召回结果作为最终的回复;
Component
Skill实现的组成部分,如针对任务型技能,包括数据预处理component、意图识别component、slotfilling component等;
Chainer
Chainer以Json配置文件的形式,将某个skill相关的所有component串联起来;
Data Storage
框架本身包含的Pre-train模型和Benchmark评测数据集

Skill框架

DeepPavlov内置的skill主要包括:
任务型skill(Goal-Oriented Dialogue Bot)
基于意图/词槽/对话管理等component实现的问答skill。
任务型skill
阅读理解skill(Open-Domain Question Answering)
基于阅读理解实现问答skill。相对于阅读理解component(Context Question Answering),skill还包含在多个召回结果中进行排序的能力。
规则型skill(Pattern Matching)
基于自定义规则实现问答skill。
Seq2Seq skill(Sequence-To-Sequence Dialogue Bot)
基于Seq2Seq实现问答skill。
Seq2Seq skill
常见问题问答skill(Frequently Asked Questions Answering)
先将句子嵌入为向量(使用词向量叠加),然后做分类处理(给每一个answer一个打分),选取打分最高的answer作为最终回复的skill。
商品查询skill(eCommerce Bot)
商品查询回复skill,支持多轮(添加过滤条件)。下面是场景示例,
商品查询skill

基本能力框架

DeepPavlov内置的基本能力主要包括:
数据预处理component(Data processors)
主要提供包括分词、嵌入向量化等预处理能力(主要基于俄文和英文)。
阅读理解component(Context Question Answering)
相对于阅读理解skill(Open-Domain Question Answering),component不包含对多个召回结果进行排序(rank)的能力。具体的处理场景示例如下,
阅读理解component
分类component(Classification)
分类组件,可以用来做场景和意图的分类。
Morphological Tagger component
一种特殊的POS?
命名实体识别component(Named Entity Recognition)
NER能力组件。
相似度计算component(Neural Ranking)
通过基于孪生网络完成相似度计算,实现在标准问答库中标准答复的查找。
词槽填充component(Slot filling)
在NER的基础上,增加了词表限制。
*拼写纠错component(Spelling Correction)
提供了两种纠错方法:

  • levenshtein_corrector :基于编辑距离
  • brillmoore:基于统计模型

TF-IDF排序component(TF-IDF Ranking)
基于TF-IDF的文档召回排序。
流行度排序component(Popularity Ranking)
将TF-IDF打分和流行度打分作为特征,通过逻辑回归计算流行度,最终实现排序。

Json配置文件解析

DeepPavlov通过Json配置文件实现开发流程控制和数据流pipeline的控制。
上面提到DeepPavlov主要分为Agent、Skill和Component三个层次。而Json配置文件主要应用在Skill和Component这两个层面。而对Agent的控制,框架通过直接的代码来实现,例如,
agent
其中,
skills
Agent支持的所有skill列表;
skills_filter
针对用户query,确定Agent使用哪些skill;
skills_filter
通过召回的不同skill结果,确定最后的回复内容给用户;
下面我们具体的介绍下Json配置文件的具体结构。

Json配置文件结构

Json配置文件结构
如上图所示,Json配置文件主要由如下五个部分组成(参考分类component):
dataset_reader
主要负责数据的读取。
dataset_reader
dataset_iterator
数据迭代器,从dataset_reader中获得数据,然后按batch抽取数据,供后面的模型训练使用。
dataset_iterator
chainer
配置文件的核心,将数据预处理、模型选优和模型预测输出,通过pipeline(”pipe”字段内进行约束)的形式串联起来。

"chainer": {
"in": [
  "x"
],
"in_y": [
  "y"
],
"pipe": [
  {
    "id": "classes_vocab",
    "class_name": "simple_vocab",
    "fit_on": [
      "y"
    ],
    "save_path": "{MODELS_PATH}/classifiers/{PROJECT_NAME}_{MODEL_NAME}/classes.dict",
    "load_path": "{MODELS_PATH}/classifiers/{PROJECT_NAME}_{MODEL_NAME}/classes.dict",
    "in": "y",
    "out": "y_ids"
  },
  {
    "in": "x",
    "out": "x_tok",
    "id": "my_tokenizer",
    "class_name": "char_tokenizer",
    "tokenizer": "char_tokenizer"
  },
  {
    "in": "x_tok",
    "out": "x_ids",
    "id": "seq_to_emb_ids",
    "class_name": "seq_to_emb_ids",
    "emb_file_path":"{EMBED_PATH}",
    "text_size":250
  },
  {
    "in": "y_ids",
    "out": "y_onehot",
    "class_name": "one_hotter",
    "id": "my_one_hotter",
    "single_vector": true,
    "depth": "#classes_vocab.len"
  },
  {
    "in": [
      "x_ids"
    ],
    "fit_on_batch_preprocess": [
      "x_ids",
      "y_onehot"
    ],
    "out": [
      "y_pred_probas"
    ],
    "main": true,
    "class_name": "keras_classifier_model",
    "graph_metrics": "multilabel_f1",
    "save_path": "{MODELS_PATH}/classifiers/{PROJECT_NAME}_{MODEL_NAME}/model",
    "load_path": "{MODELS_PATH}/classifiers/{PROJECT_NAME}_{MODEL_NAME}/model",
    "n_classes": "#classes_vocab.len",
    "train_emb": false,
    "kernel_sizes_cnn": [
      1,
      2,
      3,
      4,
      5
    ],
    "filters_cnn": 512,
    "optimizer": "Adam",
    "learning_rate": 0.001,
    "learning_rate_decay": 0.9,
    "loss": "categorical_crossentropy",
    "embedding_matrix": "#seq_to_emb_ids.matrix",
    "text_size": 250,
    "last_layer_activation": "softmax",
    "coef_reg_cnn": 0.0,
    "coef_reg_den": 0.0,
    "dropout_rate": 0.5,
    "dense_size": 30,
    "model_name": "cnn_model"
  },
  {
    "in": "y_pred_probas",
    "out": "y_pred_ids",
    "class_name": "proba2labels",
    "max_proba": true
  },
  {
    "in": "y_pred_ids",
    "out": "y_pred_onehot",
    "ref": "my_one_hotter"
  },
  {
    "in": "y_pred_ids",
    "out": "y_pred_labels",
    "ref": "classes_vocab"
  }
],
"out": [
  "y_pred_ids",
  "y_pred_onehot",
  "y_pred_labels",
  "y_pred_probas"
]
},

官方文档中,将“pipe”字段内的每一对花括号({})中的内容成为一个component(注意这里的component和上面提到的框架component是不同的。为了方便区分,我们将”pipe”中的component标识为pipe-component)。
train
模型训练、模型选优和评测配置。

"train": {
"epochs": 10,
"batch_size": 256,
"metrics": [
  {
    "name": "cal_confusion_matrix",
    "inputs": [
      "y",
      "y_pred_labels"
    ]
  },
  {
    "name": "f1_micro",
    "inputs": [
      "y",
      "y_pred_labels"
    ]
  },
  {
    "name": "recall_micro",
    "inputs": [
      "y_ids",
      "y_pred_ids"
    ]
  },
  {
    "name": "precision_micro",
    "inputs": [
      "y_onehot",
      "y_pred_onehot"
    ]
  },
  {
    "name": "f1_macro",
    "inputs": [
      "y_onehot",
      "y_pred_onehot"
    ]
  },
  {
    "name": "precision_macro",
    "inputs": [
      "y",
      "y_pred_labels"
    ]
  },
  {
    "name": "recall_macro",
    "inputs": [
      "y_ids",
      "y_pred_ids"
    ]
  },
  {
    "name": "recall_group",
    "inputs": [
      "y_onehot",
      "y_pred_onehot"
    ]
  },
  {
    "name": "precision_group",
    "inputs": [
      "y",
      "y_pred_labels"
    ]
  },
  {
    "name": "f1_group",
    "inputs": [
      "y_ids",
      "y_pred_ids"
    ]
  }
],
"validation_patience": 5,
"val_every_n_epochs": 1,
"log_every_n_epochs": 1,
"show_examples": true,
"validate_best": true,
"test_best": true,
"report_path": "{MODELS_PATH}/classifiers/{PROJECT_NAME}_{MODEL_NAME}/report.xlsx"
},

其中,
“metric”字段中排在最前面的指标,作为模型选优的标准。
metadata
相关相关的常量配置。
metadata
其中,”imports”是DeepPavlov框架之外自定义实现。

DeepPavlov存在的问题

环境依赖
DeepPavlov是基于TensorFlow和Keras实现的,不能继承其他计算框架的模型实现(如PyTorch)。
语言支持
Pre-train模型和评测数据集主要基于英文和俄文,不支持中文。
生产环境部署
DeepPavlov在运行时需要依赖整个框架源码,开发环境对框架修改后,生产环境需要更新整个框架。同时,也不能直接将功能Component作为服务独立导出,不适合在生产环境的部署和发布。

《TensorFlow内核剖析》笔记

发表于 2019-02-24

由于图片外链被禁止了,图片不能显示,完整文章看这里吧:https://zhuanlan.zhihu.com/p/57559407

市面上对TensorFlow使用介绍的书非常之多,但剖析原理的却很少。如果对TensorFlow的底层实现感兴趣,刘光聪的《TensorFlow内核剖析》是一个不错的选择。同时,这是一本开源技术书,可以免费获得。

DistBelife框架

DistBelife框架

DistBelief缺点

DistBelief缺点

TensorFlow设计原则

TensorFlow设计原则

TensorFlow优势

TensorFlow优势

TensorFlow里程碑

TensorFlow里程碑

TensorFlow技术栈

TensorFlow技术栈

TensorFlow系统架构

TensorFlow系统架构
TensorFlow系统架构
说明
说明
Client
Client
Master
Master
Worker
Worker
Kernel
Kernel

集群组建

集群组建

本地模式

本地模式
本地模式
本地模式:图操作
本地模式:图操作

分布式模式

分布式模式
分布式模式
分布式模式-图操作
分布式模式-图操作
PS与Worker
PS与Worker
服务互联
服务互联
单Client接入集群
单Client接入集群
多Client接入集群
多Client接入集群
会话协同
会话协同
会话控制领域模型
会话控制领域模型
获取远端设备集
获取远端设备集

《从零开始学习自然语言处理(NLP)》-NLP Framework开源方案梳理(3)

发表于 2019-02-01

由于图片外链被禁止了,图片不能显示,完整文章看这里吧:https://zhuanlan.zhihu.com/p/56159591

写在最前面

在这个日新月异的信息时代,海量数据的积累,计算能力的不断提升,机器学习尤其是深度学习的蓬勃发展,使得人工智能技术在不同领域焕发出蓬勃的活力。自己经历了嵌入式开发,移动互联网开发,目前从事自然语言处理算法开发工作。从工程软件开发到自然语言处理算法开发,希望通过这个系列的文章,能够由浅入深,通俗易懂的介绍自然语言处理的领域知识,分享自己的成长,同大家一起进步。

问题描述

新的项目开启时,一般会经历如下的流程:

  • 业务需求梳理
  • 算法方案选择
  • 模型实现:选择开源方案,或自己实现
  • 模型训练:数据清洗、模型训练(使用训练集)
  • 最优模型选择:依据验证集结果,选择最优模型
  • 模型评测:依据测试集结果,对模型进行评测
  • 模型优化:本模型调优,或选择新的模型
  • 模型服务上线

而在实际的项目开发中,存在如下的问题:
1模型实现问题
模型实现一般会选择开源方案,或自己编码实现。自己编码实现开发和调试成本高。直接选择开源方案,会面临开发环境不统一,编译问题,代码结果和可靠性难以保证等问题;
2模型训练和评测问题
该阶段会设计到数据清洗,输入读入,数据迭代器设计,数据预处理,词向量训练与准备,分词,文本转索引,
标签ont-hot表示,训练集/验证集/测试集划分,训练过程最优模型选择,模型评测(准确度A、精确度P、召回率R、F1值等),数据分析(结果分析,混淆矩阵分析,ROC/AUC分析),Tensorboard结果查看等。由于该部分设计的流程和步骤较多,自己编码开发和调试工作量大,而开源方案很多步骤和组件并不全面。
3 模型优化问题
除了在现有模型的基础上进行局部优化外,还会选择新的模型。如果选择新的模型,则会重新自己编码实现或选择开源方案,会再次经历前面提到的问题1(模型实现问题)和问题2(模型训练和评测问题)。
4 模型服务上线问题
模型服务上线,同模型的训练和预测和类似,但又不完全相同。模型上线需要和模型训练一样的预处理,词向量,分词,文本转索引等步骤,但不需要模型的测评。同时,模型上线要求只能包含模型的训练文件,
而不能包括模型的代码。通常需要编写专门的代码用于模型服务上线。
一般来说,针对上面的问题,公司都会有一个统一的NLP算法框架,
一方面,统一模型的实现、评测和上线流程
另一方面,框架自身包含很多现成的模型,便于业务在算法落地方面的快速验证
大多数公司并不开源自己的NLP算法框架,但开源社区NLP开源框架还是蛮多的,这里做一个统一的梳理。

针对对话系统的Framework

1 DeepPavlov

运行依赖:TensorFlow/Keras
支持功能:
支持功能
项目地址:
https://github.com/deepmipt/DeepPavlov

2 ParlAI

运行依赖:Pytorch
支持功能:
支持功能
项目地址:https://github.com/facebookresearch/ParlAI

3 Rasa

运行依赖:Python
支持功能:纯任务型对话
项目地址:https://www.rasa.com/

4 OpenDial

运行依赖:Java
支持功能:对话系统
描述:主要基于传统方法,深度网络较少涉及。
项目地址:https://github.com/plison/opendial

通用NLP Framework

1 Intel NLP-Architect

运行依赖:TensorFlow
支持功能:
支持功能
项目地址:http://nlp_architect.nervanasys.com/

2 AllenNLP

运行依赖:Pytorch
支持功能:
支持功能
项目地址:
https://allennlp.org/

3 PyText

运行依赖:Pytorch
支持功能:
支持功能
项目地址:
https://pytext-pytext.readthedocs-hosted.com/en/latest/#

NLP基础依赖组件项目(提供pre-train模型)

1 Stanford CoreNLP

运行依赖:Java
支持功能:
支持功能
项目地址:
https://stanfordnlp.github.io/CoreNLP/index.html

2 Stanford NLP

运行依赖:Pytorch
支持功能:
支持功能
项目地址:
https://stanfordnlp.github.io/stanfordnlp/tokenize.html

3 spaCy

运行依赖:Python
支持功能:
支持功能
项目地址:
https://spacy.io/

小结

本文梳理了实际的业务算法落地开发过程,并提出了其中存在的问题,和解决方案。对当前开源的NLP框架做了整理,可以依据自身的需要开发自己的NLP算法框架,规范开发流程,提升业务落地效率。同时,也可以直接从开源方案中获取自己需求的算法实现模块。后续有新的开源框架方案,会持续整理进来。

深度学习的高阶数学

发表于 2019-02-01

由于图片外链被禁止了,图片不能显示,完整文章看这里吧:https://zhuanlan.zhihu.com/p/56159815

有了基础的《概率/统计》、《线性代数》、《微积分》知识,就可以上手深度学习的算法和实践了。但经过一段时间的工程实践,慢慢觉得大多数时间都用在选模型,调超参,或者是网络结构的排列组合上。深度学习的黑盒特性越来越明显。难道深度学习工程师就当真是数据“炼丹师”吗?
如果,你有了这样的感觉,下面的视频不妨抽时间看看(都需要翻墙):

李宏毅《Machine Learning and having it deep and structured》

不多说,直接看目录吧。
课程地址:http://speech.ee.ntu.edu.tw/~tlkagk/courses_MLDS18.html
《Theory 1 - Why Deep Structure》
 Can shallow network fit any function
 Potential of Deep
 Is Deep better than Shallow
《Theory 2 - Optimization》
 When Gradient is Zero
 Deep Linear Network
 Does Deep Network have Local Minima
 Geometry of Loss Surfaces (Conjecture)
 Geometry of Loss Surfaces (Empirical)
《Theory 3 - Generalization 》
 Capability of Generalization
 Indicator of Generalization

Sanjeev Arora《The mathematics of machine learning and deep learning》

视频地址:https://www.youtube.com/watch?v=r07Sofj_puQ
这是ICM2018的主题演讲,虽然Sanjeev Arora作为普林斯顿计算机科学的教授,但演讲内容深入浅出,并没有涉及大量的数学公式和推导,这里贴一下提纲:
内容提纲

小结

这两部分的内容是相互呼应的,可以先看李宏毅老师的课程,然后在看Sanjeev Arora教授的分享总结。

《从零开始学习自然语言处理(NLP)》-TF-IDF算法(2)

发表于 2019-01-27

由于图片外链被禁止了,图片不能显示,完整文章看这里吧:https://zhuanlan.zhihu.com/p/55843621

写在最前面

在这个日新月异的信息时代,海量数据的积累,计算能力的不断提升,机器学习尤其是深度学习的蓬勃发展,使得人工智能技术在不同领域焕发出蓬勃的活力。自己经历了嵌入式开发,移动互联网开发,目前从事自然语言处理算法开发工作。从工程软件开发到自然语言处理算法开发,希望通过这个系列的文章,能够由浅入深,通俗易懂的介绍自然语言处理的领域知识,分享自己的成长,同大家一起进步。

问题描述

在上一篇文章中(《《从零开始学习自然语言处理(NLP)》-倒排索引(1)》)描述了基于关键词搜索的基本原理,以及通过倒排索引来提升和关键词相关网页的查询。本文在上文的基础上提出一个新的问题:
如果通过倒排索引查找到的网页都包含全部的查询关键字,而且,召回(符合查找条件)的网页数目又很多,这就需要将网页与查询Query的相关度进行排序了。相关度高的网页排在查询结果的前面,相关度低的网页排在后面。那问题来了,如何依据网页与查询关键词的相关性对召回的网页做排序呢?

基于TF(Term Frequency,词频)进行排序

最容易想到的便是基于词频打分进行排序,具体来说,对于查询Query:“林俊杰/2019/演唱会/行程”,下面的哪个网页跟查询Query的相关度更高呢?
网页a

[林俊杰]/[2019]/全球/[演唱会]/[行程]/发布/,/这是/[林俊杰]/的/第/20/场/全球/巡演/。
关键字 出现频次
林俊杰 2
2019 1
演唱会 1
行程 1

网页b

在 [林俊杰]/[2019]/全球/[演唱会]/[行程]/发布/之后/,/田馥甄/也/发布/了/今年/的/巡演/计划/,/她的/第一站/是/台北/。
关键字 出现频次
林俊杰 1
2019 1
演唱会 1
行程 1

显然网页a和Query的相关度更高。当然对于计算机就没有这么“显然”了,它需要依靠规则和具体算法来计算判断。基于词频的排序用公式表示就是,
相关性计算
其中,
k:Query中查询关键词序号
参数说明

为了方便计算,我们假设每个网页包含的词的总数为100,通过上面的公式,
网页a

网页a相关度=2/100+1/100+1/100+1/100=0.05

网页b

网页b相关度=1/100+1/100+1/100+1/100=0.04

通过上面的公式,计算机也能“显然”的判断,网页a与查询Query的相关度更高了。

基于TF排序的问题

假设现在有新的召回网页,
网页c

在 [林俊杰]/[2019]/全球/[演唱会]/[行程]/发布/之后/,/众多/明星/也/都/发布/了/自己/[2019]年/的/巡演/计划/,/[行程]/安排/如下/,
关键字 出现频次
林俊杰 1
2019 2
演唱会 1
行程 2
网页c相关度=1/100+2/100+1/100+2/100=0.06

显然基于词频的相关性计算公式,网页c(相关度0.06)大于网页a(相关度0.05),但真实情况是,网页c和查询Query的相关度,并没有网页a大。

IDF(Inverse DocumentFrequency,逆文件词频)

上面的问题关键在于用户的查询Query主要关注的是”林俊杰“,至于”2019“,”行程“等信息也是在林俊杰的基础上展开的。所以,现在要解决的问题便是,排序算法如何能够凸显出”林俊杰“这个关键的查询信息。在这里便引入了IDF(Inverse DocumentFrequency,逆文件词频)。
我们先看下它的定义:
IDF定义
其中,
分母的+1操作,是为了避免当所有文档都不包含该关键词时,分母出现为0的情况。
IDF的分子是固定的,所以,IDF的特性主要体现在分母上。
从IDF的定义可以看出,
1 越是能代表特定内容的关键词,包含该关键词的网页越少,IDF值越高,如“林俊杰”
2 越是和内容主旨不相关的关键词,包含该关键词的网页越多,IDF值越低,如“2019”,“行程”
所以,IDF值就能很好的体现出查询Query关键字,与需要查询内容的相关性。

基于TF-IDF进行排序

结合TF和IDF的特定,便有了TF-IDF,定义也非常直观,
TF-IDF
具体来说就是,一个网页与查询Query的相关性体现在:
1 网页中包含查询关键词的频度
2 查询关键词对查询内容的反映程度
基于TF-IDF,网页与查询Query的相关性,改写为,
相关性定义
其中,
参数说明
在实际工程中,TF和IDF值,以及TF-IDF值针对于具体网页是提前计算好的,当搜索系统接收到用户的查询Query后,能够实时计算查询关键词与网页的相关度。

小结

本文沿用了《《从零开始学习自然语言处理(NLP)》-倒排索引(1)》中搜索的例子,提出了在网页包含所有查询关键词的情况下,如何对网页与查询Query的相关性进行排序。文中提出了基于TF的相关性排序方法,同时,也指出了该方法存在的问题。最终,引出TF-IDF算法:结合查询关键词在网页中的出现频率和该关键词反映查询内容程度两个特征,对召回网页进行排序。

《从零开始学习自然语言处理(NLP)》-倒排索引(1)

发表于 2019-01-20

由于图片外链被禁止了,图片不能显示,完整文章看这里吧:https://zhuanlan.zhihu.com/p/55296265

写在最前面

在这个日新月异的信息时代,海量数据的积累,计算能力的不断提升,机器学习尤其是深度学习的蓬勃发展,使得人工智能技术在不同领域焕发出蓬勃的活力。自己经历了嵌入式开发,移动互联网开发,目前从事自然语言处理算法开发工作。从工程软件开发到自然语言处理算法开发,希望通过这个系列的文章,能够由浅入深,通俗易懂的介绍自然语言处理的领域知识,分享自己的成长,同大家一起进步。

问题描述

倒排索引是搜索引擎的基础算法,在本文中我们以一个简单的例子来详细介绍倒排索引的思想和实现。
假设用户有个搜索query:“林俊杰2019演唱会行程”。百度的搜索结果如下:
百度搜索结果
如果要求你来设计一个搜索引擎,来解决这个问题,你会如何着手呢?

问题简化

现在我们把这个问题具体化。我们除了有要查询的query:“林俊杰2019演唱会行程”。还有被查询的网页数据库。这里我们做个简化,假设我们的网页数据库内容只有如下4条:
网页1:

2019年,JJ林俊杰全球演唱会在北京首场演出,行程如下xxxxxxx;

网页2:

林俊杰,吴亦凡终于同框合影 ,惹粉丝们尖叫连连,xxxxx;

网页3:

蔡依林2019世界演唱会行程全曝光,xxxxx;

网页4:

告别2018,迎接崭新的2019,xxxxxx;

简单来说,就是从网页1~4中选取最理想的查询结果。你会怎么做呢?

关键词匹配

最容易想到的方法就是关键词匹配了,简单的来说,就是网页中包含查询的关键词越多,网页和查询query的相关度也就越大。
在做关键词查询前,一般文本会先进行预处理。这里的预处理主要包括去停用词和分词。
去停用词
去除和查询不相关的内容,比如本例子中的标点符号。在其他场景中,除了标点符号也会去除一些特别的字或词。
分词
分词主要目的是将句子切长短语或关键字,这样才利于查询匹配。比如“林俊杰2019演唱会行程”可以分词成,

林俊杰/2019/演唱会/行程

当然网页也需要这样进行分词:
网页1:

2019/年/JJ/林俊杰/全球/演唱会/在/北京/首场/演出/行程/如下/xxxxxxx

网页2:

林俊杰/吴亦凡/终于/同框/合影 /惹/粉丝们/尖叫/连连/xxxxx

网页3:

蔡依林/2019/世界/演唱会/行程/全曝光/xxxxx

网页4:

告别/2018/迎接/崭新/的/2019/xxxxxx;

分词是一项专门的技术,在实际工程中可以至今借助工具来完成,比如jieba分词。
分词处理后,我们用查询query中的关键词在网页数据库中进行关键词匹配,并统计匹配数目:

网页序号 匹配关键词 匹配个数
网页1 2019,林俊杰,演唱会,行程 4
网页2 林俊杰 1
网页3 2019,演唱会,行程 3
网页4 2019 1

从“匹配个数”中很容易确定,网页1就是和查询query最匹配的网页。

倒排索引

讲到这里大家可能会疑问,这和倒排索引有什么关系?实际上,如果仔细考虑上面的关键词查询过程,会发现这种方法有个很大的效率问题:我们的例子中只有4个待查询的网页,而实际的互联网世界的网页数目是非常巨大的。假设互联网世界的网页数据为N,那么使用关键词查询的时间复杂度就是O(N),显然,这样的时间复杂度还是太大了,而倒排索引就很好的优化了这个问题。
从倒排索引这个名字很容易联想出它的实现,关键就是“倒排”的“索引”。在前面的讲解中,我们的索引(key)是网页,内容(value)是关键字。倒排索引就是反过来:内容关键字作为索引(key),所在网页作为内容(value)。前面的表格就可以改写成,

关键词 包含关键词的网页
林俊杰 网页1,网页2
2019 网页1,网页3,网页4
演唱会 网页1,网页3,
行程 网页1,网页3

通过上面的表格,很明显网页1是包含最多关键词的网页,也是和查询query相关度最高的网页。采用倒排索引的方法,搜索的时间复杂度得到了明显的降低。

搜索引擎框架

有了倒排索引的知识,我们就可以搭建简单的搜索引擎了,
搜索引擎框架
具体步骤包括:
网页抓取
主要是借助网络爬虫,来抓取网络世界的所有网页,并进行存储。网络爬虫是一项专门的技术,目前工程上也有很多现成的开源工具。
倒排索引生成
将抓取后的网页经过预处理后,整理生成倒排索引。
用户在线查询
借助倒排索引,搜索引擎能够满足用户的实时在线查询。
前两个步骤是不用考虑实时性的,可以离线进行,而用户的在线查询则需要保证实时性。

小结

本文通过一个搜索查询的例子,引出关键词查询的方案,及遇到的问题。进而介绍了倒排索引的原理,和搜索引擎的整体框架。现代搜索引擎是一个非常庞大和复杂的系统工程,这里的例子只是为了方便大家理解做了特别的简化。文中提到的分词和网络爬虫也是专门的文本处理技术,在后续的文章后,会根据需要专门展开。

12…8
Liu Caiquan

Liu Caiquan

71 日志
11 标签
© 2019 Liu Caiquan
由 Hexo 强力驱动
主题 - NexT.Mist
本站总访问量次