| 409 | } |
| 410 | |
| 411 | Tensor CpuConvBackwardb(const Tensor &dy, const Tensor &b, |
| 412 | const ConvHandle &ch) { |
| 413 | CHECK_EQ(dy.device()->lang(), kCpp); |
| 414 | CHECK_EQ(b.device()->lang(), kCpp); |
| 415 | |
| 416 | CHECK(dy.shape(1) == ch.num_filters && dy.shape(2) == ch.conv_height && |
| 417 | dy.shape(3) == ch.conv_width) |
| 418 | << "input gradients shape should not change"; |
| 419 | |
| 420 | CHECK(b.shape(0) == ch.num_filters) << "bias shape should not change"; |
| 421 | |
| 422 | #ifdef USE_DNNL |
| 423 | Tensor db = ch.db->Clone(); |
| 424 | return db; |
| 425 | #else // Native cpp |
| 426 | Tensor db; |
| 427 | db.ResetLike(b); |
| 428 | |
| 429 | auto tmpshp = Shape{ch.batchsize * ch.num_filters, |
| 430 | dy.Size() / (ch.batchsize * ch.num_filters)}; |
| 431 | Tensor tmp1 = Reshape(dy, tmpshp); |
| 432 | |
| 433 | Tensor tmp2(Shape{ch.batchsize * ch.num_filters}); |
| 434 | SumColumns(tmp1, &tmp2); |
| 435 | Tensor tmp3 = Reshape(tmp2, Shape{ch.batchsize, ch.num_filters}); |
| 436 | |
| 437 | SumRows(tmp3, &db); |
| 438 | |
| 439 | return db; |
| 440 | #endif // USE_DNNL |
| 441 | }; |
| 442 | |
| 443 | #ifdef USE_CUDNN |
| 444 | CudnnConvHandle::CudnnConvHandle( |