【python實現卷積神經網絡】池化層實現


代碼來源:https://github.com/eriklindernoren/ML-From-Scratch

卷積神經網絡中卷積層Conv2D(帶stride、padding)的具體實現:https://www.cnblogs.com/xiximayou/p/12706576.html

激活函數的實現(sigmoid、softmax、tanh、relu、leakyrelu、elu、selu、softplus):https://www.cnblogs.com/xiximayou/p/12713081.html

損失函數定義(均方誤差、交叉熵損失):https://www.cnblogs.com/xiximayou/p/12713198.html

優化器的實現(SGD、Nesterov、Adagrad、Adadelta、RMSprop、Adam):https://www.cnblogs.com/xiximayou/p/12713594.html

卷積層反向傳播過程:https://www.cnblogs.com/xiximayou/p/12713930.html

全連接層實現:https://www.cnblogs.com/xiximayou/p/12720017.html

批量歸一化層實現:https://www.cnblogs.com/xiximayou/p/12720211.html

 

包括D的平均池化和最大池化:

class PoolingLayer(Layer):
    """A parent class of MaxPooling2D and AveragePooling2D
    """
    def __init__(self, pool_shape=(2, 2), stride=1, padding=0):
        self.pool_shape = pool_shape
        self.stride = stride
        self.padding = padding
        self.trainable = True

    def forward_pass(self, X, training=True):
        self.layer_input = X

        batch_size, channels, height, width = X.shape

        _, out_height, out_width = self.output_shape()

        X = X.reshape(batch_size*channels, 1, height, width)
        X_col = image_to_column(X, self.pool_shape, self.stride, self.padding)

        # MaxPool or AveragePool specific method
        output = self._pool_forward(X_col)

        output = output.reshape(out_height, out_width, batch_size, channels)
        output = output.transpose(2, 3, 0, 1)

        return output

    def backward_pass(self, accum_grad):
        batch_size, _, _, _ = accum_grad.shape
        channels, height, width = self.input_shape
        accum_grad = accum_grad.transpose(2, 3, 0, 1).ravel()

        # MaxPool or AveragePool specific method
        accum_grad_col = self._pool_backward(accum_grad)

        accum_grad = column_to_image(accum_grad_col, (batch_size * channels, 1, height, width), self.pool_shape, self.stride, 0)
        accum_grad = accum_grad.reshape((batch_size,) + self.input_shape)

        return accum_grad

    def output_shape(self):
        channels, height, width = self.input_shape
        out_height = (height - self.pool_shape[0]) / self.stride + 1
        out_width = (width - self.pool_shape[1]) / self.stride + 1
        assert out_height % 1 == 0
        assert out_width % 1 == 0
        return channels, int(out_height), int(out_width)


class MaxPooling2D(PoolingLayer):
    def _pool_forward(self, X_col):
        arg_max = np.argmax(X_col, axis=0).flatten()
        output = X_col[arg_max, range(arg_max.size)]
        self.cache = arg_max
        return output

    def _pool_backward(self, accum_grad):
        accum_grad_col = np.zeros((np.prod(self.pool_shape), accum_grad.size))
        arg_max = self.cache
        accum_grad_col[arg_max, range(accum_grad.size)] = accum_grad
        return accum_grad_col

class AveragePooling2D(PoolingLayer):
    def _pool_forward(self, X_col):
        output = np.mean(X_col, axis=0)
        return output

    def _pool_backward(self, accum_grad):
        accum_grad_col = np.zeros((np.prod(self.pool_shape), accum_grad.size))
        accum_grad_col[:, range(accum_grad.size)] = 1. / accum_grad_col.shape[0] * accum_grad
        return accum_grad_col

需要注意的是池化層是沒有可學習的參數的(如果不利用帶步長的卷積來代替池化的作用),還有就是池化層反向傳播的過程,這里參考:https://blog.csdn.net/Jason_yyz/article/details/80003271

為了結合代碼看直觀些,就將其內容摘了下來:

Pooling池化操作的反向梯度傳播
CNN網絡中另外一個不可導的環節就是Pooling池化操作,因為Pooling操作使得feature map的尺寸變化,假如做2×2的池化,假設那么第l+1層的feature map有16個梯度,那么第l層就會有64個梯度,這使得梯度無法對位的進行傳播下去。其實解決這個問題的思想也很簡單,就是把1個像素的梯度傳遞給4個像素,但是需要保證傳遞的loss(或者梯度)總和不變。根據這條原則,mean pooling和max pooling的反向傳播也是不同的。
1、mean pooling
mean pooling的前向傳播就是把一個patch中的值求取平均來做pooling,那么反向傳播的過程也就是把某個元素的梯度等分為n份分配給前一層,這樣就保證池化前后的梯度(殘差)之和保持不變,還是比較理解的,圖示如下 :
mean pooling比較容易讓人理解錯的地方就是會簡單的認為直接把梯度復制N遍之后直接反向傳播回去,但是這樣會造成loss之和變為原來的N倍,網絡是會產生梯度爆炸的。
2、max pooling
max pooling也要滿足梯度之和不變的原則,max pooling的前向傳播是把patch中最大的值傳遞給后一層,而其他像素的值直接被舍棄掉。那么反向傳播也就是把梯度直接傳給前一層某一個像素,而其他像素不接受梯度,也就是為0。所以max pooling操作和mean pooling操作不同點在於需要記錄下池化操作時到底哪個像素的值是最大,也就是max id,這個變量就是記錄最大值所在位置的,因為在反向傳播中要用到,那么假設前向傳播和反向傳播的過程就如下圖所示 :
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM