<jupyter_start><jupyter_text><jupyter_code>%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
from scipy.ndimage.filters import convolve
from scipy.signal import convolve2d
from scipy import misc<jupyter_output><empty_output><jupyter_text>Convolution  1-d convolutionThe mathematical definition of convolution of two 1-dimensional signals is given by$$(i * f)(T) = \sum_{t=0}^{T}i(t)f(T-t)$$Let $i$ be the input signal and $f$ be called the filter. If we had to overly simplify, given an appropriate filter the result of the convolution indicates the changes in input signal.<jupyter_code>i = np.array([0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0], dtype='float32')
f = np.array([-1,1], dtype='float32')
c = np.convolve(i, f)<jupyter_output><empty_output><jupyter_text>The spikes in result of the convolution, $c$, indicates the change in the input signal, $i$.<jupyter_code>plt.subplot(311)
plt.plot(i, 'o-')

plt.subplot(312)
plt.plot(f, 'o')

plt.subplot(313)
plt.plot(c, 'o-')<jupyter_output><empty_output><jupyter_text>2-d convolutionWhile the mathematical equation for 2-d convolution is slightly more complicated, it is similar to 1-d convolution in spirit. The result of the convulution of a filter with an input signal indicates changes in the same. The most popular 2-d signal is an image. A stark in the pixel values of an image indiacte an edge. Below example of filteres which approximately detect horizontal/vertical edges.<jupyter_code>img = misc.ascent()
print('Image shape: ', img.shape)
plt.imshow(img, cmap='gray')<jupyter_output>Image shape:  (512, 512)<jupyter_text>Horizontal edge filter<jupyter_code># horizontal lines where top is white and bottom is black
h_filter = np.array([[ 2,  2,  2],
                     [ 0,  0,  0],
                     [-2, -2, -2]])
plt.imshow(h_filter, cmap='gray')
res = convolve2d(img, h_filter)

# enhanced some parts and suppressed other parts
plt.imshow(res, cmap='gray')<jupyter_output><empty_output><jupyter_text>Vertical edge filter<jupyter_code># vertical lines where top is white and bottom is black
v_filter = np.array([[ 2,  0,  -2],
                     [ 2,  0,  -2],
                     [2, 0, -2]])
plt.imshow(v_filter, cmap='gray')
res = convolve2d(img, v_filter)

# enhanced some parts and suppressed other parts
plt.imshow(res, cmap='gray')<jupyter_output><empty_output><jupyter_text>Convolutional layer in PyTorch<jupyter_code>import torch
from torch import nn

class ConvLayer(nn.Module):
  def __init__(self):
    super().__init__()
    self.conv1 = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=(3, 3), stride=1, padding=0)

  def forward(self, xb):
    return self.conv1(xb)

conv_layer = ConvLayer()
conv_layer.conv1.weight
img = torch.tensor(img).view(1, 1, 512, 512)
conv_layer.conv1.weight = nn.Parameter(torch.FloatTensor([[[[ 2,  0,  -2],
                                             [ 2,  0,  -2],
                                             [2, 0, -2]]]]))

out = conv_layer(img.float())
plt.imshow(out.view(510, 510).detach().numpy(), cmap='gray')
plt.imshow(conv_layer.conv1.weight.view(3, 3).detach().numpy(), cmap='gray')<jupyter_output><empty_output><jupyter_text>PoolingPooling is useful to induce spacial invariance in our model. It also helps to reduce the parameters of our model by reducing the dimension of input.  Pooling layers in PyTorch  Max pooling<jupyter_code>import torch
from torch import nn

class MaxPoolLayer(nn.Module):
  def __init__(self):
    super().__init__()
    self.pool1 = nn.MaxPool2d(kernel_size=(4, 4), padding=0)

  def forward(self, xb):
    return self.pool1(xb)

max_pool_layer = MaxPoolLayer()
img = torch.tensor(img).view(1, 1, 512, 512)

out = max_pool_layer(img.float())
plt.imshow(out.view(128, 128).detach().numpy(), cmap='gray')<jupyter_output>/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:1: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).
  """Entry point for launching an IPython kernel.<jupyter_text>Average pooling<jupyter_code>import torch
from torch import nn

class AvgPoolLayer(nn.Module):
  def __init__(self):
    super().__init__()
    self.pool1 = nn.AvgPool2d(kernel_size=(4, 4), padding=0)

  def forward(self, xb):
    return self.pool1(xb)

avg_pool_layer = AvgPoolLayer()
img = torch.tensor(img).view(1, 1, 512, 512)

out = avg_pool_layer(img.float())
plt.imshow(out.view(128, 128).detach().numpy(), cmap='gray')<jupyter_output>/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:1: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).
  """Entry point for launching an IPython kernel.
{'fraction_non_alphanumeric': 0.12991803278688524, 'fraction_numerical': 0.03012295081967213, 'mean_word_length': 4.546590909090909, 'pattern_counts': {'":': 0, '<': 34, '<?xml version=': 0, '>': 34, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '506925', 'license': 'MIT', 'n_tokens_mistral': 1786, 'n_tokens_neox': 1653, 'n_words': 458, 'path': 'Lecture4_conv_pool.ipynb', 'repo_name': 'CharlesPoletowin/YCBS-273', 'size': '4880'}