windows编译TensorFlowServing
概述
整个编译打包过程的总体思路,是参照在linux
下的编译流程,配置环境,执行编译命令,根据编译器/链接器反馈的错误,修改相应的源码或者相关库文件的存放路径,编译出windows
平台下静态库和二进制执行文件。
TIP
:在碰到很多编译错误的时候,适当避开某些不好解决的第三方依赖库(libevent,gflag,glog
),把流程走通,再回头解决外部依赖库的问题。
Windows编译环境搭建
说明:本教程中部分路径的展示沿用了linux
教程中正斜杠的用法,未予修改。凡是非linux
沿用命令及输出信息中的路径,均采用windows
平台下的反斜杠。两种分隔方式除特别说明,在windows
平台下可以混用。
安装Bazel
下载bazel
的windows的安装包,版本要求>=3.7.2。在页面中找到 bazel-<version>-windows-x86_64.exe
,如bazel-3.7.2-windows-x86_64.exe
改名为bazel.exe
,并将该文件所在目录放到%PATH%
目录,打开命令行窗口,可以搜索到bazel
即可。
D:\TFServing\serving>bazel --version
bazel 3.7.2
安装Visual Studio 2019
进入visual studio 2019安装包下载界面,选择社区版,按提示安装即可。可参考安装教程。
安装Python及附属包
选择python3.9
,进入下载界面,找到对应版本,参考教程。在安装时将pip
一起安装,后需用pip
安装其他工具包比如numpy
等。
其他工具
这里主要是git,msys2,patch,git
的安装方式可参考教程。
msys2
是在windows
上模拟linux
环境,安装后可以在window
上执行linux
上的程序。安装教程可参考资料。
pacman -Syupacman -Supacman -S patch unzip
配置环境变量
将上面安装的所有工具的二进制包添加到环境变量:
在系统变量中添加变量名BAZEL_SH,BAZEL_VC,BAZEL_VS
,并设置相应的路径。
D:\msys64\usr\bin\bash.exe #BAZEL_SH
D:\Program Files\Microsoft Visual Studio\2019\Community\VC #BAZEL_VC
D:\Program Files\Microsoft Visual Studio\2019\Community #BAZEL_VS
%PATH%
中需添加:
D:\Bazel #bazel.exe所在目录
D:\ProgramData\Python\Python39 #python39.exe所在目录
D:\msys64\usr\bin #msys2中安装的软件所在目录
下载源码
下载tensorflow serving
的源码:
git clone https://github.com/tensorflow/serving.git
cd serving
通过分析依赖层级结构,获取所有依赖库源码:
bazel fetch --experimental_repo_remote_exec tensorflow_serving/model_servers:tensorflow_model_server
注意:fetch
可以通过分析依赖层级关系,下载对应的工程文件,可通过--repository_cache d:\BazelCache
选项,指定目录存放所有下载的源码文件,也可参考下一节中的bazel
配置文件修改存放位置。如遇到下载不成功,重复执行即可。直到显示
D:\TFServing\serving>bazel fetch --experimental_repo_remote_exec tensorflow_serving/model_servers:tensorflow_model_server
Starting local Bazel server and connecting to it...
DEBUG: D:/bazelcache/z4avbakx/external/org_tensorflow/third_party/repo.bzl:109:14:
Warning: skipping import of repository 'icu' because it already exists.
INFO: All external dependencies fetched successfully.
Loading: 301 packages loaded
表示全部工程文件下载完毕。
源码修改
tensorflow serving
的源码文件是通过git clone
命令下载到本地,而所有依赖库文件包括tensorflow
, libevent
等都存放在指定的bazel
缓存目录。这里以进入serving
根目录下开始
cd serving
Bazel
编译脚本的修改
-
打开
.bazelrc
文件,在文末加入startup --output_user_root=D:\BazelCache
表示将所有依赖的外部库源码下载到这个目录,且编译中生成的中间文件,缓存文件,静态库以及二进制文件均存放此目录。此操作与在
bazel
命令中使用--repository_cache d:\BazelCache
效果相同 。如不改变,则会默认在C盘中存放上述文件(不推荐)。 -
在
.\tensorflow_serving\workspace.bzl
中注释掉com_goolge_sentencepiece
及com_google_glog
的下载请求。此操作可规避sentencepiece
以及glog
等产生的平台关联性报错。 -
在
.\third_party\libevent\BUILD
文件中注释掉58~72行libevent
的编译语句(genrule
部分)。该编译语句适用于linux
平台,windows平台上采用官方提供cmake
方式编译,并将头文件和库文件放到指定搜索目录[1]。 -
进入
.\tensorflow_serving\model_servers\BUILD
文件中注释掉参数linkstamp
,此操作可避免调用java
运行时的异常 [2]。cc_library(name = "tensorflow_model_server_main_lib",srcs = ["main.cc",],hdrs = ["version.h",],#注释即可#linkstamp = "version.cc",visibility = [":tensorflow_model_server_custom_op_clients","//tensorflow_serving:internal",],... )
TensorFlow
的源码修改
如上文所述,tensorflow
的工程源码存放在自定义的D:\BazelCache
所在目录。修改tensorflow
的源码,需进入tensorflow
工程所在的根目录,例如:
cd D:\BazelCache\z4avbakx\external\org_tensorflow
-
在文件
.\tensorflow\core\framework\registration\registration.h
中找到#define TF_NEW_ID_FOR_INIT_2(m, c, ...) m(c, __VA_ARGS__)
改为:
#define EXPAND(x) x #define TF_NEW_ID_FOR_INIT_2(m, c, ...) EXPAND(m(c, __VA_ARGS__))
此操作用来解决
msvc
对__VA_ARGS__
的支持问题[3]。同理需在文件.\tensorflow\core\framework\op_kernel.h
中将#define TF_EXTRACT_KERNEL_NAME_IMPL(m, ...) m(__VA_ARGS__)
改为:
#define EXPAND(x) x #define TF_EXTRACT_KERNEL_NAME_IMPL(m, ...) EXPAND(m(__VA_ARGS__))
TIP
: 查找目录及子目录下所有包含指定字符串的文件,linux
下可使用grep "findStr" -r ./
-
分别在源码文件
.\tensorflow\core\lib\random\random_distributions.h .\tensorflow\cc\gradients\math_grad.cc .\tensorflow\compiler\xla\client\lib\prng.cc .\tensorflow\compiler\mlir\tensorflow\transforms\lower_tf.cc .\tensorflow\compiler\xla\client\lib\math.cc
中适当位置(建议在头文件包含之后)加入
#define M_PI 3.14
可解决函数中找不到该宏定义的错误。
-
在文件
.\tensorflow\core\platform\windows\error_windows.cc .\tensorflow\core\platform\cloud\gcs_dns_cache.cc
中将
window.h
和winsock2.h
的包含顺序调换[4]。 -
在
.\tensorflow\core\platform\path.cc
中将bool IsAbsolutePath(StringPiece path) {return !path.empty() && path[0] == '/';//linux中的路径第一个字符为‘/’为绝对路径 }
改为:
bool IsAbsolutePath(StringPiece path) {return !path.empty() && path[1] == ':';//windows中的路径第二个字符为‘:’为绝对路径 }
来支持在windows平台上的正常执行。
TensorFlow Serving
的源码修改
进入到tensorflow serving
工程主目录,即
cd serving
-
在文件
.\tensorflow_serving\util\net_http\server\public\response_code_enum.h
中注释掉ERROR=500
UNAVAILABLE_LEGAL = 451, // Unavailable For Legal Reasons (RFC 7725) CLIENT_CLOSED_REQUEST = 499, // Client Closed Request (Nginx)// Server Error //ERROR = 500, // Internal Server Error NOT_IMP = 501, // Not Implemented BAD_GATEWAY = 502, // Bad Gateway ...
同时修改
.\tensorflow_serving\model_servers\http_server.cc
中涉及到HTTPStatusCode::ERROR
的部分。该操作可让编译继续进行,但可能会导致调试信息缺失的问题,请谨慎操作。 -
在
.\tensorflow_serving\util\net_http\server\internal\evhttp_server.cc
中//#include <netinet/in.h> //替换为 #include <winsock2.h> #pragma comment(lib,“ws2_32.lib”)
这是由于在
windows
平台没有netinet/in.h
文件,故用windows
平台下相关文件替换[5]。同时,在该文件中void InitLibEvent() {//if (evthread_use_pthreads() != 0) { //pthread是linux平台的线程库if (evthread_use_windows_threads() != 0) { //替换成windows平台对应的接口NET_LOG(FATAL, "Server requires pthread support.");}
-
在
.\tensorflow_serving\model_servers\main.cc
中注释掉TF_Version
以及TF_Serving_Version
的函数if (!tensorflow::Flags::Parse(&argc, argv, flag_list)) {std::cout << usage;return -1; }// if (display_version) { // std::cout << "TensorFlow ModelServer: " << TF_Serving_Version() << "\n"; // << "TensorFlow Library: " << TF_Version() << "\n"; // return 0; // }tensorflow::port::InitMain(argv[0], &argc, &argv); ...
由于最开始注释掉了
linkstamp
,导致version.cc
内的版本信息没有被加入执行文件,故相关的函数缺失。该操作不会影响程序的主要功能。
libevent
编译配置
由于tensorflow serving
工程中对libevent
编译脚本不适合windows
平台。故选择手动下载并采用cmake
的方式编译[1],将头文件和生成的库文件放入指定目录。在libevent
工程的根目录中新建libevent
目录,即
D:\BazelCache\z4avbakx\external\com_github_libevent_libevent\libevent
中所有头文件放入include\
目录,将生成的库文件放入lib\
目录。
编译执行
bazel build --experimental_repo_remote_exec tensorflow_serving/model_servers:tensorflow_model_server --action_env PYTHON_BIN_PATH=D:\ProgramData\Python\Python39\python.exe --local_ram_resources=200 --local_cpu_resources=10 >log.txt
参数中--action_env PYTHON_BIN_PATH
用来指定python
的安装路径,若不指定,系统将无法正确找到python.exe
,导致错误[6]。--local_ram_resources=200 --local_cpu_resources=10
用来控制bazel
内存使用和cpu
核心使用。可有效解决编译过程中出现的堆空间分配不足的问题[7]。采用 >log.txt
可将低级别的警告信息保存至文件,方便排查错误类型。当出现类似下列输出
...
INFO: Analyzed target //tensorflow_serving/model_servers:tensorflow_model_server (276 packages loaded, 23004 targets configured).
INFO: Found 1 target...
Target //tensorflow_serving/model_servers:tensorflow_model_server up-to-date:bazel-bin/tensorflow_serving/model_servers/tensorflow_model_server.exe
INFO: Elapsed time: 27.595s, Critical Path: 7.34s
INFO: 1 process: 1 internal.
INFO: Build completed successfully, 1 total action
表明编译成功,且生成了对应的执行文件。
运行及调试
在serving
的根目录下以管理员权限执行以下命令[8]
bazel-bin\tensorflow_serving\model_servers\tensorflow_model_server.exe --model_base_path=D:\TFServing\serving\tensorflow_serving\servables\tensorflow\testdata\saved_model_half_plus_two_cpu --model_name=half_plus_two --rest_api_port=8501
当出现类似下列输出
...
2021-10-13 16:21:11.190345: I tensorflow_serving/core/loader_harness.cc:87] Successfully loaded servable version {name: half_plus_two version: 123}
2021-10-13 16:21:11.192614: I tensorflow_serving/model_servers/server_core.cc:486] Finished adding/updating models
2021-10-13 16:21:11.192739: I tensorflow_serving/model_servers/server.cc:133] Using InsecureServerCredentials
2021-10-13 16:21:11.192771: I tensorflow_serving/model_servers/server.cc:383] Profiler service is enabled
2021-10-13 16:21:11.195258: I tensorflow_serving/model_servers/server.cc:409] Running gRPC ModelServer at 0.0.0.0:8500 ...
[evhttp_server.cc : 249] NET_LOG: Entering the event loop ...
2021-10-13 16:21:11.197798: I tensorflow_serving/model_servers/server.cc:430] Exporting HTTP/REST API at:localhost:8501 ...
表明windows上的服务端正常运行。可通过客户端命令
curl -XPOST http://localhost:8501/v1/models/half_plus_two:predict -d "{\"instances\":[1.0, 2.0, 5.0]}"
测试,如出现类似下列输出
{"predictions": [2.5, 3.0, 4.5]
}
表明客户端的请求被正确处理,服务器模型正常运行。可用于测试其他模型。
其他
内存问题
在编译时如果出现类似
LINK : fatal error LNK1102: 内存不足
的问题,可在命令行中
set PreferredToolArchitecture=x64
msvc
默认采用32位的编译工具包括cl.exe
以及link.exe
,这里采用64位的编译工具编译,解决虚拟内存不足的问题[9]。
耗时问题
编译tensorflow
的某些源码文件时会遇到耗时特别长的问题,目前还不清楚是什么问题导致。如果不中断,可能需要1~3个小时才能完成某一个文件的目标码的生成。通过切换到较低版本可能会改善时长问题(待验证)。
下一步工作
- 目前编译打包的版本没有
cuda
的支持,后续将根据模型的运行时间添加。 - 关于
libevent
对windows
平台支持不好的问题,如有需要将替换成更友好的libuv
库。 - 已经注释掉未参加编译的
sentencepiece
,gflag
库,如果影响程序的正常运行,将添加支持。 - 对于通过注释
linkstamp
去掉的版本信息,将按需添加。 - 分析
Serving
工程的依赖层次结构,去掉业务实战中用不到的功能,使执行文件轻量化。
参考文档
[1] libevent
在windows
上的编译
[2] linstamp
无法在windows
上正常运行
[3] msvc
对__VA_ARGS__
的支持问题
[4] windows.h
与winsock2.h
的包含顺序
[5] windows
下找不到netinet/in.h
文件
[6] python
环境配置错误
[7] bazel
限制内存使用
[8] tensorflow serving
的运行及调试
[9] 编译器堆空间不足问题
ensorflow/tensorflow/issues/48264)
[7] bazel
限制内存使用
[8] tensorflow serving
的运行及调试
[9] 编译器堆空间不足问题
相关文章:

windows编译TensorFlowServing
概述 整个编译打包过程的总体思路,是参照在linux下的编译流程,配置环境,执行编译命令,根据编译器/链接器反馈的错误,修改相应的源码或者相关库文件的存放路径,编译出windows平台下静态库和二进制执行文件。…...
debian 12 安装 浏览器 Epiphany
Epiphany 什么epiphany-browser epiphany-browser 是: Epiphany 是一款简单而强大的 GNOME 网络浏览器,针对 非技术用户。它的原则是简单和标准 合规。 简单性是通过精心设计的用户界面和依赖来实现的 在用于执行外部任务(如阅读 电子邮件…...

Kafka-消费者-KafkaConsumer分析
与KafkaProducer不同的是,KafkaConsumer不是一个线程安全的类。 为了便于分析,我们认为下面介绍的所有操作都是在同一线程中完成的,所以不需要考虑锁的问题。 这种设计将实现多线程处理消息的逻辑转移到了调用KafkaConsumer的代码中&#x…...

Spring | Spring中的Bean--下
Spring中的Bean: 4.Bean的生命周期5.Bean的配装配式 ( 添加Bean到IOC容器的方式 依赖注入的方式 )5.1 基于XML的配置5.2 基于Annotation (注解) 的装配 (更常用)5.3 自动装配 4.Bean的生命周期 Spring容器可以管理 singleton作用域的Bean的生命周期,在此…...

本周五上海见 第二届证券基金行业先进计算技术大会暨2024低时延技术创新实践论坛(上海站)即将召开
低时延技术是证券基金期货领域业务系统的核心技术,是打造极速交易系统领先优势的关键,也是证券基金行业关注的前沿技术热点。 1月19日下午,第二届证券基金行业先进计算技术大会暨2024低时延技术创新实践论坛(上海站)即…...

怎么安装IK分词器
.安装IK分词器 1.在线安装ik插件(较慢) # 进入容器内部 docker exec -it elasticsearch /bin/bash # 在线下载并安装 ./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.12.1/elastics…...

【踩坑】flask_uploads报错cannot import name ‘secure_filename‘
转载请注明出处:小锋学长生活大爆炸[xfxuezhang.cn] 背景说明 截至目前,用新版的flask实现文件上传(用到flask_uploads库),会出现这个问题。 问题原因 版本问题,新的werkzeug已经把secure_filename的位置改了。 解决方法 手动修改…...

AI编程可视化Java项目拆解第一弹,解析本地Java项目
之前分享过一篇使用 AI 可视化 Java 项目的文章,同步在 AI 破局星球、知乎、掘金等地方都分享了。 原文在这里AI 编程:可视化 Java 项目 有很多人感兴趣,我打算写一个系列文章拆解这个项目,大家多多点赞支持~ 今天分享的是第一…...

使用arcgis pro是类似的控件样式 WPF
1.资源加载 <controls:ProWindow.Resources><ResourceDictionary><ResourceDictionary.MergedDictionaries><extensions:DesignOnlyResourceDictionary Source"pack://application:,,,/ArcGIS.Desktop.Framework;component\Themes\Default.xaml&quo…...
C语言所有字符串函数举例如何使用
strcpy: 将一个字符串复制到另一个字符串中 char source[] "Hello"; char destination[10]; strcpy(destination, source);strcat: 将一个字符串连接到另一个字符串的末尾 char str1[20] "Hello"; char str2[] "World"; strcat(str1, str2)…...

ArcGIS Pro 如何新建布局
你是否已经习惯了在ArcGIS中数据视图和布局视图之间来回切换,到了ArcGIS Pro中却找不到二者之间切换的按钮,即使新建布局后却发现地图怎么却是一片空白。 这一切的一切都是因为ArcGIS Pro的功能框架完全不同,这里为大家介绍一下在ArcGIS Pro…...
如何解决态势感知中的“时隐时现”问题
解决态势感知中的“时隐时现”问题有以下几个方法: 1、确保所有关键的监控设备和传感器正常运行,能够及时和准确地检测到各种异常情况。 2、引入先进的技术手段。例如使用人工智能和机器学习算法来识别和分析大量的数据,快速发现异常和威胁&a…...

为什么JavaScript中0.1 + 0.2 ≠ 0.3
JavaScript中的浮点数运算有时候会出现一点偏差。下面解释为什么0.1 0.2 ≠ 0.3,以及如果你需要精确运算应该怎么做。 如果1 2 3,那么为什么在JavaScript中0.1 0.2 ≠ 0.3?这个原因与计算机科学和浮点数运算有关。 我建议你打开浏览器的控制台,输入0.1 0.2来查看结果。…...

Unity关于纹理图片格式带来的内存问题和对预制体批量格式和大小减半处理
我们经常会遇到内存问题,这次就是遇到很多图片的默认格式被改成了RGB32,导致Android打包后运行内存明显增加。 发生了什么 打包Android后,发现经常崩溃,明显内存可能除了问题,看了内存后发现了问题。 见下图…...

2024美赛数学建模思路 - 案例:ID3-决策树分类算法
文章目录 0 赛题思路1 算法介绍2 FP树表示法3 构建FP树4 实现代码 建模资料 0 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 1 算法介绍 FP-Tree算法全称是FrequentPattern Tree算法,就是频繁模…...

GitHub图床搭建
1 准备Github账号 如果没有Github账号需要先在官网注册一个账号 2 创建仓库 在github上创建一个仓库,随便一个普通的仓库就行,选择公共仓库 并且配置github仓库的pages,选择默认访问的分支及默认路径 3 github token获取 github token创…...

DQN、Double DQN、Dueling DQN、Per DQN、NoisyDQN 学习笔记
文章目录 DQN (Deep Q-Network)说明伪代码应用范围 Double DQN说明伪代码应用范围 Dueling DQN实现原理应用范围伪代码 Per DQN (Prioritized Experience Replay DQN)应用范围伪代码 NoisyDQN伪代码应用范围 部分内容与图片摘自:JoyRL 、 EasyRL DQN (Deep Q-Networ…...

C++ 编程需要什么样的开发环境?
C 编程需要什么样的开发环境? 在开始前我有一些资料,是我根据网友给的问题精心整理了一份「C的资料从专业入门到高级教程」, 点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家!!&#…...
Unity文字游戏开发日志(1)—— 打字机效果
作者是一名OIer,因为兴趣,想在寒假期间开发一款文字游戏的demo。 本博客仅用作记录,马蜂极度不符合规范。 但是,可以用来避坑。 1.等待功能——使用的是协程函数,且调用与常规调用函数不同。 private IEnumerator Sco(){isScoe…...

从0开始python学习-48.pytest框架之断言
目录 1. 响应进行断言 1.1 在yaml用例中写入断言内容 1.2 封装断言方法 1.3 在执行流程中加入断言判断内容 2. 数据库数据断言 2.1 在yaml用例中写入断言内容 2.2 连接数据库并封装执行sql的方法 2.3 封装后校验方法是否可执行 2.4 使用之前封装的断言方法,…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...

C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝
目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为:一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...