| 966 | } |
| 967 | |
| 968 | void Compute(OpKernelContext* ctx) override { |
| 969 | const Tensor& a = ctx->input(0); |
| 970 | const Tensor& b = ctx->input(1); |
| 971 | OP_REQUIRES(ctx, TensorShapeUtils::IsMatrix(a.shape()), |
| 972 | errors::InvalidArgument("a is not a matrix")); |
| 973 | OP_REQUIRES(ctx, TensorShapeUtils::IsMatrix(b.shape()), |
| 974 | errors::InvalidArgument("b is not a matrix")); |
| 975 | |
| 976 | const int m = transpose_a_ ? a.dim_size(1) : a.dim_size(0); |
| 977 | const int k = transpose_a_ ? a.dim_size(0) : a.dim_size(1); |
| 978 | const int n = transpose_b_ ? b.dim_size(0) : b.dim_size(1); |
| 979 | const int k2 = transpose_b_ ? b.dim_size(1) : b.dim_size(0); |
| 980 | |
| 981 | OP_REQUIRES(ctx, k == k2, |
| 982 | errors::InvalidArgument( |
| 983 | "Matrix size incompatible: a: ", a.shape().DebugString(), |
| 984 | ", b: ", b.shape().DebugString())); |
| 985 | OP_REQUIRES(ctx, m >= 0 && n >= 0 && k >= 0, |
| 986 | errors::InvalidArgument( |
| 987 | "Matrix dimensions cannot be negative: a: ", |
| 988 | a.shape().DebugString(), ", b: ", b.shape().DebugString())); |
| 989 | Tensor* output = nullptr; |
| 990 | OP_REQUIRES_OK(ctx, ctx->allocate_output(0, TensorShape({m, n}), &output)); |
| 991 | |
| 992 | // Return early if at least one of the output dimension size is 0. |
| 993 | if (m == 0 || n == 0) { |
| 994 | return; |
| 995 | } |
| 996 | |
| 997 | if (k == 0) { |
| 998 | // If the inner dimension k in the matrix multiplication is zero, we fill |
| 999 | // the output with zeros. |
| 1000 | functor::SetZeroFunctor<CPUDevice, float> f; |
| 1001 | f(ctx->eigen_device<CPUDevice>(), output->flat<float>()); |
| 1002 | return; |
| 1003 | } |
| 1004 | |
| 1005 | auto out = output->matrix<float>(); |
| 1006 | |
| 1007 | std::unique_ptr<Tensor> a_float; |
| 1008 | std::unique_ptr<Tensor> b_float; |
| 1009 | if (!a_is_sparse_ && !b_is_sparse_) { |
| 1010 | auto left = &a; |
| 1011 | auto right = &b; |
| 1012 | // TODO(agarwal): multi-thread the conversions from bfloat16 to float. |
| 1013 | if (std::is_same<TL, bfloat16>::value) { |
| 1014 | a_float.reset(new Tensor(DT_FLOAT, a.shape())); |
| 1015 | BFloat16ToFloat(a.flat<bfloat16>().data(), |
| 1016 | a_float->flat<float>().data(), a.NumElements()); |
| 1017 | left = a_float.get(); |
| 1018 | } |
| 1019 | if (std::is_same<TR, bfloat16>::value) { |
| 1020 | b_float.reset(new Tensor(DT_FLOAT, b.shape())); |
| 1021 | BFloat16ToFloat(b.flat<bfloat16>().data(), |
| 1022 | b_float->flat<float>().data(), b.NumElements()); |
| 1023 | right = b_float.get(); |
| 1024 | } |
| 1025 | Eigen::array<Eigen::IndexPair<Eigen::DenseIndex>, 1> dim_pair; |
nothing calls this directly
no test coverage detected