手动张量化数据时如何创建自定义TensorFloat16Bit?
如何正确创建并填充TensorFloat16Bit以适配FP16 ONNX模型?
我来帮你解决这个TensorFloat16Bit的绑定问题——核心原因是你没处理好FP16数据的字节长度和格式转换,下面是具体的修改方案:
首先理清问题根源:
TensorFloat16Bit的每个元素是2字节的FP16格式(对应uint16_t),而原来的TensorFloat是4字节的32位float,所以它的buffer容量正好是前者的一半。你之前直接用float*去访问,必然会越界触发访问违规。ITensorNative::GetBuffer确实只支持返回BYTE**或uint8_t**,所以需要先拿到字节指针,再转换成uint16_t*来操作FP16数据。
接下来是修改后的完整代码,我会标注关键改动点:
#include <cstdint> // 推荐用DirectXMath提供的成熟FP16转换函数 #include <DirectXMath.h> using namespace DirectX; // 若无法使用DirectXMath,可替换为其他可靠的float转FP16实现 uint16_t float_to_half(float f) { return XMConvertFloatToHalf(f); } // ... 你的其他业务代码 ... std::vector<int64_t> shape = { 1, channels, height , width }; uint16_t* pFP16Tensor = nullptr; uint32_t uCapacity; // 1. 创建TensorFloat16Bit代替原TensorFloat TensorFloat16Bit tf16 = TensorFloat16Bit::Create(shape); com_ptr<ITensorNative> itn = tf16.as<ITensorNative>(); CHECK_HRESULT(itn->GetBuffer(reinterpret_cast<BYTE**>(&pFP16Tensor), &uCapacity)); // 2. 转换BGRA数据到FP16格式的BGR张量(丢弃Alpha通道) if (BitmapPixelFormat::Bgra8 == pixelFormat) { const uint32_t pixelCount = height * width; for (UINT32 i = 0; i < size; i += 4) { UINT32 pixelInd = i / 4; // 先将0-255像素值归一化到0-1的float范围(模型通常期望归一化输入) float b_val = static_cast<float>(pData[i]) / 255.0f; float g_val = static_cast<float>(pData[i+1]) / 255.0f; float r_val = static_cast<float>(pData[i+2]) / 255.0f; // 填充对应通道的FP16编码数据 pFP16Tensor[pixelInd] = float_to_half(b_val); pFP16Tensor[pixelCount + pixelInd] = float_to_half(g_val); pFP16Tensor[pixelCount * 2 + pixelInd] = float_to_half(r_val); } }
关键改动说明:
- Tensor类型替换:用
TensorFloat16Bit::Create(shape)创建FP16张量,形状保持不变(形状描述的是维度数量,不是字节数)。 - 指针类型转换:把
GetBuffer返回的BYTE*直接转换成uint16_t*,因为FP16元素占2字节,这样可以直接按元素索引访问,避免字节偏移计算错误。 - 数据格式转换:
- 补上了0-255到0-1的归一化步骤(你原代码遗漏了这一步,模型推理通常需要归一化后的输入)。
- 用成熟的工具函数将32位float转换成16位FP16编码值,避免手动转换引入的精度问题。
- 索引逻辑兼容:通道的索引计算和原代码一致,因为我们是按元素数而非字节数索引,无需调整偏移倍数。
最后提醒:确保你的硬件支持FP16推理(比如支持DirectML的GPU),否则即使创建了FP16张量,模型可能还是会 fallback 到FP32,无法获得预期的性能提升。
内容的提问来源于stack exchange,提问作者Anna Maule
相关产品推荐
相关产品推荐

