| 603 | |
| 604 | ######## Pool2D ################ |
| 605 | class Pool2D(LayerBase): |
| 606 | |
| 607 | def __init__(self, kernel_shape, stride=1, pad=0, mode="max", optimizer=None): |
| 608 | """ |
| 609 | 二维池化 |
| 610 | |
| 611 | 参数说明: |
| 612 | kernel_shape:池化窗口的大小,2-tuple |
| 613 | stride:和卷积类似,窗口在每一个维度上滑动的步长,int型 |
| 614 | pad:padding 数目,4-tuple, int, 或 str('same','valid')型 (default: 0) |
| 615 | 和卷积类似 |
| 616 | mode:池化函数,str型 (default: 'max'),可选{"max","average"} |
| 617 | optimizer:优化方法,str型 |
| 618 | """ |
| 619 | super().__init__(optimizer) |
| 620 | |
| 621 | self.pad = pad |
| 622 | self.mode = mode |
| 623 | self.in_ch = None |
| 624 | self.out_ch = None |
| 625 | self.stride = stride |
| 626 | self.kernel_shape = kernel_shape |
| 627 | self.is_initialized = False |
| 628 | |
| 629 | def _init_params(self): |
| 630 | self.derived_variables = {"out_rows": [], "out_cols": []} |
| 631 | self.is_initialized = True |
| 632 | |
| 633 | def forward(self, X, retain_derived=True): |
| 634 | """ |
| 635 | 池化层前向传播 |
| 636 | |
| 637 | 参数说明: |
| 638 | X:输入数组,形状为 (n_samp, in_rows, in_cols, in_ch) |
| 639 | retain_derived:是否保留中间变量,以便反向传播时再次使用,bool型 |
| 640 | |
| 641 | 输出说明: |
| 642 | Y:输出结果,形状为 (n_samp, out_rows, out_cols, out_ch) |
| 643 | """ |
| 644 | if not self.is_initialized: |
| 645 | self.in_ch = self.out_ch = X.shape[3] |
| 646 | self._init_params() |
| 647 | |
| 648 | n_samp, in_rows, in_cols, nc_in = X.shape |
| 649 | (fr, fc), s, p = self.kernel_shape, self.stride, self.pad |
| 650 | X_pad, (pr1, pr2, pc1, pc2) = pad2D(X, p, self.kernel_shape, s) |
| 651 | |
| 652 | out_rows = int((in_rows + pr1 + pr2 - fr) / s + 1) |
| 653 | out_cols = int((in_cols + pc1 + pc2 - fc) / s + 1) |
| 654 | |
| 655 | if self.mode == "max": |
| 656 | pool_fn = np.max |
| 657 | elif self.mode == "average": |
| 658 | pool_fn = np.mean |
| 659 | |
| 660 | Y = np.zeros((n_samp, out_rows, out_cols, self.out_ch)) |
| 661 | for m in range(n_samp): |
| 662 | for i in range(out_rows): |
no outgoing calls
no test coverage detected