Compute the layer output given input volume `X`. Parameters ---------- X : :py:class:`ndarray ` of shape `(n_ex, in_rows, in_cols, in_ch)` The input volume consisting of `n_ex` examples, each with dimension (`in_rows`,`in_cols`
(self, X, retain_derived=True)
| 3233 | } |
| 3234 | |
| 3235 | def forward(self, X, retain_derived=True): |
| 3236 | """ |
| 3237 | Compute the layer output given input volume `X`. |
| 3238 | |
| 3239 | Parameters |
| 3240 | ---------- |
| 3241 | X : :py:class:`ndarray <numpy.ndarray>` of shape `(n_ex, in_rows, in_cols, in_ch)` |
| 3242 | The input volume consisting of `n_ex` examples, each with dimension |
| 3243 | (`in_rows`,`in_cols`, `in_ch`) |
| 3244 | retain_derived : bool |
| 3245 | Whether to retain the variables calculated during the forward pass |
| 3246 | for use later during backprop. If False, this suggests the layer |
| 3247 | will not be expected to backprop through wrt. this input. Default |
| 3248 | is True. |
| 3249 | |
| 3250 | Returns |
| 3251 | ------- |
| 3252 | Y : :py:class:`ndarray <numpy.ndarray>` of shape `(n_ex, out_rows, out_cols, out_ch)` |
| 3253 | The layer output. |
| 3254 | """ # noqa: E501 |
| 3255 | if not self.is_initialized: |
| 3256 | self.in_ch = self.out_ch = X.shape[3] |
| 3257 | self._init_params() |
| 3258 | |
| 3259 | n_ex, in_rows, in_cols, nc_in = X.shape |
| 3260 | (fr, fc), s, p = self.kernel_shape, self.stride, self.pad |
| 3261 | X_pad, (pr1, pr2, pc1, pc2) = pad2D(X, p, self.kernel_shape, s) |
| 3262 | |
| 3263 | out_rows = np.floor(1 + (in_rows + pr1 + pr2 - fr) / s).astype(int) |
| 3264 | out_cols = np.floor(1 + (in_cols + pc1 + pc2 - fc) / s).astype(int) |
| 3265 | |
| 3266 | if self.mode == "max": |
| 3267 | pool_fn = np.max |
| 3268 | elif self.mode == "average": |
| 3269 | pool_fn = np.mean |
| 3270 | |
| 3271 | Y = np.zeros((n_ex, out_rows, out_cols, self.out_ch)) |
| 3272 | for m in range(n_ex): |
| 3273 | for i in range(out_rows): |
| 3274 | for j in range(out_cols): |
| 3275 | for c in range(self.out_ch): |
| 3276 | # calculate window boundaries, incorporating stride |
| 3277 | i0, i1 = i * s, (i * s) + fr |
| 3278 | j0, j1 = j * s, (j * s) + fc |
| 3279 | |
| 3280 | xi = X_pad[m, i0:i1, j0:j1, c] |
| 3281 | Y[m, i, j, c] = pool_fn(xi) |
| 3282 | |
| 3283 | if retain_derived: |
| 3284 | self.X.append(X) |
| 3285 | self.derived_variables["out_rows"].append(out_rows) |
| 3286 | self.derived_variables["out_cols"].append(out_cols) |
| 3287 | |
| 3288 | return Y |
| 3289 | |
| 3290 | def backward(self, dLdY, retain_grads=True): |
| 3291 | """ |