| 144 | |
| 145 | template <typename T> |
| 146 | __global__ void BiasGradNCHW_SharedAtomics(const T* output_backprop, |
| 147 | T* bias_backprop, int32 batch, |
| 148 | int32 bias_size, int32 image_size, |
| 149 | int group_size) { |
| 150 | // Initialize the shared memory. |
| 151 | typedef typename AccumulatorType<T>::type AccT; |
| 152 | const int32 kSDataSize = 32; |
| 153 | __shared__ AccT s_data[kSDataSize]; |
| 154 | for (int32 index = threadIdx.x; index < kSDataSize; index += blockDim.x) { |
| 155 | s_data[index] = AccT(0); |
| 156 | } |
| 157 | __syncthreads(); |
| 158 | |
| 159 | // Accumulate all the values within this thread. They all have the same bias |
| 160 | // index. |
| 161 | int32 bias_index = blockIdx.x % bias_size; |
| 162 | int32 group_index = blockIdx.x / bias_size; |
| 163 | int32 total_count = batch * image_size; |
| 164 | AccT sum(0); |
| 165 | for (int32 index = group_index * blockDim.x + threadIdx.x; |
| 166 | index < total_count; index += blockDim.x * group_size) { |
| 167 | int32 image_offset = index % image_size; |
| 168 | int32 batch = index / image_size; |
| 169 | T val = ldg(output_backprop + |
| 170 | (batch * bias_size + bias_index) * image_size + image_offset); |
| 171 | sum += AccT(val); |
| 172 | } |
| 173 | |
| 174 | // Write the accumulated sum in this thread to the shared memory. Each thread |
| 175 | // shifts their write location to avoid bank conflict. |
| 176 | int bias_offset = threadIdx.x % 32; |
| 177 | GpuAtomicAdd(s_data + bias_offset, sum); |
| 178 | __syncthreads(); |
| 179 | |
| 180 | // Accumulate the results in the shared memory into the first element. |
| 181 | // No syncthreads is needed since this is only in the same warp. |
| 182 | int32 thread_index = threadIdx.x; |
| 183 | #if GOOGLE_CUDA |
| 184 | if (thread_index < 32) { |
| 185 | AccT data = s_data[thread_index]; |
| 186 | for (int32 delta = warpSize / 2; delta > 0; delta /= 2) { |
| 187 | data += GpuShuffleXorSync(kCudaWarpAll, data, delta); |
| 188 | } |
| 189 | if (thread_index == 0) { |
| 190 | GpuAtomicAdd(bias_backprop + bias_index, T(data)); |
| 191 | } |
| 192 | } |
| 193 | #elif TENSORFLOW_USE_ROCM |
| 194 | if (thread_index < 16) s_data[thread_index] += s_data[thread_index + 16]; |
| 195 | if (thread_index < 8) s_data[thread_index] += s_data[thread_index + 8]; |
| 196 | if (thread_index < 4) s_data[thread_index] += s_data[thread_index + 4]; |
| 197 | if (thread_index < 2) s_data[thread_index] += s_data[thread_index + 2]; |
| 198 | if (thread_index < 1) s_data[thread_index] += s_data[thread_index + 1]; |
| 199 | |
| 200 | // The first thread writes out the accumulated result to the global location. |
| 201 | if (thread_index == 0) { |
| 202 | GpuAtomicAdd(bias_backprop + bias_index, T(s_data[0])); |
| 203 | } |
nothing calls this directly
no test coverage detected