图卷积神经网络_运用计算图搭建卷积神经网络

0fa0a265e9e0478d988ad7fa21bee294.png
“今天,我不准备多讲。原因在哪里,同志们自己回去想。嘴巴,人人都有,无非是吃饭、说话。到底哪个重要,还要看实践。我们老祖宗有一句话:‘光说不练,假把式;光练不说,傻把式;连说带练~~真!把!式!’”
—— 傅明老人,《我爱我家》

现在,由于加入了矩阵计算的算子,我们的计算图框架( VectorSlow )现在该改叫 MatrixSlow 了。也许哪一天我们会将它改进成 TensorSlow ,但总之 Slow 这个特性我们是不会放弃的。

在之前的博文中,我们介绍了计算图和自动求导的原理及实现(这里),用 MatrixSlow 搭建了一些可以被纳入“非全连接神经网络”范畴的若干模型(这里),还搭建了一些深度不一的多层全连接神经网络,并用动画展示了它们的训练过程(这里)。现在,我们用 MatrixSlow 搭建卷积神经网络(CNN)并用来识别 MNIST 。关于 CNN 的介绍,可见这里。

作者对本文代码保留后续修改的权利,完整代码请见码云


一、卷积

我们首先实现卷积算子,代码如下(node.py):

class Convolve(Node):
    """
    以第二个父节点的值为卷积核,对第一个父节点的值做二维离散卷积
    """
    def __init__(self, *parents):
        assert len(parents) == 2
        Node.__init__(self, *parents)

        self.padded = None

    def compute(self):

        data = self.parents[0].value  # 输入特征图
        kernel = self.parents[1].value  # 卷积核

        w, h = data.shape  # 输入特征图的宽和高
        kw, kh = kernel.shape  # 卷积核尺寸
        hkw, hkh = int(kw / 2), int(kh / 2)  # 卷积核长宽的一半

        # 补齐数据边缘
        pw, ph = tuple(np.add(data.shape, np.multiply((hkw, hkh), 2)))
        self.padded = np.mat(np.zeros((pw, ph)))
        self.padded[hkw:hkw + w, hkh:hkh + h] = data

        self.value = np.mat(np.zeros((w, h)))

        # 二维离散卷积
        for i in np.arange(hkw, hkw + w):
            for j in np.arange(hkh, hkh + h):
                self.value[i - hkw, j - hkh] = np.sum(
                    np.multiply(self.padded[i - hkw:i - hkw + kw, j - hkh:j - hkh + kh], kernel))

    def get_jacobi(self, parent):

        data = self.parents[0].value  # 输入特征图
        kernel = self.parents[1].value  # 卷积核

        w, h = data.shape  # 输入特征图的宽和高
        kw, kh = kernel.shape  # 卷积核尺寸
        hkw, hkh = int(kw / 2), int(kh / 2)  # 卷积核长宽的一半

        # 补齐数据边缘
        pw, ph = tuple(np.add(data.shape, np.multiply((hkw, hkh), 2)))

        jacobi = []
        mask = np.mat(np.zeros((pw, ph)))
        if parent is self.parents[0]:
            for i in np.arange(hkw, hkw + w):
                for j in np.arange(hkh, hkh + h):
                    mask *= 0
                    mask[i - hkw:i - hkw + kw, j - hkh:j - hkh + kh] = kernel
                    jacobi.append(mask[hkw:hkw+w, hkh:hkh+h].A1)
        elif parent is self.parents[1]:
            for i in np.arange(hkw, hkw + w):
                for j in np.arange(hkh, hkh + h):
                    jacobi.append(self.padded[i - hkw:i - hkw + kw, j - hkh:j - hkh + kh].A1)
        else:
            raise Exception("You're not my father")

        return np.mat(jacobi)

Convolve 接受两个父节点:图像(或叫特征图)节点,它是一个二维矩阵;卷积核节点也是一个二维矩阵。Convolve 暂时不支持设置步幅(stride)和填充方式(padding),步幅一律为 1 ,使用补零填充。compute 以第二个父节点的值为滤波器,对第一个父节点的值做二维离散卷积(滤波)。get_jacobi 函数返回当前本节点对特征图或卷积核的雅克比矩阵。


二、最大值池化

我们来实现最大值池化算子,代码如下(node.py):

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值