OpenCV使用Tensorflow2-Keras模型
前言
最近工作上需要在C++上快速集成Tensorflow/Keras訓練好的模型,做算法驗證。首先想到的就是opencv里面的dnn模塊了,但是它需要的格式文件比較郁悶,是pb格式的模型,但是keras通常保存的是h5文件,查閱了很多資料,最后找到了很方便的方法。
國際慣例,參考博客
Frozen_Graph_TensorFlow
這個地址的大佬用fashion mnist寫的訓練和測試,我這里用更簡單的線性回歸為例。
訓練
老樣子,引入相關的包,創建數據集
import numpy as np import tensorflow as tf# build data input_x = np.random.rand(1000, 4) output_y = np.dot(input_x,np.array([[3],[14],[6],[10]]))然后創建簡單的模型
# build model inputs = tf.keras.layers.Input(shape=(4,)); outputs = tf.keras.layers.Dense(units=1)(inputs) model = tf.keras.Model(inputs=inputs,outputs=outputs)編譯、訓練
model.compile(optimizer=tf.keras.optimizers.SGD(learning_rate=0.01),loss='mse') model.fit(x=input_x,y=output_y,epochs=100,validation_split=0.1)看看訓練完畢的權重是否接近我們創建的權重
model.get_weights() ''' [array([[ 2.669988],[13.562156],[ 5.622848],[ 9.587276]], dtype=float32),array([0.80391794], dtype=float32)] '''保存
保存的時候就需要注意了,要保存成pb格式的,不要直接model.save成h5格式的,如果你已經保存完了,可以model.load_model載入進來,然后再執行如下函數
# Convert Keras model to ConcreteFunction full_model = tf.function(lambda x: model(x)) full_model = full_model.get_concrete_function(tf.TensorSpec(model.inputs[0].shape, model.inputs[0].dtype))# Get frozen ConcreteFunction frozen_func = convert_variables_to_constants_v2(full_model) frozen_func.graph.as_graph_def()layers = [op.name for op in frozen_func.graph.get_operations()] print("-" * 50) print("Frozen model layers: ") for layer in layers:print(layer)print("-" * 50) print("Frozen model inputs: ") print(frozen_func.inputs) print("Frozen model outputs: ") print(frozen_func.outputs)# Save frozen graph from frozen ConcreteFunction to hard drive tf.io.write_graph(graph_or_graph_def=frozen_func.graph,logdir="./frozen_models",name="frozen_graph.pb",as_text=False) ''' -------------------------------------------------- Frozen model layers: x model/dense/MatMul/ReadVariableOp/resource model/dense/MatMul/ReadVariableOp model/dense/MatMul model/dense/BiasAdd/ReadVariableOp/resource model/dense/BiasAdd/ReadVariableOp model/dense/BiasAdd Identity -------------------------------------------------- Frozen model inputs: [<tf.Tensor 'x:0' shape=(None, 4) dtype=float32>] Frozen model outputs: [<tf.Tensor 'Identity:0' shape=(None, 1) dtype=float32>] '''這樣就會在./frozen_models/frozen_graph.pb目錄下看到模型了。
使用TensorFlow調用
在參考博客中,作者也提供了對應的調用方法
def wrap_frozen_graph(graph_def, inputs, outputs, print_graph=False):def _imports_graph_def():tf.compat.v1.import_graph_def(graph_def, name="")wrapped_import = tf.compat.v1.wrap_function(_imports_graph_def, [])import_graph = wrapped_import.graphprint("-" * 50)print("Frozen model layers: ")layers = [op.name for op in import_graph.get_operations()]if print_graph == True:for layer in layers:print(layer)print("-" * 50)return wrapped_import.prune(tf.nest.map_structure(import_graph.as_graph_element, inputs),tf.nest.map_structure(import_graph.as_graph_element, outputs))通過tensorflow1.x載入模型
with tf.io.gfile.GFile("./frozen_models/frozen_graph.pb", "rb") as f:graph_def = tf.compat.v1.GraphDef()loaded = graph_def.ParseFromString(f.read())隨后生成預測函數
frozen_func = wrap_frozen_graph(graph_def=graph_def,inputs=["x:0"],outputs=["Identity:0"],print_graph=True)調用這個預測函數試驗一下:
test_x = np.array([[1,1,1,1]],np.float32) pred_y = frozen_func(x=tf.constant(test_x))[0] print(pred_y)#tf.Tensor([[32.246185]], shape=(1, 1), dtype=float32) true_y = np.dot(test_x,np.array([[3],[14],[6],[10]])) print(true_y) #[[33.]]使用OpenCV-python調用模型
這個非常簡單了,四句話完成創建測試數據、讀取模型、載入數據、預測
test_x = np.array([[1,1,1,1]],np.float32) net = cv2.dnn.readNetFromTensorflow("./frozen_models/frozen_graph.pb") net.setInput(test_x) pred = net.forward() print(pred)#[[32.246185]]與上面用tensorflow調用的結果一模一樣。
使用opencv-C++調用模型
核心就在于opencv的readNetFromTensorflow接受的輸入固定是InputArray類型的,這個類型等價于Mat、vector等,具體可以上網查。這里我們需要創建一個大小為(1,4)的Mat數據;
下面這個函數就是使用數組去初始化Mat數據
void InitMat(Mat& m,float* num) {for(int i=0;i<m.rows;i++)for(int j=0;j<m.cols;j++)m.at<float>(i,j)=*(num+i*m.rows+j); }創建一個Mat數據
float sz[] = {1,1,1,1}; Mat input(1,4,CV_32F); InitMat(input, sz);接下來就是讀取模型、載入數據、預測
dnn::Net net = dnn::readNetFromTensorflow("./frozen_models/frozen_graph.pb"); net.setInput(input); Mat pred = net.forward(); cout<<pred<<endl; //[32.246185]后記
上面基本貼出了所有的代碼,如果運行不了,可以進入公眾號,在公眾號簡介的github中找到源碼。
總結
以上是生活随笔為你收集整理的OpenCV使用Tensorflow2-Keras模型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PHP二维数组去重(指定键名)
- 下一篇: Linux卸载并更新显卡驱动