(编辑中)C++调用python训练的神经网络模型(tensorflow训练,opencv调用)

使用tensorflow训练模型,C++通过opencv的dnn模块调用模型,并进行推理.
(如果对延时要求不是特别高的话,推荐直接用ros)

一. tensorflow训练模型,生成pb文件

这里训练了一个很简单的bp网络作为示例,输入是一维的6个数据

1. 读取数据/数据预处理

1.1读取数据

根据自己的数据存储方式编写,这里的数据是存在txt中的

#这段代码从txt中读取数据,一行为一个样本,相邻数据间由逗号隔开
def Load_Voice_Data(path):
    """
    这是导入数据的函数
    :param path: 数据文件的路径
    :return: 数据集
    """
    data = []
    label = []
    with open(path) as f:
        for line in f.readlines():
            str = line.strip().split(",")
            tmp = []
            for i in range(1,len(str)-1):
                tmp.append(float(str[i]))
            data.append(tmp)
            if 1 == int(str[0]):  #第一个参数为类别
                label.append([1.,0.])
            else:
                label.append([0.,1.])
    #data = np.array(data,dtype=np.float64)
    #label = np.array(label,dtype=np.float364)
    return data,label

path = './lamps.txt'
Data,Label = Load_Voice_Data(path)  #读取数据集

1.2 正则化

训练前先将数据正则化,并分成训练集与验证集

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import Normalizer
#正则化
Data = Normalizer().fit_transform(Data)	
#生成训练集与验证集
Train_Data,Test_Data,Train_Label,Test_Label = train_test_split(Data,Label,test_size=1/10,random_state=10)

可指定验证集的比例与选取batch的随机数种子

1.3 生成batch(删了,有空补全)

介绍一种方法:用多线程去实现batch

image_batch, label_batch = 
tf.train.shuffle_batch([Test_Data,Test_Label],batch_size=4,num_threads=16,capacity=160,min_after_dequeue=50)

本文数据量很小,最后其实没有分batch,直接将整个数据集一起喂入训练了.

2. 训练

2.1 构建网络

with tf.variable_scope('conv1'):
        X = tf.placeholder(tf.float32, shape = [None, input_size],name="x")
        Y = tf.placeholder(tf.float32, shape = [None, num_classes])
        W1 = tf.Variable(tf.random_normal ([input_size, hidden_size1], stddev = 0.1))  #初始化,给一个正态分布随机值
        B1 = tf.Variable(tf.random_normal ([ hidden_size1], stddev = 0.1))
        W2 = tf.Variable(tf.random_normal ([hidden_size1, hidden_size2], stddev = 0.1))
        B2 = tf.Variable(tf.random_normal ([ hidden_size2], stddev = 0.1))
        W3 = tf.Variable(tf.random_normal ([hidden_size2, num_classes], stddev = 0.1))
        B3 = tf.Variable(tf.random_normal ([ num_classes], stddev = 0.1))
        W4 = tf.Variable(tf.random_normal ([num_classes, num_classes], stddev = 0.1))
        hidden_opt = tf.matmul(X, W1)+B1   # 输入层到隐藏层正向传播
        hidden_opt = tf.nn.relu(hidden_opt)  # 激活函数,用于计算节点输出值
        hidden_opt2 = tf.matmul(hidden_opt, W2)+B2  # 输入层到隐藏层正向传播
        hidden_opt2 = tf.nn.relu(hidden_opt2)  # 激活函数,用于计算节点输出值
        temp=tf.matmul(hidden_opt2, W3)+B3
        final_opt=tf.matmul(temp, W4)
        softmax_Y=tf.nn.softmax(final_opt,name="y")

这一步有个大坑记录一下,python训练一切正常但opencv调用会报错

报错信息:

xxxxxxxxxx

原因仍旧是版本兼容问题,由于python训练并没有报错,也谷歌不到类似问题,解决的过程真是一把辛酸泪啊…
解决方法:需要使用随机数去初始化偏置项bias,不要用tf.constant去定义,也不能用zero、one等方式

B1 = tf.Variable(tf.random_normal ([ hidden_size1], stddev = 0.1))

2.2 设置训练器

#设置训练器
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=Y, logits=final_opt))  # 对输出层计算交叉熵损失
opt = tf.compat.v1.train.GradientDescentOptimizer(0.001).minimize(loss)  # 梯度下降算法,这里使用了反向传播算法用于修改权重,减小损失
init = tf.compat.v1.global_variables_initializer()  # 初始化变量
correct_prediction =tf.equal (tf.argmax (Y, 1)tf.argmax(softmax_Y, 1))	# 计算准确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction,'float'))   

2.3开始训练

 with tf.Session() as sess:
        tf.initialize_all_variables().run()
        for i in range (training_iterations) :	#设置epoch数
            #训练
            training_loss = sess.run ([opt, loss], feed_dict = {X: Train_Data, Y: Train_Label})
            if i % 1000 == 0 :	#每1000轮计算一次准确率与loss值
                train_accuracy = accuracy.eval (session = sess, feed_dict = {X: Test_Data,Y: Test_Label})
                step_loss = sess.run([loss],feed_dict={X:Test_Data,Y:Test_Label})
                train_accuracy2 = accuracy.eval (session = sess, feed_dict = {X: Train_Data,Y: Train_Label})
                print ("step: %d --- accuracy= %g, loss=  %g" % (i, train_accuracy2,step_loss[0]))

3. 保存模型

3.1 保存pb模型(供opencv调用)

保存时注意指定下输出的Tensor.name(输入也可以指定)

def save_pb(sess):
    constant_graph = graph_util.convert_variables_to_constants(sess, sess.graph_def, ['conv1/y'])    #需要注意下 'conv/y',事先定义好输出Tensor的name后在这里填好就行
    with tf.gfile.FastGFile("./graph.pb", mode='wb') as f:
        f.write(constant_graph.SerializeToString())   
"""
	训练过程...
"""
# 训练结束后  
save_pb(sess)

3.2 保存ckpt

基本操作

import tensorflow as tf
"""
	训练过程...
"""
saver = tf.train.Saver()
sess = tf.Session()
sess.run(tf.global_variables_initializer())
saver.save(sess, './checkpoint_dir/MyModel')

至此,完成了tensorflow模型的训练与保存,接下来就可以用opencv去调用了.

二. opencv-dnn模块调用模型

1. 加载pb模型

std::string pbfile = ros::package::getPath("opcv_tf")+"/src/graph.pb"; //改为自己pb文件的路径
cv::dnn::Net net = cv::dnn::readNetFromTensorflow(pbfile);		//加载模型

一般来说,除了pb文件还需要一个pbtxt文件(由opencv-samples转化pb文件生成,具体可以百度.若网络结构很简单,则只需pb文件即可)

2. 喂数据进网络

使用Net对象的setInput函数即可将数据喂入网络. 但注意,需要先转化下数据的格式

Mat blob = (Mat_ <float>(6, 1) << 21.8658, 205.5499, 205.5449, 0.0463, 7.6381, 0.7756);
blob = cv::dnn::blobFromImage(blob, 1.0, Size(6,1), Scalar(), false, false);  //转化格式
net.setInput(blob,"conv1/x"); //将数据喂给网络(可指定Tensor名)

按实际情况修改scalesize

注意: 大多数网络使用blobFromImage函数处理下Mat即可,但有些特殊的网络结构需要额外进行一些处理.

3. 模型推理,数据解析

调用Net对象的forward函数即可进行前向推理并得到预测结果

cv::Mat pred = net.forward("conv1/y");		//如果网络输出层是softmax的话,pred即为各类别的概率

三. 完整代码

tensorflow训练

# -*- coding: utf-8 -*-

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import Normalizer
import tensorflow as tf
from tensorflow.python.framework import graph_util
# # from BPNN import BPNN

def Load_Voice_Data(path):
    """
    这是导入数据的函数
    :param path: 数据文件的路径
    :return: 数据集
    """
    data = []
    label = []
    with open(path) as f:
        for line in f.readlines():
            str = line.strip().split(",")
            tmp = []
            for i in range(1,len(str)-1):
                tmp.append(float(str[i]))
            data.append(tmp)
            if 1 == int(float(str[0])):  #第一个参数为类别
                label.append([0.,1.])
            else:
                label.append([1.,0.])
    return data,label


 
def save_pb(sess):
    constant_graph = graph_util.convert_variables_to_constants(sess, sess.graph_def, ['conv1/y'])
    with tf.gfile.FastGFile("./graph.pb", mode='wb') as f:
        f.write(constant_graph.SerializeToString())
 
 
def main():
    num_classes = 2  # 输出大小
    input_size = 5  # 输入大小
    hidden_size1 = 6  # 隐藏层节点数量
    training_iterations=100000
    path = './lamps.txt'
    Data,Label = Load_Voice_Data(path)  #读取数据集
    
    # 分割数据集,并对数据集进行标准化
    Train_Data,Test_Data,Train_Label,Test_Label = train_test_split(Data,Label,test_size=1/10,random_state=10)
    # Train_Data = Normalizer().fit_transform(Train_Data)
    # Test_Data = Normalizer().fit_transform(Test_Data)
    with tf.variable_scope('conv1'):
 
        X = tf.placeholder(tf.float32, shape = [None, input_size],name="x")
        Y = tf.placeholder(tf.float32, shape = [None, num_classes])
        W1 = tf.Variable(tf.random_normal ([input_size, hidden_size1], stddev = 0.1))  #初始化,给一个正态分布随机值
        B1 = tf.Variable(tf.random_normal ([ hidden_size1], stddev = 0.1))
        W2 = tf.Variable(tf.random_normal ([hidden_size1, num_classes], stddev = 0.1))
        B2 = tf.Variable(tf.random_normal ([ num_classes], stddev = 0.1))
        hidden_opt = tf.matmul(X, W1)+B1   # 输入层到隐藏层正向传播
        hidden_opt = tf.nn.relu(hidden_opt)  # 激活函数,用于计算节点输出值
        final_opt=tf.matmul(hidden_opt, W2)+B2
        #final_opt=tf.matmul(temp, W4)
        softmax_Y=tf.nn.softmax(final_opt,name="y")
    loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=Y, logits=final_opt))  # 对输出层计算交叉熵损失
    opt = tf.compat.v1.train.GradientDescentOptimizer(0.001).minimize(loss)  # 梯度下降算法,这里使用了反向传播算法用于修改权重,减小损失
    init = tf.compat.v1.global_variables_initializer()  # 初始化变量
    # 计算准确率
    correct_prediction =tf.equal (tf.argmax (Y, 1), tf.argmax(softmax_Y, 1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, 'float'))

    saver = tf.train.Saver()
    with tf.Session() as sess:
        tf.initialize_all_variables().run()
        for i in range (training_iterations) :
            #训练
            training_loss = sess.run ([opt, loss], feed_dict = {X: Train_Data, Y: Train_Label})
            if i % 1000 == 0 :
                train_accuracy = accuracy.eval (session = sess, feed_dict = {X: Test_Data,Y: Test_Label})
                step_loss = sess.run([loss],feed_dict={X:Test_Data,Y:Test_Label})
                train_accuracy2 = accuracy.eval (session = sess, feed_dict = {X: Train_Data,Y: Train_Label})
                #pro=tf.nn.softmax(step_loss = sess.run([final_opt],feed_dict={X:Test_Data,Y:Test_Label}))
                print ("step: %d --- accuracy= %g, loss=  %g, pro:%g" % (i, train_accuracy,sum(step_loss),step_loss[0]))
            #训练
            #training_loss = sess.run ([opt, loss], feed_dict batch= {X: [[9,7]], Y: [[0,1]]})
            #print(sess.run(final_opt, feed_dict={X:[[7.4, 9.1]]}))
        save_pb(sess)
        saver.save(sess,"./model")
main()

C++调用

#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>
#include <iostream>
#include <vector>
#include <string>
#include "ros/ros.h"
#include "ros/package.h"
using namespace cv;
using namespace std;
//多分类问题用这个函数判断类别,二分类的话不用也行
std::vector<int> Argmax(cv::Mat x)
{
    std::vector<int> res;
    for (int i = 0; i < x.rows; i++)
    {
        int maxIdx = 0;
        float maxNum = 0.0;
        for (int j = 0; j < x.cols; j++)
        {
            float tmp = x.at<float>(i, j);
            if (tmp > maxNum)
            {
                maxIdx = j;		//更新最优值序号
                maxNum = tmp;	//更新最优值
            }
        }
        res.push_back(maxIdx);	//最优预测值的序号
    }
    return res;
}

int main(){
    std::string config_path = ros::package::getPath("armor_detect_uestc");
    std::string pbfile = config_path+"/src/graph.pb";


    cv::dnn::Net net = cv::dnn::readNetFromTensorflow(pbfile);
    //用Mat存储数据
    Mat blob = (Mat_ <float>(6, 1) << 21.8658, 205.5499, 205.5449, 0.0463, 7.6381, 0.7756);
    blob = cv::dnn::blobFromImage(blob, 1.0, Size(6,1), Scalar(), false, false);  //转化格式
    //将数据喂给网络(可指定Tensor名)
    net.setInput(blob,"conv1/x");
    //前向传播,得到推理结果
    cv::Mat pred = net.forward("conv1/y");		//如果网络输出层是softmax的话,pred即为各类别的概率
    //分类结果
    vector<int> res = Argmax(pred);		
}


  • 6
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: 要使用OpenCV调用神经网络,你可以按照以下步骤进行操作。首先,你需要下载并提取预训练模型文件,比如ssd_mobilenet_v1_coco_2017_11_17。\[3\]然后,你可以使用OpenCV的dnn模块来加载模型和权重文件。你可以参考OpenCV的官方文档和示例代码来了解如何使用dnn模块。\[1\]在代码,你可以使用cv.VideoCapture(0)来打开摄像头,并使用cap.get(cv.CAP_PROP_FRAME_HEIGHT)和cap.get(cv.CAP_PROP_FRAME_WIDTH)来获取摄像头的高度和宽度。\[2\]接下来,你可以使用加载的模型进行图像识别或目标检测等任务。具体的实现细节可以根据你的需求和模型的要求进行调整。希望这些信息对你有帮助! #### 引用[.reference_title] - *1* *3* [使用opencv qt 以及 tensorflow2 进行神经网络分类](https://blog.csdn.net/qianbo042311/article/details/126253546)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [OpenCV深度神经网络实现人体姿态评估](https://blog.csdn.net/qq_42722197/article/details/121347346)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值