zoukankan      html  css  js  c++  java
  • CNN理解与实现

    CNN理解与实现

    组成部分

    • Convolution Layer
    • Pool Layer:
      • Max-pooling layer
      • Average-pooling layer
    • Full Connected(FC) Layer

    需要的函数

    注意

    • 参数(W), (b)和数据(X)它们的维度是一样的, 这个非常重要, 在使用代码实现的时候不至于搞懵; 如果(X)是RGB图像, 它的维度假设为((100, 24, 24, 3)), 100表示样本数量, 24与24位图像的高与宽(我们人类习惯讲成宽与高, 但是在编程语言领域中, 如Matlab和Python中, 都是先锁定y轴, 再锁定x轴的, 同样迁移过来, 我们应该采用高与宽), 此时的W也是4个维度的, 加入为((3, 3, 3, 8)), 这里前两个3表示W(filter)的高与宽, 第三个3位通道数量, 要与X的通道数一致, 8表示W(filter)的个数, 可就是这次过滤器过滤之后得到的结果的通道数, 为b就简单了, 为((1, 1, 1, 8)), 每一个filter对应一个b

    实现

    • zero_pad: 使用0填充原始图像, 在水平方向与垂直方向添加padding
    • conv_single: 使用一个过滤器(W)对原始图像中的slice进行卷积
    • conv_forward: 卷积的前向传播
      • 根据公式计算出过滤之后的维度: (n_h=int({(n_{hprev}+2p-f)over{s}}+1)), (n_w=int({(n_{wprev}+2p-f)over{s}}+1)), 其中(n_{hprev})为上一层的高度, (n_{wprev})为上一层的宽度, (f)为filter的维度, filter一般为(f imes f), (p)为padding, (n_h)表示通过过滤器之后得到的结果的高度, (n_w)表示通过过滤器之后得到的结果的宽度, (s)表示stride, 为步幅
      • 调用zero_pad函数为(A_{prev})添加padding, 使用(int())是为了向下取整
      • 由于卷积比较复杂, 这里不适用矩阵的计算, 而是采用多个嵌套的for循环
        
        for i in range(m):
            # 获取到一个样本, 因为我们不打算使用矩阵化提高计算速率, 这样简单一点
            a_prev_pad = A_prev_pad[i, :, :, :]
            for h in range(n_h):
                for w in range(n_w):
                    for c in range(n_C):
                        # 此公式将从原始的a_prev_pad单样本的图像中获取到一个Convolution Window
                        vert_start = h * stride
                        vert_end = vert_start + f
                        horiz_start = w * stride
                        horiz_end = horiz_start + f
                        # 得到在原始图像中与filter同样大小窗口
                        a_slice_prev = a_prev_pad[vert_start:vert_end, horiz_start:horiz_end, :]
                        # 调用conv_single进行卷积计算
                        Z[i, h, w, c] = conv_single(a_slice_prev, W[:, :, :, c], b[:, :, :, c])
                        # 计算激活函数
                        A[i, h, w, c] = activate(Z[i, h, w, c])
        
    • pool_forward: 池化层的前向传播
      • 根据公式计算出(n_h)(n_w)
      • 同样不使用矩阵计算, 使用多个for循环迭代, 这样简单
        
        for i in range(m):
            a_prev = A_prev[i, :, :, :]
            for h in range(n_h):
                for w in range(n_w):
                    for c in range(n_c):
                        # 计算窗口坐标
                        vert_start = h * stride
                        vert_end = vert_start + f
                        horiz_start = w * stride
                        horiz_end = horiz_start + f
                        a_slice = a_prev[vert_start:vert_end, horiz_start:horiz_end, c]
                        # 这里采用Max-pooling的计算方法
                        # 其中A为我们函数的返回矩阵
                        A[i, h, w, c] = np.max(a_slice)
        
    • compute_cost: 计算损失函数(J)
    • conv_backward:
      • 计算dA, dW和db
        
        for i in range(m):
            da_prev_pad = dA_prev_pad[i, :, :, :]
            a_prev_pad = A_prev_pad[i, :, :, :]
            for h in range(n_h):
                for w in range(n_w):
                    for c in range(n_C):
                        vert_start = h * stride
                        vert_end = vert_start + f
                        horiz_start = h * stride
                        horiz_end = horiz_start + f
                        a_slice = a_prev_pad[vert_start:vert_end, horiz_start:horiz_end, :]
                        da_prev_pad[vert_start:vert_end, horiz_start:horiz_end, :] += dZ[i, h, w, c] * W[:, :, :, c]
                        dW[:, :, :, c] += dZ[i, h, w, c] * a_slice
                        db[:, :, :, c] += dZ[i, h, w, c]
            dA_prev[i, :, :, :] = da_prev_pad[pad:-pad, pad:-pad, :]
        
    • pool_backward:
      • conv_backward类似
      
      for i in range(m):
          a_prev = A_prev[i, :, :, :]
          for h in range(n_h):
              for w in range(n_w):
                  for c in range(n_C):
                      vert_start = h * stride
                      vert_end = vert_start + f
                      horiz_start = w * stride
                      horiz_end = horiz_start + f
                      a_slice = a_prev[vert_start:vert_end, horiz_start:horiz_end, c]
                      mask = create_mask_from_window(a_slice)
                      dA_prev[i, vert_start: vert_end, horiz_start: horiz_end, c] += np.multiply(mask, dA[i,h,w,c])
      

    总结反向传播用到的公式

    • 对于单个样本来说, 不使用矩阵表达式
    • (da += dw imes dz)
    • (dw += dz imes a)
    • (db += dz)

    使用的结构

    • Conv->ReLU->Pool->Conv->ReLU->Pool->FC
  • 相关阅读:
    [Python学习之路] 猜大小游戏
    C语言学生成绩管理系统(简易版)
    malloc动态分配字符串数组“ 一个月内的提醒”
    结构体指针排序
    C语言结构体排序
    数据测压,数据库查询,修改,添加
    badboy脚本录制
    性能测试
    JDK开发环境搭建及环境变量配置(win10)Jmeter之安装和配置
    Charles 修改返回值response(方法 breakpoints)
  • 原文地址:https://www.cnblogs.com/megachen/p/10606617.html
Copyright © 2011-2022 走看看