| 113 | } |
| 114 | |
| 115 | Status validate_mm(const ITensorInfo &src, |
| 116 | const ITensorInfo &weights, |
| 117 | const ITensorInfo *bias, |
| 118 | const ITensorInfo &dst, |
| 119 | const FullyConnectedLayerInfo &fc_info, |
| 120 | bool use_matmul) |
| 121 | { |
| 122 | // Note : If input is dynamic and data is not batched, use matmul, else use gemm |
| 123 | const bool transpose_weights = fc_info.transpose_weights ? !fc_info.are_weights_reshaped : false; |
| 124 | const bool use_dynamic_gemm = |
| 125 | !use_matmul && !weights.are_values_constant() && transpose_weights; // use dynamic gemm as fallback for matmul |
| 126 | const bool is_quantized = is_data_type_quantized_asymmetric(src.data_type()); |
| 127 | |
| 128 | if (use_matmul) |
| 129 | { |
| 130 | const MatMulInfo m_info = MatMulInfo().adj_rhs(transpose_weights); |
| 131 | |
| 132 | // Note: LHS is reshaped here to match ClMatMul expectations of batch index - From [M, B0, B1] to [M, 1, B0, B1] |
| 133 | TensorInfo lhs_to_use = src.clone()->set_tensor_shape(get_reshaped_matmul_tensor(src.tensor_shape())); |
| 134 | |
| 135 | const GPUTarget gpu_target = CLScheduler::get().target(); |
| 136 | std::unique_ptr<cl_matmul::IClMatMulNativeKernelConfig> t = |
| 137 | cl_matmul::ClMatMulNativeKernelConfigurationFactory::create(gpu_target); |
| 138 | const MatMulKernelInfo kernel_info = t->configure(&lhs_to_use, &weights, m_info); |
| 139 | |
| 140 | return is_quantized ? kernels::ClMatMulLowpNativeKernel::validate(&lhs_to_use, &weights, bias, &dst, |
| 141 | kernel_info, fc_info.activation_info) |
| 142 | : kernels::ClMatMulNativeKernel::validate(&lhs_to_use, &weights, bias, &dst, kernel_info, |
| 143 | fc_info.activation_info); |
| 144 | } |
| 145 | else |
| 146 | { |
| 147 | GEMMLowpOutputStageInfo gemmlowp_output_stage; |
| 148 | ARM_COMPUTE_RETURN_ON_ERROR( |
| 149 | construct_gemmlowp_output_stage(src, weights, dst, gemmlowp_output_stage, fc_info.activation_info)); |
| 150 | |
| 151 | const GEMMInfo &gemm_info = GEMMInfo(false, // is_a_reshaped |
| 152 | false, // is_b_reshaped |
| 153 | !use_dynamic_gemm, // reshape_b_only_on_first_run |
| 154 | 0, // depth_output_gemm3d |
| 155 | false, // reinterpret_input_as_3d |
| 156 | fc_info.retain_internal_weights, // retain_internal_weights |
| 157 | gemmlowp_output_stage, // gemmlowp_output_stage |
| 158 | fc_info.fp_mixed_precision, // fp_mixed_precision |
| 159 | false, // fast_math |
| 160 | true, // broadcast_bias |
| 161 | ActivationLayerInfo()); // activation_info |
| 162 | |
| 163 | if (is_quantized) |
| 164 | { |
| 165 | const UniformQuantizationInfo iq_info = src.quantization_info().uniform(); |
| 166 | const UniformQuantizationInfo wq_info = weights.quantization_info().uniform(); |
| 167 | |
| 168 | // Since we need negative offsets for computing convolution, we need to change QuantizationInfo() |
| 169 | // Extract and negate src and weights offset |
| 170 | const QuantizationInfo src_quantization_info(iq_info.scale, -iq_info.offset); |
| 171 | const QuantizationInfo weights_quantization_info(wq_info.scale, -wq_info.offset); |
| 172 |
no test coverage detected