使用bert模型将可变长度句子映射到固定长度向量(服务器)

bert-serving-multilingual-server的Python项目详细描述


>**此readme.md是pypi的镜像。请访问https://github.com/hanxiao/bert-as-service/blob/master/readme.md获取最新的自述文件。md.**
<;h1 align="center">;bert-as-service<;h1>;

<;p align="center">;将bert模型用作句子编码服务,即,将可变长度句子映射到固定长度向量。<;/p>;

<;p align="center">;
<;a href="https://github.com/hanxiao/bert as service/stargazers">;
<;img src="https://img.shields.io/github/stars/hanxiao/bert-as-service.svg?colora=orange&;colorb=orange&;logo=github"
a lt="github stars">;
<;/a>;
<;a href="https://pypi.org/search/?q=bert serving">;
<;img src="https://img.shields.io/pypi/v/bert-serving-server.svg?colorb=brightgreen"
a lt="pypi package">;
<;/a>;
<;a href="https://bert as service.readthedocs.io/">;
<;img src="https://readthedocs.org/projects/bert-as-service/badge/?version=latest"
a lt="readthedoc">;
<;/a>;
<;a href="https://github.com/hanxiao/bert as service/releases">;
<;img src="https://img.shields.io/github/release/hanxiao/bert as service.svg"
alt="github release">;
<;/a>;
<;a href="https://github.com/hanxiao/bert as service/issues">;
<;img src="https://img.shields.io/github/issues/hanxiao/bert as service.svg"
alt="github issues">;
<;/a>;
<;a href="https://github.com/hanxiao/bert as service/blob/master/license">;
<;img src="https://img.shields.io/github/license/hanxiao/bert as service.svg"
alt="github license">;
<;/a>;
<;a href="https://twitter.com/intent/tweet?text=wow:&url=https%3a%2f%2fgithub.com%2fhanxiao%2fbert as service">;
<;img src="https://img.shields.io/twitter/url/https/github.com/hanxiao/bert-as-service.svg?
<;p>;

<;p align="Center">;
<;br/>
<;p align="Center">;
<;lt;lt;lt;lt;lt;lt;lt;a;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;是的《入门入门入门入门》lt;lt;lt;lt;a;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;a;lt;lt;a;lt;lt;a;lt;lt;lt;a;lt;lt;lt;lt;lt;a;lt;lt;a;lt;lt;a;lt;lt;a;lt;lt;a;lt;lt;lt;a;lt;lt;lt;a;lt;lt;lt;lt;a;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;a;lt;lt;lt;lt;lt;lt;a;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt;lt>;•
<;a href="https://hanxiao.github.io/2019/01/02/serving-google-bert-in-production-using-tensorflow-and-zeromq/"target=""空白">;博客<;/a>;

<;/p>;


<;p align="center">;
<;img src=".github/demo.gif?raw=true"width="700">;
<;/p>;

<;h6 align="center">;由han xiao制作。•:globe戋u with戋子午线:<;a href="https://hanxiao.github.io">;https://hanxiao.github.io<;/a>;


<;h2 align="center">;它是什么<;/h2>;

**bert**是一个NLP模型[由谷歌开发](https://github.com/google-research/bert),用于训练前语言表示。它利用了大量在web上公开的纯文本数据,并以无监督的方式进行培训。对每种语言来说,预先训练bert模型是一个相当昂贵但一次性的过程。幸运的是,google发布了几个预先训练的模型,其中[您可以从这里下载](https://github.com/google research/bert pre-trained models)。



**句子编码/嵌入**是许多nlp应用程序(如情感分析、文本分类)所需的上游任务。目标是将可变长度的句子表示为固定长度的向量,例如"hello world"到"0.1,0.3,0.9"。向量的每个元素都应该"编码"原始句子的一些语义。

**最后,`bert as service`**使用bert a是一个句子编码器,通过zeromq将其作为服务托管,允许您将句子映射到两行代码中的固定长度表示。

<;h2 align="center">;突出显示<;/h2>;

-:望远镜:**最新技术**:建立在google ai发布的12/24层bert模型上,该模型被认为是nlp社区的里程碑。
-:孵化器:**易于使用**:只需要两行代码获取句子/标记级别的编码。
-:zap:**快速**:单个tesla m40 24gb上900个句子/秒。低延迟,速度优化。请参阅[Benchmark](Zap Benchmark)。
-:octopus:**scalable**:在多个GPU和多个客户端上平滑地扩展,而不必担心并发性。参见[Benchmark](speed-wrt-num嫒客户端)。
-:gem:**可靠**:在数十亿个句子中进行测试;连续几天不间断运行或出现任何令人讨厌的异常。

更多功能:[xla&fp16支持](覲speed wrt--fp16和--xla);混合GPU-CPU工作负载;优化图形;` tf.数据"友好的;自定义标记器;灵活的池策略;[内置http服务器](使用bert作为服务以json方式服务http请求)和仪表板;[异步编码](异步编码);[多播](向多个客户端广播)等。



<;h2 align="center">;通过"pip"安装服务器和客户端。它们可以单独安装,甚至可以安装在*不同的*机器上:
``bash
pip install bert serving server``server
pip install bert serving client` client,独立于`bert serving server`
````

注意,服务器必须在**python>上运行;=3.5**,其中**tensorflow>;=1.10**(*一点十*)。同样,服务器不支持python 2!

:要点:客户机可以同时在python 2和python 3上运行[出于以下考虑](q-can-i-run-it-in-python-2)。

<;h2 align="center">;入门<;h2>;

下载一个预先训练过的bert模型
下载下面列出的模型,然后将zip文件解压缩到某个文件夹中,例如`/tmp/english_l-12_h-768_a-12/`

<;details>;
<;summary>;已发布的预训练bert模型列表(单击展开…)<;summary>;


<;表>;
<;tr>;<;td>;<;a href="https://storage.googleapis.com/bert廑u models/2018廑u 10廑18/uncased廑u l-12廑u h-768廑a-12.zip">;bert base,uncased<;/a>;<;/td>;<;td>;12层,768隐藏,12头,110m参数<;/td>;<;
<;tr>;<;td>;>;<;a href="https://storage.googleapis.com/bert_models/2018_10_18/uncased_l-24_h-1024_a-16.zip">;伯特大,uncased<;/a>;lt;/td>;<;td>;24层,1024个隐藏,16个头,340m参数<;/td>;
<;tr>;<;td>;>;a href="https://storage.googleapis.com/bert_models/2018_10_18/cased_l-12_h-768_a-12.zip">;bert base,cased<;/a>;<;/td>;<;td>;12层,768隐藏,12个头,110m参数<;/td>;<;/tr>;
<;tr>;<;td>;<;a href="https://storage.googleapis.com/bert_models/2018_10_18/cased_l-24_h-1024_a-16.zip">;bert large,cased<;/a>;<;/td>;<;td>;24层,1024个隐藏,16个头,340m参数<;/td>;
<;tr>;<;td>;>;a href="https://storage.googleapis.com/bert_models/2018_11_23/multi_cased_l-12_h-768_a-12.zip">;bert base,多语言cased(new)<;/a>;<;/td>;<;td>;104种语言,12层,768隐藏,12个磁头,110m参数<;/td>;
<;tr>;<;td>;<;a href="https://storage.googleapis.com/bert戋u models/2018戋u 11戋03/multilingual戋u l-12戋u h-768戋u a-12.zip">;bert base,multilingual cased(old)<;/a>;<;/td>;>;102 languages,12 layer,768 hidden,12 heads,110m parameters<;/td>;
<;tr>;<;td>;<;a href="https://storage.googleapis.com/bert_models/2018_11_03/chinese_l-12_h-768_a-12.zip">;bert base,中文<;/a>;<;/td>;<;td>;简体中文nd Traditional,12层,768隐藏,12个磁头,110m参数<;/td>;<;/tr>;
<;/table>;


<;/details>;



>;**可选:**在下游任务中微调模型。[为什么是可选的?](q-are-you-suggesting-using-bert-without-fine-tuning)


2。启动bert服务
在安装服务器之后,您应该能够使用"bert-serving start"cli,如下所示:
`` bash
bert-serving start-model\dir/tmp/english\u l-12\u h-768\u a-12/-num\worker=4
```
这将启动一个有四个工人的服务,这意味着它可以处理多达四个**并发**请求。更多并发请求将在负载平衡器中排队。有关详细信息,请参见我们的[FAQ](q-what-is-the-parallel-processing-model-behind-the-scene)和[The benchmark on number of clients](speed-wrt-num-client)。

raw=true"/>;


<;details>;
<;summary>;或者,可以在docker容器中启动bert服务(单击展开…)<;/summary>;

`` bash
docker-build-t-bert as service-f./docker/dockerfile.
num-worker=1
path-model=/path-u-to/\u你的模型/
docker-run-runtime-nvidia-dit-p 5555:5555-p 5556:5556-v$path-model:/model-t-bert-bert as service$num-worker
````
<;详细信息>;






//3。使用client获取句子编码
现在您可以简单地将句子编码如下:
``python
from bert戋u serving.client import bertclient
bc=bertclient()
bc.encode(['首先执行,'然后正确执行','然后做得更好')
```
它将返回一个'ndarray`(或者'list[list[float]]`如果您愿意的话),其中每一行是一个固定长度的向量,表示一个句子。有成千上万个句子?只是"编码"!*甚至不用批处理*,服务器会处理它。

作为bert的一个特性,您可以通过将一对句子与` `(前后有空格)连接来获得它们的编码,例如,
``python
bc.encode(['先做然后做正确的事情')
````

原始值=真"/>;<;/p>;

gpu机器
bc.encode(['先做','然后做对','然后做得更好')
````

注意,您只需要'pip install-u bert serving client',在这种情况下,不需要服务器端。您还可以[通过http请求调用该服务](使用bert作为服务,以json形式提供http请求)

>;:bulb:**想了解更多信息吗?查看我们的教程:**
>;-[在3分钟内构建一个qa语义搜索引擎]("在3分钟内构建一个qa-qa-semantic-search-engine")
>;-[提供一个微调的bert模型]("服务一个微调的bert-model")
>;-[获取类似elmo的上下文单词嵌入](获取类似elmo的上下文单词嵌入)
>;-[使用自己的标记化器](使用自己的标记化器)
>;-[将"bertclient"与"tf.data"api一起使用](将bertclient与tfdata api一起使用)
>;-[使用bert特征和tf.estimator api训练文本分类器](training-a-text-classifier-use-bert-features-and-tfestimator-api)
>;-[使用tfrecord数据保存和加载](使用tfrecord数据保存和加载)
>;-[异步编码](异步编码)
>;-[向多个客户端广播](向多个客户端广播)
>;-[在仪表板中监视服务状态](在仪表板中监视服务状态)
>;-[使用"bert作为服务"来服务以json格式保存http请求](使用bert作为服务以json格式提供http请求)
>;-[从python启动'bert server'(从python启动bertserver)


<;h2 align="center">;服务器和客户端api<;/h2>;
<;p align="right">;<;a href=""bert as service">;<;sup>;返回顶部<;/sup>;<;/a>;<;/p>;

[![阅读文档](https://readthedocs.org/projects/bert-as-service/badge/?version=latest&style=for the badge)(http://bert as service.readthedocs.io)


这里有文档。](https://bert as service.readthedocs.io/en/latest/source/server.html服务器端api)您可以通过:
``bash
bert serving start--help
bert serving terminate--help
bert serving benchmark--help
````
|
——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————|
微调的bert模型的"tuned_model_u dir str(可选)文件夹路径。|检查点文件的文件名。|
`config_name`str `bert_config.json` bert模型的json配置文件的文件名。|
"graph_tmp_dir` str none graph temp file路径
"max_seq_len` int"25序列的最大长度,较长的序列将在右侧修剪。对于动态使用(小)批处理中最长的序列,将其设置为"无"。|
|
|
|
并在作业队列中向前跳转以更快地获取结果
"port` int `5555`用于将数据从客户端推送到服务器的端口
"port u out` int `5556`用于将结果从服务器发布到客户端的端口
"http port` int none用于接收http请求的服务器端口
|` cors` str`*``为http请求设置"访问控制允许源代码"
pooling_strategy` str`` reduce_mean``生成编码向量的池策略,有效值为'none`、'reduce_mean`、'reduce_max`、'reduce_mean_max`、'cls_token`、'first_token`、'sep_token`,`最后一个标记。对这些策略的解释[可以在这里找到](q-什么是-可用-池策略)。要获取序列中每个令牌的编码,请将其设置为"none"。
"pooling layer list `[-2]`池操作的编码层,其中"-1"表示最后一层,"-2"表示倒数第二层,"[-1,-2"表示连接最后两层的结果,等等。|` GPU内存碎片float `0.5每个GPU应该为每个工作线程分配的总内存碎片
cpu bool false在CPU上运行,而不是在图形优化中的GPU
xla bool false启用[xla编译器](https://www.tensorflow.org/xla/jit)(*实验性!*)|
`fp16 bool false使用float16精度(实验性)的float16精度

`device\u-map list `[]``指定将使用的gpu设备id的列表(id从0开始)
`show\u tokens bool false将令牌化结果发送到客户端



[请始终参考她记录的最新客户端apie.](https://bert as service.readthedocs.io/en/latest/source/client.html 35; module client)客户端提供一个名为"bertclient"的python类,它接受如下参数:

|` 5555`用于将数据从客户端推送到服务器的端口,*必须与用于将结果从服务器发布到客户端的服务器端配置*
这个句子编码,在numpy数组或python list[list[float]](`ndarray`/`list`)
`show_server_u config` bool `false`是否显示服务器在首次连接时配置
`check_version` bool `true`是否强制客户端和服务器具有相同的版本
`identity` str|`无`标识客户端的uuid,在多类型转换中有用
"timeout` int `-1`设置客户端上接收操作的超时(毫秒)

a"bertclient"实现以下方法和属性:

method description
-----
。encode()`编码字符串列表对于向量列表
`.encode_async()`从生成器异步编码批处理
`.fetch()`从服务器获取所有编码的向量并将它们返回到生成器中,与`.encode_async()`或`.encode(blocking=false)`一起使用。不保留发送顺序。
`.fetch_all()`从服务器获取所有编码向量并将其返回到列表中,与`.encode_async()`或`.encode(blocking=false)`一起使用。保持发送顺序。
`.close()`优雅地关闭客户端和服务器之间的连接
`.status`以json格式获取客户端状态
`.server_u status`以json格式获取服务器状态

<;p align="right">;<;a href="bert as service">;<;sup>;返回顶部<;/sup>;<;/a>;<;/p>;

[![阅读文档](https://readthedocs.org/projects/bert-as-service/badge/?version=latest&;style=for the badge)](https://bert as service.readthedocs.io/en/latest/section/faq.html)

您可以通过"python example/example-k.py"运行每个脚本。大多数示例要求您首先启动bertserver,请遵循[此处的说明](2-start-the-bert-service)。请注意,尽管"bertclient"在python 2.x和3.x上都通用,但示例只在python 3.6上测试。

<;details>;
<;summary>;目录(单击展开…)<;summary>;

>;-[在3分钟内构建qa语义搜索引擎](在3分钟内构建-a-qa-semantic-search-engine)
>;-[提供微调的bert模型](在3分钟内提供微调的bert模型)
>;-[获得elmo-like上下文词嵌入](获得elmo-like上下文词嵌入)
>;-[使用自己的标记器](使用自己的标记器)
>;-[将"bertclient"与"tf.data"api一起使用](将bertclient与tfdata api一起使用)
>;-[使用bert特征和tf.estimator api训练文本分类器](training-a-text-classifier-use-bert-features-and-tfestimator-api)
>;-[使用tfrecord数据保存和加载](使用tfrecord数据保存和加载)
>;-[异步编码](异步编码)
>;-[向多个客户端广播](向多个客户端广播)
>;-[在仪表板中监视服务状态](在仪表板中监视服务状态)
>;-[使用"bert as service"以json格式提供http请求](使用"bert as service"以json格式提供http请求)
>;-[从python启动"bertserver"]("starting be"来自python的rtserver)

<;details>;


\我们将在三分钟内使用"bert as service"实现一个简单的qa搜索引擎。别开玩笑!目标是找到与用户输入相似的问题并返回相应的答案。首先,我们需要一个问答对列表。幸运的是,这个自述文件已经包含[常见问题列表](speech_buloon-faq),所以我将使用它使这个示例完全独立。让我们首先加载所有问题并显示一些统计信息。

``python
prefix_q='__q:**'
%(len(questions),np.mean([len(d.split())表示d in questions])
```

这给出了"33个加载的问题,平均len为9"。看来我们的问题已经够多了。现在用"uncased_l-12_h-768_a-12"预训练的bert模型启动bertserver:
``bash
bert service start-num_worker=1-model_dir=/data/cips/data/lab/data/model/uncased_l-12_h-768_a-12
```

next,我们需要将问题编码成向量:
``python
bc=bertclient(port=4000,port_out=4001)
doc_vecs=bc.encode(questions)
````

为此,每当有新的查询出现时,我们将其编码为一个向量,并使用"doc_vecs"计算其点积;对结果进行向下排序;返回top-k类似的问题如下:
``python
为真:
query=input('your question:')
query-vec=bc.encode([query])[0]
将标准化的点积计算为score
score=np.sum(query-vec*doc-vecs,axis=1)/np.linalg.norm(doc-vecs,axis=1)
topk-idx=np.argsort(score)[::-1][:topk]
topk-idx中的idx:
打印('>;%s\t%s'%(score[idx],questions[idx]))
````

就这样!现在运行代码并键入查询,查看此搜索引擎如何处理模糊匹配:
<;p align="center">;<;img src=".github/qasearch-demo.gif?raw=true"/>;<;/p>;


然而,要释放bert的真正威力,就必须对下游任务(或特定于域的数据)进行微调。在这个例子中,我将向您展示如何提供经过微调的bert模型。

我们遵循[句子(和句子对)分类任务]中的说明(https://github.com/google research/bert'句子和句子对分类任务)并使用'run湫classifier.py'进行微调` mrpc任务的无基础模型。微调后的模型存储在`/tmp/mrpc_output/`,可以通过指定`-run_classifier.py`--output_dir`来更改该模型。

4.0k
eval_results.txt 86
eval.tfu record 219k
events.out.tfevents.1545202214.tencent64.site 6.1m
events.out.tfevents.1545203242.tencent64.site 14m
graph.pbtxt9.0米
型号.ckpt-0.data-00000-of-00001 1.3g
型号.ckpt-0.index 23k
型号.ckpt-0.meta 3.9米
型号.ckpt-343.data-00000-of-00001 1.3g
型号.ckpt-343.index23k
model.ckpt-343.meta 3.9m
train.tf_记录2.0m
```


不要害怕那些神秘的文件,因为对我们来说唯一重要的文件是'model.ckpt-343.data-00000-of-00001'(看起来我的培训在343步就结束了)。根据总的训练步骤,可以得到'model.ckpt-123.data-00000-of-00001'或'model.ckpt-9876.data-00000-of-00001'。现在,我们已经收集了为这个微调模型服务所需的所有三条信息:
-预调整的模型被下载到`/path/to/bert/uncased_l-12_h-768_a-12`
-我们的微调模型存储在`/tmp/mrpc_output/`;
-我们的微调模型检查点命名为` model.ckpt-343"某物"。

应该在日志中找到这一行:
``text
i:graphopt:[gra:opt:50]:检查点(由微调模型覆盖):/tmp/mrpc_output/model.ckpt-343
````
,这意味着bert参数被重写,并从微调的`/tmp/mrpc_output/model.ckpt-343`成功加载。完成!

简而言之,找到经过微调的模型路径和检查点名称,然后将它们输入到"优化的模型目录"和"ckpt名称",分别进行。

令牌,您可以简单地使用切片索引,如下所示:
`` python
])

vec[2,25,25768]
vec[0][1,25,768],hey you`
vec[0][0][0][1,1,768]的句子嵌入,hey you`[hey you`
vec[0][0][0][0]>vec[1,1,768],hey`[br/>vec[0][1,1,768],hey`
vec[0][2][1,1,1768],wec[2,1,1768],wec[2,25,25768],wec[0][0][0][0][1,25,25768],vec[1,2576>矢量[0][3][1,1,768],单词嵌入用于`[sep]`
vec[0][4][1,1,768],单词嵌入用于填充符号
vec[0][25]错误,索引外!
``

请注意,无论原始序列有多长,服务始终会为每个序列返回一个`[max_seq_len,768]`矩阵。使用切片索引获取单词嵌入时,请注意填充到序列中的特殊标记,即`[cls]`,`[sep]`,`0u pad`。

只需在客户端幻灯片上调用"encode(is_tokenized=true)",如下所示:

`` python
texts=['hello world!'","good day"]

。如果查看它的值,您将发现只有前四个元素(即,`[1,0:3768]`有值,其他所有元素都是零。这是因为伯特认为"你好,世界!"作为四个标记:`[cls]``hello``世界!``[sep]`,其余的是填充符号,在输出之前被屏蔽。

请注意,不需要启动单独的服务器来处理标记化/未标记化的语句。服务器可以自动区分和处理这两种情况。

有时您希望明确知道在服务器端执行的标记化,以便更好地理解嵌入结果。其中一个例子是要求从服务器嵌入单词(使用`-pooling_strategy none`),人们想知道哪个单词是标记化的,哪个是不可识别的。您可以通过以下步骤获得此类信息:

1。在服务器端启用"-show_tokens_to_client";
2。调用通过"encode(…,show_tokens=true)"启动服务器。

,show_tokens=true)
```
返回一个元组,其中第一个元素是嵌入,第二个元素是来自服务器的标记化结果:

``text
(数组([[[0)。,-0。,0。,…,0。,-0。,-0。],
[1.1100919,-0.20474958,0.9895898,…,0.3873255,-1.4093989,-0.47620595],
…,-0.,-0。]],

[[0.,-0。,0。,…,0。,0。,0。],
[0.6293478,-0.4088490.6022662,…,0.41740108,1.214456,1.2532915],
…,0.,0。]]],dtype=float32),

[['[cls]','hello','world','!','[sep]],['[cls]','this','\is','it','[sep]']])
````

例如,
`` python
bc.encode([['hello','world!'],['thisis','it']],show_tokens=true,is_tokenized=true)
````
返回:

```text
(数组([[[0)。,-0。,0。,…,0。,-0。,0。],
[1.1111546,-0.56572634,0.37183186,…,0.02397121,-0.5445367,1.1009651],
…,-0.,0。]],

[[0.,0。,0。,…,0。,-0。,0。],
[0.39262453,0.3782491,0.27096173,…,0.7122045,-0.9874849,0.9318679],
…,-0.,0。]]],dtype=float32),

[['[cls]','hello','[unk]','[sep]',['[cls]','[unk]','it','[sep]]])
````

`服务器上无法识别"this",因此将其设置为"unk"。

因此,如果使用字级切分算法预处理数据并将其馈送到这样的模型中是没有意义的。

。原因是标记化结果将**始终**包括`[cls]`和`[unk]`而不考虑`-mask_cls_sep`的设置。当您希望以后对齐标记时,这可能很有用。记住,`-mask_cls_sep`只屏蔽了`[cls]`和`[sep]`不在计算范围内。它不会影响标记化算法。



还有[Keras中的一个例子](https://github.com/hanxiao/bert as service/issues/29 35; issuecomment-442362241)。

[`tf.data`](https://www.tensorflow.org/guide/datasets)api允许您从简单、可重用的片段构建复杂的输入管道。还可以使用"bertclient"动态编码句子,并在下游模型中使用向量。下面是一个示例:

`` python
批处理大小=256
num廑parallel廑calls=4
num廑clients=num廑parallel廑calls*2应该至少大于'num廑parallel廑calls`

启动客户端池
bc廑clients=[bertclient(show廑server廑config=falserange(num_clients)]


x是行的"批处理大小",每个行都是一个json对象
samples=[json.loads(l)for l in x]
text=[s['raw_text']for s in samples]\list[list[str]
labels=[s['label']for s in samples]\list[str]
#从可用客户端获取客户端
bc_client=bc_clients.pop()
features=bc_client.encode(文本)


ds=(tf.data.textlinedataset(train_fp).batch(batch_size)
.map(lambda x:tf.py_func(get_encodes,[x],[tf.float32,tf.string]),num_parallel_calls=num_parallel_calls)
.map(lambda x,y:{'feature':x,"label":y})
。使"one_shot_iterator().get_next())
````

这里的诀窍是启动一个"bertclient"池并逐个重用它们。这样,我们就可以充分利用"dataset.map()"api的"num_parallel_calls"的能力。


只需要对输入函数进行如下的小更改:

`` python
估计器=dnnclassifier(
隐藏单元=[512],
特征列=[tf.feature列.数值列('feature',shape=(768,))],
n个类=len(laws),
配置=run配置,
label_词汇=laws_str,
dropout=0.1)

input-fn=lambda-fp:(tf.data.textlinedataset(fp)
.apply(tf.contrib.data.shuffle-u and-u repeat(buffer-size=10000))
.batch(batch-size)
.map(lambda x:tf.py-func(get-u-encodes,[x],[tf.float32,tf.string]),num_parallel_calls=num_parallel_calls)
.map(lambda x,y:({'feature':x},y))
预取(20))

train_spec=trainspec(input_fn=lambda:input_fn(train_fp))
eval_spec=evalspec(input_fn=lambda:input_fn(eval_fp),throttle_secs=0)
train_and_evaluate(估计器,train_spec,评估规范)
```

这个问题是[中国人工智能与法律挑战赛](https://github.com/thunlp/cail/blob/master/readme_n.md)的一部分。



\blob/master/readme_en.md;使用tfrecord数据保存和加载

>;完整的示例可以[参见example6.py](example/example6.py)。

tfrecord文件格式是一种简单的面向记录的二进制格式,许多tensorflow应用程序使用它来训练数据。您还可以对所有序列进行预编码,并将它们的编码存储到tfrecord文件中,然后加载该文件以构建"tf.dataset"。例如,要将编码写入tfrecord文件:

``python
bc=bertclient()
list_vec=bc.encode(lst_str)
list_label=[0 for in lst_str]所有零标签的虚拟列表

def create_float_feature(values):
返回tf.train.feature(float_list=tf.train.floatlist(value=values))

def create_int_feature(values):
返回tf.train.feature(int64_list=tf.train.int64list(value=list(values))

列表标签:
features={features':创建浮动功能(vec),"labels":创建"intu-feature([label])}
tf-example=tf.train.example(features=tf.train.features(feature=features))
writer.write(tf-example.serializeToString())
``````

_解码记录(记录):
"将记录解码为TensorFlow示例。"
返回tf.parse单个示例(记录,{
"功能":tf.fixedLenFeature([768],tf.float32),
"标签":tf.fixedLenFeature([],tf.int64),
}

tf.contrib.data.map\u and_batch(lambda record:_decode_record(record),batch_size=64))
.制作一个shot_迭代器().get_next())
````

g到tfrecord,首先需要将`[max_seq_len,num_hidden]`将张量转换为一维数组,如下所示:
``python
def create_float_feature(values):
return tf.train.feature(float_list=tf.train.floatlist(value=values.reshape(-1))
`````
然后在加载时重新构造形状:
``python
name_to_features={
"feature":tf.fixedlenfeature([max_seq_length*num_hidden],tf.float32),
"label_ids":tf.fixedlenfeature([],tf.int64),
}


def_decode_record(record,name_to_features):
"将记录解码为tensorflow示例。""
example=tf.parse_single_example(record,name_u to_u features)
example['feature']=tf.reshape(example['feature'],[max_seq_u length,-1])
返回example
````
小心,这将生成一个巨大的tfrecord文件。

完整的示例可以[找到example2.py](example/example2.py)。

`bertclient.encode()`提供了一种很好的同步方式来获取句子编码。但是,有时我们希望以异步方式执行此操作,首先将所有文本数据提供给服务器,然后再获取编码的结果。这很容易做到:
`` python
一个无止境的数据流,以极快的速度生成数据
def text_gen():
为真:
生成lst_str;生成一批文本行

bc=bertclient()

获取bc中j的编码向量
。encode_async(text_gen(),max_num_batch=10):
print('received%d x%d'%(j.shape[0],j.shape[1]))
````


_广播到多个客户端

>;完整的示例可以在example3.py(example/example3.py)中找到。

如果你有多个相同身份的客户,那么他们都会收到结果!您可以使用这个*多播*功能来做一些很酷的事情,例如在多个独立进程中训练多个不同的模型(有些使用'scikit learn',有些使用'tensorflow',而只调用'bertserver'一次。在下面的示例中,"bc"及其两个克隆都将接收编码向量。

``python
id x):
bc=bertclient(identity=id)
对于bc.listen()中的j:
print('clone-client-%d:received%d x%d'%(idx,j.shape[0],j.shape[1]))


bc=bertclient()
j)).start()

还可能需要监视服务状态并将其显示在仪表板中。为此,我们可以使用:
``python
bc=bertclient(ip='server戋ip')

````

这将以json格式显示服务器的当前状态,包括请求数、客户端数等。唯一剩下的事情就是启动一个http服务器,将这个json返回到呈现它的前端。在启动服务器时,可以通过以下方式简单地公开http端口:

``bash
bert-serving-start-http-port 8001-model-dir…
````


基于引导和vue.js的仪表板。

<;p align="center">;<;img src=".github/dashboard.png?raw=true"/>;<;/p>;

它非常有用,尤其是在低运输层禁止使用ER。在场景背后,"bert as service"在一个单独的进程中生成一个flask服务器,然后将"bertclient"实例作为代理来与通风机通信。

要启用内置http服务器,我们需要首先(重新)使用一些额外的python依赖项来安装服务器:
``bash
pip install-u bert serving server[http]
`````


>然后简单地使用以下命令启动服务器:
``bash
`bert serving start-model\u dir=/your\u model-http-port 8125
````

您的服务器正在同时监听端口"8125"的http和tcp请求!

要发送一个http请求,首先用json编写负载,如下所示:
``json
{
"id":123,
"texts":["你好,世界","你好!"]",
"is-tokenized":false
}
```
,其中"id"是帮助您同步结果的唯一标识符;"is-tokenized"遵循[`bert client`api'(https://bert as service.readthedocs.io/en/latest/source/client.html\client.bertclient.encode\u async)和"false"by"默认设置。

然后通过http post请求在`/encode'调用服务器。您可以使用javascript或其他方式,下面是一个使用curl的示例:
``bash
curl-x post http://x x.xx.xx.xx:8125/encode\
-h'内容类型:application/json'\
-d'{"id":123,"texts":["hello world"],"is_tokenized":false}
````
,它返回一个json:
`` json
{
"id":123,
"results":[[768 float list],[768 float list]],
"status":200
}
`````

要获取服务器的状态和客户端的状态,可以在`/status/server`和`/status/client`发送get请求,最后,还可以通过在启动"bert-serving-start"时指定"-cors"来配置cors以限制服务器的公共访问。默认情况下,-cors=*`,这意味着服务器是公共访问的。



\只需执行
``python
from bert_serving.server.helper import get_args_parser
from bert_serving.server import bertserver
args=get_args_parser().parse_args(['-model_dir','your_model_path_here',
'-port','5555',
'-port_out'、'5556'、
'-max_seq_len'、'none'、
'-mask_cls_sep',
'-cpu']
server=bertserver(arg s)
server.start()
````

请注意,它基本上反映了cli中的arg解析行为,因此该`.parse_args([])`list中的所有内容都应该是字符串,例如`['-port',5555']`而不是`['-port',5555]`.

要关闭服务器,您可以通过以下方式调用"bert server"类中的静态方法:
``python
bertserver.shutdown(port=5555)
`````

>或通过shell cli:
``bash
`bert serving terminate-port 5555
````

这将终止在5555端口的本地主机上运行的服务器。您也可以使用它来终止远程服务器,有关详细信息,请参见"Bert Serving Terminate--帮助"。


<;h2 align="center">;:语音提示框:常见问题解答<;/h2>;
<;p align="right">;<;a href=""Bert as Service">;<;sup>;>;<;sup>;<;&sup>;>;<;&a>;<;&p>;< BR>[阅读文档](https://readthedocs.org/projects/bert-as-service/badge/?version=latest&style=for the badge)(https://bert a s service.readthedocs.io/en/latest/section/faq.html)




设计理念和技术细节可以在[我的博客文章]中找到(https://hanxiao.github.io/2019/01/02/使用TensorFlow和ZeroMQ/在生产中为Google Bert服务)。




**a:**[本回购协议的伯特代码](server/bert_serving/server/bert/)从[原始协议]派生l bert repo](https://github.com/google-research/bert)进行了必要的修改,[特别是在extract_features.py](server/bert_serving/server/bert/extract_features.py)。



一般来说,每个句子都被翻译成768维向量。根据您使用的预先训练的bert,"pooling_strategy"和"pooling_layer",输出向量的维度可能不同。

你是不是在合伙什么的?

**a:**是的,需要使用池来获取句子的固定表示。在默认策略"reduce_mean"中,我取句子中所有标记的第二个到最后一个隐藏层,并进行平均池。



**a:*是和否。一方面,google预先训练了wikipedia数据中的bert,因此应该在模型中编码足够的语言先验知识。拥有这样的功能并不是一个坏主意。另一方面,这些先验知识并不特定于任何特定领域。如果你在使用它的时候表现得不理想,比如说,对法律案件进行分类,这应该是完全合理的。尽管如此,您始终可以首先在下游任务上微调自己的bert,然后使用"bert as service"有效地提取特征向量。请记住,"bert as service"只是一个基于bert的特征提取服务。没有什么能阻止您使用经过微调的bert。



**A:**当然!调用服务器时,只需使用要连接的层的列表。示例:

`` bash
bert_serving_start-pooling_layer-4-3-2-1-model_dir/tmp/english_l-12_h-768_a-12/
````



**a:**这里有一个表,总结了我实施的所有池策略。通过指定"bert_serving_start-pooling_strategy"来选择您最喜欢的策略。

这将导致768]`encode matrix for a sequence.
`reduce_mean``取编码层在时间轴上的隐藏状态的平均值
然后将它们在最后一个轴上连接起来,得到1536个dim语句编码
'cls_u token'或'first_u token';得到对应于`[cls]`的隐藏状态,即第一个token
'sep_u token'或'last_u token';得到对应于`[sep]`的隐藏状态,即最后一个token|



**a:**因为预先训练的模型尚未对任何下游任务进行微调。在这种情况下,`[cls]`的隐藏状态不是一个好的句子表示。如果稍后对模型进行微调,也可以使用"[cls"。



**a:**默认情况下,此服务在最后一层的第二层上工作,即"pooling-layer=-2"。您可以通过将"pooling_u layer"设置为其他负值来更改它,例如-1对应于最后一层。


为什么是倒数第二?

**a:*在预训练期间,最后一层与目标函数(即蒙面语言模型和下一句预测)太接近,因此可能偏向这些目标。如果您对这个参数有疑问,并且仍然想使用最后一个隐藏层,请随意设置"pooling_layer=-1"。




**A:*取决于记住,不同的bert层捕获不同的信息。为了更清楚地看到这一点,这里是[UCI News Aggregator数据集](https://www.kaggle.com/uciml/News Aggregator数据集)上的可视化,我随机抽取了20k个新闻标题;从不同的层和不同的池策略获取句子编码,最后通过主成分分析(pca)将其减少到2d(当然也可以做t-sne,但这不是我的观点)。只有四类数据,用红色、蓝色、黄色和绿色表示。要复制结果,请运行[example7.py](example/example7.py)。

<;p align="center">;<;img src=".github/pool\u mean.png?原始=真">;


<;p align="center">;<;img src=".github/pool_max.png?raw=true">;<;/p>;


直观地说,"池层=-1"接近训练输出,因此可能偏向训练目标。如果不对模型进行微调,则可能导致不正确的表示。` pooling_layer=-12`接近单词嵌入,可以保留非常原始的单词信息(没有花哨的自我关注等)。另一方面,您只需使用单词嵌入就可以获得相同的性能。也就是说,介于[1,-12]之间的任何东西都是一种权衡。



**a:**当然。但是,如果在图中引入新的"tf.variables",则需要在使用模型之前训练这些变量。您可能还想查看[我在博客中提到的一些池技术](https://hanxiao.github.io/2018/06/24/4-encoding-blocks-you-need-to-know-addition-lstm-rnn-in-tensorflow/"池块"。



不,一点也不。只需"编码"并让服务器处理其余部分。如果批处理太大,服务器将自动进行批处理,而且比自己进行批处理效率更高。不管你有多少句子,10k或100k,只要你能把它保存在客户端的内存中,就把它发送到服务器。另请阅读[关于客户机批处理大小的基准](https://github.com/hanxiao/bert as service speed-wrt-client u batch size)。





**A:**是的!这就是回购的目的。事实上,你可以随心所欲地创建更多的客户。一台服务器可以处理所有请求(只要有足够的时间)。



**a:**最大并发请求数由"bert_serving_start"中的"num_worker"决定。如果同时发送多个"num戥worker"请求,则新请求将临时存储在队列中,直到空闲的worker可用为止。



**a:**没有。一个请求表示从客户端发送的句子列表。将请求的大小视为批处理大小。请求可以包含256、512或1024个句子。请求的最佳大小通常是根据经验确定的。一个大的请求当然可以提高gpu的利用率,但同时也增加了传输开销。您可以运行"python example/example1.py"作为一个简单的基准测试。


**a:**这在很大程度上取决于"max_seq_len"和请求的大小。在一个"max_seq_len=40"的tesla m40 24gb上,使用12层bert每秒应该可以获得470个样本。一般来说,我建议使用较小的"max_seq_len"(25)和较大的请求大小(512/1024)。

**A:**是的。请参阅[benchmark](zap benchmark)。



**a:**[zeromq](http://zeromq.org/)。




<;img src=".github/bert-parallel-pipeline.png?raw=true"width="600">;


一个端口用于将文本数据推入服务器,另一个端口用于将编码结果发布到客户端。这样,我们就消除了背后的闲聊,也就是说,在每一个层次上,收件人都不会和发件人顶嘴。如上图所示,整个消息流是严格单向的。消除喋喋不休对真正的可伸缩性至关重要,它允许我们以异步方式使用"bertclient"。



**a:**no.将"bertclient"视为一个通用的特征提取程序,其输出可以输入*任何*ml模型,例如"scikit learn"、"pytorch"、"tensorflow"。客户机需要的唯一文件是[`client.py`](service/client.py)。将此文件复制到您的项目并导入,然后您就可以开始了。



**a:*是的。



**A:**是的。事实上,这是建议。确保"model_dir"中有以下三项:

-一个包含预先训练的权重(实际上是3个文件)的TensorFlow检查点(`bert_model.ckpt`)。
-一个vocab文件(`vocab.txt`)将wordpiece映射到word id。
-一个配置文件(`bert_config.json`),指定模型的超参数。



**A:**服务器端没有,客户端有。这是基于这样的考虑:Python2.x可能仍然是某些技术堆栈中的一个主要部分。将整个下游堆栈迁移到python 3以支持"bert as service"可能需要相当多的努力。另一方面,设置"bertserver"只是一次性的事情,甚至可以[在docker容器中运行](在nvidia docker上运行bert服务)。为了简化集成,我们在客户端支持Python2,以便您可以直接将"bertclient"用作Python2项目的一部分,而服务器端应该始终由Python3托管。



不,如果你使用的是[谷歌发布的预训练中文伯特](https://github.com/google research/bert pre trained chinese bert released by google)你不需要分词。因为这个中文伯特是基于字符的模型。即使你有意在两个单词之间加上空格,它也不会识别单词/短语。为了更清楚地看到这一点,这就是bert模型在标记化之后实际接收到的信息:

`` python
bc.encode(['hey you','what ts up?'","第二季第三季第二季第二季第三季第二季第三季第三季第])
``` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `
代币:[cls]嘿你[sep]
输入识别号:101 13153 8357 8357 102 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0代币:[cls]怎么了?[sep]
输入输入:101 9100 8118 8644 8644 136 136 102 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0是的中文bert的字符嵌入。





因为你的单词词汇量不足(oov)。来自google的tokenizer使用贪婪的最长匹配优先算法来使用给定的词汇表执行tokenization。

例如:
``python
input="unafable"
tokenizer_output=["un","aff","**q:**我可以使用自己的tokenizer吗?

是的。如果你已经在你身上标记了这个句子r own,只需发送use`encode`和`list[list[str]`作为输入,并打开`is掼tokenized`,即'bc.encode(texts,is掼tokenized=true)`.






**a:**这通常是由于在多线程/进程环境中误用了"bertclient"。注意,不能在多个线程/进程中重用一个"bertclient",必须为每个线程/进程创建单独的实例。例如,下面这些根本不起作用:在proc1/thread1/proc1/thread1作用域:
bc.encode(lst_str)




`` python
/>在过程1/线程1中作用域:
bc1=bertclient()
bc1.encode(lst_str)

在proc2/thread2中作用域:
bc2=bertclient()
bc2.encode(lst_str)
````

我怎样才能改变这种行为?

**a:**ZeroMQ使用这些文件夹存储套接字。您可以通过设置环境变量"zeromq_sock_tmp_dir":
"export zeromq_sock_tmp dir=/tmp/`



**a:**下游任务的恰当表示并不意味着它在余弦距离方面有意义。因为余弦距离是一个线性空间,所有维度的权重相等。如果你想使用余弦距离,那么请关注排名而不是绝对值。也就是说,不要使用:
```
如果余弦(a,b)>;0.9,那么a和b是相似的
```
请考虑以下内容:
````
如果余弦(a,b)>;余弦(a,c),那么a比c更接近b。
````

长度<;25)。我们基于句子向量计算余弦相似度,并基于原始文本计算[rouge-l](https://en.wikipedia.org/wiki/rouge-l(metric))。为了清晰起见,删除了对角线(自相关)。正如我们所看到的,这两个指标之间存在一些正相关关系。

<;p align="center">;<;img src=".github/cosine-vs-rougel.png?raw=true"/>;<;/p>;





**a:*这通常表明预先训练的bert无法生成下游任务的下降表示。因此,可以对下游任务的模型进行微调,然后使用"bert as service"为微调的bert提供服务。注意,"bert as service"只是一个基于bert的特征提取服务。没有什么能阻止您使用经过微调的bert。



**a:**是的,请运行"bert serving start-cpu-max_batch_size 16"。请注意,CPU在大批量上的扩展不如GPU,因此服务器端的"最大批处理大小"需要更小,例如16或32。




**a:**通常,工作线程数应小于或等于您拥有的GPU/CPU数。否则,将为一个GPU/CPU分配多个工作线程,这可能无法很好地扩展(并可能导致GPU内存不足)。




**a:**是的,您可以指定`-device_map`如下:
``bash
bert service start-device_map 0 1 4-num_worker 4-model_dir…
````
这将分别启动四个工作进程并将它们分配给gpu0、gpu1、gpu4和再次分配给gpu0。一般来说,如果"num-worker">;"device-map",则设备将被工人重用和共享(可能会缩放到次优或导致OOM);如果"num-worker"<;`设备映射,仅使用"设备映射[:num_worker]"。

< BR>[阅读文档](https://readthedocs.org/projects/bert-as-service/badge/?version=latest&style=for the badge)(https://bert as service.readthedocs.io/en/latest/section/benchmark.html)

benchmarking的主要目标是测试该服务的可伸缩性和速度,这对于在开发/生产环境中使用它至关重要。基准测试在Tesla M40 24GB上进行,重复10次,并报告平均值。

|
第二、第二、第四速度WRT。` max_seq_len`

`max_seq_len`是服务器端的一个参数,它控制bert模型可以处理的序列的最大长度。大于"max_seq_len"的序列将在左侧被截断。因此,如果您的客户想向模型发送长序列,请确保服务器能够正确地处理它们。


从性能上讲,长序列意味着较慢的速度和更多的OOM机会,因为多头自我关注(BERT的核心单元)需要做点积和矩阵序列中每两个符号之间的乘法。

<;img src=".github/max_seq_len.png?raw=true" width="600">

| `max_seq_len` | 1 GPU | 2 GPU | 4 GPU |
|---------------|-------|-------|-------|
| 20 | 903 | 1774 | 3254 |
| 40 | 473 | 919 | 1687 |
| 80 | 231 | 435 | 768 |
| 160 | 119 | 237 | 464
320 54 108 212

速度wrt。` client_batch_size`

`client_batch_size`是调用"encode()"时来自客户端的序列数。出于性能原因,请考虑批量编码序列,而不是逐个编码。

例如,要做到:
``python
我的"corpus.iter():
vec.append(bc.encode(s))
```


如果将"bertclient()"放在循环中,情况会更糟。不要这样做。

<;img src=".github/client_batch_size.png?生=真"width="600">;


客户批量1个GPU 2个GPU 4个GPU
1个GPU 2个GPU 4个GPU 274 270 267
16| 332 329 330
64 64 365 365

256 382 383
512 432 766
1024 459 862 862 917|1681
4096 481 943 1809





` num嫒client`
`num嫒client`表示同时连接到服务器的并发客户端数。

<;img src=".github/num嫒clients.png?raw=true"width="600">;


1个gpu 2个gpu 4个gpu
124; 133 267 533
8 67 136 270
16 34 68 136
32 17 34 68

可以观察到,1个客户端1 gpu=381 seqs/s,2个客户端2 gpu 402 seqs/s,4个客户机4个GPU 413序列/秒。这显示了并行管道和作业调度的效率,因为随着并发请求的增加,服务可以更充分地利用GPU时间。



` max_batch_size`

`max_batch_size`是服务器端的一个参数,用于控制每个工作进程每批的最大样本数。如果来自客户端的传入批处理大于"最大批处理大小",则服务器会将其分成小批,以便在将其发送给工作人员之前,每个批处理都小于或等于"最大批处理大小"。

<;img src=".github/max\u batch\u size.png?生=真"width="600">;


1 gpu 2 gpu 4 gpu
1 gpu 2 gpu 4 gpu 4 gpu 2 2 124128 473 931 1816
256| 473 919 1688
512 464 866 1483




` pooling_layer`

`pooling_layer`确定池操作的编码层。例如,在一个12层的bert模型中,`-1'表示接近输出的层,`-12'表示接近嵌入层的层。如下所示,池层的深度会影响速度。

<;img src=".github/pooling_layer.png?raw=row=true"width="600>;

1个gpu 2个gpu 4个gpu 2个gpu 4/>[-3]516 995 1823
[-4]| 1986年
[-5]633 1193 2184
[-6]711 1340 2430
[-7][-7 820
[-8][-8 945 3104<3104
[-9]>[-9
[-10]1392 2542|4241
[-11]1523 2737 4752
[-12]1568 2985 5303



速度WRT。`-fp16和`-xla`

`bert as service`支持另外两个优化:半精度和xla,这两个优化可以分别通过将`-fp16`和`-xla`添加到'bert service start'来启用。要启用这两个选项,您必须满足以下要求:

-您的gpu支持fp16指令;
-您的tensorflow是用xla和`-march=native`自编译的;
-您的CUDA和CUDNN并不太旧。


在Tesla V100上,`tensorflow=1.13.0-rc0`它给出:

<;img src=".github/fp16 xla.svg"width="600">;

fp16与fp32相比,实现了约1.4倍的加速(往返)。若要重新生成结果,请运行"python example/example1.py"。


<;h2 align="center">;引用<;/h2>;
<;p align="right">;<;a href=""bert as service">;<;sup>;<;p align="right">;<;a href;>;<;/p>;

如果您在科学出版物中使用bert作为服务,我们希望引用以下bibtex条目:

``乳胶
@misc{xiao2018bertservice,
title={bert as service},
author={xiao,han},
howpublished={\url{https://github.com/hanxiao/bert as service},
year={2018}
}
`````



欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java使用无循环和乘法的递归调用查找值   java字符串大小冲突   在一组Java文件对象中查找唯一的超级目录   没有Eclipse控制台输出窗口(Java)?   java这怎么等于105而不是15?   java Adempiere列调出,用于不处理从(代码)选项导入和创建行的字段   java tomcat、2个webapps、2个log4js,但这两个应用都记录到一个文件中   lambda理解Java谓词   HotspotFX上的Java EOF问题   java google应用程序引擎:如何向连接/断开通道“ping”添加信息?   java如何使用VTDXML获取一个元素的所有名称空间声明?   java如何使用drawLine()获得一条线以随机方向拍摄?   java transactionManager应该使用哪个SessionFactory?   java在安卓上播放声音   在Mac上使用JBDC对SQL Server进行java Windows身份验证   java基本列表和字符串[]   java NamedParameterJdbcTemplate从中选择*   扩展上的java Android可扩展列表视图   使用ApacheAxis2的java SOAP附件