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=500UNAVAILABLE_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 使用之前封装的断言方法,…...
Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...
NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)
前言: 双亲委派机制对于面试这块来说非常重要,在实际开发中也是经常遇见需要打破双亲委派的需求,今天我们一起来探索一下什么是双亲委派机制,在此之前我们先介绍一下类的加载器。 目录 编辑 前言: 类加载器 1. …...
Ubuntu系统复制(U盘-电脑硬盘)
所需环境 电脑自带硬盘:1块 (1T) U盘1:Ubuntu系统引导盘(用于“U盘2”复制到“电脑自带硬盘”) U盘2:Ubuntu系统盘(1T,用于被复制) !!!建议“电脑…...
在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南
在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南 背景介绍完整操作步骤1. 创建Docker容器环境2. 验证GUI显示功能3. 安装ROS Noetic4. 配置环境变量5. 创建ROS节点(小球运动模拟)6. 配置RVIZ默认视图7. 创建启动脚本8. 运行可视化系统效果展示与交互技术解析ROS节点通…...
RushDB开源程序 是现代应用程序和 AI 的即时数据库。建立在 Neo4j 之上
一、软件介绍 文末提供程序和源码下载 RushDB 改变了您处理图形数据的方式 — 不需要 Schema,不需要复杂的查询,只需推送数据即可。 二、Key Features ✨ 主要特点 Instant Setup: Be productive in seconds, not days 即时设置 :在几秒钟…...
