Denoise image using Kornia and Ivy’s Transpiler#

Introduction#

This tutorial is adapted from Kornia’s official tutorial. We demonstrate how to denoise an image using the differentiable total_variation loss, leveraging Ivy’s Transpiler to run these augmentations in TensorFlow using ivy.transpile.

Original Tutorial Credits#

The original tutorial and code are courtesy of Kornia. This notebook serves as an adapted version, showcasing the integration with Ivy’s Transpiler for TensorFlow compatibility.

Open in google colab

Installation and Setup#

[1]:
%%capture
!pip install kornia
!pip install kornia-rs
!pip install matplotlib
!pip install -q ivy

!rm -rf ivy_transpiled_outputs/
[2]:
import kornia as K
import matplotlib.pyplot as plt
import torch
import torchvision
import ivy
import tensorflow as tf
/usr/local/lib/python3.10/dist-packages/kornia/feature/lightglue.py:44: FutureWarning: `torch.cuda.amp.custom_fwd(args...)` is deprecated. Please use `torch.amp.custom_fwd(args..., device_type='cuda')` instead.
  @torch.cuda.amp.custom_fwd(cast_inputs=torch.float32)

This line lazily transpiles everything in the kornia api to TensorFlow, and creates a new module for this transpiled version of kornia. Because the transpilation happens lazily, no function or class will be transpiled until it’s actually called.

[3]:
tf_kornia = ivy.transpile(K, source='torch', target="tensorflow")
[4]:
import io

import requests


def download_image(url: str, filename: str = "") -> str:
    filename = url.split("/")[-1] if len(filename) == 0 else filename
    # Download
    bytesio = io.BytesIO(requests.get(url).content)
    # Save file
    with open(filename, "wb") as outfile:
        outfile.write(bytesio.getbuffer())

    return filename


url = "https://github.com/kornia/data/raw/main/doraemon.png"
download_image(url)
[4]:
'doraemon.png'

Defining imshow function#

[5]:
%%writefile imshow.py

import kornia as K
import matplotlib.pyplot as plt
import torch
import torchvision

def imshow(input: torch.Tensor):
    out = torchvision.utils.make_grid(input, nrow=2, padding=5)
    out_np = K.utils.tensor_to_image(out)
    plt.imshow(out_np)
    plt.axis("off")
    plt.show()
Writing imshow.py

Transpiling imshow Function to TensorFlow#

[6]:
from imshow import imshow
transpiled_imshow = ivy.transpile(imshow, source='torch', target='tensorflow')
Transpilation of imshow complete.

loading an visualizing the image.#

This cell triggers the transpilation of kornia.io.load_image from PyTorch to TensorFlow. Due to Ivy’s lazy transpilation, the actual compilation occurs only when the function is called.

[7]:
# read the image with kornia and add a random noise to it
img = tf_kornia.io.load_image("doraemon.png", tf_kornia.io.ImageLoadType.RGB32)  # CxHxW

noise = tf.random.normal(shape=tf.shape(img), mean=0.0, stddev=0.1)
# Add noise to the image and clamp values between 0 and 1
noisy_image_tf = tf.clip_by_value(img + noise, 0.0, 1.0)
transpiled_imshow(noisy_image_tf)
Transpilation of load_image complete.
../../_images/demos_examples_and_demos_kornia_total_variation_denoising_12_1.png

Defining Total Variation Denoising Network#

[8]:
%%writefile TVDenoise.py

import torch
import kornia as K

class TVDenoise(torch.nn.Module):
    def __init__(self, noisy_image):
        super().__init__()
        self.l2_term = torch.nn.MSELoss(reduction="mean")
        self.regularization_term = K.losses.TotalVariation()
        # create the variable which will be optimized to produce the noise free image
        self.clean_image = torch.nn.Parameter(data=noisy_image.clone(), requires_grad=True)

    def forward(self, noisy_image):
        return self.l2_term(self.clean_image, noisy_image) + 0.0001 * self.regularization_term(self.clean_image)

    def get_clean_image(self):
        return self.clean_image
Writing TVDenoise.py

Transpiling TVDenoise Network to TensorFlow#

[9]:
from TVDenoise import TVDenoise
transpiledTVDenoise = ivy.transpile(TVDenoise, source="torch", target="tensorflow")

Transpilation of TVDenoise complete.

Running Optimization Loop#

[10]:

tv_denoiser = transpiledTVDenoise(noisy_image_tf) optimizer = tf.keras.optimizers.SGD(learning_rate=0.1, momentum=0.9) num_iters = 500 for i in range(num_iters): with tf.GradientTape() as tape: loss = tf.reduce_sum(tv_denoiser(noisy_image_tf)) # Every 50 iterations, print the loss if i % 50 == 0: print(f"Loss in iteration {i} of {num_iters}: {loss.numpy():.3f}") # Compute gradients and apply optimization step gradients = tape.gradient(loss, tv_denoiser.trainable_variables) optimizer.apply_gradients(zip(gradients, tv_denoiser.trainable_variables))
Loss in iteration 0 of 500: 3.075
Loss in iteration 50 of 500: 2.718
Loss in iteration 100 of 500: 2.352
Loss in iteration 150 of 500: 2.057
Loss in iteration 200 of 500: 1.822
Loss in iteration 250 of 500: 1.637
Loss in iteration 300 of 500: 1.493
Loss in iteration 350 of 500: 1.381
Loss in iteration 400 of 500: 1.294
Loss in iteration 450 of 500: 1.227

Visualizing Results#

[11]:
# convert back to numpy
img_clean = tf_kornia.utils.tensor_to_image(tv_denoiser.get_clean_image())

# Create the plot
fig, axs = plt.subplots(1, 2, figsize=(16, 10))
axs = axs.ravel()

axs[0].axis("off")
axs[0].set_title("Noisy image")
axs[0].imshow(tf_kornia.tensor_to_image(noisy_image_tf))

axs[1].axis("off")
axs[1].set_title("Cleaned image")
axs[1].imshow(img_clean)

plt.show()
../../_images/demos_examples_and_demos_kornia_total_variation_denoising_20_0.png

Conclusion#

In this tutorial, we demonstrated how to leverage Ivy’s Transpiler to run Kornia’s total variation denoising algorithm in TensorFlow.

What’s Next?#

Want to explore more? Dive into our documentation for in-depth guides, tutorials, and API references. Your feedback is invaluable – join our Discord to share your thoughts and suggestions.