| 5981 | } |
| 5982 | |
| 5983 | bool CudnnSupport::DoBiasAdd(Stream* stream, |
| 5984 | const DeviceMemory<float>& input_data, |
| 5985 | const DeviceMemory<float>& biases, |
| 5986 | const dnn::BatchDescriptor& dimensions, |
| 5987 | DeviceMemory<float>* output_data) { |
| 5988 | CudnnTensorDescriptor input_descriptor(dimensions, CUDNN_DATA_FLOAT); |
| 5989 | |
| 5990 | dnn::BatchDescriptor bias_dimensions; |
| 5991 | bias_dimensions.set_count(1) |
| 5992 | .set_feature_map_count(dimensions.feature_map_count()) |
| 5993 | .set_height(1) |
| 5994 | .set_width(1) |
| 5995 | .set_layout(dnn::DataLayout::kBatchYXDepth); |
| 5996 | CudnnTensorDescriptor bias_descriptor(bias_dimensions, CUDNN_DATA_FLOAT); |
| 5997 | |
| 5998 | // cudnnAddTensor after R3 is in-place, so we need to copy input_data to |
| 5999 | // output_data before doing the addition, unless the input and |
| 6000 | // output are at the same address. |
| 6001 | if (input_data.opaque() != output_data->opaque()) { |
| 6002 | stream->ThenMemcpy(output_data, input_data, |
| 6003 | dimensions.ElementCount() * sizeof(float)); |
| 6004 | if (!stream->ok()) { |
| 6005 | LOG(ERROR) |
| 6006 | << "stream " << stream |
| 6007 | << " could not enqueue a tensor copy as part of bias addition."; |
| 6008 | return false; |
| 6009 | } |
| 6010 | } |
| 6011 | |
| 6012 | const float alpha = 1.0f; |
| 6013 | const float beta = 1.0f; |
| 6014 | |
| 6015 | auto cudnn = cudnn_->GetHandle(parent_, stream); |
| 6016 | |
| 6017 | const auto status = [&] { |
| 6018 | RETURN_IF_CUDNN_ERROR(cudnnAddTensor( |
| 6019 | cudnn.handle(), &alpha, bias_descriptor.handle(), biases.opaque(), |
| 6020 | &beta, input_descriptor.handle(), output_data->opaque())); |
| 6021 | return port::Status::OK(); |
| 6022 | }(); |
| 6023 | return IsStatusOk(status, /*report_error=*/true); |
| 6024 | } |
| 6025 | |
| 6026 | bool CudnnSupport::DoActivate(Stream* stream, |
| 6027 | dnn::ActivationMode activation_mode, |
nothing calls this directly
no test coverage detected