faster_rcnn c++版本的 caffe 封装,动态库(2)

本文介绍了一个Faster R-CNN的C++封装项目,该项目将Faster R-CNN模型的功能封装为动态链接库libfaster_rcnn.so。通过这种方式,可以方便地在其他C++项目中复用该模型进行目标检测任务。

摘要: 转载请注明出处,楼燚(yì)航的blog,http://www.cnblogs.com/louyihang-loves-baiyan/

github上的代码链接,求给星星:) https://github.com/YihangLou/FasterRCNN-Encapsulation-Cplusplus

在上一篇文章中,我们是将对caffe的调用隔离了出来,可以说相当于原来caffe源码下的tools中cpp文件使用相同,然后自己写了个CMakeLists.txt进行编译。这里是进一步将代码进行分离,封装成libfaster_rcnn.so文件进行使用。对于部分接口,我可能做了一些改动。
目录结构
├── CMakeLists.txt
├── lib
│   ├── CMakeLists.txt
│   ├── faster_rcnn.cpp
│   ├── faster_rcnn.hpp
├── main.cpp
├── pbs_cxx_faster_rcnn_demo.job

在这里main.cpp就是直接调用faster_rcnn.cpp的接口,他的内容也很简单,只是在之前的基础上,再加上libfaster_rcnn.so这个动态库文件

#include "faster_rcnn.hpp"
int main()
{
    string model_file = "/home/lyh1/workspace/py-faster-rcnn/models/pascal_voc/VGG_CNN_M_1024/faster_rcnn_alt_opt/faster_rcnn_test.pt";
    string weights_file = "/home/lyh1/workspace/py-faster-rcnn/output/default/yuanzhang_car/vgg_cnn_m_1024_fast_rcnn_stage2_iter_40000.caffemodel";
    int GPUID=0;
    Caffe::SetDevice(GPUID);
    Caffe::set_mode(Caffe::GPU);
    Detector det = Detector(model_file, weights_file);
    det.Detect("/home/lyh1/workspace/py-faster-rcnn/data/demo/car.jpg");
    return 0;
}

可以看到这里只是include了faster_rcnn.hpp头文件,其对应的CMakeLists.txt文件如下:


#This part is used for compile faster_rcnn_demo.cpp
cmake_minimum_required (VERSION 2.8)

project (main_demo)

add_executable(main main.cpp)

include_directories ( "${PROJECT_SOURCE_DIR}/../caffe-fast-rcnn/include"
    "${PROJECT_SOURCE_DIR}/../lib/nms" 
    "${PROJECT_SOURCE_DIR}/lib" 
    /share/apps/local/include
    /usr/local/include 
    /opt/python/include/python2.7
    /share/apps/opt/intel/mkl/include 
    /usr/local/cuda/include )

target_link_libraries(main /home/lyh1/workspace/py-faster-rcnn/faster_cxx_lib/lib/libfaster_rcnn.so
    /home/lyh1/workspace/py-faster-rcnn/caffe-fast-rcnn/build/lib/libcaffe.so
    /home/lyh1/workspace/py-faster-rcnn/lib/nms/gpu_nms.so 
    /share/apps/local/lib/libopencv_highgui.so 
    /share/apps/local/lib/libopencv_core.so 
    /share/apps/local/lib/libopencv_imgproc.so 
    /share/apps/local/lib/libopencv_imgcodecs.so
    /share/apps/local/lib/libglog.so
    /share/apps/local/lib/libboost_system.so
    /share/apps/local/lib/libboost_python.so
    /share/apps/local/lib/libglog.so
    /opt/rh/python27/root/usr/lib64/libpython2.7.so
    )

对于faster_rcnn.hppfaster_rcnn.cpp ,我们需要将他们编译成动态库,下面是他们对应的CMakeLists.txt,在文件中,可以看到跟上面这个区别是用了add_library语句,并且加入了SHARED关键字,SHARED代表动态库。其次,在编译动态库的过程中,是不需要链接的,但是我们知道这个库是依赖别的很多个库的,所以在最后形成可执行文件也就是上面这个CMakeLists.txt,我们需要添加这个动态库所依赖的那些动态库,至此就OK了。编译的话,非常傻瓜cmake .然后在执行make即可。

cmake_minimum_required (VERSION 2.8)

SET (SRC_LIST faster_rcnn.cpp)
include_directories ( "${PROJECT_SOURCE_DIR}/../../caffe-fast-rcnn/include"
    "${PROJECT_SOURCE_DIR}/../../lib/nms" 
    /share/apps/local/include
    /usr/local/include 
    /opt/python/include/python2.7
    /share/apps/opt/intel/mkl/include 
    /usr/local/cuda/include )

add_library(faster_rcnn SHARED ${SRC_LIST})

首先将原来的cpp文件中的声明提取出来,比较简单,就是hpp文件对应cpp文件。如下:

#ifndef FASTER_RCNN_HPP
#define FASTER_RCNN_HPP
#include <stdio.h>  // for snprintf
#include <string>
#include <vector>
#include <math.h>
#include <fstream>
#include <boost/python.hpp>
#include "caffe/caffe.hpp"
#include "gpu_nms.hpp"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace caffe;
using namespace std;

#define max(a, b) (((a)>(b)) ? (a) :(b))
#define min(a, b) (((a)<(b)) ? (a) :(b))

//background and car
const int class_num=2;

/*
 * ===  Class  ======================================================================
 *         Name:  Detector
 *  Description:  FasterRCNN CXX Detector
 * =====================================================================================
 */
class Detector {
public:
    Detector(const string& model_file, const string& weights_file);
    void Detect(const string& im_name);
    void bbox_transform_inv(const int num, const float* box_deltas, const float* pred_cls, float* boxes, float* pred, int img_height, int img_width);
    void vis_detections(cv::Mat image, int* keep, int num_out, float* sorted_pred_cls, float CONF_THRESH);
    void boxes_sort(int num, const float* pred, float* sorted_pred);

private:
    shared_ptr<Net<float> > net_;
    Detector(){}
};

//Using for box sort
struct Info
{
    float score;
    const float* head;
};
bool compare(const Info& Info1, const Info& Info2)
{
    return Info1.score > Info2.score;
}
#endif

相应的cpp文件

#include <stdio.h>  // for snprintf
#include <string>
#include <vector>
#include <math.h>
#include <fstream>
#include <boost/python.hpp>
#include "caffe/caffe.hpp"
#include "gpu_nms.hpp"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "faster_rcnn.hpp"
using namespace caffe;
using namespace std;

/*
 * ===  FUNCTION  ======================================================================
 *         Name:  Detector
 *  Description:  Load the model file and weights file
 * =====================================================================================
 */
//load modelfile and weights
Detector::Detector(const string& model_file, const string& weights_file)
{
    net_ = shared_ptr<Net<float> >(new Net<float>(model_file, caffe::TEST));
    net_->CopyTrainedLayersFrom(weights_file);
}

/*
 * ===  FUNCTION  ======================================================================
 *         Name:  Detect
 *  Description:  Perform detection operation
 *                 Warning the max input size should less than 1000*600
 * =====================================================================================
 */
//perform detection operation
//input image max size 1000*600
void Detector::Detect(const string& im_name)
{
    float CONF_THRESH = 0.8;
    float NMS_THRESH = 0.3;
    const int  max_input_side=1000;
    const int  min_input_side=600;

    cv::Mat cv_img = cv::imread(im_name);
    cv::Mat cv_new(cv_img.rows, cv_img.cols, CV_32FC3, cv::Scalar(0,0,0));
    if(cv_img.empty())
    {
        std::cout<<"Can not get the image file !"<<endl;
        return ;
    }
    int max_side = max(cv_img.rows, cv_img.cols);
    int min_side = min(cv_img.rows, cv_img.cols);

    float max_side_scale = float(max_side) / float(max_input_side);
    float min_side_scale = float(min_side) /float( min_input_side);
    float max_scale=max(max_side_scale, min_side_scale);

    float img_scale = 1;

    if(max_scale > 1)
    {
        img_scale = float(1) / max_scale;
    }

    int height = int(cv_img.rows * img_scale);
    int width = int(cv_img.cols * img_scale);
    int num_out;
    cv::Mat cv_resized;

    std::cout<<"imagename "<<im_name<<endl;
    float im_info[3];
    float data_buf[height*width*3];
    float *boxes = NULL;
    float *pred = NULL;
    float *pred_per_class = NULL;
    float *sorted_pred_cls = NULL;
    int *keep = NULL;
    const float* bbox_delt;
    const float* rois;
    const float* pred_cls;
    int num;

    for (int h = 0; h < cv_img.rows; ++h )
    {
        for (int w = 0; w < cv_img.cols; ++w)
        {
            cv_new.at<cv::Vec3f>(cv::Point(w, h))[0] = float(cv_img.at<cv::Vec3b>(cv::Point(w, h))[0])-float(102.9801);
            cv_new.at<cv::Vec3f>(cv::Point(w, h))[1] = float(cv_img.at<cv::Vec3b>(cv::Point(w, h))[1])-float(115.9465);
            cv_new.at<cv::Vec3f>(cv::Point(w, h))[2] = float(cv_img.at<cv::Vec3b>(cv::Point(w, h))[2])-float(122.7717);

        }
    }

    cv::resize(cv_new, cv_resized, cv::Size(width, height));
    im_info[0] = cv_resized.rows;
    im_info[1] = cv_resized.cols;
    im_info[2] = img_scale;

    for (int h = 0; h < height; ++h )
    {
        for (int w = 0; w < width; ++w)
        {
            data_buf[(0*height+h)*width+w] = float(cv_resized.at<cv::Vec3f>(cv::Point(w, h))[0]);
            data_buf[(1*height+h)*width+w] = float(cv_resized.at<cv::Vec3f>(cv::Point(w, h))[1]);
            data_buf[(2*height+h)*width+w] = float(cv_resized.at<cv::Vec3f>(cv::Point(w, h))[2]);
        }
    }

    net_->blob_by_name("data")->Reshape(1, 3, height, width);
    net_->blob_by_name("data")->set_cpu_data(data_buf);
    net_->blob_by_name("im_info")->set_cpu_data(im_info);
    net_->ForwardFrom(0);
    bbox_delt = net_->blob_by_name("bbox_pred")->cpu_data();
    num = net_->blob_by_name("rois")->num();


    rois = net_->blob_by_name("rois")->cpu_data();
    pred_cls = net_->blob_by_name("cls_prob")->cpu_data();
    boxes = new float[num*4];
    pred = new float[num*5*class_num];
    pred_per_class = new float[num*5];
    sorted_pred_cls = new float[num*5];
    keep = new int[num];

    for (int n = 0; n < num; n++)
    {
        for (int c = 0; c < 4; c++)
        {
            boxes[n*4+c] = rois[n*5+c+1] / img_scale;
        }
    }

    bbox_transform_inv(num, bbox_delt, pred_cls, boxes, pred, cv_img.rows, cv_img.cols);
    for (int i = 1; i < class_num; i ++)
    {
        for (int j = 0; j< num; j++)
        {
            for (int k=0; k<5; k++)
                pred_per_class[j*5+k] = pred[(i*num+j)*5+k];
        }
        boxes_sort(num, pred_per_class, sorted_pred_cls);
        _nms(keep, &num_out, sorted_pred_cls, num, 5, NMS_THRESH, 0);
        //for visualize only
        vis_detections(cv_img, keep, num_out, sorted_pred_cls, CONF_THRESH);
    }

    cv::imwrite("vis.jpg",cv_img);
    delete []boxes;
    delete []pred;
    delete []pred_per_class;
    delete []keep;
    delete []sorted_pred_cls;

}

/*
 * ===  FUNCTION  ======================================================================
 *         Name:  vis_detections
 *  Description:  Visuallize the detection result
 * =====================================================================================
 */
void Detector::vis_detections(cv::Mat image, int* keep, int num_out, float* sorted_pred_cls, float CONF_THRESH)
{
    int i=0;
    while(sorted_pred_cls[keep[i]*5+4]>CONF_THRESH && i < num_out)
    {
        if(i>=num_out)
            return;
        cv::rectangle(image,cv::Point(sorted_pred_cls[keep[i]*5+0], sorted_pred_cls[keep[i]*5+1]),cv::Point(sorted_pred_cls[keep[i]*5+2], sorted_pred_cls[keep[i]*5+3]),cv::Scalar(255,0,0));
        i++;
    }
}

/*
 * ===  FUNCTION  ======================================================================
 *         Name:  boxes_sort
 *  Description:  Sort the bounding box according score
 * =====================================================================================
 */
void Detector::boxes_sort(const int num, const float* pred, float* sorted_pred)
{
    vector<Info> my;
    Info tmp;
    for (int i = 0; i< num; i++)
    {
        tmp.score = pred[i*5 + 4];
        tmp.head = pred + i*5;
        my.push_back(tmp);
    }
    std::sort(my.begin(), my.end(), compare);
    for (int i=0; i<num; i++)
    {
        for (int j=0; j<5; j++)
            sorted_pred[i*5+j] = my[i].head[j];
    }
}

/*
 * ===  FUNCTION  ======================================================================
 *         Name:  bbox_transform_inv
 *  Description:  Compute bounding box regression value
 * =====================================================================================
 */
void Detector::bbox_transform_inv(int num, const float* box_deltas, const float* pred_cls, float* boxes, float* pred, int img_height, int img_width)
{
    float width, height, ctr_x, ctr_y, dx, dy, dw, dh, pred_ctr_x, pred_ctr_y, pred_w, pred_h;
    for(int i=0; i< num; i++)
    {
        width = boxes[i*4+2] - boxes[i*4+0] + 1.0;
        height = boxes[i*4+3] - boxes[i*4+1] + 1.0;
        ctr_x = boxes[i*4+0] + 0.5 * width;
        ctr_y = boxes[i*4+1] + 0.5 * height;
        for (int j=0; j< class_num; j++)
        {
            dx = box_deltas[(i*class_num+j)*4+0];
            dy = box_deltas[(i*class_num+j)*4+1];
            dw = box_deltas[(i*class_num+j)*4+2];
            dh = box_deltas[(i*class_num+j)*4+3];
            pred_ctr_x = ctr_x + width*dx;
            pred_ctr_y = ctr_y + height*dy;
            pred_w = width * exp(dw);
            pred_h = height * exp(dh);
            pred[(j*num+i)*5+0] = max(min(pred_ctr_x - 0.5* pred_w, img_width -1), 0);
            pred[(j*num+i)*5+1] = max(min(pred_ctr_y - 0.5* pred_h, img_height -1), 0);
            pred[(j*num+i)*5+2] = max(min(pred_ctr_x + 0.5* pred_w, img_width -1), 0);
            pred[(j*num+i)*5+3] = max(min(pred_ctr_y + 0.5* pred_h, img_height -1), 0);
            pred[(j*num+i)*5+4] = pred_cls[i*class_num+j];
        }
    }
}

转载于:https://www.cnblogs.com/louyihang-loves-baiyan/p/5493344.html

<think>好的,我现在需要帮助用户解决运行Faster R-CNN训练脚本时遇到的问题。用户提到了错误或者对用法不太清楚,所以我要详细分析可能的情况。 首先,用户提供的命令是python tools/train.py configs/faster_rcnn/faster_rcnn_r50_fpn_1x_didi.py,这可能涉及到配置文件的路径是否正确。我需要检查用户是否在正确的项目目录下运行命令,比如MMDetection框架通常需要从根目录执行。如果用户在其他目录下运行,可能会找不到配置文件或依赖文件。 然后,配置文件faster_rcnn_r50_fpn_1x_didi.py是否存在?用户可能没有正确设置配置文件,或者文件路径有误。比如,如果用户的项目结构中没有configs目录,或者该目录下没有相应的配置文件,就会出错。需要建议用户确认文件路径,并检查_base_中的引用是否正确,比如是否有../_base_/models/faster_rcnn_r50_fpn.py这样的引用,这些基础文件是否存在。 接下来,用户可能缺少依赖库。MMDetection需要PyTorch、CUDA等环境。如果用户没有正确安装这些依赖,或者版本不匹配,会导致运行错误。建议用户检查requirements.txt,确保所有依赖已安装,并确认CUDA版本与PyTorch兼容。 数据集的配置也是常见的问题。用户提到的didi_detection.py可能是指自定义的数据集,需要检查数据集路径是否正确,标注文件是否存在,数据格式是否符合要求。例如,COCO格式的数据集需要特定的目录结构和json文件。 GPU资源问题也可能导致错误。如果用户没有可用的GPU,或者显存不足,训练脚本可能会崩溃。建议用户使用--gpu-id参数指定GPU,或者调整batch size以减少显存占用。 日志和错误信息是关键。用户需要查看终端输出的错误信息,或者日志文件,比如work_dirs中的日志,来定位具体问题。常见的错误包括导入错误、文件未找到、CUDA内存不足等。 另外,用户可能需要了解如何继续训练、多GPU训练或者指定工作目录。比如,使用--resume-from参数继续训练,或者--work-dir指定输出目录。多GPU训练可以通过工具如分布式训练脚本启动。 最后,建议用户参考提供的引用中的示例命令,比如引用[1]和引用[2],里面提到了类似的训练命令,可能帮助用户正确执行。同时,可以提示用户进行FPS测试,如引用[3]中的方法,来验证模型性能。 总结可能的问题点:路径错误、依赖缺失、数据集配置、GPU问题、参数使用。需要逐步引导用户检查这些方面,并提供相应的解决方法和示例命令。</think>根据引用[1][2]提供的训练命令及配置信息,运行Faster R-CNN训练脚本的正确步骤如下: ### 一、基础执行命令 ```bash # 单GPU训练 python tools/train.py configs/faster_rcnn/faster_rcnn_r50_fpn_1x_didi.py --work-dir work_dirs/faster_rcnn # 多GPU训练(例如8卡) bash tools/dist_train.sh configs/faster_rcnn/faster_rcnn_r50_fpn_1x_didi.py 8 --work-dir work_dirs/faster_rcnn ``` 参数说明: - `--work-dir`指定模型和日志保存路径[^2] - 配置文件`faster_rcnn_r50_fpn_1x_didi.py`需包含正确的_base_配置链[^2] ### 二、常见问题排查 1. **路径错误** - 确认在项目根目录执行命令 - 检查配置文件中的`_base_`路径是否正确: ```python # faster_rcnn_r50_fpn_1x_didi.py _base_ = [ '../_base_/models/faster_rcnn_r50_fpn.py', # 模型结构 '../_base_/datasets/didi_detection.py', # 数据集配置 '../_base_/schedules/schedule_1x.py', # 训练策略 '../_base_/default_runtime.py' # 运行时配置 ] ``` 2. **依赖缺失** ```bash # 安装必要依赖 pip install -r requirements.txt # 确认CUDA与PyTorch版本匹配 nvidia-smi # 查看CUDA版本 ``` 3. **数据集配置** - 检查`didi_detection.py`中的路径: ```python data = dict( train=dict( img_prefix='data/didi/train/', ann_file='data/didi/annotations/train.json'), val=dict( img_prefix='data/didi/val/', ann_file='data/didi/annotations/val.json')) ``` 4. **GPU资源问题** ```bash # 指定单卡训练 python tools/train.py configs/faster_rcnn/faster_rcnn_r50_fpn_1x_didi.py --gpu-id 0 # 减少batch_size防止OOM sed -i 's/samples_per_gpu=2/samples_per_gpu=1/g' configs/faster_rcnn/faster_rcnn_r50_fpn_1x_didi.py ``` ### 三、进阶用法 1. **恢复训练** ```bash python tools/train.py configs/faster_rcnn/faster_rcnn_r50_fpn_1x_didi.py \ --resume-from work_dirs/faster_rcnn/latest.pth ``` 2. **性能验证** ```bash # 训练完成后测试FPS(需修改路径) python tools/analysis_tools/benchmark.py \ configs/faster_rcnn/faster_rcnn_r50_fpn_2x_coco.py \ work_dirs/faster_rcnn/epoch_12.pth \ --fuse-conv-bn ``` 引用[3]展示了基准测试的标准方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值