目录

  • Beyond a Gaussian Denoiser: Residual Learning of Deep CNN for Image Denoising
  • 本文贡献
  • 网络架构
  • 损失函数
  • mobilenet
  • 网络结构
  • 宽度因子和分辨率因子
  • 代码


Beyond a Gaussian Denoiser: Residual Learning of Deep CNN for Image Denoising

本文贡献

提出了一种端到端CNN网络用于高斯去噪网络,称为DnCNN。该网络采用残差学习策略从噪声图片中去除潜在干净图像,而不是用神经网络直接预测干净图像
使用残差学习(residue learning,RL)和批量归一化(batch normalization,BN)加快训练过程,提高去噪性能
可以训练一个单一的DnCNN模型进行盲高斯去噪,也可以很容易地扩展到一般的图像去噪任务,如盲高斯去噪,SISR, JPEG去噪
使用残差学习(residue learning,RL)和批量归一化(batch normalization,BN)加快训练过程,提高去噪性能
可以训练一个单一的DnCNN模型进行盲高斯去噪,也可以很容易地扩展到一般的图像去噪任务,如盲高斯去噪,SISR, JPEG去噪

网络架构

卷积神经网络声音分类 卷积神经网络去噪_ide


DnCNN以VGG网络为基础,加入了残差学习(RL)和批量归一化(BN)。为了保持输出图片的尺寸,去除了池化层

橙色:first layer: conv+relu, 64x3x3xC
蓝色:2-(d-1) layers: conv+bn+relu, 3x3x64
橘红:last layer, Cx3x3x64
输出:图像噪声R ( y ) R(y)R(y)
其中64表示卷积核个数;c表示图片通道,c=1或c=3;卷积核大小为3x3

损失函数

卷积神经网络声音分类 卷积神经网络去噪_自动驾驶_02


该损失函数计算的是,期望残差图像与噪声输入估计残差之间的平均均方误差

mobilenet

网络结构

除了最后一层,每一层后面都是跟着一个batchnorm和一个RELU激活函数。最后一层后面是跟着一个softmax用于分类。一共28层网络。下图就是原来的卷积计算和现在的depthwise卷积运算的对比。

卷积神经网络声音分类 卷积神经网络去噪_神经网络_03

宽度因子和分辨率因子

obileNet有两个简单的全局超参数,分别是宽度因子和分辨率因子,可有效的在延迟和准确率之间做折中。允许我们依据约束条件选择合适大小、低延迟、易满足嵌入式设备要求的模型。
宽度因子: 上述的逐通道卷积的卷积核个数通常是M,也就是Dk* Dk*1 的卷积核个数等于输入通道数,宽度因子是一个参数为(0,1]之间的参数,作用于通道数,可以理解为按照比例缩减输入通道数。同理,输出的通道数也可以通过这个参数进行按比例缩减。用α表示这个参数,则计算量为:

卷积神经网络声音分类 卷积神经网络去噪_深度学习_04


分辨率因子: 上述的输入特征图大小为DW*DH,分辨率因子取值范围在(0,1]之间,可以理解为对特征图进行下采样,也就是按比例降低特征图的大小,使得输入数据以及由此在每一个模块产生的特征图都变小,用β表示这个参数,结合宽度因子α,则计算量为:

卷积神经网络声音分类 卷积神经网络去噪_深度学习_05

代码

"""
mobilenet in tensorflow 2.0, tf.keras.
[1] Andrew G. Howard, Menglong Zhu, Bo Chen, Dmitry Kalenichenko, Weijun Wang, Tobias Weyand, Marco Andreetto, Hartwig Adam
    MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications
    https://arxiv.org/abs/1704.04861
"""

import os
import tensorflow as tf
import tensorflow.keras as keras
from tensorflow.keras import layers, Sequential

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'


class BasicConv2D(keras.Model):
    """This is the implement of native convolution operation."""
    def __init__(self, num_filters, kernel_size, **kwargs):
        super(BasicConv2D, self).__init__()
        self.conv = layers.Conv2D(num_filters, kernel_size, use_bias=False, **kwargs)
        self.bn = layers.BatchNormalization()
        self.relu = layers.Activation('relu')

    def call(self, inputs, training=None):
        out = self.conv(inputs)
        out = self.bn(out)
        out = self.relu(out)
        return out


class DepthSeparableConv2D(keras.Model):
    """This is the combination of depthwise convolution and pointwise convolution."""
    def __init__(self, pointwise_conv_filters, kernel_size, alpha, **kwargs):
        super(DepthSeparableConv2D, self).__init__()
        self.depthwise_conv = Sequential([
            layers.DepthwiseConv2D(kernel_size, padding='same', use_bias=False, **kwargs),
            layers.BatchNormalization(),
            layers.Activation('relu')
        ])
        self.pointwise_conv = Sequential([
            layers.Conv2D(int(pointwise_conv_filters*alpha), (1, 1), padding='same', use_bias=False),
            layers.BatchNormalization(),
            layers.Activation('relu')
        ])

    def call(self, inputs, training=None):
        out = self.depthwise_conv(inputs)
        out = self.pointwise_conv(out)
        return out


class MobileNetV1(keras.Model):
    """This is the implement of MobileNet v1."""
    def __init__(self, width_multipler=1.0, num_classes=10):
        super(MobileNetV1, self).__init__()
        self.conv1 = Sequential([
            BasicConv2D(int(32*width_multipler), (3, 3), strides=2, padding='same'),
            DepthSeparableConv2D(64, (3, 3), alpha=width_multipler, strides=1)
        ])
        self.conv2 = Sequential([
            DepthSeparableConv2D(128, (3, 3), alpha=width_multipler, strides=2),
            DepthSeparableConv2D(128, (3, 3), alpha=width_multipler, strides=1)
        ])
        self.conv3 = Sequential([
            DepthSeparableConv2D(256, (3, 3), alpha=width_multipler, strides=2),
            DepthSeparableConv2D(256, (3, 3), alpha=width_multipler, strides=1)
        ])
        self.conv4 = Sequential([
            DepthSeparableConv2D(512, (3, 3), alpha=width_multipler, strides=2),
            DepthSeparableConv2D(512, (3, 3), alpha=width_multipler, strides=1),
            DepthSeparableConv2D(512, (3, 3), alpha=width_multipler, strides=1),
            DepthSeparableConv2D(512, (3, 3), alpha=width_multipler, strides=1),
            DepthSeparableConv2D(512, (3, 3), alpha=width_multipler, strides=1),
            DepthSeparableConv2D(512, (3, 3), alpha=width_multipler, strides=1)
        ])
        self.conv5 = Sequential([
            DepthSeparableConv2D(1024, (3, 3), alpha=width_multipler, strides=2),
            DepthSeparableConv2D(1024, (3, 3), alpha=width_multipler, strides=1)
        ])
        self.avg_pool = layers.GlobalAveragePooling2D()
        self.fc = layers.Dense(num_classes)

    def call(self, inputs, training=None):
        out = self.conv1(inputs)
        out = self.conv2(out)
        out = self.conv3(out)
        out = self.conv4(out)
        out = self.conv5(out)
        out = self.avg_pool(out)
        out = self.fc(out)
        return out



if __name__ == '__main__':
    model = MobileNetV1(width_multipler=0.5, num_classes=1000)
    model.build(input_shape=(2, 224, 224, 3))
    model.summary()
    print(model.predict(tf.ones((2, 224, 224, 3))).shape)