使用paho.mqtt.embedded-c库编译的应用程序在linux环境下监听topic时,过段时间会概率性地发生连接失败并重连的现象。具体表现为会打印yield -1
void loop() {
static int count=0;
int ret=MQTTYield(&c, 1000);
if (SUCCESS != ret) {
LOGI("yield:%d",ret);
if(0 == count%reconnect_delay){
reconnect_count++;
if(10<reconnect_count){
reconnect_delay=60;
}
count=0;
connect_mqtt();
}
count++;
} else{
reconnect_delay=10;
reconnect_count=0;
count=0;
}
}
出现问题首先要缩小问题搜索范围,然后在小范围内定位问题。网络相关的首先怀疑是否是网络问题导致的,因些我首先对网络问题进行排查。具体排查方法为:
使用另外的库 mosquitto_sub
监听同一MQTT服务的同一topic,在相同情况下mosquitto_sub
没有问题,可以初步判定MQTT服务本身没有问题。
确定网络没有问题后,应该可以确定是是我自己写的应用程序的问题,我自己写的应用程序也有两部分:自己写的代码和库代码。先确定是自己写的代码有问题还是库代码有问题,比较好的方式就是直接使用官方例程代码看是否有问题。如果官方例程也有问题就说明是库的问题,否则就是自己写的代码有问题。
在paho.mqtt.embedded-c自带监听的sample上加入失败打印,然后监听同一MQTT服务的同一topic,发现也会打印 connect err: -1
。说明问题是出自paho.mqtt.embedded-c库
int main(int argc, char** argv)
{
...
while (!toStop)
{
int ret= MQTTYield(&c, 1000);
if (SUCCESS != ret) {
printf("connect err:%d\n",ret);
}
}
...
}
本文为系列博客tensorflow模型部署系列的一部分,用于实现通用模型的独立简单服务器部署。本文主要实现用flask搭建tensorflow模型推理服务器。实现了tensorflow模型在服务器端计算方案,并提供相关示例源代码。相关源码见链接
本文为系列博客tensorflow模型部署系列的一部分,用于实现通用模型的独立简单服务器部署。本文主要实现用flask搭建tensorflow模型推理服务器。实现了tensorflow模型在服务器端计算的简单方案,该方案适用于BS和CS架构,易于部署和维护。从模型文件中获取输入输出op名请参考博客tensorflow模型部署系列————单机python部署
前面的博文tensorflow模型部署系列————嵌入式(c/c++ android)部署就如何将tensorflow在本地部署做出了讲解,覆盖了边缘计算应用的大部分场景,在实际应用时还有一种常用的应用场景:将数据传给服务器,由服务器来进行推理。该方案易于部署和维护适用于前期开发和测试。本文分别对tensorflow模型在服务器上的部署进行解说。
Flask是一个使用 Python编写的轻量级 Web 应用框架。可以用来搭建后台服务器、网页等。可以通过 pip install flask
安装,用flask搭建web应用只需以下几行代码即可
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run()
其中 app = Flask(__name__)
创建一个flask实例;使用 @app.route('/')
装饰器告诉 Flask 访问根目录时会触发函数hello_world
模型封装类直接使用tensorflow模型部署系列————单机python部署已经写好的模型代码文件。如果需要查看自己模型的op名称,请参考博客tensorflow模型部署系列————单机python部署
模型封装类主要包括两个方法:初始化和推理。
初始化只用于处理与sess.run无关的所有操作,以减少推理时的操作,保证模型推理高效运行。初始化主要进行的操作包括:模型文件加载、获取计算图和计算session、根据输入输出tensor名称获取输入输出tensor
推理仅仅执行sesson.run操作
服务端在一开始加载时就把模型类实例化,然后添加inference
接口和路由。inference接口接收一个待预测文件,经过推理后将结果放入到‘result’
里,并以json格式返回。
这种独立简单服务器部署方式存在一个问题是:模型只实例化了一个对象,在并发访问在情况下存在临界区的问题,可以简单的通过加锁来避免并发,或者自己写一个模型资源池来优化,提高并发访问的吞吐量
本文为系列博客tensorflow模型部署系列的一部分,用于实现通用模型的TensorFlow Serving部署。本文主要实现用TensorFlow Serving部署tensorflow模型推理服务器。实现了tensorflow模型在服务器端计算方案,并提供相关示例源代码。相关源码见链接
本文为系列博客tensorflow模型部署系列的一部分,用于实现通用模型的独立简单服务器部署。本文主要实现用TensorFlow Serving部署tensorflow模型推理服务器。实现了tensorflow模型在服务器端计算的简单方案,该方案适用于BS和CS架构,易于部署和维护。上一篇博文讲解了利用flask搭建一个简单的模型服务,但模型只实例化了一个对象,在并发访问在情况下存在临界区的问题。TensorFlow Serving则很好地解决了这个问题。
前面的博文tensorflow模型部署系列————独立简单服务器部署就如何将tensorflow在服务器上做简单部署做出了讲解,但模型只实例化了一个对象,在并发访问在情况下存在临界区的问题。本文要介绍的TensorFlow Serving模型部署则很好地解决了这个问题。当然,TensorFlow Serving是一个强大的工具,做一个模型部署仅仅使用了它很小的一块功能。由于本文的专题在模型部署,其它方面就不做太多介绍。
TensorFlow Serving是google官方推出的用于生产的机器学习组件之一。他支持模型版本控制(用于实现包含回滚选项的模型更新)和多个模型(用于实现通过 A/B 测试进行的实验),同时还能够确保并发模型能够在硬件加速器(GPU 和 TPU)上以较低的延迟实现较高的吞吐量。
服务端安装有以下三种方式
下载docker镜像
命令行安装(ubuntu)
添加源
echo "deb [arch=amd64] http://storage.googleapis.com/tensorflow-serving-apt stable tensorflow-model-server tensorflow-model-server-universal" | sudo tee /etc/apt/sources.list.d/tensorflow-serving.list && \curl https://storage.googleapis.com/tensorflow-serving-apt/tensorflow-serving.release.pub.gpg | sudo apt-key add - apt-get update
安装
apt-get install tensorflow-model-server
源码安装https://github.com/tensorflow/serving.git
转换。下面是针对keras模型的转换代码。针对pb模型需要先手动确定输入输出op名称,从模型文件中获取输入输出op名请参考博客tensorflow模型部署系列————单机python部署
model = keras.models.load_model('../model/saved_keras/save.h5')
tf.saved_model.simple_save(
keras.backend.get_session(),
export_path,
inputs={'input_image': model.input},
outputs={t.name:t for t in model.outputs})
测试。通过命令saved_model_cli show --dir ./export/1 --all
可以查看输入输出签名是否是我们预期的
模型准备好后,就可以使用以下命令部署服务了
```tensorflow_model_server \ tensorflow_model_server \ –rest_api_port=8501 \ –model_name=saved_model \ –model_base_path=/…./model_deployment/tensorflow_serving/export/
#### 客户端测试
服务端正常启动后就可以使用客户端进行测试了。TensorFlow Serving的请求和回复都是json格式,请求地址为`http://host:port/v1/models/${MODEL_NAME}`
预测接口的请求格式为
```javascript
{
// (Optional) Serving signature to use.
// If unspecifed default serving signature is used.
"signature_name": <string>,
// Input Tensors in row ("instances") or columnar ("inputs") format.
// A request can have either of them but NOT both.
"instances": <value>|<(nested)list>|<list-of-objects>
"inputs": <value>|<(nested)list>|<object>
}
回复格式为:
{
"predictions": <value>|<(nested)list>|<list-of-objects>
}
本文为系列博客tensorflow模型部署系列的一部分,用于实现通用模型的独立简单服务器部署。本文主要实现用flask搭建tensorflow模型推理服务器。实现了tensorflow模型在服务器端计算方案,并提供相关示例源代码。相关源码见链接
本文为系列博客tensorflow模型部署系列的一部分,用于实现通用模型的独立简单服务器部署。本文主要实现用flask搭建tensorflow模型推理服务器。实现了tensorflow模型在服务器端计算的简单方案,该方案适用于BS和CS架构,易于部署和维护。从模型文件中获取输入输出op名请参考博客tensorflow模型部署系列————单机python部署
前面的博文tensorflow模型部署系列————嵌入式(c/c++ android)部署就如何将tensorflow在本地部署做出了讲解,覆盖了边缘计算应用的大部分场景,在实际应用时还有一种常用的应用场景:将数据传给服务器,由服务器来进行推理。该方案易于部署和维护适用于前期开发和测试。本文分别对tensorflow模型在服务器上的部署进行解说。
Flask是一个使用 Python编写的轻量级 Web 应用框架。可以用来搭建后台服务器、网页等。可以通过 pip install flask
安装,用flask搭建web应用只需以下几行代码即可
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run()
其中 app = Flask(__name__)
创建一个flask实例;使用 @app.route('/')
装饰器告诉 Flask 访问根目录时会触发函数hello_world
模型封装类直接使用tensorflow模型部署系列————单机python部署已经写好的模型代码文件。如果需要查看自己模型的op名称,请参考博客tensorflow模型部署系列————单机python部署
模型封装类主要包括两个方法:初始化和推理。
初始化只用于处理与sess.run无关的所有操作,以减少推理时的操作,保证模型推理高效运行。初始化主要进行的操作包括:模型文件加载、获取计算图和计算session、根据输入输出tensor名称获取输入输出tensor
推理仅仅执行sesson.run操作
服务端在一开始加载时就把模型类实例化,然后添加inference
接口和路由。inference接口接收一个待预测文件,经过推理后将结果放入到‘result’
里,并以json格式返回。
这种独立简单服务器部署方式存在一个问题是:模型只实例化了一个对象,在并发访问在情况下存在临界区的问题,可以简单的通过加锁来避免并发,或者自己写一个模型资源池来优化,提高并发访问的吞吐量
本文为系列博客tensorflow模型部署系列的一部分,用于javascript实现通用模型的部署。本文主要实现用javascript接口调用tensorflow模型进行推理。实现了tensorflow在浏览器前端计算方案,将计算任务分配在终端,可以有效地降低服务端负荷,并提供相关示例源代码。相关源码见链接
本文为系列博客tensorflow模型部署系列的一部分,用于javascript实现通用模型的部署。本文主要实现用javascript接口调用tensorflow模型进行推理。实现了tensorflow在浏览器前端计算方案,将计算任务分配在终端,可以有效地降低服务端负荷,而且javascript免安装,同时又有并没有增加运营成本。从模型文件中获取输入输出op名请参考博客tensorflow模型部署系列————单机python部署
上一篇博文tensorflow模型部署系列————嵌入式(c/c++ android)部署就如何将tensorflow在边缘计算及一些低成本方案、物联网或工业级应用中使用的轻量级模型部署方案进行讲解,博文中也开放了使用tflite
进行模型推理的C C++ JAVA PYTHON代码,覆盖了边缘计算应用的大部分场景,在实际应用时还有一种特殊的边缘计算场景:使用本地PC计算资源来做为终端进行推理。javascript由于其特有的优势使得终端部署基本上可以做到免维护,从而大大降低运营成本。目前tensorflow提供了专门用于浏览器的TensorFlow.js。本文先对TensorFlow.js作简单介绍,然后分别介绍从keras模型和tensorflow模型转换到tfjs模型,最后分别对keras模型和tensorflow模型在TensorFlow.js上的部署进行解说。
TensorFlow.js是一个JavaScript库,它可以将机器学习功能添加到任何Web应用程序中。使用TensorFlow.js,可以构建、训练和部署深度模型
浏览器只需在html文件中加入 <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.0.0/dist/tf.min.js"></script>
即可
TensorFlow.js的接口主要是模仿keras接口来做的,对keras比较熟悉的人可以很快上手。如TensorFlow.js的接口详见官方文档。这里针对常用接口做一个说明。
加载模型文件
// 加载keras模型 tf.loadLayersModel(this.MODEL_URL) // 加载tensorflow模型 tf.loadGraphModel (this.MODEL_URL)
创建tensors
xs = tf.fill([1, 784], 0)
运行推理
result = model.predict(xs)
获取张量值
result.dataSync()
本文为系列博客tensorflow模型部署系列的一部分,用于实现通用模型的部署。本文主要实现用tflite接口调用tensorflow模型进行推理。实现了tensorflow在边缘计算及一些低成本方案、物联网或工业级应用中使用的轻量级模型部署方案,并提供相关示例源代码。相关源码见链接
本文为系列博客tensorflow模型部署系列的一部分,用于tflite实现通用模型的部署。本文主要使用pb格式的模型文件,其它格式的模型文件请先进行格式转换,参考tensorflow模型部署系列————预训练模型导出。从模型文件中获取输入输出op名请参考博客tensorflow模型部署系列————单机python部署
上一篇博文tensorflow模型部署系列————单机JAVA部署就如何使用JAVA语言加载模型文件并利用模型文件进行推理进行讲解,博文中也开放了使用JAVA
进行模型推理的代码,目前多数智能终端都已经支持JAVA,但在一些低成本方案、物联网或工业级应用中更多的是使用嵌入式linux甚至是单片机,主要使用的编译语言是C。博文tensorflow模型部署系列————单机C++部署介绍了使用C/C++进行模型部署的方法,但实际应用时因为tensorflow库文件太大(已超过100M),限制了tensorflow在嵌入式上的应用。目前tensorflow提供了专门用于嵌入式的tflite框架(仅700K左右)。tflite的目标是嵌入式部署,嵌入式部署需要针对处理器进行特殊优化。google官方除了android库以外,并没有已编译好的文件可供下载。本文先对tflite及运行作简单介绍,然后分别对tflite在python c/c++ java上的部署进行解说。
tflite是google为深度学习在嵌入式物联网应用而推出的轻量级框架。它提供了python、java和C++接口,同时可以将浮点运算转换为整数运算,从而在特定的硬件平台上加快推理速度。tflite使用的模型不是pb文件,而是更小的基于FlatBuffers的模型文件。
tflite主要有两个组件:推理组件和模型转换组件。推理组件用于运行模型;模型转换组件用于将需要的模型转换为tflite模型文件
模型文件转换时需要指定输入输出张量名,从模型文件中获取输入输出op名请参考博客tensorflow模型部署系列————单机python部署
import tensorflow as tf
img = tf.placeholder(name="img", dtype=tf.float32, shape=(1, 64, 64, 3))
var = tf.get_variable("weights", dtype=tf.float32, shape=(1, 64, 64, 3))
val = img + var
out = tf.identity(val, name="out")
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
converter = tf.lite.TFLiteConverter.from_session(sess, [img], [out])
tflite_model = converter.convert()
open("converted_model.tflite", "wb").write(tflite_model)
import tensorflow as tf
graph_def_file = "/path/to/Downloads/mobilenet_v1_1.0_224/frozen_graph.pb"
input_arrays = ["input"]
output_arrays = ["MobilenetV1/Predictions/Softmax"]
converter = tf.lite.TFLiteConverter.from_frozen_graph(
graph_def_file, input_arrays, output_arrays)
tflite_model = converter.convert()
open("converted_model.tflite", "wb").write(tflite_model)
python语言目前在嵌入式系统上应用的还不多。这里把python也拿出来讲有两个原因:
python版不需要额外安装,安装完毕tensorflow pip install tensorflow
后就可以使用了 tf.lite
tflite的python接口详见官方文档。这里针对常用接口做一个说明。
加载模型文件
interpreter = tf.lite.Interpreter(model_path=tflite_file)
创建tensors
interpreter.allocate_tensors()
获取输入输出OP
input_details = interpreter.get_input_details() output_details = interpreter.get_output_details()
张量填充
interpreter.set_tensor(input_details[0]['index'], d)
运行推理
interpreter.invoke()
获取张量值
interpreter.get_tensor(output_details[0]['index'])
模型封装类主要包括两个方法:初始化和推理。
初始化只用于处理与invoke
无关的所有操作,以减少推理时的操作,保证模型推理高效运行。初始化主要进行的操作包括:模型文件加载、获取输入输出张量。
推理主要进行的操作有:输入张量填充、interpreter.invoke
、和输出张量获取。
经过模型封装类封装以后,示例代码就很简单了。只用准备数据,然后推理就行了。
这里针对tflite的c++常用接口做一个说明,并跟将C接口跟本文中的python部署代码进行对应,以便于读者更好地理解接口
加载模型文件,对应python代码interpreter = tf.lite.Interpreter(model_path=tflite_file)
std::unique_ptr<Interpreter> interpreter; std::unique_ptr<tflite::FlatBufferModel> model = tflite::FlatBufferModel::BuildFromFile(model_file); InterpreterBuilder builder(*model, resolver); builder(&interpreter);
创建tensors,对应python代码interpreter.allocate_tensors()
interpreter->AllocateTensors()
获取输入输出OP,对应python代码interpreter.get_input_details()
interpreter.get_output_details()
in_index = interpreter->inputs()[0]; out_index = interpreter->outputs()[0];
张量填充,对应python代码interpreter.set_tensor(input_details[0]['index'], d)
memcpy(interpreter->typed_tensor<float>(in_index), &input_vals[0], INPUT_SIZE*sizeof(input_vals[0]));
运行推理,对应python代码interpreter.invoke()
interpreter->Invoke()
获取张量值,对应python代码interpreter.get_tensor(output_details[0]['index'])
float* output = interpreter->typed_tensor<float>(out_index); memcpy(&output_vals[0], output, OUTPUT_SIZE*sizeof(output_vals[0]));
模型封装类主要包括两个方法:初始化和推理。
初始化只用于处理与invoke
无关的所有操作,以减少推理时的操作,保证模型推理高效运行。初始化主要进行的操作包括:模型文件加载、获取输入输出张量。
推理主要进行的操作有:输入张量填充、interpreter.invoke
、和输出张量获取。
经过模型封装类封装以后,示例代码就很简单了。只用准备数据,然后推理就行了。
tflite的编译需要使用tensorflow源代码,下面给出简单的编译步骤。后续在我的博客中会放出各平台下已编译好的tflite库文件,请持续关注
拷贝代码文件夹C++
到tensorflow/lite/tools/make/
在tensorflow/lite/tools/make/Makefile
文件中增加如下代码
HELLOW_TFLIET := hellow_tf
HELLOW_TFLIET_BINARY := $(BINDIR)$(HELLOW_TFLIET)
HELLOW_TFLIET_SRCS := \
tensorflow/lite/tools/make/C++/model.cc \
tensorflow/lite/tools/make/C++/example.cc
INCLUDES += \
-Itensorflow/lite/tools/make/C++/
ALL_SRCS += \
$(HELLOW_TFLIET_SRCS)
CORE_CC_EXCLUDE_SRCS += \
$(wildcard tensorflow/lite/tools/make/C++/model.cc) \
$(wildcard tensorflow/lite/tools/make/C++/example.cc)
HELLOW_TFLIET_OBJS := $(addprefix $(OBJDIR), \
$(patsubst %.cc,%.o,$(patsubst %.c,%.o,$(HELLOW_TFLIET_SRCS))))
$(HELLOW_TFLIET): $(LIB_PATH) $(HELLOW_TFLIET_OBJS)
@mkdir -p $(BINDIR)
$(CXX) $(CXXFLAGS) $(INCLUDES) \
-o $(HELLOW_TFLIET_BINARY) $(HELLOW_TFLIET_OBJS) \
$(LIBFLAGS) $(LIB_PATH) $(LDFLAGS) $(LIBS)
执行编译命令make hellow_tf -j8 -f tensorflow/lite/tools/make/Makefile
tflite官方代码提供了直接在android代码上使用tflite库的方法,本文针对android中使用库为例进行说明。
要在android代码中使用tflite库,只需在工程配置中加入implementation 'org.tensorflow:tensorflow-lite:0.0.0-nightly'
即可,另外需要注意的是android打包时会对assets下不认识的文件压缩,这会导致模型文件读取失败,解决方法是在配置文件添加
android {
...
aaptOptions {
noCompress "tflite"
}
...
}
模型封装类主要包括两个方法:初始化、关闭和推理。
初始化只用于处理与invoke
无关的所有操作,以减少推理时的操作,保证模型推理高效运行。初始化主要进行的操作包括:模型文件加载。
推理主要进行的操作有:interpreter.invoke
经过模型封装类封装以后,示例代码就很简单了。只用准备数据,然后推理就行了。
tflite的python模型部署代码
因最近在做一个嵌入式移植的实际项目,前面我放出的源码需要修改多处Makefile,容易出错,加上评论区有人咨询代码编译相关问题,故对嵌入式部署博文及代码进行更新。主要目的是简化编译操作,不需要下载整个tensorflow代码,只需引用相关头文件就可完成编译。
要达到以上目的,需要去除编译自已写的代码时对tflite相关源码的依赖,一种方式是将tensorflow代码先编译为库,这样大家在编译自己的特殊应用时只需链接编译好的库即可。因为官方的编译脚本也在不断更新中,我这里主要把修改点进行说明。同样的,我会把相关代码放到github里。
主要通过修改官方编译示例的编译脚本来实现。
复制一份编译脚本
cp Makefile Makefile_tflib
cp build_rpi_lib.sh build_tflib.sh
在Makefile_tflib
文件修改如下行
$(LIB_PATH): tensorflow/lite/schema/schema_generated.h $(LIB_OBJS)
@mkdir -p $(dir $@)
$(AR) $(ARFLAGS) $(LIB_PATH) $(LIB_OBJS)
++++$(CC) -shared -o $(LIBDIR)libtensorflow-lite.so $(LIB_OBJS)
在build_tflib.sh
文件中将Makefile
替换为Makefile_tflib
加载交叉编译环境,然后执行./build_tflib.sh
进行编译
编译完成后,会在./gen/rpi_armv7l/lib
下生成libtensorflow-lite.a
和libtensorflow-lite.so
文件。只要嵌入式环境的编译器没变,我们就可以一直用生成的这两个文件
打包库文件。
mkdir -p mpapp/tflib/lib
cp ./gen/rpi_armv7l/lib/libtensorflow* mpapp/tflib/lib
执行build.sh
即可