Skip to content

Commit 95b9b3b

Browse files
committed
yolov5 v4.0 int8
1 parent 86b8f5f commit 95b9b3b

File tree

8 files changed

+206
-128
lines changed

8 files changed

+206
-128
lines changed

yolov5/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ target_link_libraries(myplugins nvinfer cudart)
2727
find_package(OpenCV)
2828
include_directories(OpenCV_INCLUDE_DIRS)
2929

30-
add_executable(yolov5 ${PROJECT_SOURCE_DIR}/yolov5.cpp)
30+
add_executable(yolov5 ${PROJECT_SOURCE_DIR}/calibrator.cpp ${PROJECT_SOURCE_DIR}/yolov5.cpp)
3131
target_link_libraries(yolov5 nvinfer)
3232
target_link_libraries(yolov5 cudart)
3333
target_link_libraries(yolov5 myplugins)

yolov5/README.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ Currently, we support yolov5 v1.0(yolov5s only), v2.0, v3.0, v3.1 and v4.0.
2222

2323
## How to Run, yolov5s as example
2424

25-
```
2625
1. generate yolov5s.wts from pytorch with yolov5s.pt, or download .wts from model zoo
2726

27+
```
2828
git clone https://github.com/wang-xinyu/tensorrtx.git
2929
git clone https://github.com/ultralytics/yolov5.git
3030
// download its weights 'yolov5s.pt'
@@ -33,9 +33,11 @@ git clone https://github.com/ultralytics/yolov5.git
3333
// go to ultralytics/yolov5
3434
python gen_wts.py
3535
// a file 'yolov5s.wts' will be generated.
36+
```
3637

3738
2. build tensorrtx/yolov5 and run
3839

40+
```
3941
// put yolov5s.wts into tensorrtx/yolov5
4042
// go to tensorrtx/yolov5
4143
// ensure the macro NET in yolov5.cpp is s
@@ -46,16 +48,28 @@ cmake ..
4648
make
4749
sudo ./yolov5 -s // serialize model to plan file i.e. 'yolov5s.engine'
4850
sudo ./yolov5 -d ../samples // deserialize plan file and run inference, the images in samples will be processed.
51+
```
4952

5053
3. check the images generated, as follows. _zidane.jpg and _bus.jpg
5154

5255
4. optional, load and run the tensorrt model in python
5356

57+
```
5458
// install python-tensorrt, pycuda, etc.
5559
// ensure the yolov5s.engine and libmyplugins.so have been built
5660
python yolov5_trt.py
5761
```
5862

63+
# INT8 Quantization
64+
65+
1. Prepare calibration images, you can randomly select 1000s images from your train set. For coco, you can also download my calibration images `coco_calib` from [BaiduPan](https://pan.baidu.com/s/1GOm_-JobpyLMAqZWCDUhKg) pwd: a9wh
66+
67+
2. unzip it in yolov5/build
68+
69+
3. set the macro `USE_INT8` in yolov3.cpp and make
70+
71+
4. serialize the model and test
72+
5973
<p align="center">
6074
<img src="https://user-images.githubusercontent.com/15235574/78247927-4d9fac00-751e-11ea-8b1b-704a0aeb3fcf.jpg">
6175
</p>

yolov5/calibrator.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#include <iostream>
2+
#include <iterator>
3+
#include <fstream>
4+
#include <opencv2/dnn/dnn.hpp>
5+
#include "calibrator.h"
6+
#include "cuda_runtime_api.h"
7+
#include "utils.h"
8+
9+
Int8EntropyCalibrator2::Int8EntropyCalibrator2(int batchsize, int input_w, int input_h, const char* img_dir, const char* calib_table_name, const char* input_blob_name, bool read_cache)
10+
: batchsize_(batchsize)
11+
, input_w_(input_w)
12+
, input_h_(input_h)
13+
, img_idx_(0)
14+
, img_dir_(img_dir)
15+
, calib_table_name_(calib_table_name)
16+
, input_blob_name_(input_blob_name)
17+
, read_cache_(read_cache)
18+
{
19+
input_count_ = 3 * input_w * input_h * batchsize;
20+
CUDA_CHECK(cudaMalloc(&device_input_, input_count_ * sizeof(float)));
21+
read_files_in_dir(img_dir, img_files_);
22+
}
23+
24+
Int8EntropyCalibrator2::~Int8EntropyCalibrator2()
25+
{
26+
CUDA_CHECK(cudaFree(device_input_));
27+
}
28+
29+
int Int8EntropyCalibrator2::getBatchSize() const
30+
{
31+
return batchsize_;
32+
}
33+
34+
bool Int8EntropyCalibrator2::getBatch(void* bindings[], const char* names[], int nbBindings)
35+
{
36+
if (img_idx_ + batchsize_ > (int)img_files_.size()) {
37+
return false;
38+
}
39+
40+
std::vector<cv::Mat> input_imgs_;
41+
for (int i = img_idx_; i < img_idx_ + batchsize_; i++) {
42+
std::cout << img_files_[i] << " " << i << std::endl;
43+
cv::Mat temp = cv::imread(img_dir_ + img_files_[i]);
44+
if (temp.empty()){
45+
std::cerr << "Fatal error: image cannot open!" << std::endl;
46+
return false;
47+
}
48+
cv::Mat pr_img = preprocess_img(temp, input_w_, input_h_);
49+
input_imgs_.push_back(pr_img);
50+
}
51+
img_idx_ += batchsize_;
52+
cv::Mat blob = cv::dnn::blobFromImages(input_imgs_, 1.0 / 255.0, cv::Size(input_w_, input_h_), cv::Scalar(0, 0, 0), true, false);
53+
54+
CUDA_CHECK(cudaMemcpy(device_input_, blob.ptr<float>(0), input_count_ * sizeof(float), cudaMemcpyHostToDevice));
55+
assert(!strcmp(names[0], input_blob_name_));
56+
bindings[0] = device_input_;
57+
return true;
58+
}
59+
60+
const void* Int8EntropyCalibrator2::readCalibrationCache(size_t& length)
61+
{
62+
std::cout << "reading calib cache: " << calib_table_name_ << std::endl;
63+
calib_cache_.clear();
64+
std::ifstream input(calib_table_name_, std::ios::binary);
65+
input >> std::noskipws;
66+
if (read_cache_ && input.good())
67+
{
68+
std::copy(std::istream_iterator<char>(input), std::istream_iterator<char>(), std::back_inserter(calib_cache_));
69+
}
70+
length = calib_cache_.size();
71+
return length ? calib_cache_.data() : nullptr;
72+
}
73+
74+
void Int8EntropyCalibrator2::writeCalibrationCache(const void* cache, size_t length)
75+
{
76+
std::cout << "writing calib cache: " << calib_table_name_ << " size: " << length << std::endl;
77+
std::ofstream output(calib_table_name_, std::ios::binary);
78+
output.write(reinterpret_cast<const char*>(cache), length);
79+
}
80+

yolov5/calibrator.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#ifndef ENTROPY_CALIBRATOR_H
2+
#define ENTROPY_CALIBRATOR_H
3+
4+
#include "NvInfer.h"
5+
#include <string>
6+
#include <vector>
7+
8+
//! \class Int8EntropyCalibrator2
9+
//!
10+
//! \brief Implements Entropy calibrator 2.
11+
//! CalibrationAlgoType is kENTROPY_CALIBRATION_2.
12+
//!
13+
class Int8EntropyCalibrator2 : public nvinfer1::IInt8EntropyCalibrator2
14+
{
15+
public:
16+
Int8EntropyCalibrator2(int batchsize, int input_w, int input_h, const char* img_dir, const char* calib_table_name, const char* input_blob_name, bool read_cache = true);
17+
18+
virtual ~Int8EntropyCalibrator2();
19+
int getBatchSize() const override;
20+
bool getBatch(void* bindings[], const char* names[], int nbBindings) override;
21+
const void* readCalibrationCache(size_t& length) override;
22+
void writeCalibrationCache(const void* cache, size_t length) override;
23+
24+
private:
25+
int batchsize_;
26+
int input_w_;
27+
int input_h_;
28+
int img_idx_;
29+
std::string img_dir_;
30+
std::vector<std::string> img_files_;
31+
size_t input_count_;
32+
std::string calib_table_name_;
33+
const char* input_blob_name_;
34+
bool read_cache_;
35+
void* device_input_;
36+
std::vector<char> calib_cache_;
37+
};
38+
39+
#endif // ENTROPY_CALIBRATOR_H

yolov5/common.hpp

Lines changed: 0 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -6,45 +6,11 @@
66
#include <sstream>
77
#include <vector>
88
#include <opencv2/opencv.hpp>
9-
#include <dirent.h>
109
#include "NvInfer.h"
1110
#include "yololayer.h"
1211

13-
#define CHECK(status) \
14-
do\
15-
{\
16-
auto ret = (status);\
17-
if (ret != 0)\
18-
{\
19-
std::cerr << "Cuda failure: " << ret << std::endl;\
20-
abort();\
21-
}\
22-
} while (0)
23-
2412
using namespace nvinfer1;
2513

26-
cv::Mat preprocess_img(cv::Mat& img) {
27-
int w, h, x, y;
28-
float r_w = Yolo::INPUT_W / (img.cols*1.0);
29-
float r_h = Yolo::INPUT_H / (img.rows*1.0);
30-
if (r_h > r_w) {
31-
w = Yolo::INPUT_W;
32-
h = r_w * img.rows;
33-
x = 0;
34-
y = (Yolo::INPUT_H - h) / 2;
35-
} else {
36-
w = r_h * img.cols;
37-
h = Yolo::INPUT_H;
38-
x = (Yolo::INPUT_W - w) / 2;
39-
y = 0;
40-
}
41-
cv::Mat re(h, w, CV_8UC3);
42-
cv::resize(img, re, re.size(), 0, 0, cv::INTER_LINEAR);
43-
cv::Mat out(Yolo::INPUT_H, Yolo::INPUT_W, CV_8UC3, cv::Scalar(128, 128, 128));
44-
re.copyTo(out(cv::Rect(x, y, re.cols, re.rows)));
45-
return out;
46-
}
47-
4814
cv::Rect get_rect(cv::Mat& img, float bbox[4]) {
4915
int l, r, t, b;
5016
float r_w = Yolo::INPUT_W / (img.cols * 1.0);
@@ -290,28 +256,6 @@ ILayer* SPP(INetworkDefinition *network, std::map<std::string, Weights>& weightM
290256
return cv2;
291257
}
292258

293-
int read_files_in_dir(const char *p_dir_name, std::vector<std::string> &file_names) {
294-
DIR *p_dir = opendir(p_dir_name);
295-
if (p_dir == nullptr) {
296-
return -1;
297-
}
298-
299-
struct dirent* p_file = nullptr;
300-
while ((p_file = readdir(p_dir)) != nullptr) {
301-
if (strcmp(p_file->d_name, ".") != 0 &&
302-
strcmp(p_file->d_name, "..") != 0) {
303-
//std::string cur_file_name(p_dir_name);
304-
//cur_file_name += "/";
305-
//cur_file_name += p_file->d_name;
306-
std::string cur_file_name(p_file->d_name);
307-
file_names.push_back(cur_file_name);
308-
}
309-
}
310-
311-
closedir(p_dir);
312-
return 0;
313-
}
314-
315259
std::vector<float> getAnchors(std::map<std::string, Weights>& weightMap)
316260
{
317261
std::vector<float> anchors_yolo;

yolov5/utils.h

Lines changed: 47 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#include <vector>
66
#include <algorithm>
77
#include <cudnn.h>
8+
#include <dirent.h>
9+
#include <opencv2/opencv.hpp>
810

911
#ifndef CUDA_CHECK
1012

@@ -21,61 +23,6 @@
2123

2224
namespace Tn
2325
{
24-
class Profiler : public nvinfer1::IProfiler
25-
{
26-
public:
27-
void printLayerTimes(int itrationsTimes)
28-
{
29-
float totalTime = 0;
30-
for (size_t i = 0; i < mProfile.size(); i++)
31-
{
32-
printf("%-40.40s %4.3fms\n", mProfile[i].first.c_str(), mProfile[i].second / itrationsTimes);
33-
totalTime += mProfile[i].second;
34-
}
35-
printf("Time over all layers: %4.3f\n", totalTime / itrationsTimes);
36-
}
37-
private:
38-
typedef std::pair<std::string, float> Record;
39-
std::vector<Record> mProfile;
40-
41-
virtual void reportLayerTime(const char* layerName, float ms)
42-
{
43-
auto record = std::find_if(mProfile.begin(), mProfile.end(), [&](const Record& r){ return r.first == layerName; });
44-
if (record == mProfile.end())
45-
mProfile.push_back(std::make_pair(layerName, ms));
46-
else
47-
record->second += ms;
48-
}
49-
};
50-
51-
//Logger for TensorRT info/warning/errors
52-
class Logger : public nvinfer1::ILogger
53-
{
54-
public:
55-
56-
Logger(): Logger(Severity::kWARNING) {}
57-
58-
Logger(Severity severity): reportableSeverity(severity) {}
59-
60-
void log(Severity severity, const char* msg) override
61-
{
62-
// suppress messages with severity enum value greater than the reportable
63-
if (severity > reportableSeverity) return;
64-
65-
switch (severity)
66-
{
67-
case Severity::kINTERNAL_ERROR: std::cerr << "INTERNAL_ERROR: "; break;
68-
case Severity::kERROR: std::cerr << "ERROR: "; break;
69-
case Severity::kWARNING: std::cerr << "WARNING: "; break;
70-
case Severity::kINFO: std::cerr << "INFO: "; break;
71-
default: std::cerr << "UNKNOWN: "; break;
72-
}
73-
std::cerr << msg << std::endl;
74-
}
75-
76-
Severity reportableSeverity{Severity::kWARNING};
77-
};
78-
7926
template<typename T>
8027
void write(char*& buffer, const T& val)
8128
{
@@ -91,4 +38,48 @@ namespace Tn
9138
}
9239
}
9340

94-
#endif
41+
static inline cv::Mat preprocess_img(cv::Mat& img, int input_w, int input_h) {
42+
int w, h, x, y;
43+
float r_w = input_w / (img.cols*1.0);
44+
float r_h = input_h / (img.rows*1.0);
45+
if (r_h > r_w) {
46+
w = input_w;
47+
h = r_w * img.rows;
48+
x = 0;
49+
y = (input_h - h) / 2;
50+
} else {
51+
w = r_h * img.cols;
52+
h = input_h;
53+
x = (input_w - w) / 2;
54+
y = 0;
55+
}
56+
cv::Mat re(h, w, CV_8UC3);
57+
cv::resize(img, re, re.size(), 0, 0, cv::INTER_LINEAR);
58+
cv::Mat out(input_h, input_w, CV_8UC3, cv::Scalar(128, 128, 128));
59+
re.copyTo(out(cv::Rect(x, y, re.cols, re.rows)));
60+
return out;
61+
}
62+
63+
static inline int read_files_in_dir(const char *p_dir_name, std::vector<std::string> &file_names) {
64+
DIR *p_dir = opendir(p_dir_name);
65+
if (p_dir == nullptr) {
66+
return -1;
67+
}
68+
69+
struct dirent* p_file = nullptr;
70+
while ((p_file = readdir(p_dir)) != nullptr) {
71+
if (strcmp(p_file->d_name, ".") != 0 &&
72+
strcmp(p_file->d_name, "..") != 0) {
73+
//std::string cur_file_name(p_dir_name);
74+
//cur_file_name += "/";
75+
//cur_file_name += p_file->d_name;
76+
std::string cur_file_name(p_file->d_name);
77+
file_names.push_back(cur_file_name);
78+
}
79+
}
80+
81+
closedir(p_dir);
82+
return 0;
83+
}
84+
85+
#endif

0 commit comments

Comments
 (0)