问题描述
如标题,我的yolov5是从官方模型用工具剪枝的,原模型,剪枝模型,转为onnx和kmodel后的模型在pc端全都能正常使用,在开发板端就不行了,没找到明显的问题(也有可能是resize问题,但我确实不知道怎么改),可能是我对官方工具的理解有些出入,请大佬帮忙看看
硬件板卡
k230_canmv_v3
软件版本
rtos+linux
复现步骤
代码在主体就发不出来
void Model::preprocess(uintptr_t vaddr, uintptr_t paddr)
{
// input tensor
dims_t in_shape{1,720,1280,3};
auto in_tensor = host_runtime_tensor::create(dt_uint8, in_shape, { (gsl::byte *)vaddr, compute_size(in_shape) },false,hrt::pool_shared,paddr).expect("cannot create input tensor");
hrt::sync(in_tensor, sync_op_t::sync_write_back, true).expect("write back input failed");
// output tensor
dims_t out_shape=interp_.input_shape(0);
printf("kmodel:%dx%dx%dx%d\n",kmodel_shape[0],kmodel_shape[1],kmodel_shape[2],kmodel_shape[3]);
printf("shape:%dx%dx%dx%d\n",out_shape[0],out_shape[1],out_shape[2],out_shape[3]);
// config ai2d
ai2d_datatype_t ai2d_dtype { ai2d_format::RGB_packed, ai2d_format::NCHW_FMT, dt_uint8,dt_float32};//在头文件里找到相似定义(simple_types)
ai2d_crop_param_t crop_param { false, 0, 0, 720,1280};//横向裁减2/3,false了,美使用
ai2d_shift_param_t shift_param { false, 0 };
ai2d_pad_param_t pad_param { true, { { 0, 0 }, { 0, 0 }, { 70, 70 }, { 0, 0 } }, ai2d_pad_mode::constant, { 114,114,114 } };//pad模式常数
ai2d_resize_param_t resize_param { true, ai2d_interp_method::tf_bilinear, ai2d_interp_mode::half_pixel};
ai2d_affine_param_t affine_param { false};
// run
ai2d_builder builder { in_shape, out_shape, ai2d_dtype, crop_param, shift_param, pad_param, resize_param, affine_param };
auto start = std::chrono::steady_clock::now();
builder.build_schedule().expect("error occurred in ai2d build_schedule");
builder.invoke(in_tensor, ai2d_out_tensor_).expect("error occurred in ai2d invoke");
auto stop = std::chrono::steady_clock::now();
double duration = std::chrono::duration<double, std::milli>(stop - start).count();
std::cout << "ai2d run: duration = " << duration << " ms, fps = " << 1000 / duration << std::endl;
return;
}
int Model::run(uintptr_t vaddr, uintptr_t paddr)
{
preprocess(vaddr, paddr);
kpu_run();
return postprocess();
}
// ==================== NMS后处理 ====================
int Model::nms_filter(const float* model_output, float conf_threshold, float iou_threshold)
{
static int n=0;
// 直接写文件,最简版
FILE *fp = fopen("out.txt", "a");
fprintf(fp,"第%d次\n",n++);
for (int i = 0; i < 6300; i++) {
for (int j = 0; j < 7; j++) {
fprintf(fp, "%.6f ", model_output[i * 7 + j]);
}
fprintf(fp, "\t\n");
}
fclose(fp);
const int num_boxes = 6300; // 固定总框数
const int num_classes = 2; // 固定2分类
int valid_boxes[num_boxes]; // 存储有效框索引
int stride[num_boxes];
int num_valid = 0;
float x=0,y=0,w=0,h=0;
float max_conf=0,conf=0,max_conf_o=0;
float conf_i=0,conf_j=0;
k_vo_draw_frame frame{false,0,0,0,0,0};
int class_id=0;
//清除框(便顺序了)
for(int n=0;n<16;n++)
{
frame.draw_en=false;
frame.frame_num=n;
int ret=kd_mpi_vo_draw_frame(&frame);
if(ret)
{
printf("clear triangle error!!!\n");
}
}
// ====================== 1. 筛选有效框(置信度过滤) ======================
for (int i = 0; i < num_boxes; i++)
{
max_conf = 0;
// 6300×7结构:[x,y,w,h,conf,cls0,cls1]
conf = model_output[i * 7 + 4];
if (conf > max_conf)
max_conf = conf;
// 低于阈值跳过
if (max_conf < conf_threshold)
continue;
valid_boxes[num_valid++] = i;
}
printf("num_valid:%d\n",num_valid);
if (num_valid <= 0)
return 0;
for (int i = 0; i < num_valid - 1; i++)
{
int idx_i = valid_boxes[i];
// 只用第5个值作为置信度
float score_i = model_output[idx_i * 7 + 4];
for (int j = i + 1; j < num_valid; j++)
{
int idx_j = valid_boxes[j];
// 只用第5个值作为置信度
float score_j = model_output[idx_j * 7 + 4];
// 降序:分数小的往后排
if (score_i < score_j)
{
// 交换 box 索引
swap_float(valid_boxes[i], valid_boxes[j]);
// 同时更新 score_i
swap_float(score_i, score_j);
}
}
}
// ====================== 3. NMS 抑制 ======================
int removed[num_valid];
for (int i = 0; i < num_valid; i++)
removed[i] = 0;
int keep_count = 0;
for (int i = 0; i < num_valid; i++)
{
if (removed[i])
continue;
keep_count++;
int a_idx = valid_boxes[i];
float ax = model_output[a_idx * 7 + 0];
float ay = model_output[a_idx * 7 + 1];
float aw = model_output[a_idx * 7 + 2];
float ah = model_output[a_idx * 7 + 3];
float a_x1 = ax - aw * 0.5f;
float a_y1 = ay - ah * 0.5f;
float a_x2 = ax + aw * 0.5f;
float a_y2 = ay + ah * 0.5f;
for (int j = i + 1; j < num_valid; j++)
{
if (removed[j])
continue;
int b_idx = valid_boxes[j];
float bx = model_output[b_idx * 7 + 0];
float by = model_output[b_idx * 7 + 1];
float bw = model_output[b_idx * 7 + 2];
float bh = model_output[b_idx * 7 + 3];
float b_x1 = bx - bw * 0.5f;
float b_y1 = by - bh * 0.5f;
float b_x2 = bx + bw * 0.5f;
float b_y2 = by + bh * 0.5f;
// 计算 IoU
float inter_x1 = (a_x1 > b_x1) ? a_x1 : b_x1;
float inter_y1 = (a_y1 > b_y1) ? a_y1 : b_y1;
float inter_x2 = (a_x2 < b_x2) ? a_x2 : b_x2;
float inter_y2 = (a_y2 < b_y2) ? a_y2 : b_y2;
float iou = 0.0f;
if (inter_x2 > inter_x1 && inter_y2 > inter_y1)
{
float inter_area = (inter_x2 - inter_x1) * (inter_y2 - inter_y1);
float a_area = aw * ah;
float b_area = bw * bh;
iou = inter_area / (a_area + b_area - inter_area);
}
if (iou > iou_threshold)
removed[j] = 1;
}
}
// ====================== 4. 输出最终保留的框 ======================
printf("\n===== NMS 最终保留框 =====\n");
//清除框
int final_count = 0;
for (int i = 0,p=0; i < num_valid; i++)
{
if (!removed[i])
{
int idx = valid_boxes[i];
float x = model_output[idx * 7 + 0];
float y = model_output[idx * 7 + 1];
float w = model_output[idx * 7 + 2];
float h = model_output[idx * 7 + 3];
float conf = 0;
class_id = 0;
for (int c = 0; c < num_classes; c++)
{
float v = model_output[idx * 7 + 5 + c];
if (v > conf) {
conf = v;
class_id = c;
}
}
// 输出坐标
frame.draw_en=true;
frame.line_x_start = (x-w*0.5f) * (1280.0f / 320.0f);
frame.line_y_start = (y-h*0.5f) * (1280.0f / 320.0f);
frame.line_x_end = (x + w*0.5f) * (1280.0f / 320.0f);
frame.line_y_end = (y + h*0.5f) * (1280.0f / 320.0f);
frame.frame_num=p++;
int ret=kd_mpi_vo_draw_frame(&frame);
final_count++;
printf("x:%d,y:%d,w:%d,h:%d\n",frame.line_x_start,frame.line_y_start,frame.line_x_end,frame.line_y_end);
}
}
printf("numg valid:%d\n",num_valid);
return final_count;
}
int Model::postprocess()
{
float *out;
auto tensor = output_tensor(0);
auto buf = tensor.impl()->to_host().unwrap()->buffer().as_host().unwrap().map(map_access_::map_read).unwrap().buffer();
out = reinterpret_cast<float *>(buf.data());
auto input_shape = interp_.input_shape(0);
printf("in_shape:%dx%dx%d\n",input_shape[0],input_shape[1],input_shape[2]);
auto output_shape = interp_.output_shape(0);
printf("out_shape:%dx%dx%d\n",output_shape[0],output_shape[1],output_shape[2]);
int final_boxes = nms_filter(
out, // 输入
0.5f, // 置信度阈值
0.45f // IOU 阈值
);
printf("final_boxes:%d\n",final_boxes);
return final_boxes;
}
硬件板卡
k230_canmv_v3
软件版本
rtos+linux