You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Microsoft.ML中优化分割网络输出的处理效率?

问题

分割网络输出形状为1×N×K的张量(N为像素总数,K为类别数),每个元素对应像素位置的类别得分。当前用于获取每个像素最优类别的代码可正常运行,但耗时是网络推理的4倍,代码如下:

private int[,] GetClasses(List<DisposableNamedOnnxValue> output)
{            
    Tensor<float> outTensor = output.First().AsTensor<float>();
    
    int[,] classes = new int[frameWidth,frameHeight];

    for (int i = 0; i < frameWidth; ++i)
    {
        for (int j = 0; j < frameHeight; ++j)
        {
            int finalClass = 0;
            float finalClassScore = 0;
            for (int k = 0; k < nClasses; ++k)
            {
                float score = outTensor[0, i * frameHeight + j, k];
                if (score > finalClassScore)
                {
                    finalClassScore = score;
                    finalClass = k;
                }
            }
            classes[i, j] = finalClass;
        }
    }

    return classes;
}

请问在Microsoft.ML中是否有更高效的实现方式?

优化方案

在Microsoft.ML中可以利用内置的张量操作和硬件加速大幅提升性能,主要有两种优化思路:

1. 使用ArgMax内置操作直接获取类别索引

Microsoft.ML的Tensor类原生支持ArgMax方法,能在指定维度上快速找出最大值的索引。该方法底层借助SIMD指令或硬件加速实现,比手动嵌套循环效率高得多:

using Microsoft.ML.OnnxRuntime.Tensors;
using Microsoft.ML.OnnxRuntime;

private int[,] GetClassesOptimized(List<DisposableNamedOnnxValue> output)
{
    Tensor<float> outTensor = output.First().AsTensor<float>();
    
    // 在第2维度(类别维度,索引从0开始)执行ArgMax,得到每个像素的最优类别索引
    Tensor<long> argMaxTensor = outTensor.ArgMax(dimensions: new[] { 2 });
    
    // 将一维ArgMax结果转换为frameWidth×frameHeight的二维数组
    int[,] classes = new int[frameWidth, frameHeight];
    for (int i = 0; i < frameWidth; i++)
    {
        for (int j = 0; j < frameHeight; j++)
        {
            int idx = i * frameHeight + j;
            classes[i, j] = (int)argMaxTensor[0, idx];
        }
    }
    
    return classes;
}

2. 优化内存访问模式

原代码中i * frameHeight + j的索引计算会导致张量访问不连续,降低缓存命中率。可以先转置张量,让同一像素的类别得分连续存储,再配合ArgMax进一步提升效率:

private int[,] GetClassesWithTranspose(List<DisposableNamedOnnxValue> output)
{
    Tensor<float> outTensor = output.First().AsTensor<float>();
    
    // 转置张量,将维度从(1, N, K)转为(1, K, N),让同一像素的类别得分连续排列
    Tensor<float> transposedTensor = outTensor.Transpose(new[] { 0, 2, 1 });
    
    // 在第1维度(原类别维度)执行ArgMax
    Tensor<long> argMaxTensor = transposedTensor.ArgMax(dimensions: new[] { 1 });
    
    // 转换为二维数组
    int[,] classes = new int[frameWidth, frameHeight];
    for (int i = 0; i < frameWidth; i++)
    {
        for (int j = 0; j < frameHeight; j++)
        {
            int idx = i * frameHeight + j;
            classes[i, j] = (int)argMaxTensor[0, idx];
        }
    }
    
    return classes;
}

额外优化建议

  • 避免在循环内重复计算索引值,提前计算并复用可减少不必要的运算开销
  • 如果使用GPU推理,OnnxRuntime会自动将ArgMax操作调度到GPU执行,无需额外代码,能进一步缩短耗时

内容的提问来源于stack exchange,提问作者George

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 06:40:43