\copydoc Layer::Backward(int, const Tensor&, const Tensor&);
| 137 | |
| 138 | /// \copydoc Layer::Backward(int, const Tensor&, const Tensor&); |
| 139 | const std::pair<Tensor, vector<Tensor>> Convolution::Backward( |
| 140 | int flag, const Tensor &grad) { |
| 141 | CHECK_EQ(grad.device()->lang(), kCpp); |
| 142 | CHECK_EQ(grad.nDim(), 4u); |
| 143 | CHECK(!buf_.empty()); |
| 144 | Tensor src_data = buf_.top(); |
| 145 | buf_.pop(); |
| 146 | vector<Tensor> param_grad; |
| 147 | Tensor dx; |
| 148 | Tensor db, dw; |
| 149 | dx.ResetLike(src_data); |
| 150 | dw.ResetLike(weight_); |
| 151 | dw.SetValue(0.0f); |
| 152 | size_t batchsize = grad.shape(0); |
| 153 | size_t imagesize = src_data.Size() / batchsize; |
| 154 | if (bias_term_) { |
| 155 | auto tmpshp = Shape{batchsize * num_filters_, grad.Size() / (batchsize * num_filters_)}; |
| 156 | Tensor tmp1 = Reshape(grad, tmpshp); |
| 157 | |
| 158 | Tensor tmp2(Shape{batchsize * num_filters_}); |
| 159 | SumColumns(tmp1, &tmp2); |
| 160 | Tensor tmp3 = Reshape(tmp2, Shape{batchsize, num_filters_}); |
| 161 | |
| 162 | db.ResetLike(bias_); |
| 163 | SumRows(tmp3, &db); |
| 164 | } |
| 165 | |
| 166 | auto in_data = src_data.data<float>(); |
| 167 | Tensor col_data(Shape{col_height_, col_width_}); |
| 168 | float *data_col = new float[col_height_ * col_width_]; |
| 169 | float *dx_b = new float[imagesize]; |
| 170 | for (size_t b = 0; b < batchsize; b++) { |
| 171 | Im2col(in_data + b * imagesize, channels_, height_, width_, kernel_h_, |
| 172 | kernel_w_, pad_h_, pad_w_, stride_h_, stride_w_, data_col); |
| 173 | |
| 174 | col_data.CopyDataFromHostPtr(data_col, col_height_ * col_width_); |
| 175 | Tensor grad_b(Shape{num_filters_, conv_height_ * conv_width_}); |
| 176 | CopyDataToFrom(&grad_b, grad, grad_b.Size(), 0, b * grad_b.Size()); |
| 177 | dw += Mult(grad_b, Transpose(col_data)); |
| 178 | Tensor dcol_b = Mult(Transpose(weight_), grad_b); |
| 179 | auto dcol_data = dcol_b.data<float>(); |
| 180 | Col2im(dcol_data, channels_, height_, width_, kernel_h_, kernel_w_, pad_h_, |
| 181 | pad_w_, stride_h_, stride_w_, dx_b); |
| 182 | dx.CopyDataFromHostPtr(dx_b, imagesize, b * imagesize); |
| 183 | } |
| 184 | param_grad.push_back(dw); |
| 185 | if (bias_term_) |
| 186 | param_grad.push_back(db); |
| 187 | delete[] data_col; |
| 188 | delete[] dx_b; |
| 189 | return std::make_pair(dx, param_grad); |
| 190 | } |
| 191 | void Convolution::ToDevice(std::shared_ptr<Device> device) { |
| 192 | Layer::ToDevice(device); |
| 193 | weight_.ToDevice(device); |
nothing calls this directly
no test coverage detected