| 71 | } |
| 72 | |
| 73 | core::TensorValue LinearModule::build( |
| 74 | core::ModuleBuildContext & ctx, |
| 75 | const core::TensorValue & input, |
| 76 | const LinearWeights & weights) const { |
| 77 | if (ctx.ggml == nullptr) { |
| 78 | throw std::runtime_error("ModuleBuildContext.ggml is null"); |
| 79 | } |
| 80 | |
| 81 | core::validate_rank_between(input, 1, core::kMaxTensorRank, "input"); |
| 82 | core::validate_last_dim(input, config_.in_features, "input"); |
| 83 | validate_weight_shape(config_, weights); |
| 84 | |
| 85 | const core::TensorValue contiguous_input = core::ensure_backend_addressable_layout(ctx, input); |
| 86 | |
| 87 | const core::TensorShape matrix_input_shape = flatten_to_matrix_shape(contiguous_input.shape); |
| 88 | core::TensorValue matrix_input = core::reshape_tensor(ctx, contiguous_input, matrix_input_shape); |
| 89 | |
| 90 | ggml_tensor * projected_raw = ggml_mul_mat(ctx.ggml, weights.weight.tensor, matrix_input.tensor); |
| 91 | if (config_.precision != GGML_PREC_DEFAULT) { |
| 92 | ggml_mul_mat_set_prec(projected_raw, config_.precision); |
| 93 | } |
| 94 | core::TensorValue projected = core::wrap_tensor( |
| 95 | projected_raw, |
| 96 | core::TensorShape::from_dims({matrix_input_shape.at(0), config_.out_features}), |
| 97 | GGML_TYPE_F32); |
| 98 | |
| 99 | if (config_.use_bias) { |
| 100 | ggml_tensor * biased_raw = ggml_add(ctx.ggml, projected.tensor, weights.bias->tensor); |
| 101 | projected = core::wrap_tensor( |
| 102 | biased_raw, |
| 103 | core::TensorShape::from_dims({matrix_input_shape.at(0), config_.out_features}), |
| 104 | GGML_TYPE_F32); |
| 105 | } |
| 106 | |
| 107 | return core::reshape_tensor(ctx, projected, input.shape.with_last_dim(config_.out_features)); |
| 108 | } |
| 109 | |
| 110 | const core::ModuleSchema & LinearModule::static_schema() noexcept { |
| 111 | return kLinearSchema; |
nothing calls this directly
no test coverage detected