OS Platform and Distribution : ( Ubuntu 18.04)
TensorFlow installed from : (source)
TensorFlow version: Tags v2.4.1
Python version: Python 3.7.6
Installed using virtualenv? pip? conda?: conda
Bazel version (if compiling from source): have tried bazel 3.4.0 、 bazel 3.1.0
GCC/Compiler version (if compiling from source): gcc (GCC) 7.4.0
CUDA/cuDNN version: cuda_11.1 , cudnn 8.0.5
GPU model and memory: rtx3060
nvidia-driver version: 460.91
eigen version : eigen-3.3.90
建议搭配:tf2.4.0 、cuda 11.0、cudnn 8.0.5
bazel:用来自动化构建大型工程的,和make、maven属于同一类工具。
bazel版本需要和tensorflow版本对应
tf2.4 适配的bazel版本为3.1.0
使用sh文件安装bazel,执行bazel version时报错
/usr/local/lib/bazel/bin/bazel-real: cannot execute binary file: Exec format error
改为下载zip后解压安装
wget https://github.com/bazelbuild/bazel/releases/download/3.1.0/bazel-3.1.0-dist.zip
mkdir bazel
unzip -d bazel bazel-3.1.0-dist.zip
cd bazel
bash ./compile.sh
sudo cp output/bazel /usr/local/bin
#验证
bazel version
镜像源
(国内外各镜像源都没有7.3.1版本,可以用7.4.0或7.5.0)
gcc安装步骤
在选择编译的tensorflow版本的github官方源码里的workspace.bzl中查看该版本适配的protobuf版本和下载url,
比如tf2.4.0 适配的protobuf版本为3.9.2 :
https://github.com/tensorflow/tensorflow/blob/r2.4/tensorflow/workspace.bzl
tf_http_archive(
name = "com_google_protobuf",
patch_file = clean_dep("//third_party/protobuf:protobuf.patch"),
sha256 = "cfcba2df10feec52a84208693937c17a4b5df7775e1635c1e3baffc487b24c9b",
strip_prefix = "protobuf-3.9.2",
system_build_file = clean_dep("//third_party/systemlibs:protobuf.BUILD"),
system_link_files = {
"//third_party/systemlibs:protobuf.bzl": "protobuf.bzl",
},
urls = [
"https://storage.googleapis.com/mirror.tensorflow.org/github.com/protocolbuffers/protobuf/archive/v3.9.2.zip",
"https://github.com/protocolbuffers/protobuf/archive/v3.9.2.zip",
],
)
安装步骤
wget https://storage.googleapis.com/mirror.tensorflow.org/github.com/protocolbuffers/protobuf/archive/v3.9.2.zip
# 或 wget https://github.com/protocolbuffers/protobuf/archive/v3.9.2.zip
unzip v3.9.2.zip
cd protobuf-3.9.2
./autogen.sh
./configure
make
sudo make install
# sudo make uninstall 安装错版本后卸载指令
protoc --version # 查看protobuf版本
eigen下载url eigen3.3.9。下载tar.gz后解压
tar -zxvf eigen-3.3.90.tar.gz
cd eigen-3.3.90/
mkdir build
cd build
cmake ..
sudo make
sudo make install
参考
mkdir tensorflow
cd tensorflow
git clone --depth 1 --branch v2.4.1 https://github.com/tensorflow/tensorflow.git
cd tensorflow
./configure #配置编译选项
compute capability计算力点进提示给的nvidia官网url中查看
#使用Bazel编译C++ API的库
#CPU版本
bazel build --config=opt //tensorflow:libtensorflow_cc.so
#GPU版本
bazel build --config=opt --config=cuda //tensorflow:libtensorflow_cc.so
...include/cudnn_backend.h No such file or directory
Error downloading [https://storage.googleapis.com/mirror.tensorflow.org/github.com/llvm/llvm-project/archive/f402e682d0ef5598eeffc9a21a691b03e602ff58.tar.gz, https://github.com/llvm/llvm-project/archive/f402e682d0ef5598eeffc9a21a691b03e602ff58.tar.gz]
LLVM_URLS = [
"file:///home/app/llvm-project-f402e682d0ef5598eeffc9a21a691b03e602ff58.tar.gz",
"https://github.com/llvm/llvm-project/archive/{commit}.tar.gz".format(commit = LLVM_COMMIT),
]
cd tensorflow/tensorflow/lite/tools/make
./download_dependencies.sh
若网络原因下载失败,可分别手动下载相应文件并解压,下载的文件url见 download_dependencies.sh文件;
将以上下载的文件解压后并按照以上文件名进行命名,统一存放在 tensorflow/tensorflow/lite/tools/make/downloads
文件夹中。
大概的步骤:
$ cd ~/demo/build
$ cmake ..
$ make
$ ./demo
注: 我的tensorflow 2.4.1编译完成后没有contrib文件夹、没有bazel-genfiles文件夹。
这里采取的是将依赖的文件夹移动到运行项目demo/
目录下,为的是方便后期该项目迁移到其他主机运行时能带着 依赖一起迁移。
如果你只在本机运行该项目,那么移动的目的文件夹就是/usr/local/include/tf/
我移动后的 demo/
文件夹层级结构:
demo/
CMakeLists.txt
build/
model.pb
include/
UseTensorFlowDLL.h
src/
main.cpp
opencv3.4.0/
bin/
include/
lib/
share/
tf2/
bazel-bin/
external/
_solib_local/
tensorflow/
third_party/
eigen/
..太多这里省略
lib/
libtensorflow_cc.so.2
libtensorflow_framework.so.2
tensorflow/
..省略
third_party/
..省略
其中tf2目录为自己手动创建,tf2/ 下的各个文件夹手动从编译完成的目录下拷贝过来,各文件夹来源:
① bazel-bin/:tensorflow/bazel-bin/
(tensorflow/
为编译完成的最终文件夹)
② eigen/ :tensorflow/lite/tools/make/downloads/eigen
③ lib/: 两个文件(拷贝完可能需要重命名)分别来自
tensorflow/bazel-bin/tensorflow/libtensorflow_cc.so.2.4.1
和
tensorflow/bazel-bin/tensorflow/libtensorflow_framework.so.2.4.1
④ tensorflow/ :tensorflow/
⑤ third_party/ :tensorflow/third_party
其中CMakeLists.txt 内容:
# cmake needs this line
cmake_minimum_required(VERSION 3.10)
# Define project name
project(shufflenetPbLinuxDemo)
find_package(OpenCV REQUIRED)
message(STATUS "OpenCV library status:")
message(STATUS " config: ${OpenCV_DIR}")
message(STATUS " version: ${OpenCV_VERSION}")
message(STATUS " libraries: ${OpenCV_LIBS}")
message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}")
set(TENSORFLOW_LIBS
${CMAKE_CURRENT_SOURCE_DIR}/tf2/lib/libtensorflow_cc.so.2
${CMAKE_CURRENT_SOURCE_DIR}/tf2/lib/libtensorflow_framework.so.2
)
# 头文件的搜索目录
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/tf2
${CMAKE_CURRENT_SOURCE_DIR}/tf2/bazel-bin
${CMAKE_CURRENT_SOURCE_DIR}/tf2/tensorflow
${CMAKE_CURRENT_SOURCE_DIR}/tf2/third-party
${CMAKE_CURRENT_SOURCE_DIR}/tf2/eigen
)
# Declare the executable target built from your sources
add_executable(shufflenetPbLinuxDemo ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp)
# Link your application with OpenCV libraries
target_link_libraries(shufflenetPbLinuxDemo PRIVATE ${OpenCV_LIBS} ${TENSORFLOW_LIBS})
cmake ..
报错合集tensorflow/core/framework/device_attributes.pb.h:没有那个文件或目录
或者报错没有其他的pb.h文件正常情况下,pb.h是在编译过程中由protobuf编译生成的,应该存在于
bazel-genfiles/tensorflow/core/framework
文件夹下。
.pb.h is a generated file when you build with bazel build. The
.pb.h files should appear under bazel-genfiles folder thereafter.
而我之前用tensorflow2.4.0版本虽然也没生成bazel-genfiles/ ,但没有这个报错,不知道为什么换成tf2.4.1 分支后就报错了。
解决方法:手动用命令挨个将报错中的 proto文件转为pb.h
sudo protoc
在tensorflow github的相关提问
若执行protoc命令报错tensorflow/core/framework/xx.proto File not found
即import的文件未找到。可能是执行protoc命令时所处的路径层级不对,在import后跟的路径的层级下重新尝试。
方法:设置环境变量:
sudo gedit /etc/profile
添加: export OpenCV_DIR=/home/workspace/demo/opencv3.4.0
保存退出,source /etc/profile
make
报错合集cv::glob(cv::String,std)
未定义的引用原因:CMakeLists.txt中的opencv路径没加或者不对。(”未定义的引用“这类报错都是因为缺少链接库)
对‘cv::imread(cv::String const&, int)’未定义的引用
Session* session "Session was not declared in this scope"
文件头加入tensorflow定义域:
#include "tensorflow/core/public/session.h"
#include "tensorflow/core/platform/env.h"
如果你的 model.pb为 meta_graph,ReadBinaryProto可能只适用于frozen graph,
因此需要将加载模型方式改为 tensorflow::LoadSavedModel(session_options, run_options, model_path,{tensorflow::kSavedModelTagServe}, &bundle))
LoadSavedModel示例
.../eigen3/unsupported/Eigen/CXX11/Tensor:1:42: error: #include nested too deeply
方法
find . -name "eigen*" -type d
修改CMakeLists.txt 的include_directories 里eigen的路径,换成上面find出来的结果(如果find出来多个路径则可以挨个尝试)。
./your_demo
过程报错合集原因:程序发生了越界访问
1)内存访问越界(数组越界)
2)多线程 线程不安全
3)堆栈溢出(使用大的局部变量容易造成栈溢出,因为局部变量都分配在栈上)
扩展:core报错具体原因可以 配置操作系统使其生成core文件,用gdb查看core文件 结合程序崩溃后的core文件分析bug
最终原因以及解决办法:
升级到tf2.4.1+cuda11.1后报这个错是因为main.cpp最后输出outputs置信度这里的outputs数组越界,
//前向运行,网络进行实际推理inference
tensorflow::Status status_run = session->Run(inputs, { out_put_nodes }, {}, &outputs);
//获取置信度
auto confidence_vector = outputs[0].tensor<float, 2>();
for (int ProposalNum = 0; ProposalNum < maxbatchSize; ProposalNum++) {
float confidence_float1 = confidence_vector(ProposalNum, 1);
cout << "the confidence is:" << confidence_float1 << endl;
}
return 0;
outputs[0] 越界
是因为session 根本就没有run成功,
(通过在session->Run 之后加上
tensorflow::Status status_run = session->Run(inputs, {out_put_nodes}, {}, &output)
if (!status_run.ok()) {
std::cout << "ERROR: RUN failed in session run..." << std::endl;
std::cout << status_run.ToString() << "\n";
判断出session没有run成功,所以outputs自然是空数组,outputs[0]
也就越界访问了)
而session没有run成功的原因在 下一个问题中描述。
Invalid argument:Tensor ShuffleOutputPb:0,specified in either feed_devices or fetch_devices was not found in the Graph
原因: main.cpp中的 Tensor变量
ShuffleOutputPb:0
和python中生成pb模型的设置的tensor名不一样,修改main.cpp中的变量名。
然后再重新跑,终于status_run.ok()
为True了,但是又报下面的错:
No algorithm worked
① main.cpp 中的 bundle.session->Run(inputs,{out_put_nodes},{},&outputs);
这里直接写inputs,而不是{{input_name, input}}
因为本项目中已经提前把input_name和resized_tensor都push_back进inputs张量中了。
②OP_REQUIRES failed at conv_ops.cc:Not found: No algorithm worked!
原因:tensorflow官方github的issue中查询这个报错,判断可能是OOM内存超出,可以在运行时同时
watch -n 0.5 nvidia-smi
看到当memory使用快到达最大容量时,就报错。
python的解决方案
c++的解决方法:
在session定义前如果没有设置限制GPU的内存使用,要加上内存限制的相关语句:
tensorflow::SessionOptions session_options;
tensorflow::ConfigProto* session_options_config = &session_options.config;
// 内存限制
session_options_config->set_allow_soft_placement(true);
session_options_config->mutable_gpu_options()->set_per_process_gpu_memory_fraction(0.33);
session_options_config->mutable_gpu_options()->set_allow_growth(true);
//创建新的会话 并进行参数配置
status = NewSession(session_options, &session);//创建新会话Session
status_load = tensorflow::ReadBinaryProto(tensorflow::Env::Default(), "model.pb", &graphdef); //从pb文件中读取图模型;
status_create = session->Create(graphdef); //将模型导入会话Session中;
我的问题是把 session_options_config-> ...
这3行写在了NewSession定义之后了,把这3行设置移到 NewSession定义语句前面就可以了。
问题搜索的网站:
1、tensorflow官方github的 Issues 中搜索报错或问题关键词。
2、和cuda相关的问题搜索 nvidia官网论坛
3、stackoverflow
总结解决问题中卡壳的原因以及获取的经验:
① 如果报错没有展开详细描述,寻找其是否存在错误log日志,根据错误日志分析原因。
② 明确报错的最初有可能产生位置,而非眉毛胡子一把抓。
③ 同样的代码在别人主机上能运行成功,不代表这份代码或流程就是正确的(可能其中几行逻辑错误,但他人主机上这几行等于注释、不起作用)
重点是理清排查思路,再下手。