目录
- 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去噪
网络架构
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
损失函数
该损失函数计算的是,期望残差图像与噪声输入估计残差之间的平均均方误差
mobilenet
网络结构
除了最后一层,每一层后面都是跟着一个batchnorm和一个RELU激活函数。最后一层后面是跟着一个softmax用于分类。一共28层网络。下图就是原来的卷积计算和现在的depthwise卷积运算的对比。
宽度因子和分辨率因子
obileNet有两个简单的全局超参数,分别是宽度因子和分辨率因子,可有效的在延迟和准确率之间做折中。允许我们依据约束条件选择合适大小、低延迟、易满足嵌入式设备要求的模型。
宽度因子: 上述的逐通道卷积的卷积核个数通常是M,也就是Dk* Dk*1 的卷积核个数等于输入通道数,宽度因子是一个参数为(0,1]之间的参数,作用于通道数,可以理解为按照比例缩减输入通道数。同理,输出的通道数也可以通过这个参数进行按比例缩减。用α表示这个参数,则计算量为:
分辨率因子: 上述的输入特征图大小为DW*DH,分辨率因子取值范围在(0,1]之间,可以理解为对特征图进行下采样,也就是按比例降低特征图的大小,使得输入数据以及由此在每一个模块产生的特征图都变小,用β表示这个参数,结合宽度因子α,则计算量为:
代码
"""
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)