Ubuntu16.04 CUDA10.2 CUDNN7.6.5 tensorflow1.13.1下训练的网络,封装成pb模型,在win10下调用,需要先编译TensorFlow。一开始尝试编译GPU的版本,踩坑没爬上来。先编译一个CPU版本的试试,回头有机会再搞GPU的。
参考:https://blog.csdn.net/atpalain_csdn/article/details/97945536,https://blog.csdn.net/weixin_43868576/article/details/108491879,感谢大佬们的无私奉献!!
Step1. 安装vs2015
vs2015*(2019不行,环境变量路径不一样,编译完成之后可以在2019里面测试*)的安装这里就不多说了,Anaconda3、CUDA和cuDNN的安装可参考cmake编译opencv: Win10+cmake3.14.4+cuda10.0+cudnn7.6+opencv-4.0.0+contrib+vs2015。
Step2. 安装msys2
进入msys2官网,选择msys2-x86_64-20210228.exe。
下载好后开始安装,安装路径推荐使用默认,即安装在 C:\msys64 下。安装完成,点击Finish。
弹出一个类似cmd的命令窗口,输入一下命令:
pacman -Syu
如果报秘钥错误尝试换msys2新一点儿的版本,在官网上找个新版本。第一个命令执行成功之后,分别执行:
pacman -S git
pacman -S patch unzip grep
Step3. 安装bazel
进入https://github.com/bazelbuild/bazel/tags,选择合适的bazel版本进行下载。
bazel合适版本查询:https://www.tensorflow.org/install/source_windows
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dtYA1FXp-1616465501890)(C:\Users\30109\AppData\Roaming\Typora\typora-user-images\image-20210312153234256.png)]
将下载好的 .exe 文件复制到 C:\msys64 下(路径根据个人安装情况而定),更名为 bazel.exe。
复制完成后,配置bazel环境变量(环境变量配置完成之后需要重启电脑以生效设置)
新建三个系统变量:BAZEL_SH,BAZEL_VC,BAZEL_VS(For Visual Studio 2017 and 2019, set one of BAZEL_VC
or BAZEL_VS
. Additionally you may also set BAZEL_VC_FULL_VERSION
.
BAZEL_VS
the Visual Studio installation directory
set BAZEL_VS=C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools
BAZEL_VC
the Visual C++ Build Tools installation directory
set BAZEL_VC=C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC
BAZEL_VC_FULL_VERSION
(Optional) Only for Visual Studio 2017 and 2019, the full version number of your Visual C++ Build Tools. You can choose the exact Visual C++ Build Tools version via BAZEL_VC_FULL_VERSION
if more than one version are installed, otherwise Bazel will choose the latest version.)。
- 相应的路径如以下表格所示:
变量 | 值 |
---|---|
BAZEL_SH | C:\msys64\usr\bin\bash.exe |
BAZEL_VC | C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC |
BAZEL_VS | C:\Program Files (x86)\Microsoft Visual Studio 14.0 |
Step4. 下载编译所需文件(tensorflow源码及其他文件)
-
进入tensorflow-v1.13.1源码的github的页面https://github.com/tensorflow/tensorflow/tree/v1.13.1 ,点击页面右侧绿色按钮Clone or download,然后点击Download ZIP进行下载
-
进入tensorflow-windows-build-script-master的github页面,下载tensorflow-windows-build-script-master.zip
以上两个 .zip 文件下载完成后,在D盘新建一个文件夹,命名为 tensorflow-1.13.1 (也可根据个人喜好决定)。
- 将下载好的 tensorflow-1.13.1.zip 解压到刚刚新建的文件夹下,重新命名为 source;
- 将 tensorflow-windows-build-script-master.zip 解压到任意位置,然后把其中的 patches 和 build.ps1 文件,复制到新建的 D:\tensorflow-1.13.1目录下。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wWEwy1yC-1616465501890)(C:\Users\30109\AppData\Roaming\Typora\typora-user-images\image-20210312163145643.png)]
-
将 patches 下的 eigen_half.patch 复制到 tensorflow-1.13.1\source\third_party 下
-
将 patches 下的 tf_exported_symbols_msvc.lds 复制到 tensorflow-1.13.1\source\tensorflow 下
-
用文本编辑器打开 build.ps1 文件,将以下语句注释掉,防止编译时出现Copy-Item命令的问题。
Copy-Item …\patches\tf_exported_symbols_msvc.lds tensorflow\
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6FyT4V89-1616465501891)(C:\Users\30109\AppData\Roaming\Typora\typora-user-images\image-20210312164406150.png)]
可能的报错信息:
pip3 install six numpy wheel
后面添加-i http://pypi.douban.com/simple --trusted-host pypi.douban.com
防止安装失败,包括后面的两三个pip安装项
patch安装失败的话试试单独使用pacman -S --noconfirm patch
安装,能成功最好,失败也不影响后面
git-fetch之前添加git init
Step5. 使用powershell进行配置与编译
在 C:\Windows\SysWOW64\WindowsPowerShell\v1.0 目录下,右键以管理员身份运行 powershell.exe:
在 powershell 窗口中输入以下命令,转到 tensorflow-1.13.1 目录下:
cd D:\tensorflow-1.13.1
输入bazel编译的选项:
$parameterString = "--config=opt --config=cuda --define=no_tensorflow_py_deps=true --copt=-nvcc_options=disable-warnings //tensorflow:libtensorflow_cc.so --verbose_failures"
然后输入以下命令,执行 build.ps1 脚本文件:
.\build.ps1 -BazelBuildParameters $parameterString -BuildCppAPI -ReserveSource
执行命令时出现 UnauthorizedAccess 错误,说明可能是 powershell 的执行策略受限,输入以下命令查看当前执行策略:
Get-ExecutionPolicy
我这里显示的是Restricted(受限的),所以需要输入以下语句来取消限制:
Set-ExecutionPolicy Unrestricted
询问是否改变执行策略,输入 y,回车。
修改好后,可以再次输入:
Get-ExecutionPolicy
查看当前执行策略是否已经取消限制。
执行策略的问题解决以后,重新执行 build.ps1 脚本文件:
.\build.ps1 -BazelBuildParameters $parameterString -BuildCppAPI -ReserveSource
如果一切正常,我们将开始编译前的配置。可参照以下两图进行配置。有些提问可以直接按回车来选择默认配置,括号中出现 default 字眼的,都可以这么做。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fW4kitn8-1616465501891)(C:\Users\30109\AppData\Roaming\Typora\typora-user-images\image-20210312165933673.png)]
如果报错:D:\tensorflow-1.13.1\build.ps1 : 无法将“py”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。
解决方法:以管理员权限打开PowerShell,将python.exe所在的路径加到系统环境变量Path中,命令如下:
[Environment]::SetEnvironmentVariable("Path", "$env:Path;C:\softwares\anaconda\install")
注意 :python版本必须为3.6.7。当问到GPU的计算能力(compute capability),即出现 [Default is: 3.5, 7.0]: 时,先不要急着按回车。我们先找到跟自己显卡对应的计算能力,再进行填写,可参考后面的方法来查看显卡的计算能力。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ApqsdbGS-1616465501891)(C:\Users\30109\AppData\Roaming\Typora\typora-user-images\image-20210323100148734.png)]
打开设备管理器,找到自己的显卡型号:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FbLUD6o0-1616465501892)(C:\Users\30109\AppData\Roaming\Typora\typora-user-images\image-20210312170040856.png)]
然后进入NVDIA官网的CUDA GPUs页面,点击 CUDA-Enabled GeForce and TITAN Products,找到自己的显卡型号对应的数值,将其填入 [Default is: 3.5, 7.0]: 后面,回车继续配置。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PXu0nNzC-1616465501892)(C:\Users\30109\AppData\Roaming\Typora\typora-user-images\image-20210312170100758.png)]
都配置完成后,编译正式开始。注意保持网络通畅,因为编译之前需要下载各种依赖库,网络异常会导致下载失败停止编译。
**报错:**如果icu、grpc包下载错误(报错信息中,有下载链接),通过chrome浏览器下载包,然后将tar.gz包上传到http文件服务器,通过http文件服务器加载tar.gz包。架设简单文件服务器参考https://jingyan.baidu.com/article/3c48dd348c5f04e10ae35876.html。
最终编译完成cpu版本的截图如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eIKFUOmp-1616465501893)(C:\Users\30109\AppData\Roaming\Typora\typora-user-images\image-20210321085104048.png)]
Step6. 整理生成的文件——dll,lib,include(!!!复制!!!不能剪切!!!因为有些是重复引用的)
新建一个文件夹,在文件夹中创建以下三个目录:dll,lib,include。
根据编译结束时显示的动态库所在位置,找到生成的库 libtensorflow_cc.so 和 liblibtensorflow_cc.so.ifso。
- 将 libtensorflow_cc.so 更名为 tensorflow_cc.dll,放到刚才创建的 dll 目录下;
- 将 liblibtensorflow_cc.so.ifso 更名为 tensorflow_cc.lib,放到刚才创建的 lib 目录下。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rr6bhaF3-1616465501893)(C:\Users\30109\AppData\Roaming\Typora\typora-user-images\image-20210321085304373.png)]
接下来要做的是填满 include 目录,该步相对繁琐,最终将包含以下文件夹:
1)在include目录中新建名为 _bin 的文件夹。参考以下路径,打开 _embedded_binaries 目录,将下图红框中的文件复制到 _bin 文件夹中:
C:\Users\xxx_bazel_xxx\install\d5b1be53d8db6a1e2d160364df2e7ef6\_embedded_binaries
或C:\Users\****\_bazel_****\install\d5b1be53d8db6a1e2d160364df2e7ef6\_embedded_binaries
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pIsnjKQT-1616465501894)(C:\Users\30109\AppData\Roaming\Typora\typora-user-images\image-20210321085607162.png)]
2-1) 参考以下路径,将下图红框中的 bazel-out 文件夹复制到 include 目录下:
C:\Users\xxx_bazel_xxx\y46qiod6\execroot\org_tensorflow
或C:\Users\****\_bazel_****\y46qiod6\execroot\org_tensorflow
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z8jZ7Oag-1616465501894)(C:\Users\30109\AppData\Roaming\Typora\typora-user-images\image-20210321085734661.png)]
2-2) 参考以下路径,将 protobuf_archive 文件夹复制到 include 下的 bazel-out\x64_windows-opt\genfiles\external 目录中:
C:\Users\xxx_bazel_xxx\y46qiod6\external
或C:\Users\****\_bazel_****\y46qiod6\external
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OVRsioIS-1616465501894)(C:\Users\30109\AppData\Roaming\Typora\typora-user-images\image-20210321095843932.png)]
3) 将 D:\tensorflow-1.13.1\source 下的 tensorflow 和 third_party 复制到 include 目录下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2e1bqjPU-1616465501895)(C:\Users\30109\AppData\Roaming\Typora\typora-user-images\image-20210321100030375.png)]
4-1) 参照以下路径,将下图红框中的 external 文件夹复制到 include 目录下:
C:\Users\xxx_bazel_xxx\y46qiod6
或C:\Users\****\_bazel_****\y46qiod6
4-2) 参照以下路径,将 embedded_tools 文件夹下的所有文件复制到 include 下的 external\bazel_tools 目录中(如果 external 里面没有该文件夹,需新建并命名为 bazel_tools):
C:\Users\xxx_bazel_xxx\install\d5b1be53d8db6a1e2d160364df2e7ef6_embedded_binaries\embedded_tools
4-3) 将 D:\tensorflow-1.13.1\source 下的 tensorflow 复制到 include 下的 external\org_tensorflow 目录中(如果 external 里面没有该文件夹,需新建并命名为 org_tensorflow):
至此,调用tensorflow所需的库及包含的目录准备完毕!
测试
新建控制台程序,测试代码:
test_tensorflow.cpp
#include "TestTensorFlow.h"
#include "tensorflow/cc/client/client_session.h"
#include "tensorflow/cc/ops/standard_ops.h"
#include "tensorflow/core/framework/tensor.h"
int main() {
using namespace tensorflow;
using namespace tensorflow::ops;
Scope root = Scope::NewRootScope();
// Matrix A = [3 2; -1 0]
auto A = Const(root, { { 3.f, 2.f },{ -1.f, 0.f } });
// Vector b = [3 5]
auto b = Const(root, { { 3.f, 5.f } });
// v = Ab^T
auto v = MatMul(root.WithOpName("v"), A, b, MatMul::TransposeB(true));
std::vector<Tensor> outputs;
ClientSession session(root);
// Run and fetch v
TF_CHECK_OK(session.Run({ v }, &outputs));
// Expect outputs[0] == [19; -3]
LOG(INFO) << outputs[0].matrix<float>();
return 0;
}
test_tensorflow.h
#pragma once //这一句防止重复include头文件
#define COMPILER_MSVC
#define NOMINMAX //这一句防止max/min函数命名冲突#pragma once
环境配置
1)包含目录:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-10j0W89D-1616465501896)(C:\Users\30109\AppData\Roaming\Typora\typora-user-images\image-20210321112655337.png)]
C:\libtensorflow-cpu-x64-1.13.1
C:\libtensorflow-cpu-x64-1.13.1\include
C:\libtensorflow-cpu-x64-1.13.1\include\external\org_tensorflow
C:\libtensorflow-cpu-x64-1.13.1\include\external\protobuf_archive\src
C:\libtensorflow-cpu-x64-1.13.1\include\external\com_google_absl
C:\libtensorflow-cpu-x64-1.13.1\include\external\eigen_archive
C:\libtensorflow-cpu-x64-1.13.1\include\bazel-out\x64_windows-opt\genfiles
2)库目录:
C:\libtensorflow-cpu-x64-1.13.1\lib
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bKRQ8GYf-1616465501896)(C:\Users\30109\AppData\Roaming\Typora\typora-user-images\image-20210321112753230.png)]
3)链接器输入附加依赖项:
tensorflow_cc.lib;
环境配置好后,将之前生成的动态库放入应用程序目录,即复制 tensorflow_cc.dll 和tensorflow_cc.lib到与工程文件 .sln 同级的 x64\Release 文件夹下,如下图所示:
生成解决方案
报错1:
E1696 无法打开 源 文件 “tensorflow/core/framework/tensor.pb.h” Dll1 C:\libtensorflow-cpu-x64-1.13.1\include\tensorflow\cc\framework\ops.h 22
解决方法:相关问题描述可见https://github.com/tensorflow/tensorflow/issues/9253,不过没有拷贝,直接重启vs就行,重启治百病
报错2: C2857 在源文件中没有找到用 /Ycpch.h 命令行选项指定的“#include”语句
解决方法:在属性->c/c+±>预编译头中,选择“不适用预编译头”,把预编译头文件的pch.h删掉。
报错3:编译可能出现无法解析的外部符号的问题,以下面的错误为例:
无法解析的外部符号 “public: virtual __cdecl tensorflow::internal::LogMessage::~LogMessage(void)” (??1LogMessage@internal@tensorflow@@UEAA@XZ),该符号在函数 “public: void __cdecl tensorflow::internal::LogMessage::`vbase destructor’(void)” (??_DLogMessage@internal@tensorflow@@QEAAXXZ) 中被引用
解决方法:用文本编辑器打开 D:\tensorflow-1.13.1\source\tensorflow\tf_exported_symbols_msvc.lds ,将前面一个括号中带问号的内容:
??1LogMessage@internal@tensorflow@@UEAA@XZ
复制到该文件的末尾,如下图所示。
如果有多个无法解析外部符号的问题,用同样的方法逐一添加。全部添加完成后保存关闭文件,然后重新编译tensorflow,也就是说从运行脚本文件开始,后面的流程要重新走一遍。
??0MatMul@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@1AEBUAttrs@012@@Z
?Const@ops@tensorflow@@YA?AVOutput@2@AEBVScope@2@AEBUInitializer@Input@2@@Z
??1LogMessage@internal@tensorflow@@UEAA@XZ
??0LogMessage@internal@tensorflow@@QEAA@PEBDHH@Z
?WithOpNameImpl@Scope@tensorflow@@AEBA?AV12@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z
?NewRootScope@Scope@tensorflow@@SA?AV12@XZ
??1Scope@tensorflow@@QEAA@XZ
?Run@ClientSession@tensorflow@@QEBA?AVStatus@2@AEBV?$vector@VOutput@tensorflow@@V?$allocator@VOutput@tensorflow@@@std@@@std@@PEAV?$vector@VTensor@tensorflow@@V?$allocator@VTensor@tensorflow@@@std@@@5@@Z
??1ClientSession@tensorflow@@QEAA@XZ
??0ClientSession@tensorflow@@QEAA@AEBVScope@1@@Z
??0Initializer@Input@tensorflow@@QEAA@AEBV?$initializer_list@UInitializer@Input@tensorflow@@@std@@@Z
报错4:无法打开源文件 “google/protobuf/stubs/common.h”。文件不要剪切,要复制!!!