| 5846 | } |
| 5847 | |
| 5848 | bool CudnnSupport::DoMatMul(Stream* stream, |
| 5849 | const DeviceMemory<float>& input_data, |
| 5850 | const DeviceMemory<float>& weights, |
| 5851 | const dnn::BatchDescriptor& input_dimensions, |
| 5852 | const dnn::BatchDescriptor& output_dimensions, |
| 5853 | DeviceMemory<float>* output_data) { |
| 5854 | if (input_dimensions.count() != output_dimensions.count()) { |
| 5855 | LOG(ERROR) << "MatMul input and output dimensions are not compatible."; |
| 5856 | return false; |
| 5857 | } |
| 5858 | |
| 5859 | // We do not permute the input or output, instead we just |
| 5860 | // reinterpret the layout. We are working with row-major matrices |
| 5861 | // and the rows of the input and output correspond to batch, so |
| 5862 | // batch has to be outermost in both the input and output. |
| 5863 | // |
| 5864 | // By adding transposes to the BLAS gemm call we could perhaps make |
| 5865 | // the kYXDepthBatch layout work as well, but there has been no need |
| 5866 | // for that so far. |
| 5867 | if (input_dimensions.layout() != dnn::DataLayout::kBatchYXDepth && |
| 5868 | input_dimensions.layout() != dnn::DataLayout::kBatchDepthYX) { |
| 5869 | LOG(ERROR) << "Unsupported MatMul input layout."; |
| 5870 | return false; |
| 5871 | } |
| 5872 | if (output_dimensions.layout() != dnn::DataLayout::kBatchYXDepth && |
| 5873 | output_dimensions.layout() != dnn::DataLayout::kBatchDepthYX) { |
| 5874 | LOG(ERROR) << "Unsupported MatMul output layout."; |
| 5875 | return false; |
| 5876 | } |
| 5877 | |
| 5878 | if (output_dimensions.width() == 1 && output_dimensions.height() == 1) { |
| 5879 | // This is a fast path that also supports the kBatchYXDepth layout. |
| 5880 | |
| 5881 | // The matrices here are in row-major format while BLAS expects |
| 5882 | // column-major, i.e. our matrices are transposed as far as BLAS |
| 5883 | // is concerned. So we need to compute output^T = |
| 5884 | // input^T*weights^T. There is no parameter for transposing the |
| 5885 | // output in BLAS gemm, but instead we can transpose both sides of |
| 5886 | // the equality to see that this is equivalent to |
| 5887 | // output=weights*input. So we only need to swap the order of |
| 5888 | // weights and input in the matrix product to correct for the |
| 5889 | // row-major versus column-major difference. |
| 5890 | const float alpha = 1.0f; // Take the matrix product without scaling it. |
| 5891 | const float beta = 0.0f; // Ignore the original values in output_data. |
| 5892 | const int64 m = output_dimensions.NodesAcrossFeatureMaps(); |
| 5893 | const int64 n = input_dimensions.count(); |
| 5894 | const int64 k = input_dimensions.NodesAcrossFeatureMaps(); |
| 5895 | stream->ThenBlasGemm(blas::Transpose::kNoTranspose, |
| 5896 | blas::Transpose::kNoTranspose, m, n, k, alpha, weights, |
| 5897 | m, input_data, k, beta, output_data, m); |
| 5898 | } else { |
| 5899 | // This is a slower and more complex path that supports output |
| 5900 | // width() * height() > 1, though it only supports the |
| 5901 | // kBatchYXDepth layout. Does support kBatchDepthYX if output |
| 5902 | // feature_map_count() == 1, as then there is no difference |
| 5903 | // between the two layouts. |
| 5904 | // |
| 5905 | // The operation here is the same as above, except that we have to |
nothing calls this directly
no test coverage detected