摘要: 这里置顶一个索引吧,方便所有人查找。 基础与技巧: matlab练习程序(Schur补) matlab练习程序(正交分解) matlab练习程序(GPU加速) matlab练习程序(生成gif图片) matlab练习程序(克莱姆法则解方程) matlab练习程序(读取列不一致的数据) matlab练 阅读全文
posted @ 2021-01-27 21:45 Dsp Tian 阅读(4736) 评论(0) 推荐(5) 编辑

yolo11和yolo8后处理方法是完全一样的。

首先安装ultralytics,然后执行下面代码导出yolo11l.onnx模型。

from ultralytics import YOLO
model = YOLO('yolo11l.pt')
success = model.export(format = 'onnx', opset = 11)

模型输入维度是[1,3,640,640],输出维度是[1,84,8400]。

输出84中前4个值代表目标[x,y,w,h],余下80个代表目标类别可能性。8400代表候选目标个数。

C++后处理代码如下,代码没有恢复比例,没有映射ID,这两步应该比较容易:

#include <iostream>
#include <vector>
#include <onnxruntime_cxx_api.h>
#include "opencv2/opencv.hpp"
using namespace std;

struct CDetectBox
{
    int id;
    float score;
    float x1;
    float y1;
    float x2;
    float y2;
};

float compute_iou(const CDetectBox& box1, const CDetectBox& box2)
{
    float xmin = std::max(box1.x1, box2.x1);
    float ymin = std::max(box1.y1, box2.y1);
    float xmax = std::min(box1.x2, box2.x2);
    float ymax = std::min(box1.y2, box2.y2);

    float intersection_area = std::fmax(0.0, xmax - xmin) * std::fmax(0.0, ymax - ymin);
    float boxArea1 = (box1.x2 - box1.x1) * (box1.y2 - box1.y1);
    float boxArea2 = (box2.x2 - box2.x1) * (box2.y2 - box2.y1);
    float union_area = boxArea1 + boxArea2 - intersection_area + 1e-10;

    return intersection_area / union_area;
}

int main()
{
    int imgH = 640;
    int imgW = 640;

    cv::Mat image = cv::imread("test2.png", 1);
    cv::resize(image, image, cv::Size(imgW, imgH));

    vector<float> imgData;
    imgData.resize(3 * imgW * imgH);
    for (int k = 0; k < 3; k++)
    {
        for (int i = 0; i < imgH; i++)
        {
            for (int j = 0; j < imgW; j++)
            {
                imgData[k * imgW * imgH + i * imgW + j] = image.at<cv::Vec3b>(i, j)[3 - k] / 255.0;
            }
        }
    }

    Ort::Env env(ORT_LOGGING_LEVEL_ERROR, "yolo11");
    OrtCUDAProviderOptions cudaOptions;
    cudaOptions.device_id = 0;
    Ort::SessionOptions sessionOptions;
    sessionOptions.SetIntraOpNumThreads(1);
    sessionOptions.AppendExecutionProvider_CUDA(cudaOptions);
    sessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL);
    static Ort::Session yolo_session(env, L"yolo11l.onnx", sessionOptions);

    vector<int64_t> inputShape{ 1, 3, imgH, imgW };

    Ort::MemoryInfo memoryInfo = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);
    Ort::Value inputTensor = Ort::Value::CreateTensor<float>(memoryInfo, imgData.data(), imgData.size(), inputShape.data(), inputShape.size());

    const char* inputNames[] = { "images" };
    const char* outputNames[] = { "output0" };
    Ort::RunOptions runOptions;

    vector<Ort::Value> out = yolo_session.Run(runOptions, inputNames, &inputTensor, 1, outputNames, 1);
    std::vector<int64_t> shape = out[0].GetTensorTypeAndShapeInfo().GetShape();
    float* data = (float*)out[0].GetTensorMutableData<void>();  //data shape {1,84,8400}

    /////////////////////////////postprocess////////////////////////////////////////////
    std::vector<CDetectBox> allBoxes, nmsBoxes;
    allBoxes.reserve(200);
    for (int w = 0; w < 8400; w++)
    {
        float maxScore = 0;
        int id = -1;
        for (int h = 4; h < 84; h++)
        {
            if (maxScore < data[h * 8400 + w])
            {
                maxScore = data[h * 8400 + w];
                id = h - 4;
            }
        }

        if (maxScore > 0.3)
        {
            CDetectBox box;
            box.id = id;
            box.score = maxScore;
            box.x1 = data[0 * 8400 + w] - data[2 * 8400 + w] / 2;
            box.y1 = data[1 * 8400 + w] - data[3 * 8400 + w] / 2;
            box.x2 = data[0 * 8400 + w] + data[2 * 8400 + w] / 2;
            box.y2 = data[1 * 8400 + w] + data[3 * 8400 + w] / 2;
            allBoxes.emplace_back(box);
        }
    }

    std::sort(allBoxes.begin(), allBoxes.end(), [](CDetectBox& a, CDetectBox& b) { return a.score > b.score; });

    while (!allBoxes.empty())        //nms
    {
        nmsBoxes.emplace_back(allBoxes.front());
        auto it = allBoxes.begin();
        allBoxes.erase(it);

        for (auto it = allBoxes.begin(); it != allBoxes.end();)
        {
            float iou = compute_iou(nmsBoxes.back(), *it);
            if (iou > 0.5)
            {
                it = allBoxes.erase(it);
            }
            else
            {
                it++;
            }
        }
    }
    /////////////////////////////////////////////////////////////////////////

    for (int i = 0; i < nmsBoxes.size(); i++)
    {
        int x = nmsBoxes[i].x1;
        int y = nmsBoxes[i].y1;
        int w = nmsBoxes[i].x2 - nmsBoxes[i].x1;
        int h = nmsBoxes[i].y2 - nmsBoxes[i].y1;

        printf("%d %f %f %f %f %f\n", nmsBoxes[i].id, nmsBoxes[i].score, nmsBoxes[i].x1, nmsBoxes[i].y1, nmsBoxes[i].x2, nmsBoxes[i].y2);
        cv::Rect rect(x, y, w, h);
        cv::rectangle(image, rect, cv::Scalar(0, 255, 0), 1, 8, 0);
    }
    cv::imshow("img", image);
    cv::waitKey(0);
    return 0;
}

结果如下:

 

posted @ 2025-02-15 20:40 Dsp Tian 阅读(41) 评论(0) 推荐(0) 编辑
摘要: 上一篇熟悉了LSTM之后,就可以用这个工具做nlp相关的实验了。 下面两组代码是使用LSTM做文本分类的实验: 一、更多使用自定义方法做文本分类的代码,有几个特点: 1. 数据集是根据csv文件格式解析的,用的自定义数据类。 2. 使用jieba分词。 3. 数据对齐使用了collate_fn和pa 阅读全文
posted @ 2025-02-03 16:22 Dsp Tian 阅读(9) 评论(0) 推荐(0) 编辑
摘要: 三个网络的架构图: RNN: LSTM: GRU: 特性对比列表: 特性 RNN LSTM GRU 门控数量 无 3门(输入/遗忘/输出) 2门(更新/重置) 记忆机制 仅隐藏状态ht 显式状态Ct + 隐藏状态ht 隐式记忆(通过门控更新状态) 核心操作 直接状态传递 门控细胞状态更新 门控候选状 阅读全文
posted @ 2025-02-03 13:37 Dsp Tian 阅读(38) 评论(0) 推荐(0) 编辑
摘要: 在深度学习中,归一化操作有BN,LN,GN,IN这几种形式,下表给出了各种方法的主要区别: 归一化方法 计算维度 固定维度 适用场景 特点 BatchNorm 沿 (N, H, W) 对每个通道独立计算 Channel 卷积神经网络 依赖批次大小,训练和推理行为不同 LayerNorm 沿 (C, 阅读全文
posted @ 2025-01-28 14:36 Dsp Tian 阅读(21) 评论(0) 推荐(0) 编辑
摘要: onnx对于einsum算子是在opset12之后才支持的,但是有些芯片对于onnx量化的支持只到opset11版本,遇到这种情况可以使用matmul替换einsum。 流程通常是将tensor先view成三维,然后将第一个tensor待消掉维度permute到最后一维,第二个tensor待消掉的维 阅读全文
posted @ 2025-01-26 22:31 Dsp Tian 阅读(25) 评论(0) 推荐(0) 编辑
摘要: 将onnx模型参数从fp32转为fp16,可以减少一半模型大小。 import onnx from onnxconverter_common import float16 model = onnx.load("fp32.onnx") model_fp16 = float16.convert_floa 阅读全文
posted @ 2025-01-25 15:36 Dsp Tian 阅读(29) 评论(0) 推荐(0) 编辑
摘要: 下面实现了深度学习中的几种优化器,包括SGD,Momentum, Nesterov,AdaGrad,RMSProp,AdaDelta,Adam和AdamW。 代码如下: import torch import torch.nn as nn from torchvision import transf 阅读全文
posted @ 2025-01-04 20:23 Dsp Tian 阅读(14) 评论(0) 推荐(0) 编辑
摘要: 有时需要向linux系统scp数据时报出Read-only file system。 可以用下面命令解决: mount -o remount rw /home 阅读全文
posted @ 2024-12-28 20:25 Dsp Tian 阅读(130) 评论(0) 推荐(0) 编辑
摘要: 简单训练了一个模型,可以实现超分辨率效果。模型在这里。 模型用了一些卷积层,最后接一个PixelShuffle算子。 训练数据是原始图像resize后的亮度通道。 标签是原始图像的亮度通道。 损失函数设为MSE。 代码如下: import torch import torch.nn as nn im 阅读全文
posted @ 2024-12-21 21:48 Dsp Tian 阅读(19) 评论(0) 推荐(0) 编辑
摘要: 截止这篇笔记,llama.cpp主分支暂时不支持部署VL模型,需要切到一个分支上编译。部署流程整理自这个帖子。 部署流程如下: 1. 在modelscope上将Qwen2-VL-7B-Instruct下载下来。 2. 下载llama.cpp,需要下载这个分支。 3. 编译llama.cpp,流程和上 阅读全文
posted @ 2024-11-17 23:46 Dsp Tian 阅读(1605) 评论(0) 推荐(0) 编辑
点击右上角即可分享
微信分享提示