Skip to content

Commit 7cbd610

Browse files
authored
vulkan/cpu: Support f16 as SET_ROWS src. (ggml-org#25432)
* vulkan/cpu: Support f16 as SET_ROWS src. This adds full support for f16 SET_ROWS (equivalent to f32) to vulkan and CPU backends, and adds more backend tests. * Set DenormPreserve 16 when supported, to try to fix failures on Intel * tune error threshold * update metal supports_op
1 parent 8ff8c42 commit 7cbd610

7 files changed

Lines changed: 153 additions & 103 deletions

File tree

ggml/src/ggml-cpu/ggml-cpu.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2863,6 +2863,12 @@ struct ggml_cplan ggml_graph_plan(
28632863
cur = ggml_type_size(GGML_TYPE_F32) * node->src[0]->ne[0] * n_tasks;
28642864
}
28652865
} break;
2866+
case GGML_OP_SET_ROWS:
2867+
{
2868+
if (node->src[0]->type == GGML_TYPE_F16 && node->type != GGML_TYPE_F16) {
2869+
cur = ggml_type_size(GGML_TYPE_F32) * node->src[0]->ne[0] * n_tasks;
2870+
}
2871+
} break;
28662872
case GGML_OP_SOFT_MAX:
28672873
case GGML_OP_ROPE:
28682874
case GGML_OP_ROPE_BACK:

ggml/src/ggml-cpu/ops.cpp

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5041,7 +5041,7 @@ static void ggml_compute_forward_set_rows_impl(
50415041
assert(ne0 == nc);
50425042
assert(ne2 == ne02);
50435043
assert(ne3 == ne03);
5044-
GGML_ASSERT(src0->type == GGML_TYPE_F32 || (src0->type == GGML_TYPE_F16 && dst->type == GGML_TYPE_F16));
5044+
GGML_ASSERT(src0->type == GGML_TYPE_F32 || src0->type == GGML_TYPE_F16);
50455045
assert(ne02 % ne11 == 0);
50465046
assert(ne03 % ne12 == 0);
50475047

@@ -5075,10 +5075,19 @@ static void ggml_compute_forward_set_rows_impl(
50755075
(const float *) ((char *) src0->data + i*nb01 + i02*nb02 + i03*nb03),
50765076
((char *) dst->data + i1*nb1 + i02*nb2 + i03*nb3), nc);
50775077
} else if constexpr (std::is_same_v<src_t, ggml_fp16_t>) {
5078-
memcpy(
5078+
if (dst->type == GGML_TYPE_F16) {
5079+
memcpy(
50795080
((char *) dst->data + i1*nb1 + i02*nb2 + i03*nb3),
50805081
((char *) src0->data + i*nb01 + i02*nb02 + i03*nb03),
50815082
rs);
5083+
} else {
5084+
float * wdata = (float *) params->wdata + (nc + CACHE_LINE_SIZE_F32) * ith;
5085+
ggml_fp16_to_fp32_row(
5086+
(const ggml_fp16_t *) ((char *) src0->data + i*nb01 + i02*nb02 + i03*nb03),
5087+
wdata, nc);
5088+
from_float(wdata,
5089+
((char *) dst->data + i1*nb1 + i02*nb2 + i03*nb3), nc);
5090+
}
50825091
} else {
50835092
GGML_ABORT("src0->type = %d (%s) not supported", src0->type, ggml_type_name(src0->type));
50845093
}
@@ -5107,16 +5116,12 @@ void ggml_compute_forward_set_rows(
51075116
} break;
51085117
case GGML_TYPE_F16:
51095118
{
5110-
if (dst->type == GGML_TYPE_F16) {
5111-
if (src1->type == GGML_TYPE_I64) {
5112-
ggml_compute_forward_set_rows_impl<ggml_fp16_t, int64_t>(params, dst);
5113-
} else if (src1->type == GGML_TYPE_I32) {
5114-
ggml_compute_forward_set_rows_impl<ggml_fp16_t, int32_t>(params, dst);
5115-
} else {
5116-
GGML_ABORT("src1->type = %d (%s) not supported", src1->type, ggml_type_name(src1->type));
5117-
}
5119+
if (src1->type == GGML_TYPE_I64) {
5120+
ggml_compute_forward_set_rows_impl<ggml_fp16_t, int64_t>(params, dst);
5121+
} else if (src1->type == GGML_TYPE_I32) {
5122+
ggml_compute_forward_set_rows_impl<ggml_fp16_t, int32_t>(params, dst);
51185123
} else {
5119-
GGML_ABORT("dst->type = %d (%s) not supported with src0->type = %d (%s)", dst->type, ggml_type_name(dst->type), src0->type, ggml_type_name(src0->type));
5124+
GGML_ABORT("src1->type = %d (%s) not supported", src1->type, ggml_type_name(src1->type));
51205125
}
51215126
} break;
51225127
default:

ggml/src/ggml-metal/ggml-metal-device.m

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1340,7 +1340,11 @@ bool ggml_metal_device_supports_op(ggml_metal_device_t dev, const struct ggml_te
13401340
return op->src[0]->type != GGML_TYPE_NVFP4;
13411341
case GGML_OP_SET_ROWS:
13421342
{
1343-
if (op->src[0]->type != GGML_TYPE_F32 && op->src[0]->type != GGML_TYPE_F16) {
1343+
if (op->src[0]->type == GGML_TYPE_F16) {
1344+
return op->type == GGML_TYPE_F16;
1345+
}
1346+
1347+
if (op->src[0]->type != GGML_TYPE_F32) {
13441348
return false;
13451349
}
13461350

ggml/src/ggml-vulkan/ggml-vulkan.cpp

Lines changed: 75 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,7 @@ struct vk_device_struct {
723723
bool uma;
724724
bool prefer_host_memory;
725725
bool float_controls_rte_fp16;
726+
bool float_controls_denorm_preserve_fp16;
726727
bool subgroup_basic;
727728
bool subgroup_arithmetic;
728729
bool subgroup_shuffle;
@@ -868,8 +869,9 @@ struct vk_device_struct {
868869
vk_pipeline pipeline_cpy_f32_quant[GGML_TYPE_COUNT];
869870
vk_pipeline pipeline_cpy_quant_f32[GGML_TYPE_COUNT];
870871
vk_pipeline pipeline_cpy_transpose_16, pipeline_cpy_transpose_32;
871-
vk_pipeline pipeline_set_rows_i32[GGML_TYPE_COUNT];
872-
vk_pipeline pipeline_set_rows_i64[GGML_TYPE_COUNT];
872+
// [src0 0=fp32,1=fp16][dst]
873+
vk_pipeline pipeline_set_rows_i32[2][GGML_TYPE_COUNT];
874+
vk_pipeline pipeline_set_rows_i64[2][GGML_TYPE_COUNT];
873875
vk_pipeline pipeline_norm_f32;
874876
vk_pipeline pipeline_group_norm_f32;
875877
vk_pipeline pipeline_rms_norm_f32;
@@ -2595,10 +2597,10 @@ static void ggml_vk_create_pipeline_func(vk_device& device, vk_pipeline& pipelin
25952597

25962598
vk::ShaderModuleCreateInfo shader_module_create_info({}, spv_size, reinterpret_cast<const uint32_t *>(spv_data));
25972599

2598-
// Patch SPIR-V to enable RTE rounding for FP16, avoiding the need for
2599-
// separate shader variants compiled with -DRTE16.
2600+
// Patch SPIR-V to enable supported FP16 float controls, avoiding the need
2601+
// for separate shader variants.
26002602
std::vector<uint32_t> spirv;
2601-
if (device->float_controls_rte_fp16) {
2603+
if (device->float_controls_rte_fp16 || device->float_controls_denorm_preserve_fp16) {
26022604
const uint32_t* spv_words = reinterpret_cast<const uint32_t *>(spv_data);
26032605
size_t word_count = spv_size / sizeof(uint32_t);
26042606
spirv.assign(spv_words, spv_words + word_count);
@@ -2635,9 +2637,17 @@ static void ggml_vk_create_pipeline_func(vk_device& device, vk_pipeline& pipelin
26352637

26362638
// Insert from latest position first so earlier indices stay valid.
26372639

2638-
// OpExecutionMode %entrypoint RoundingModeRTE 16
2639-
uint32_t exec_mode[] = { (4u << spv::WordCountShift) | spv::OpExecutionMode, entry_point_id, spv::ExecutionModeRoundingModeRTE, 16 };
2640-
spirv.insert(spirv.begin() + exec_insert_pos, std::begin(exec_mode), std::end(exec_mode));
2640+
if (device->float_controls_rte_fp16) {
2641+
// OpExecutionMode %entrypoint RoundingModeRTE 16
2642+
uint32_t exec_mode[] = { (4u << spv::WordCountShift) | spv::OpExecutionMode, entry_point_id, spv::ExecutionModeRoundingModeRTE, 16 };
2643+
spirv.insert(spirv.begin() + exec_insert_pos, std::begin(exec_mode), std::end(exec_mode));
2644+
}
2645+
2646+
if (device->float_controls_denorm_preserve_fp16) {
2647+
// OpExecutionMode %entrypoint DenormPreserve 16
2648+
uint32_t exec_mode[] = { (4u << spv::WordCountShift) | spv::OpExecutionMode, entry_point_id, spv::ExecutionModeDenormPreserve, 16 };
2649+
spirv.insert(spirv.begin() + exec_insert_pos, std::begin(exec_mode), std::end(exec_mode));
2650+
}
26412651

26422652
// OpExtension "SPV_KHR_float_controls"
26432653
const char ext_str[] = "SPV_KHR_float_controls";
@@ -2647,9 +2657,17 @@ static void ggml_vk_create_pipeline_func(vk_device& device, vk_pipeline& pipelin
26472657
memcpy(&extension[1], ext_str, sizeof(ext_str));
26482658
spirv.insert(spirv.begin() + ext_insert_pos, extension.begin(), extension.end());
26492659

2650-
// OpCapability RoundingModeRTE
2651-
uint32_t capability[] = { (2u << spv::WordCountShift) | spv::OpCapability, spv::CapabilityRoundingModeRTE };
2652-
spirv.insert(spirv.begin() + cap_insert_pos, std::begin(capability), std::end(capability));
2660+
if (device->float_controls_rte_fp16) {
2661+
// OpCapability RoundingModeRTE
2662+
uint32_t capability[] = { (2u << spv::WordCountShift) | spv::OpCapability, spv::CapabilityRoundingModeRTE };
2663+
spirv.insert(spirv.begin() + cap_insert_pos, std::begin(capability), std::end(capability));
2664+
}
2665+
2666+
if (device->float_controls_denorm_preserve_fp16) {
2667+
// OpCapability DenormPreserve
2668+
uint32_t capability[] = { (2u << spv::WordCountShift) | spv::OpCapability, spv::CapabilityDenormPreserve };
2669+
spirv.insert(spirv.begin() + cap_insert_pos, std::begin(capability), std::end(capability));
2670+
}
26532671

26542672
shader_module_create_info = vk::ShaderModuleCreateInfo({}, spirv.size() * sizeof(uint32_t), spirv.data());
26552673
}
@@ -5187,20 +5205,22 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
51875205
ggml_vk_create_pipeline(device, device->pipeline_cpy_f32_quant[GGML_TYPE_Q8_0], "cpy_f32_q8_0", cpy_f32_q8_0_len, cpy_f32_q8_0_data, "main", 2, sizeof(vk_op_unary_push_constants), {32, 1, 1}, {}, 1);
51885206
ggml_vk_create_pipeline(device, device->pipeline_cpy_f32_quant[GGML_TYPE_IQ4_NL], "cpy_f32_iq4_nl", cpy_f32_iq4_nl_len, cpy_f32_iq4_nl_data, "main", 2, sizeof(vk_op_unary_push_constants), {32, 1, 1}, {}, 1);
51895207

5190-
#define SET_ROWS(itype) \
5191-
ggml_vk_create_pipeline(device, device->pipeline_set_rows ## itype [GGML_TYPE_F32], "set_rows_f32" #itype, set_rows_f32 ## itype ## _len, set_rows_f32 ## itype ## _data, "main", 3, sizeof(vk_op_binary_push_constants), {1, 1, 1}, {1}, 1, true); \
5192-
ggml_vk_create_pipeline(device, device->pipeline_set_rows ## itype [GGML_TYPE_F16], "set_rows_f16" #itype, set_rows_f16 ## itype ## _len, set_rows_f16 ## itype ## _data, "main", 3, sizeof(vk_op_binary_push_constants), {1, 1, 1}, {1}, 1, true); \
5193-
ggml_vk_create_pipeline(device, device->pipeline_set_rows ## itype [GGML_TYPE_BF16], "set_rows_bf16" #itype, set_rows_bf16 ## itype ## _len, set_rows_bf16 ## itype ## _data, "main", 3, sizeof(vk_op_binary_push_constants), {1, 1, 1}, {1}, 1, true); \
5194-
ggml_vk_create_pipeline(device, device->pipeline_set_rows ## itype [GGML_TYPE_Q1_0], "set_rows_q1_0" #itype, set_rows_q1_0 ## itype ## _len, set_rows_q1_0 ## itype ## _data, "main", 3, sizeof(vk_op_binary_push_constants), {1, 1, 1}, {1}, 1, true); \
5195-
ggml_vk_create_pipeline(device, device->pipeline_set_rows ## itype [GGML_TYPE_Q4_0], "set_rows_q4_0" #itype, set_rows_q4_0 ## itype ## _len, set_rows_q4_0 ## itype ## _data, "main", 3, sizeof(vk_op_binary_push_constants), {1, 1, 1}, {1}, 1, true); \
5196-
ggml_vk_create_pipeline(device, device->pipeline_set_rows ## itype [GGML_TYPE_Q4_1], "set_rows_q4_1" #itype, set_rows_q4_1 ## itype ## _len, set_rows_q4_1 ## itype ## _data, "main", 3, sizeof(vk_op_binary_push_constants), {1, 1, 1}, {1}, 1, true); \
5197-
ggml_vk_create_pipeline(device, device->pipeline_set_rows ## itype [GGML_TYPE_Q5_0], "set_rows_q5_0" #itype, set_rows_q5_0 ## itype ## _len, set_rows_q5_0 ## itype ## _data, "main", 3, sizeof(vk_op_binary_push_constants), {1, 1, 1}, {1}, 1, true); \
5198-
ggml_vk_create_pipeline(device, device->pipeline_set_rows ## itype [GGML_TYPE_Q5_1], "set_rows_q5_1" #itype, set_rows_q5_1 ## itype ## _len, set_rows_q5_1 ## itype ## _data, "main", 3, sizeof(vk_op_binary_push_constants), {1, 1, 1}, {1}, 1, true); \
5199-
ggml_vk_create_pipeline(device, device->pipeline_set_rows ## itype [GGML_TYPE_Q8_0], "set_rows_q8_0" #itype, set_rows_q8_0 ## itype ## _len, set_rows_q8_0 ## itype ## _data, "main", 3, sizeof(vk_op_binary_push_constants), {1, 1, 1}, {1}, 1, true); \
5200-
ggml_vk_create_pipeline(device, device->pipeline_set_rows ## itype [GGML_TYPE_IQ4_NL], "set_rows_iq4_nl" #itype, set_rows_iq4_nl ## itype ## _len, set_rows_iq4_nl ## itype ## _data, "main", 3, sizeof(vk_op_binary_push_constants), {1, 1, 1}, {1}, 1, true);
5201-
5202-
SET_ROWS(_i32)
5203-
SET_ROWS(_i64)
5208+
#define SET_ROWS(src_idx, src, itype) \
5209+
ggml_vk_create_pipeline(device, device->pipeline_set_rows ## itype [src_idx][GGML_TYPE_F32], "set_rows_" #src "_f32" #itype, set_rows_ ## src ## _f32 ## itype ## _len, set_rows_ ## src ## _f32 ## itype ## _data, "main", 3, sizeof(vk_op_binary_push_constants), {1, 1, 1}, {1}, 1, true); \
5210+
ggml_vk_create_pipeline(device, device->pipeline_set_rows ## itype [src_idx][GGML_TYPE_F16], "set_rows_" #src "_f16" #itype, set_rows_ ## src ## _f16 ## itype ## _len, set_rows_ ## src ## _f16 ## itype ## _data, "main", 3, sizeof(vk_op_binary_push_constants), {1, 1, 1}, {1}, 1, true); \
5211+
ggml_vk_create_pipeline(device, device->pipeline_set_rows ## itype [src_idx][GGML_TYPE_BF16], "set_rows_" #src "_bf16" #itype, set_rows_ ## src ## _bf16 ## itype ## _len, set_rows_ ## src ## _bf16 ## itype ## _data, "main", 3, sizeof(vk_op_binary_push_constants), {1, 1, 1}, {1}, 1, true); \
5212+
ggml_vk_create_pipeline(device, device->pipeline_set_rows ## itype [src_idx][GGML_TYPE_Q1_0], "set_rows_" #src "_q1_0" #itype, set_rows_ ## src ## _q1_0 ## itype ## _len, set_rows_ ## src ## _q1_0 ## itype ## _data, "main", 3, sizeof(vk_op_binary_push_constants), {1, 1, 1}, {1}, 1, true); \
5213+
ggml_vk_create_pipeline(device, device->pipeline_set_rows ## itype [src_idx][GGML_TYPE_Q4_0], "set_rows_" #src "_q4_0" #itype, set_rows_ ## src ## _q4_0 ## itype ## _len, set_rows_ ## src ## _q4_0 ## itype ## _data, "main", 3, sizeof(vk_op_binary_push_constants), {1, 1, 1}, {1}, 1, true); \
5214+
ggml_vk_create_pipeline(device, device->pipeline_set_rows ## itype [src_idx][GGML_TYPE_Q4_1], "set_rows_" #src "_q4_1" #itype, set_rows_ ## src ## _q4_1 ## itype ## _len, set_rows_ ## src ## _q4_1 ## itype ## _data, "main", 3, sizeof(vk_op_binary_push_constants), {1, 1, 1}, {1}, 1, true); \
5215+
ggml_vk_create_pipeline(device, device->pipeline_set_rows ## itype [src_idx][GGML_TYPE_Q5_0], "set_rows_" #src "_q5_0" #itype, set_rows_ ## src ## _q5_0 ## itype ## _len, set_rows_ ## src ## _q5_0 ## itype ## _data, "main", 3, sizeof(vk_op_binary_push_constants), {1, 1, 1}, {1}, 1, true); \
5216+
ggml_vk_create_pipeline(device, device->pipeline_set_rows ## itype [src_idx][GGML_TYPE_Q5_1], "set_rows_" #src "_q5_1" #itype, set_rows_ ## src ## _q5_1 ## itype ## _len, set_rows_ ## src ## _q5_1 ## itype ## _data, "main", 3, sizeof(vk_op_binary_push_constants), {1, 1, 1}, {1}, 1, true); \
5217+
ggml_vk_create_pipeline(device, device->pipeline_set_rows ## itype [src_idx][GGML_TYPE_Q8_0], "set_rows_" #src "_q8_0" #itype, set_rows_ ## src ## _q8_0 ## itype ## _len, set_rows_ ## src ## _q8_0 ## itype ## _data, "main", 3, sizeof(vk_op_binary_push_constants), {1, 1, 1}, {1}, 1, true); \
5218+
ggml_vk_create_pipeline(device, device->pipeline_set_rows ## itype [src_idx][GGML_TYPE_IQ4_NL], "set_rows_" #src "_iq4_nl" #itype, set_rows_ ## src ## _iq4_nl ## itype ## _len, set_rows_ ## src ## _iq4_nl ## itype ## _data, "main", 3, sizeof(vk_op_binary_push_constants), {1, 1, 1}, {1}, 1, true);
5219+
5220+
SET_ROWS(0, f32, _i32)
5221+
SET_ROWS(0, f32, _i64)
5222+
SET_ROWS(1, f16, _i32)
5223+
SET_ROWS(1, f16, _i64)
52045224
#undef SET_ROWS
52055225

52065226

@@ -6031,6 +6051,7 @@ static vk_device ggml_vk_get_device(size_t idx) {
60316051
device->shader_core_count = 0;
60326052
}
60336053
device->float_controls_rte_fp16 = vk12_props.shaderRoundingModeRTEFloat16;
6054+
device->float_controls_denorm_preserve_fp16 = vk12_props.shaderDenormPreserveFloat16;
60346055

60356056
device->subgroup_basic = (vk11_props.subgroupSupportedStages & vk::ShaderStageFlagBits::eCompute) &&
60366057
(vk11_props.subgroupSupportedOperations & vk::SubgroupFeatureFlagBits::eBasic);
@@ -10843,10 +10864,17 @@ static vk_pipeline ggml_vk_op_get_pipeline(ggml_backend_vk_context * ctx, const
1084310864
case GGML_OP_DUP:
1084410865
return ggml_vk_get_cpy_pipeline(ctx, src0, dst, dst->type);
1084510866
case GGML_OP_SET_ROWS:
10846-
if (src1->type == GGML_TYPE_I64) {
10847-
return ctx->device->pipeline_set_rows_i64[dst->type];
10848-
} else {
10849-
return ctx->device->pipeline_set_rows_i32[dst->type];
10867+
{
10868+
if (src0->type != GGML_TYPE_F32 && src0->type != GGML_TYPE_F16) {
10869+
return nullptr;
10870+
}
10871+
const int src_idx = src0->type == GGML_TYPE_F16;
10872+
if (src1->type == GGML_TYPE_I64) {
10873+
return ctx->device->pipeline_set_rows_i64[src_idx][dst->type];
10874+
} else if (src1->type == GGML_TYPE_I32) {
10875+
return ctx->device->pipeline_set_rows_i32[src_idx][dst->type];
10876+
}
10877+
return nullptr;
1085010878
}
1085110879
case GGML_OP_SILU_BACK:
1085210880
if (src0->type == GGML_TYPE_F32 && src1->type == GGML_TYPE_F32 && dst->type == GGML_TYPE_F32) {
@@ -17500,24 +17528,25 @@ static bool ggml_backend_vk_device_supports_op(ggml_backend_dev_t dev, const ggm
1750017528
return op->type == GGML_TYPE_F32 && op->src[0]->type == GGML_TYPE_F32;
1750117529
case GGML_OP_SET_ROWS:
1750217530
{
17503-
if (op->src[0]->type == GGML_TYPE_F32) {
17504-
switch (op->type) {
17505-
case GGML_TYPE_F32:
17506-
case GGML_TYPE_F16:
17507-
case GGML_TYPE_BF16:
17508-
case GGML_TYPE_Q1_0:
17509-
case GGML_TYPE_Q4_0:
17510-
case GGML_TYPE_Q4_1:
17511-
case GGML_TYPE_Q5_0:
17512-
case GGML_TYPE_Q5_1:
17513-
case GGML_TYPE_Q8_0:
17514-
case GGML_TYPE_IQ4_NL:
17515-
return true;
17516-
default:
17517-
return false;
17518-
}
17531+
if ((op->src[0]->type != GGML_TYPE_F32 && op->src[0]->type != GGML_TYPE_F16) ||
17532+
(op->src[1]->type != GGML_TYPE_I32 && op->src[1]->type != GGML_TYPE_I64)) {
17533+
return false;
17534+
}
17535+
switch (op->type) {
17536+
case GGML_TYPE_F32:
17537+
case GGML_TYPE_F16:
17538+
case GGML_TYPE_BF16:
17539+
case GGML_TYPE_Q1_0:
17540+
case GGML_TYPE_Q4_0:
17541+
case GGML_TYPE_Q4_1:
17542+
case GGML_TYPE_Q5_0:
17543+
case GGML_TYPE_Q5_1:
17544+
case GGML_TYPE_Q8_0:
17545+
case GGML_TYPE_IQ4_NL:
17546+
return true;
17547+
default:
17548+
return false;
1751917549
}
17520-
return false;
1752117550
}
1752217551
case GGML_OP_CONT:
1752317552
case GGML_OP_CPY:

0 commit comments

Comments
 (0)