Проблема при использовании YOLOv8 с NCNN на Raspberry Pi 4C++

Программы на C++. Форум разработчиков
Anonymous
Проблема при использовании YOLOv8 с NCNN на Raspberry Pi 4

Сообщение Anonymous »


Я использую эту программу на C++ на Raspberry Pi 4: https://github.com/Qengineering/YoloV8- ... berry-Pi-4, при использовании стандартного yolov8n.bin и веса yolov8.param, которые вы можете найти в репозитории, он работает нормально и быстро, но когда я пытаюсь изменить код и использовать свою лично обученную модель, он не работает и останавливается из-за ошибки сегментации.
Я попробовал несколько методов, чтобы получить модель ncnn:
  • Метод Python yolov8:
from ultralytics import YOLO
import ncnn

model=YOLO('yolov8n.pt')

model.train(data="data.yaml", epochs=100, batch=8)
path = model.export(format="ncnn")
  • Преобразование из onnx в ncnn
from ultralytics import YOLO

model=YOLO('yolov8n.pt')

model.train(data="data.yaml", epochs=100, batch=8)
path = model.export(format="onxx")

После запуска этого кода я выполнил действия, описанные в этом руководстве: https://github.com/Tencent/ncnn/wiki/us ... ytorch-or- onnx
Эти два метода создают два разных файла model.param, но ни один из них не работает. Я пробовал использовать эти файлы для прогнозирования с помощью YOLOv8 в Python, и модель работает в Python, но перестал работать с кодом C++.
Я пытался найти точку, где Возникает ошибка сегментации, но она слишком глубока в коде, чтобы я мог ее понять.

Если кто-то сможет помочь, я буду благодарен, потому что это сводит меня с ума
Код C++ работает с скомпилированным OpenCV 4.9.0.
Это модифицированный исходный код C++:
yolov8.cpp
#include "yoloV8.h"

#include
#include

const char* class_names[] = {
"ambulance"
};

static float fast_exp(float x)
{
union {
uint32_t i;
float f;
} v{};
v.i = (1 score)
{
label = k;
score = confidence;
}
}
float box_prob = sigmoid(score);
if (box_prob >= prob_threshold)
{
ncnn::Mat bbox_pred(reg_max_1, 4, (void*)pred.row(i));
{
ncnn::Layer* softmax = ncnn::create_layer("Softmax");

ncnn::ParamDict pd;
pd.set(0, 1); // axis
pd.set(1, 1);
softmax->load_param(pd);

ncnn::Option opt;
opt.num_threads = 1;
opt.use_packing_layout = false;

softmax->create_pipeline(opt);

softmax->forward_inplace(bbox_pred, opt);

softmax->destroy_pipeline(opt);

delete softmax;
}

float pred_ltrb[4];
for (int k = 0; k < 4; k++)
{
float dis = 0.f;
const float* dis_after_sm = bbox_pred.row(k);
for (int l = 0; l < reg_max_1; l++)
{
dis += l * dis_after_sm[l];
}

pred_ltrb[k] = dis * grid_strides.stride;
}

float pb_cx = (grid_strides.grid0 + 0.5f) * grid_strides.stride;
float pb_cy = (grid_strides.grid1 + 0.5f) * grid_strides.stride;

float x0 = pb_cx - pred_ltrb[0];
float y0 = pb_cy - pred_ltrb[1];
float x1 = pb_cx + pred_ltrb[2];
float y1 = pb_cy + pred_ltrb[3];

Object obj;
obj.rect.x = x0;
obj.rect.y = y0;
obj.rect.width = x1 - x0;
obj.rect.height = y1 - y0;
obj.label = label;
obj.prob = box_prob;

objects.push_back(obj);
}
}
}

YoloV8::YoloV8()
{
}

int YoloV8::load(int _target_size)
{
yolo.clear();

yolo.opt = ncnn::Option();

yolo.opt.num_threads = 4;

yolo.load_param("./best.param");
yolo.load_model("./best.bin");

target_size = _target_size;
mean_vals[0] = 103.53f;
mean_vals[1] = 116.28f;
mean_vals[2] = 123.675f;
norm_vals[0] = 1.0 / 255.0f;
norm_vals[1] = 1.0 / 255.0f;
norm_vals[2] = 1.0 / 255.0f;

return 0;
}

int YoloV8::detect(const cv::Mat& rgb, std::vector& objects, float prob_threshold, float nms_threshold)
{
int width = rgb.cols;
int height = rgb.rows;

// pad to multiple of 32
int w = width;
int h = height;
float scale = 1.f;
if (w > h)
{
scale = (float)target_size / w;
w = target_size;
h = h * scale;
}
else
{
scale = (float)target_size / h;
h = target_size;
w = w * scale;
}

ncnn::Mat in = ncnn::Mat::from_pixels_resize(rgb.data, ncnn::Mat::PIXEL_RGB2BGR, width, height, w, h);

// pad to target_size rectangle
int wpad = (w + 31) / 32 * 32 - w;
int hpad = (h + 31) / 32 * 32 - h;
ncnn::Mat in_pad;
ncnn::copy_make_border(in, in_pad, hpad / 2, hpad - hpad / 2, wpad / 2, wpad - wpad / 2, ncnn::BORDER_CONSTANT, 0.f);

in_pad.substract_mean_normalize(0, norm_vals);

ncnn::Extractor ex = yolo.create_extractor();

ex.input("images", in_pad);

std::vector proposals;

ncnn::Mat out;
ex.extract("output0", out);

std::vector strides = {8, 16, 32}; // might have stride=64
std::vector grid_strides;
generate_grids_and_stride(in_pad.w, in_pad.h, strides, grid_strides);
generate_proposals(grid_strides, out, prob_threshold, proposals);

// sort all proposals by score from highest to lowest
qsort_descent_inplace(proposals);

// apply nms with nms_threshold
std::vector picked;
nms_sorted_bboxes(proposals, picked, nms_threshold);

int count = picked.size();

objects.resize(count);
for (int i = 0; i < count; i++)
{
objects = proposals[picked];

// adjust offset to original unpadded
float x0 = (objects.rect.x - (wpad / 2)) / scale;
float y0 = (objects.rect.y - (hpad / 2)) / scale;
float x1 = (objects.rect.x + objects[i].rect.width - (wpad / 2)) / scale;
float y1 = (objects[i].rect.y + objects[i].rect.height - (hpad / 2)) / scale;

// clip
x0 = std::max(std::min(x0, (float)(width - 1)), 0.f);
y0 = std::max(std::min(y0, (float)(height - 1)), 0.f);
x1 = std::max(std::min(x1, (float)(width - 1)), 0.f);
y1 = std::max(std::min(y1, (float)(height - 1)), 0.f);

objects[i].rect.x = x0;
objects[i].rect.y = y0;
objects[i].rect.width = x1 - x0;
objects[i].rect.height = y1 - y0;
}

// sort objects by area
struct
{
bool operator()(const Object& a, const Object& b) const
{
return a.rect.area() > b.rect.area();
}
} objects_area_greater;
std::sort(objects.begin(), objects.end(), objects_area_greater);

return 0;
}

int YoloV8::draw(cv::Mat& rgb, const std::vector& objects)
{
for (size_t i = 0; i < objects.size(); i++)
{
const Object& obj = objects[i];

// fprintf(stderr, "%d = %.5f at %.2f %.2f %.2f x %.2f\n", obj.label, obj.prob,
// obj.rect.x, obj.rect.y, obj.rect.width, obj.rect.height);

cv::rectangle(rgb, obj.rect, cv::Scalar(255, 0, 0));

char text[256];
sprintf(text, "%s %.1f%%", class_names[obj.label], obj.prob * 100);

int baseLine = 0;
cv::Size label_size = cv::getTextSize(text, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);

int x = obj.rect.x;
int y = obj.rect.y - label_size.height - baseLine;
if (y < 0)
y = 0;
if (x + label_size.width > rgb.cols)
x = rgb.cols - label_size.width;

cv::rectangle(rgb, cv::Rect(cv::Point(x, y), cv::Size(label_size.width, label_size.height + baseLine)),
cv::Scalar(255, 255, 255), -1);

cv::putText(rgb, text, cv::Point(x, y + label_size.height),
cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0));
}

return 0;
}

yolov8 main.cpp#include "yoloV8.h"

#include
#include
#include
#include
#include
#include

YoloV8 yolov8;
int target_size = 640; //416; //320; must be divisible by 32.

int main(int argc, char** argv)
{
const char* imagepath = argv[1];

if (argc != 2)
{
fprintf(stderr, "Usage: %s [imagepath]\n", argv[0]);
return -1;
}

cv::Mat m = cv::imread(imagepath, 1);
if (m.empty())
{
fprintf(stderr, "cv::imread %s failed\n", imagepath);
return -1;
}

yolov8.load(target_size); //load model (once) see yoloyV8.cpp line 246

std::vector objects;
yolov8.detect(m, objects); //recognize the objects
yolov8.draw(m, objects); //show the outcome

cv::imshow("RPi4 - 1.95 GHz - 2 GB ram",m);
// cv::imwrite("out.jpg",m);
cv::waitKey(0);

return 0;
}

yolov8.h

#ifndef YOLOV8_H
#define YOLOV8_H

#include
#include

struct Object
{
cv::Rect_ rect;
int label;
float prob;
};

struct GridAndStride
{
int grid0;
int grid1;
int stride;
};

class YoloV8
{
public:
YoloV8();
int load(int target_size);
int detect(const cv::Mat& rgb, std::vector& objects, float prob_threshold = 0.4f, float nms_threshold = 0.5f);
int draw(cv::Mat& rgb, const std::vector& objects);
private:
ncnn::Net yolo;
int target_size;
float mean_vals[3];
float norm_vals[3];
};

#endif // YOLOV8_H


Подробнее здесь: https://stackoverflow.com/questions/784 ... berry-pi-4

Вернуться в «C++»