Skip to content

Commit 5e529af

Browse files
committed
initial commit
0 parents  commit 5e529af

File tree

6 files changed

+216
-0
lines changed

6 files changed

+216
-0
lines changed

DnCNN.py

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import tensorflow as tf
2+
"""
3+
https://danijar.com/structuring-models/
4+
"""
5+
6+
class DnCNN(tf.keras.Model):
7+
8+
def __init__(self,depth = 5,grayscale=True):
9+
super(DnCNN,self).__init__()
10+
# Network params
11+
self.channels = 1 if grayscale else 3
12+
self.depth = depth
13+
14+
def call(self,input_tensor,training=True):
15+
# First Convolution Layer with Conv and ReLU
16+
x = tf.keras.layers.Conv2D(64,(3,3),padding="same",kernel_initializer='Orthogonal')(input_tensor)
17+
x = tf.keras.activations.relu(x)
18+
19+
# Add Conv+Batch_Norm+ReLU for layers 2 to (depth-1)
20+
for _ in range(self.depth - 1):
21+
x = tf.keras.layers.Conv2D(64,(3,3),padding="same",kernel_initializer='Orthogonal')(x)
22+
x = tf.keras.layers.BatchNormalization(epsilon=0.0001)(x,training=training)
23+
x = tf.keras.activations.relu(x)
24+
25+
# The final conv layer will use only 1 filter to recontruct the original image
26+
x = tf.keras.layers.Conv2D(1,(3,3),padding="same",kernel_initializer='Orthogonal')(x)
27+
28+
# Subtract the predicted noise from the noisy input image
29+
x = tf.keras.layers.Subtract()([input_tensor,x]) #input - noise
30+
31+
return x
32+
33+
def model(self):
34+
# Funtion to build the model
35+
x = tf.keras.Input(shape=(None,None,self.channels))
36+
return tf.keras.Model(inputs=[x],outputs= self.call(x) )
37+
38+
39+
40+
41+
# Simple code to instantiate , compile and print the summary of the model architecture
42+
# if __name__ == "__main__":
43+
# model = DnCNN(depth=5).model()
44+
# model.compile(optimizer='Adam',loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True),metrics=["accuracy"])
45+
# print(model.summary())

README.md

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Deep Denoise
2+
3+
This is a tensorflow-2 implementation of the paper [Beyond a Gaussian Denoiser: Residual Learning ofDeep CNN for Image Denoising](https://arxiv.org/pdf/1608.03981.pdf).
4+
5+
### Dataset used :
6+
[BSDS200](https://www2.eecs.berkeley.edu/Research/Projects/CS/vision/bsds/BSDS300-images.tgz)
7+
8+
To download and unpack run:
9+
10+
`wget https://www2.eecs.berkeley.edu/Research/Projects/CS/vision/bsds/BSDS300-images.tgz`
11+
12+
`tar -xvzf BSDS300-images.tgz`
13+
14+
### Requriments :
15+
* tensorflow==2.3.1
16+
* matplotlib
17+
* numpy
18+
19+
### Run Model
20+
Run train_denoise.py
21+
22+
### Results
23+
After training by setting depth=5 for 25 epoch we get the below results. The original paper suggests a deeper architecture feel free to tweak the hyper params in the [train_denoise.py](train_denoise.py) file.
24+
25+
![alt](res1.png)
26+
27+
![alt](res2.png)

deepDenoise.txt

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
2+
NOTES
3+
4+
Reading the paper : Beyond a Gaussian Denoiser:Residual Learning of Deep CNN for image denoising.
5+
6+
GOAL of image denoising :
7+
Derive a clean image x from a noisy image y which follows a degradation model : y = x + v ; v = noise
8+
9+
Aim is to implicitly remove the clean image and learn v .
10+
11+
This can also be used in image super resolution problem where can see v to be the difference between the
12+
groud truth high res image and the bicubic upsampling of a low resolution image , similarly JPEG image
13+
deblocking problem can also be solved by taking v as the difference between the original image and the
14+
compressed image.
15+
16+
Section III
17+
============
18+
Proposed model :
19+
training a Deep CNN involves 2 tasks:
20+
> Network architecture and design
21+
> Model learning and training data ( adopt Residual-Learning with batch normalization )
22+
23+
A. Network Depth
24+
-----------------
25+
> filter size : 3 x 3 and remove all pooling layers
26+
> Receptive field of DnCNN of depth d should be (2d + 1) x (2d + 1) // why ? what is this ?
27+
28+
B. Network Architecture
29+
-----------------------
30+
Generally Denoising algorithms tend to try to learn a mapping function such as F(y) = x to learn the
31+
clean image x , but here we adopt residual learning , we want to map R(y) = v and then we can get the clean
32+
image by doing: x = y - R(y)
33+
34+
LOSS FUNCTION : averaged mean square error between the desired residual image and estimated ones from noisy input
35+
36+
Given we have a net of depth D we are gonna have 3 types of layers :
37+
1) Conv + Relu :
38+
> This is the first layer
39+
> has 64 filters of (3 x 3 x c)
40+
41+
2) Conv + BN + Relu :
42+
> from layer 2 till layer (D-1)
43+
> 64 filters of size (3 x 3)
44+
> do Batch Norm after Conv and before ReLU
45+
46+
3) Conv
47+
> Last Later
48+
> 'c' number of filters of size (3 x 3 x 64) is used to recostruct the output
49+
50+
* Reducing Boundry artifacts
51+
> zero pad intermediate layers so as to retain the original size as input image
52+
53+
EXPERIMENTAL RESULTS AS MENTIONED BY THE AUTHORS OF THE PAPER
54+
> Training and Testing Data:
55+
TRAIN
56+
DnCNN-S (S for specific noise level)
57+
> 400 images of 180 x 180 for training
58+
> considered noise levels of sigma = 15,25,50
59+
> patch size = (40 x 40)
60+
> crop = (128 x 1)
61+
> 600 patches to train the model
62+
63+
DnCNN-B (B for blind noise level)
64+
> noise levels sigma = [0,55]
65+
> patch size = (50 x 50)
66+
> crop = (128 x 3000)
67+
68+
> data-augmentation : rotate/flip pairs within mini-batch
69+
70+
> depth = 17(DnCNN-S) , 20 (DnCNN-B)
71+
72+
> SGD with decay = 0.0001 , momentum = 0.9 , mini-batch size =128
73+
74+
>epoch = 50
75+
76+
> lr = 1e-1 to 1e-4 over the 50 epoch
77+
78+

res1.png

88.4 KB
Loading

res2.png

93.7 KB
Loading

train_denoise.py

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
"""
2+
Learnt a lot about building the input pipeline in tf2 from here
3+
https://financial-engineering.medium.com/tensorflow-2-0-load-images-to-tensorflow-897b8b067fc2
4+
5+
"""
6+
import matplotlib.pyplot as plt
7+
import tensorflow as tf
8+
import numpy as np
9+
from DnCNN import DnCNN
10+
11+
data_dir = "./BSDS300/images/"
12+
13+
BATCH_SIZE = 32
14+
IMG_HEIGHT = 321
15+
IMG_WIDTH = 481
16+
17+
CHANNELS = 1
18+
19+
20+
def decode_img(img,channels):
21+
img = tf.image.decode_jpeg(img, channels=channels) #color/greyscale images
22+
img = tf.image.convert_image_dtype(img, tf.float32)
23+
#convert unit8 tensor to floats in the [0,1]range
24+
return tf.image.resize(img, [IMG_WIDTH, IMG_HEIGHT])
25+
26+
def process_path(file_path):
27+
clean_img = tf.io.read_file(file_path)
28+
clean_img = decode_img(clean_img,1) #Setting CHANNELS=1
29+
noisy_img = clean_img + np.random.normal(0,25/255.0,size=clean_img.shape)
30+
return noisy_img, clean_img
31+
32+
33+
34+
# Incase u dont have the dataset you can get it by running the following 2 commands in the dir of this file
35+
# wget https://www2.eecs.berkeley.edu/Research/Projects/CS/vision/bsds/BSDS300-images.tgz
36+
# tar -xvzf BSDS300-images.tgz
37+
38+
# Setup data by reading files for input and testing
39+
train_list_ds = tf.data.Dataset.list_files(str(data_dir+'train/*'))
40+
test_list_ds = tf.data.Dataset.list_files(str(data_dir+'test/*'))
41+
42+
# Load up the files for the model
43+
train_ds = train_list_ds.map(process_path)
44+
test_ds = test_list_ds.map(process_path)
45+
46+
# Build the model , compile and fit it to the data
47+
model = DnCNN(depth=5).model()
48+
49+
opt = tf.keras.optimizers.Adam(lr=0.0001,beta_1=0.9)
50+
loss_fn = tf.losses.mse
51+
52+
model.compile(optimizer= opt,loss=loss_fn,metrics=["accuracy"])
53+
54+
model.fit(train_ds,epochs=1,batch_size=32)
55+
56+
# Lets now see how the model performs
57+
test_noise,test_clean = next(iter(test_ds)) #Picking up a sample from test set
58+
# Make a prediction using the model
59+
prediction = model.predict(test_noise)
60+
61+
#Plotting out all the 3 images
62+
fig, (ax1, ax2,ax3) = plt.subplots(1,3,figsize=(7,7))
63+
fig.suptitle('1) Clean img 2) input noisy img 3) Model output' )
64+
ax1.imshow( test_clean.numpy().reshape((test_noise.shape[0],test_noise.shape[1])) , cmap = 'gray')
65+
ax2.imshow(test_noise.numpy().reshape((test_noise.shape[0],test_noise.shape[1])) , cmap='gray')
66+
ax3.imshow(prediction.reshape((prediction.shape[0],prediction.shape[1])),cmap='gray', )

0 commit comments

Comments
 (0)