【发布时间】:2019-01-17 14:38:05
【问题描述】:
我想做的是:
- 将输入浮点数乘以一个固定因子。
- 将它们转换为 8 位有符号字符。
请注意,大多数输入的绝对值范围都很小,例如 [-6, 6],因此固定因子可以将它们映射到 [-127, 127]。
我只处理 avx2 指令集,因此不能使用像 _mm256_cvtepi32_epi8 这样的内在函数。我想使用_mm256_packs_epi16,但它将两个输入混合在一起。 :(
我还编写了一些将 32 位浮点数转换为 16 位整数的代码,它完全符合我的要求。
void Quantize(const float* input, __m256i* output, float quant_mult, int num_rows, int width) {
// input is a matrix actuaaly, num_rows and width represent the number of rows and columns of the matrix
assert(width % 16 == 0);
int num_input_chunks = width / 16;
__m256 avx2_quant_mult = _mm256_set_ps(quant_mult, quant_mult, quant_mult, quant_mult,
quant_mult, quant_mult, quant_mult, quant_mult);
for (int i = 0; i < num_rows; ++i) {
const float* input_row = input + i * width;
__m256i* output_row = output + i * num_input_chunks;
for (int j = 0; j < num_input_chunks; ++j) {
const float* x = input_row + j * 16;
// Process 16 floats at once, since each __m256i can contain 16 16-bit integers.
__m256 f_0 = _mm256_loadu_ps(x);
__m256 f_1 = _mm256_loadu_ps(x + 8);
__m256 m_0 = _mm256_mul_ps(f_0, avx2_quant_mult);
__m256 m_1 = _mm256_mul_ps(f_1, avx2_quant_mult);
__m256i i_0 = _mm256_cvtps_epi32(m_0);
__m256i i_1 = _mm256_cvtps_epi32(m_1);
*(output_row + j) = _mm256_packs_epi32(i_0, i_1);
}
}
}
欢迎任何帮助,非常感谢!
【问题讨论】:
-
截断可以吗?使用
_mm256_shuffle_epi8。否则使用pack(same,same),或者更好地将4个浮点向量打包成int8_t的1个向量,分多个步骤:2x epi32和1x epi16。 (然后使用单个vpermq修复通道内排序)。使用 128 位epi32的示例参见 SSE - AVX conversion from double to char ->epi8 -
车道交叉修正类似于 float->int16 的情况:How can I convert a vector of float to short int using avx instructions?。奇怪的是,
_mm256_packs_epi16的 SO(除此之外)没有命中,因此不存在与此完全相同的副本。 -
@PeterCordes 截断没问题。顺便说一句,你能告诉我哪个解决方案最快,吞吐量是绝对标准吗?谢谢!
-
你有多个输入浮点向量,所以 2x vpackssdw + 1x vpacksswb + 1x vpermd 从 4 个输入向量中产生 1 个宽向量优于 4x vpshufb + 4x vpermd + 4x 存储。
标签: c x86 simd intrinsics avx2