Generative Image Inpainting
Explore the concept of generative image inpainting.
We'll cover the following...
We know that GANs, if trained properly, are capable of learning the latent distribution of data and using that information to create new samples. This extraordinary ability of GANs makes them perfect for applications such as image inpainting, which is filling the missing part in images with plausible pixels.
In this section, we will learn how to train a GAN model to perform image inpainting based on 
Efficient convolution from im2col to nn.Unfold 
If you have previously been curious enough to try implementing convolutional neural networks on your own (either with Python or C/C++), you must know the most painful part of work is the backpropagation of gradients, and the most time-consuming part is the convolutions (assuming that it is a plain CNN implementation such as LeNet).
There are several ways to perform the convolution in our code (apart from directly using deep learning tools such as PyTorch):
- Calculate the convolution directly as per definition, which is usually the slowest way. 
- Use - Fast Fourier Transform (FFT) - An algorithm that computes the discrete Fourier transform of a sequence, or its inverse. 
- Treat the convolution as matrix multiplication (in other words, General Matrix Multiply or GeMM) using - im2col. This is the most common method used by numerous software and tools and is a lot faster.
- Use the - Winograd method - In Winograd convolution, the input and kernel are sampled at a given set of points using transform matrices. 
In this section, we will only talk about the first three methods. To learn more about the Winograd method, feel free to check out 
Now that we have understood different types of convolution operations, take the opportunity to test your knowledge by interacting with our AI widget below. You can begin the conversation with a simple “Hello.”
Python code for 2D convolution
Here, we will use Python code for 2D convolution with different methods. Let's follow these steps:
- Directly calculate the convolution. Note that all of the following convolution implementations have a stride size of - and a padding size of - , which means that the output size is - : 
import numpy as npdef conv2d_direct(x, w):w = np.flip(np.flip(w, 0), 1)rows = x.shape[0]cols = x.shape[1]kh = w.shape[0]kw = w.shape[1]rst = np.zeros((rows-kh+1, cols-kw+1))for i in range(rst.shape[0]):for j in range(rst.shape[1]):tmp = 0.for ki in range(kh):for kj in range(kw):tmp += x[i+ki][j+kj] * w[ki][kj]rst[i][j] = tmpreturn rst
As we said before, directly calculating the convolution as per definition is extremely slow. Here is the elapsed time when convolving a