1 | /* Copyright 2019 The TensorFlow Authors. All Rights Reserved. |
2 | |
3 | Licensed under the Apache License, Version 2.0 (the "License"); |
4 | you may not use this file except in compliance with the License. |
5 | You may obtain a copy of the License at |
6 | |
7 | http://www.apache.org/licenses/LICENSE-2.0 |
8 | |
9 | Unless required by applicable law or agreed to in writing, software |
10 | distributed under the License is distributed on an "AS IS" BASIS, |
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | See the License for the specific language governing permissions and |
13 | limitations under the License. |
14 | ==============================================================================*/ |
15 | |
16 | #ifndef TFLITE_WITH_RUY |
17 | |
18 | #include "tensorflow/lite/kernels/cpu_backend_gemm_eigen.h" |
19 | |
20 | // See b/131835803: in TFLite code, because eigen_spatial_convolutions.h does |
21 | // #define Eigen EigenForTFLite, it is difficult to have any #include of Eigen |
22 | // headers in a header file, as that results in name classes (compilation |
23 | // errors) depending on the order in which these headers are #included. |
24 | // So we have moved the #include of Eigen here, in a .cc file, where we have |
25 | // control over the header #include sequence. |
26 | #include "third_party/eigen3/Eigen/Core" |
27 | #include "tensorflow/lite/kernels/cpu_backend_context.h" |
28 | #include "tensorflow/lite/kernels/cpu_backend_gemm_params.h" |
29 | #include "tensorflow/lite/kernels/internal/common.h" |
30 | |
31 | namespace tflite { |
32 | namespace cpu_backend_gemm { |
33 | namespace detail { |
34 | |
35 | // This function is out-of-line in a .cc file because of the issue |
36 | // noted above in the comment on the #include for Eigen/Core. |
37 | void GemmImplUsingEigen::Run( |
38 | const MatrixParams<float>& lhs_params, const float* lhs_data, |
39 | const MatrixParams<float>& rhs_params, const float* rhs_data, |
40 | const MatrixParams<float>& dst_params, float* dst_data, |
41 | const GemmParams<float, float>& params, CpuBackendContext* /* context */) { |
42 | // This code assumes specific storage orders, encoded in these Eigen types. |
43 | // These assumptions have been checked by TF_LITE_ASSERT's in the public |
44 | // Gemm entry point already, before the implementation gets to this point. |
45 | using EigenMatrixMapRowMajorConst = |
46 | Eigen::Map<const Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, |
47 | Eigen::RowMajor>>; |
48 | using EigenMatrixMapColMajorConst = |
49 | Eigen::Map<const Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, |
50 | Eigen::ColMajor>>; |
51 | using EigenMatrixMapColMajorMutable = Eigen::Map< |
52 | Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor>>; |
53 | |
54 | EigenMatrixMapRowMajorConst eigen_lhs(lhs_data, lhs_params.rows, |
55 | lhs_params.cols); |
56 | EigenMatrixMapColMajorConst eigen_rhs(rhs_data, rhs_params.rows, |
57 | rhs_params.cols); |
58 | EigenMatrixMapColMajorMutable eigen_dst(dst_data, dst_params.rows, |
59 | dst_params.cols); |
60 | |
61 | if (rhs_params.cols == 1) { |
62 | eigen_dst.col(0).noalias() = eigen_lhs * eigen_rhs.col(0); |
63 | } else if (lhs_params.rows == 1) { |
64 | eigen_dst.row(0).noalias() = eigen_lhs.row(0) * eigen_rhs; |
65 | } else { |
66 | eigen_dst.noalias() = eigen_lhs * eigen_rhs; |
67 | } |
68 | |
69 | if (params.bias) { |
70 | BiasAndClamp(params.clamp_min, params.clamp_max, dst_params.rows, |
71 | params.bias, dst_params.rows * dst_params.cols, dst_data); |
72 | } else { |
73 | eigen_dst = eigen_dst.cwiseMin(params.clamp_max).cwiseMax(params.clamp_min); |
74 | } |
75 | } |
76 | |
77 | } // namespace detail |
78 | } // namespace cpu_backend_gemm |
79 | } // namespace tflite |
80 | |
81 | #endif // not TFLITE_WITH_RUY |
82 | |