windows编译TensorFlowServing

news2025/1/12 9:44:31

概述

整个编译打包过程的总体思路,是参照在linux下的编译流程,配置环境,执行编译命令,根据编译器/链接器反馈的错误,修改相应的源码或者相关库文件的存放路径,编译出windows平台下静态库和二进制执行文件。

TIP:在碰到很多编译错误的时候,适当避开某些不好解决的第三方依赖库(libevent,gflag,glog),把流程走通,再回头解决外部依赖库的问题。

在这里插入图片描述

windows编译tensorflow serving流程图

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 -Syu
 pacman -Su
 pacman -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_sentencepiececom_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.hwinsock2.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的支持,后续将根据模型的运行时间添加。
  • 关于libeventwindows平台支持不好的问题,如有需要将替换成更友好的libuv库。
  • 已经注释掉未参加编译的sentencepiecegflag库,如果影响程序的正常运行,将添加支持。
  • 对于通过注释linkstamp去掉的版本信息,将按需添加。
  • 分析Serving工程的依赖层次结构,去掉业务实战中用不到的功能,使执行文件轻量化。

参考文档

[1] libeventwindows上的编译

[2] linstamp无法在windows上正常运行

[3] msvc__VA_ARGS__的支持问题

[4] windows.hwinsock2.h的包含顺序

[5] windows下找不到netinet/in.h文件

[6] python环境配置错误

[7] bazel限制内存使用

[8] tensorflow serving的运行及调试

[9] 编译器堆空间不足问题
ensorflow/tensorflow/issues/48264)

[7] bazel限制内存使用

[8] tensorflow serving的运行及调试

[9] 编译器堆空间不足问题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1393229.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入了解Transformer:先进语言模型背后的两个强大引擎

Transformer模型的出现对自然语言处理&#xff08;NLP&#xff09;领域来说堪称革命性。在Transformer崛起之前&#xff0c;循环神经网络&#xff08;RNNs&#xff09;是处理序列数据的标准。然而&#xff0c;Transformer的引入在各种NLP任务中大大超越了RNN的性能&#xff0c;…

RTMP对接腾讯云问题记录

RTMP对接腾讯云问题分析报告 问题现象及原因分析 1. 连不上腾讯云RTMP服务器 连不上腾讯云RTMP服务器&#xff0c;抓包显示服务器在握手完成后&#xff0c;主动断开了当前TCP链接。问题原因可能是connect中的tcUrl不能把域名转为IP&#xff0c;导致在握手不久服务器主动断开…

vue3前端开发,感受一下组合式api和VUE2选项式的差异

vue3前端开发,感受一下组合式api和VUE2选项式的差异&#xff01;今天开始&#xff0c;正式开始&#xff0c;进入学习Vue3的内容。以后代码&#xff0c;案例分享&#xff0c;都会采用组合式api的模式为大家做展示。 今天是第一节&#xff0c;带大家感受一下&#xff0c;Vue3的组…

【C++入门到精通】智能指针 auto_ptr、unique_ptr简介及C++模拟实现 [ C++入门 ]

阅读导航 引言一、std::auto_ptr1. 简介2. 使用示例3. C模拟实现 二、std::unique_ptr1. 简介2. 使用示例3. C模拟实现 温馨提示 引言 在 C 中&#xff0c;智能指针是一种非常重要的概念&#xff0c;它能够帮助我们自动管理动态分配的内存&#xff0c;避免出现内存泄漏等问题。…

axios的原理及源码解析

面试官&#xff1a;你了解axios的原理吗&#xff1f;有看过它的源码吗&#xff1f; 一、axios的使用 关于axios的基本使用&#xff0c;上篇文章已经有所涉及&#xff0c;这里再稍微回顾下&#xff1a; 发送请求 import axios from axios;axios(config) // 直接传入配置 axio…

Python实战 -- PySide6 制作天气查询软件

一、环境准备 开发环境&#xff1a;Python 3.9.2 pycharm PySide6 申请天气情况 API &#xff1a;https://console.amap.com/dev/key/app designer 设计 ui 目录下 Weather.ui 转换为 Weather.py 结果显示 二、完整代码 import sysfrom PySide6 import QtWidgetsimport…

安全牧场,保障优质奶源 追溯羊奶品质

安全牧场&#xff0c;保障优质奶源 追溯羊奶品质 近年来&#xff0c;人们对食品安全和健康越来越关注&#xff0c;而安全牧场的兴起正能够满足人们对优质奶源的需求。安全牧场以严格的品质监控和科学的管理&#xff0c;为消费者提供可追溯的高品质羊奶产品。本文小编羊大师将为…

机器学习算法理论:贝叶斯

贝叶斯定理对于机器学习来说是经典的概率模型之一&#xff0c;它基于先验信息和数据观测来得到目标变量的后验分布。具体来说&#xff0c;条件概率&#xff08;也称为后验概率&#xff09;描述的是事件A在另一个事件B已经发生的条件下的发生概率&#xff0c;公式表示为P(A|B)&a…

前端公共组件库优化

背景 前段时间入职了新公司后&#xff0c;做一些内部前端基建的工作&#xff0c;其中一个工作就是优化现有的frontend-common公共组件库。之前的组件库一直是以源码依赖的形式存在&#xff0c;即各个项目通过git submodule的方式将该仓库引入到各个项目中&#xff0c;作为一个…

Linux学习记录——사십삼 高级IO(4)--- Epoll型服务器(1)

文章目录 1、理解Epoll和对应接口2、简单实现 1、理解Epoll和对应接口 poll依然需要OS去遍历所有fd。一个进程去多个特定的文件中等待&#xff0c;只要有一个就绪&#xff0c;就使用select/poll系统调用&#xff0c;让操作系统把所有文件遍历一遍&#xff0c;哪些就绪就加上哪…

基于SURF算法的图像匹配

基础理论 2006年Herbert Bay提出了SURF算法&#xff0c;该算法是对SIFT算法的改进&#xff0c;不仅继承了SIFT算法的优点&#xff0c;而且比SIFT算法速度快。下面是SURF算法的步骤。 &#xff08;1&#xff09;建立积分图像 &#xff08;2&#xff09;构建尺度空间 &#x…

python使用Apache+mod_wsgi部署Flask

python使用Apachemod_wsgi部署Flask 一、安装python环境&#xff08;V3.10.10&#xff09;二、安装mod_wsgi三、安装Apache1、下载2、解压3、配置 四、安装项目依赖五、启动六、基于多端口部署多个flask项目 一、安装python环境&#xff08;V3.10.10&#xff09; 安装时勾选&q…

Elasticsearch:将数据从 Snowflake 摄取到 Elasticsearch

作者&#xff1a;来自 Elastic Ashish Tiwari 为了利用 Elasticsearch 提供的强大搜索功能&#xff0c;许多企业在 Elasticsearch 中保留可搜索数据的副本。 Elasticsearch 是一种经过验证的技术&#xff0c;适用于传统文本搜索以及用于语义搜索用例的向量搜索。 Elasticsearch…

C#,入门教程(38)——大型工程软件中类(class)修饰词partial的使用方法

上一篇&#xff1a; C#&#xff0c;入门教程(37)——优秀程序员的修炼之道https://blog.csdn.net/beijinghorn/article/details/125011644 一、大型&#xff08;工程应用&#xff09;软件倚重 partial 先说说大型&#xff08;工程应用&#xff09;软件对源代码的文件及函数“…

【白皮书下载】GPU计算在汽车中的应用

驾驶舱域控制器 (CDC) 是汽车 GPU 的传统应用领域。在这里&#xff0c;它可以驱动仪表板上的图形&#xff0c;与车辆保持高度响应和直观的用户界面&#xff0c;甚至为乘客提供游戏体验。随着车辆屏幕数量的增加和分辨率的提高&#xff0c;对汽车 GPU 在 CDC 中进行图形处理的需…

基础+常用的数据结构

基础 java基础 JDK 和 JRE JDK&#xff0c;它是功能齐全的 Java SDK&#xff0c;是提供给开发者使用&#xff0c;能够创建和编译 Java 程序的开发套件。它包含了 JRE,同时还包含了编译 java 源码的编译器 javac 以及一些其他工具比如 javadoc&#xff08;文档注释工具&#…

贪心算法-活动安排-最详细注释解析

贪心算法-活动安排-最详细注释解析 题目&#xff1a; 学校在最近几天有n个活动&#xff0c;这些活动都需要使用学校的大礼堂&#xff0c;在同一时间&#xff0c;礼堂只能被一个活动使用。由于有些活动时间上有冲突&#xff0c;学校办公室人员只好让一些活动放弃使用礼堂而使用…

Ubuntu20.4 Mono C# gtk 编程习练笔记(二)

界面设计习练后&#xff0c;下面写一些程序设计心得。 程序结构 先看一下程序总体结构&#xff0c;先在program.cs中找到main入口&#xff0c;在命名空间下是MainClass类&#xff0c;Main函数进入后首先建立应用程序环境 Application.Init&#xff0c;然后对MainWindow进行实…

2.mac 安装 Visual studio code 整合go开发

目录 概述前置下载关键命令整合C#go配置go插件常见的go工具安装测试 结束 概述 mac 安装 Visual studio code 整合go开发 相关前置文章 go安装及相关配置 文章 前置 官网速递 mac 系统高于等于 10.15.x 可以直接最新版本 我的系统是 10.13 &#xff0c;所以只能安装此版本…

JRTP实时音视频传输(2)-使用TCP通信的案例

1.创建自己的demo 先将example1拷贝为myclienttcp.cpp和myservertcp.cpp cp example1.cpp myclienttcp.cpp cp example1.cpp myservertcp.cpp 改写jrtplib/JRTPLIB/examples/CMakeLists.txt&#xff0c;添加myclienttcp和myservertcp编译 重新生成Makefile并编译 sudo cmak…