Keras:Keras训练模型的C++调用尝试

最近遇到一个项目中需要使用Keras进行训练然后还要用C++去调用模型.但是Keras没有C++接口,因此目前是将Keras模型转换为TensorFlow模型然后再使用TensorFlow的C++接口进行调用.

为了快速验证效果,这里只使用原来图片中的2个分类同时每个分类中只使用少部分图片进行训练.
数据集存放目录为:

------------------\tmp
----------\train
------\0
------\1
----------\validation
------\0
------\1
----------\test
------\0
------\1
Keras模型

Keras训练部分(分别将训练模型的网络结构和网络权重存放在json文件和h5文件中)

Keras模型训练部分
#!/usr/bin/python
# coding:utf8
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense

model = Sequential()
model.add(Conv2D(32, (3, 3), padding='same',input_shape=(64, 64, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D((2, 2)))

model.add(Conv2D(64, (3, 3), padding='same'))
model.add(Activation('relu'))
model.add(MaxPooling2D((2, 2)))

model.add(Conv2D(64, (3, 3), padding='same'))
model.add(Activation('relu'))
model.add(MaxPooling2D((2, 2)))

model.add(Flatten())  
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(1))
model.add(Activation('sigmoid'))

model.compile(loss='binary_crossentropy',
              optimizer='rmsprop',
              metrics=['accuracy'])

train_datagen = ImageDataGenerator(rescale=1. / 255,
                                    shear_range=0.2,
                                    zoom_range=0.2,
                                    horizontal_flip=True)

test_datagen = ImageDataGenerator(rescale=1. / 255)


train_generator = train_datagen.flow_from_directory(
    'tmp/train',  # this is the target directory
    target_size=(64, 64),  
    batch_size=32,
    class_mode='binary')  

# this is a similar generator, for validation data
validation_generator = test_datagen.flow_from_directory(
    'tmp/validation',
    target_size=(64, 64),
    batch_size=32,
    class_mode='binary')


model.fit_generator(
        train_generator,
        steps_per_epoch=50,
        epochs=10,
        validation_data=validation_generator,
        validation_steps=25)

model.save_weights('tmp/first_try.h5')
model.save('tmp/first_try.hdf5')

json_string = model.to_json()
open('tmp/first_try.json','w').write(json_string)
Keras模型验证

使用测试集中的数据验证模型,这里只使用了其中一个分类进行验证.

#!/usr/bin/python
# coding:utf8
# # 模型结构的恢复
from keras.models import model_from_yaml
from keras.preprocessing import image
from keras.preprocessing.image import load_img
import numpy as np
import os

yaml_string = open('tmp/first_try.json').read()
model = model_from_yaml(yaml_string)
# 打印模型
# model.summary()
# 加载权重
classifier = model.load_weights('tmp/first_try.h5')

# # 遍历图像
rootdir = 'tmp/test/1'
list = os.listdir(rootdir)
for i in range(0,len(list)):
    path = os.path.join(rootdir, list[i])
    if os.path.isfile(path):
        print (path)
        # 加载图像
        img = load_img(path, target_size=(64, 64))
        img = image.img_to_array(img) / 255.0
        img = np.expand_dims(img, axis=0)

        predictions = model.predict(img)
        if predictions[0][0] > 0.1:
            print (predictions)
        else:
            print ('Error!!!')

输出:

tmp/test/1/pandas_0_435.jpg
[[1.]]
tmp/test/1/pandas_0_453.jpg
[[1.]]
tmp/test/1/pandas_0_422.jpg
[[1.]]
tmp/test/1/pandas_0_483.jpg
[[1.]]
tmp/test/1/pandas_0_479.jpg
[[1.]]
tmp/test/1/pandas_0_464.jpg
[[1.]]
tmp/test/1/pandas_0_612.jpg
[[1.]]
tmp/test/1/pandas_0_571.jpg
[[1.]]
tmp/test/1/pandas_0_519.jpg
[[1.]]
......
Keras训练模型转换为tensorflow二进制模型

多方查找,在github上找到一个将Keras训练模型转换为tensorflow二进制模型的方法(github::eras_to_tensorflow),亲测可用,在这里记录一下吧:

#!/usr/bin/python
# coding:utf8
##-------keras模型保存为tensorflow的二进制模型-----------
import sys
from keras.models import load_model
import tensorflow as tf
import os
import os.path as osp
from keras import backend as K
from tensorflow.python.framework.graph_util import convert_variables_to_constants

def freeze_session(session, keep_var_names=None, output_names=None, clear_devices=True):
    # 将会话状态冻结为已删除的计算图,创建一个新的计算图,其中变量节点由在会话中获取其当前值的常量替换.
    # session要冻结的TensorFlow会话,keep_var_names不应冻结的变量名列表,或者无冻结图中的所有变量
    # output_names相关图输出的名称,clear_devices从图中删除设备以获得更好的可移植性
    graph = session.graph
    with graph.as_default():
        freeze_var_names = list(set(v.op.name for v in tf.global_variables()).difference(keep_var_names or []))
        output_names = output_names or []
        output_names += [v.op.name for v in tf.global_variables()]
        input_graph_def = graph.as_graph_def()
        # 从图中删除设备以获得更好的可移植性
        if clear_devices:
            for node in input_graph_def.node:
                node.device = ""
        # 用相同值的常量替换图中的所有变量
        frozen_graph = convert_variables_to_constants(session, input_graph_def, output_names, freeze_var_names)
        return frozen_graph

output_fld = sys.path[0] + '/tmp/'
if not os.path.isdir(output_fld):
    os.mkdir(output_fld)
weight_file_path = osp.join(sys.path[0], 'tmp/first_try.hdf5')
K.set_learning_phase(0)
net_model = load_model(weight_file_path)

print('input is :', net_model.input.name)
print ('output is:', net_model.output.name)

# 获得当前图
sess = K.get_session()
# 冻结图
frozen_graph = freeze_session(sess, output_names=[net_model.output.op.name])

from tensorflow.python.framework import graph_io
graph_io.write_graph(frozen_graph, output_fld, 'new_tensor_model.pb', as_text=False)
print('saved the constant graph (ready for inference) at: ', osp.join(output_fld, 'new_tensor_model.pb'))
print (K.get_uid())

输出pb文件,打印出:

('input is :', u'conv2d_1_input:0')
('output is:', u'activation_5/Sigmoid:0')
Converted 24 variables to const ops.
('saved the constant graph (ready for inference) at: ', '/home/w/mycode/pythoncode/tmp/new_tensor_model.pb')
用测试集验证
#!/usr/bin/python
# coding:utf8
import tensorflow as tf
import numpy as np
import os
import cv2

def predict(jpg_path, pb_file_path):
    with tf.Graph().as_default():
        output_graph_def = tf.GraphDef()

        with open(pb_file_path, "rb") as f:
            output_graph_def.ParseFromString(f.read())
            tensors = tf.import_graph_def(output_graph_def, name="")
            # print (tensors)
        with tf.Session() as sess:
            init = tf.global_variables_initializer()
            sess.run(init)
            sess.graph.get_operations()
            input_x = sess.graph.get_tensor_by_name("conv2d_1_input:0")  # 具体名称看上一段代码的input.name
            out_softmax = sess.graph.get_tensor_by_name("activation_5/Sigmoid:0")  # 具体名称看上一段代码的output.name
            img = cv2.imread(jpg_path, 1)
            img_out_softmax = sess.run(out_softmax,feed_dict={input_x: np.array(img).reshape((-1, 64, 64, 3)) / 255.0})

            # print (img_out_softmax)
            return img_out_softmax


pb_path = 'tmp/new_tensor_model.pb'
rootdir = 'tmp/test/0'

if __name__ == '__main__':
    list = os.listdir(rootdir)
    for i in range(0,len(list)):
        path = os.path.join(rootdir, list[i])
        if os.path.isfile(path):
            print (path)
            index = predict(path, pb_path)
            print (index)

输出:

tmp/test/0/pandas_0_702.jpg
[[1.6394738e-11]]
tmp/test/0/pandas_0_737.jpg
[[5.2570143e-11]]
tmp/test/0/pandas_0_663.jpg
[[7.964132e-14]]
tmp/test/0/pandas_0_661.jpg
[[1.4841452e-10]]
tmp/test/0/pandas_0_693.jpg
[[5.834242e-15]]
tmp/test/0/pandas_0_723.jpg
[[3.9710753e-13]]
tmp/test/0/pandas_0_711.jpg
[[1.6867729e-12]]
......

然后就是TensorFlow的C++接口编译问题,还在进行中……

另外,看到github上有朋友直接将Keras模型直接转化为C++可点调用的文本文件github::keras2cpp.在QT中尝试了一下,发现样例可以用:
这里写图片描述
但是从keras.model.cc文件中的代码片段中可以看出,目前应该只是针对Keras1.x版本.

   Layer *l = 0L;
    if(layer_type == "Convolution2D") {
      l = new LayerConv2D();
    } else if(layer_type == "Activation") {
      l = new LayerActivation();
    } else if(layer_type == "MaxPooling2D") {
      l = new LayerMaxPooling();
    } else if(layer_type == "Flatten") {
      l = new LayerFlatten();
    } else if(layer_type == "Dense") {
      l = new LayerDense();
    } else if(layer_type == "Dropout") {
      continue; // we dont need dropout layer in prediciton mode
    }
    if(l == 0L) {
      cout << "Layer is empty, maybe it is not defined? Cannot define network." << endl;
      return;
    }
    l->load_weights(fin);
    m_layers.push_back(l);
  }

  fin.close();
}

而且后端是Theano.因此没有使用该方法.

还得继续编译一下TensorFlow……


参考:

github::eras_to_tensorflow

github::keras2cpp

评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值