| 405 | namespace { |
| 406 | |
| 407 | core::TensorValue build_wavlm_self_attention( |
| 408 | core::ModuleBuildContext & ctx, |
| 409 | const core::TensorValue & hidden_btc, |
| 410 | const core::TensorValue & position_bias, |
| 411 | const core::TensorValue & attention_mask, |
| 412 | const WavlmEncoderWeights & weights, |
| 413 | int64_t layer_index) { |
| 414 | const auto & config = weights.config; |
| 415 | const int64_t batch = hidden_btc.shape.dims[0]; |
| 416 | const int64_t tokens = hidden_btc.shape.dims[1]; |
| 417 | const int64_t head_dim = config.hidden_size / config.num_attention_heads; |
| 418 | const std::string prefix = "encoder.layers." + std::to_string(layer_index) + ".attention"; |
| 419 | |
| 420 | auto q = LinearModule({config.hidden_size, config.hidden_size, true, GGML_PREC_F32}) |
| 421 | .build(ctx, hidden_btc, linear_weights(weights, prefix + ".q_proj")); |
| 422 | auto k = LinearModule({config.hidden_size, config.hidden_size, true, GGML_PREC_F32}) |
| 423 | .build(ctx, hidden_btc, linear_weights(weights, prefix + ".k_proj")); |
| 424 | auto v = LinearModule({config.hidden_size, config.hidden_size, true, GGML_PREC_F32}) |
| 425 | .build(ctx, hidden_btc, linear_weights(weights, prefix + ".v_proj")); |
| 426 | |
| 427 | q = core::reshape_tensor(ctx, contiguous(ctx, q), core::TensorShape::from_dims({batch, tokens, config.num_attention_heads, head_dim})); |
| 428 | k = core::reshape_tensor(ctx, contiguous(ctx, k), core::TensorShape::from_dims({batch, tokens, config.num_attention_heads, head_dim})); |
| 429 | v = core::reshape_tensor(ctx, contiguous(ctx, v), core::TensorShape::from_dims({batch, tokens, config.num_attention_heads, head_dim})); |
| 430 | q = TransposeModule({{0, 2, 1, 3}, 4}).build(ctx, q); |
| 431 | k = TransposeModule({{0, 2, 1, 3}, 4}).build(ctx, k); |
| 432 | v = TransposeModule({{0, 2, 1, 3}, 4}).build(ctx, v); |
| 433 | |
| 434 | auto query_layer = core::reshape_tensor( |
| 435 | ctx, |
| 436 | contiguous(ctx, hidden_btc), |
| 437 | core::TensorShape::from_dims({batch, tokens, config.num_attention_heads, head_dim})); |
| 438 | query_layer = TransposeModule({{0, 2, 1, 3}, 4}).build(ctx, query_layer); |
| 439 | auto gates = LinearModule({head_dim, 8, true, GGML_PREC_F32}) |
| 440 | .build(ctx, query_layer, linear_weights(weights, prefix + ".gru_rel_pos_linear")); |
| 441 | auto gate_a = SliceModule({3, 0, 4}).build(ctx, gates); |
| 442 | auto gate_b = SliceModule({3, 4, 4}).build(ctx, gates); |
| 443 | gate_a = SigmoidModule().build(ctx, ReduceSumModule({3}).build(ctx, gate_a)); |
| 444 | gate_b = SigmoidModule().build(ctx, ReduceSumModule({3}).build(ctx, gate_b)); |
| 445 | gate_a = core::reshape_tensor(ctx, contiguous(ctx, gate_a), core::TensorShape::from_dims({batch, config.num_attention_heads, tokens, 1})); |
| 446 | gate_b = core::reshape_tensor(ctx, contiguous(ctx, gate_b), core::TensorShape::from_dims({batch, config.num_attention_heads, tokens, 1})); |
| 447 | auto rel_const = core::reshape_tensor( |
| 448 | ctx, |
| 449 | require_tensor(weights, prefix + ".gru_rel_pos_const"), |
| 450 | core::TensorShape::from_dims({1, config.num_attention_heads, 1, 1})); |
| 451 | rel_const = RepeatModule({gate_b.shape}).build(ctx, rel_const); |
| 452 | auto gated = MulModule().build(ctx, gate_b, rel_const); |
| 453 | gated = add_scalar(ctx, gated, -1.0F); |
| 454 | gated = MulModule().build(ctx, gate_a, gated); |
| 455 | gated = add_scalar(ctx, gated, 2.0F); |
| 456 | gated = RepeatModule({position_bias.shape}).build(ctx, gated); |
| 457 | auto rel_bias = MulModule().build(ctx, gated, position_bias); |
| 458 | |
| 459 | const auto k_t = TransposeModule({{0, 1, 3, 2}, 4}).build(ctx, k); |
| 460 | auto scores = MatMulModule().build(ctx, q, k_t); |
| 461 | scores = mul_scalar(ctx, scores, static_cast<float>(1.0 / std::sqrt(static_cast<double>(head_dim)))); |
| 462 | scores = add_same(ctx, scores, rel_bias); |
| 463 | auto attn = core::wrap_tensor( |
| 464 | ggml_soft_max_ext(ctx.ggml, contiguous(ctx, scores).tensor, attention_mask.tensor, 1.0F, 0.0F), |
no test coverage detected