Tensorflow在手机端的部署——yolo模型转tensorflow模型(3)

如需转载请向本人确认~谢谢!

本系列文章中前几篇介绍了

tensorflow提供的android demo工程的结构;https://blog.csdn.net/c20081052/article/details/83145836

其目标检测的运行(工程默认的ssd-mobilenet v1),https://blog.csdn.net/c20081052/article/details/82865830

以及将yolo v2模型运行;https://blog.csdn.net/c20081052/article/details/83659476

所有的相似点就是该工程目前似乎只支持用户提供pb文件。(其实后来发现weights貌似可以直接读,后面会写文章阐述)

其中网上提供了yolo转为pb格式的权重文件可在链接中下载:https://drive.google.com/drive/folders/1GfS1Yle7Xari1tRUEi2EDYedFteAOaoN

那么问题来了,如何将其他模型转为tensorflow android工程调用所需的pb文件呢?

(比如将yolo训练的.weights转为.pb;将keras训练的.h5转为.pb文件)


案例一: darknet的yolo训练得到的.weights转为tensorflow的.pb

 

方式一:使用darkflow

网上有较为成熟的第三方工具:darkflow (链接:darkflow)该链接提供了详细的安装方式,你需要编译生成一个可执行文件“flow”,最后你在转换时需要使用如下指令即可:

## Saving graph and weights to protobuf file
flow --model cfg/yolo.cfg --load bin/yolo.weights --savepb

When saving the .pb file, a .meta file will also be generated alongside it. This .meta file is a JSON dump of everything in the meta dictionary that contains information nessecary for post-processing such as anchors and labels. This way, everything you need to make predictions from the graph and do post processing is contained in those two files - no need to have the .cfg or any labels file tagging along.

The created .pb file can be used to migrate the graph to mobile devices (JAVA / C++ / Objective-C++). The name of input tensor and output tensor are respectively 'input' and 'output'. For further usage of this protobuf file, please refer to the official documentation of Tensorflow on C++ API here. To run it on, say, iOS application, simply add the file to Bundle Resources and update the path to this file inside source code.

会在master文件夹的built_graph下生成两个模型文件:

*****但上诉第三方工具目前只支持yolo v1和 yolo v2以及他们的tiny版本;对于yolo v3本人尝试了,并没有成功(或是成功了,没啥印象了……)~

方法二:先将.weights转为.h5然后再转为.pb

由于目前有tensorflow-keras方式训练yolo v3的方法,而且有现成的脚本将yolo的weights转为h5文件;

keras训练yolo的的仓库链接为:A Keras implementation of YOLOv3 (Tensorflow backend)

具体有如下使用方法:

Quick Start

  1. Download YOLOv3 weights from YOLO website.
  2. Convert the Darknet YOLO model to a Keras model.
  3. Run YOLO detection.
wget https://pjreddie.com/media/files/yolov3.weights
python convert.py yolov3.cfg yolov3.weights model_data/yolo.h5
python yolo_video.py [OPTIONS...] --image, for image detection mode, OR
python yolo_video.py [video_path] [output_path (optional)]

使用其中的convert.py可将weights转为.h5文件,而且也可以用该仓库直接训练yolo v3生成h5文件;

有一点需要注意的是:用convert.py文件转h5时,需要传入yolo的weights和cfg文件,导出的h5文件格式有两种情况!!

convert.py文件中有如下内容:

上图划线处表示导出的h5文件是只保存了模型的权重信息,那么其结构信息是不在里面的。

如何保存 Keras 模型?

保存/加载整个模型(结构 + 权重 + 优化器状态)

不建议使用 pickle 或 cPickle 来保存 Keras 模型。

你可以使用 model.save(filepath) 将 Keras 模型保存到单个 HDF5 文件中,该文件将包含:

  • 模型的结构,允许重新创建模型
  • 模型的权重
  • 训练配置项(损失函数,优化器)
  • 优化器状态,允许准确地从你上次结束的地方继续训练。

你可以使用 keras.models.load_model(filepath) 重新实例化模型。load_model 还将负责使用保存的训练配置项来编译模型(除非模型从未编译过)。

例子:

from keras.models import load_model

model.save('my_model.h5')  # 创建 HDF5 文件 'my_model.h5'
del model  # 删除现有模型

# 返回一个编译好的模型
# 与之前那个相同
model = load_model('my_model.h5')

查阅了Keras的官方文档(Keras官方文档)发现,对于模型的保存有如下两种方式:

  • 只保存/加载 模型的结构

如果您只需要保存模型的结构,而非其权重或训练配置项,则可以执行以下操作:

# 保存为 JSON
json_string = model.to_json()

# 保存为 YAML
yaml_string = model.to_yaml()

生成的 JSON/YAML 文件是人类可读的,如果需要还可以手动编辑。

你可以从这些数据建立一个新的模型:

# 从 JSON 重建模型:
from keras.models import model_from_json
model = model_from_json(json_string)

# 从 YAML 重建模型:
from keras.models import model_from_yaml
model = model_from_yaml(yaml_string)
  • 只保存/加载 模型的权重

如果您只需要 模型的权重,可以使用下面的代码以 HDF5 格式进行保存。

请注意,我们首先需要安装 HDF5 和 Python 库 h5py,它们不包含在 Keras 中。

model.save_weights('my_model_weights.h5')

假设你有用于实例化模型的代码,则可以将保存的权重加载到具有相同结构的模型中:

model.load_weights('my_model_weights.h5')

如果你需要将权重加载到不同的结构(有一些共同层)的模型中,例如微调或迁移学习,则可以按层的名字来加载权重:

model.load_weights('my_model_weights.h5', by_name=True)

例如:

"""
假设原始模型如下所示:
    model = Sequential()
    model.add(Dense(2, input_dim=3, name='dense_1'))
    model.add(Dense(3, name='dense_2'))
    ...
    model.save_weights(fname)
"""

# 新模型
model = Sequential()
model.add(Dense(2, input_dim=3, name='dense_1'))  # 将被加载
model.add(Dense(10, name='new_dense'))  # 将不被加载

# 从第一个模型加载权重;只会影响第一层,dense_1
model.load_weights(fname, by_name=True)

 综上所述需要将convert.py中的model.save_weights更改成model.save生成的h5文件包含了结构信息~这点很重要,因为下一步将h5转为pb调用的文件中需要读取h5的结构信息,否则会报缺少cfg信息的错误!!


上述内容实现了将weights转为h5文件了,接下来就需要将h5转为pb了;

github上有这么个仓库可实现keras to tensorflow(keras to tensorflow)看了相关资料,发现有的人运行成功了有些还有问题;不过建议尝试!

How to use

Keras models can be saved as a single [.hdf5 or h5] file, which stores both the architecture and weights, using the model.save() function. 如果这种方式生成的h5文件用下面指令转换:

python keras_to_tensorflow.py 
    --input_model="path/to/keras/model.h5" 
    --output_model="path/to/save/model.pb"

Keras models can also be saved in two separate files where a [.hdf5 or h5] file stores the weights, using the model.save_weights() function, and another .json file stores the network architecture using the model.to_json() function. 如果用这种方式生成的h5文件和json文件用下面指令转换:

python keras_to_tensorflow.py 
    --input_model="path/to/keras/model.h5" 
    --input_model_json="path/to/keras/model.json" 
    --output_model="path/to/save/model.pb"

转换成功后就可以将pb文件导入到tensorflow的android  tensorflow的安卓demo工程(四个功能)工程下做目标检测啦~


在拿上面的仓库做h5转pb时可能遇到的错误有:

错误:如果你用keras训练了mobilenet v2得到的h5,且你的keras版本2.2.0以上,tensorflow1.9.0,可能会提示你无法找到relu6;

解析:由于mobilenet有许多自定义的层,包括relu6,为了转换方便,可在load_model之前添加如下内容:

#model = keras.models.load_model(input_model_path)
 from keras.utils.generic_utils import CustomObjectScope
 with CustomObjectScope({'relu6': keras.applications.mobilenet.relu6,'DepthwiseConv2D': keras.applications.mobilenet.DepthwiseConv2D}):
 model = load_model('yourmodelname.hdf5')
 return model

如果上面的操作仍解决不了问题,可能是你keras的版本的问题了;网上有如下几种可尝试方式(参考链接:keras训练的mobilenet的h5文件转pb的解决方法):

If your keras is at "from tensorflow.python import keras" instead of at "import keras" then here is what worked for me:
from tensorflow.python.keras._impl.keras.utils.generic_utils import CustomObjectScope
from tensorflow.python.keras._impl.keras.applications import mobilenet
from tensorflow.python.keras._impl.keras.models import load_model
with CustomObjectScope({'relu6': mobilenet.relu6,'DepthwiseConv2D': mobilenet.DepthwiseConv2D}):
    model = load_model('weights.hdf5')

或者

有反馈在keras-applications/keras_applications/mobilenet_v2.py找到relu6的;

或者

i downgraded to 2.1.4, it works fine. noticed pr on removing relu6 in 2.2, but the pretrained model still has it.

(将keras换成低版本的2.1.4怀疑2.2之后位置挪了)

或者

from keras_applications import mobilenet as mn 尝试了在keras_applications的mobilenet下找到了relu6;

或者

from keras.layers import DepthwiseConv2D

from keras_applications.mobilenet import relu6

Just for information, before they were imported as

from keras.applications.mobilenet import DepthwiseConv2D,  relu6

或者

In Keras2.2, modified to(在keras2.2下更改为)
from keras.utils.generic_utils import CustomObjectScope

with CustomObjectScope({'relu6': keras.layers.ReLU(6.),'DepthwiseConv2D': keras.layers.DepthwiseConv2D}):
model = load_model('weights.hdf5')

或者

convert MobileNet from Keras 2.1.3 to CoreML

或者


案例二: keras做yolo v3训练生成的h5转为tensorflow的.pb

此案例可参考案例一方法二中部分~

如果你尝试成功了,请留言告知哈~列出你的库的版本以便大家参考~

猜你喜欢

转载自blog.csdn.net/c20081052/article/details/83660714
今日推荐