# Neural Network Programming - Deep Learning with PyTorch

Deep Learning Course 3 of 4 - Level: Intermediate

## Build PyTorch CNN - Object Oriented Neural Networks

### video

expand_more chevron_left

### text

expand_more chevron_left

### Building neural networks with PyTorch

Welcome back to this series on neural network programming with PyTorch. In this post, we will begin building our first convolutional neural network (CNN) using PyTorch. Without further ado, let's get started.

#### Bird's eye view of the process

From a high-level perspective or bird's eye view of our deep learning project, we prepared our data, and now, we are ready to build our model.

• Prepare the data
• Build the model
• Train the model
• Analyze the model’s results

When say model, we mean our network. The words model and network mean the same thing. What we want our network to ultimately do is model or approximate a function that maps image inputs to the correct output class.

#### Prerequisites

To build neural networks in PyTorch, we extend the torch.nn.Module PyTorch class. This means we need to utilize a little bit of object oriented programming (OOP) in Python.

We’ll do a quick OOP review in this post to cover the details needed for working with PyTorch neural networks, but if you find that you need more, the Python docs have an overview tutorial here.

To build a convolutional neural network, we need to have a general understanding of how CNNs work and what components are used to build CNNs. This deep learning fundamentals series is a good prerequisite for this series, so I highly recommend you cover that one if you haven't already. If you just want a crash course on CNNs, these are the specific posts to see:

Let's jump in now with a quick object oriented programming review.

#### Quick object oriented programming review

When we’re writing programs or building software, there are two key components, code and data. With object oriented programming, we orient our program design and structure around objects.

Objects are defined in code using classes. A class defines the object's specification or spec, which specifies what data and code each object of the class should have.

When we create an object of a class, we call the object an instance of the class, and all instances of a given class have two core components:

• Methods (code)
• Attributes (data)

The methods represent the code, while the attributes represent the data, and so the methods and attributes are defined by the class.

In a given program, many objects, a.k.a instances of a given class, can exist simultaneously, and all of the instances will have the same available attributes and the same available methods. They are uniform from this perspective.

The difference between objects of the same class is the values contained within the object for each attribute. Each object has its own attribute values. These values determine the internal state of the object. The code and data of each object is said to be encapsulated within the object.

Let’s build a simple lizard class to demonstrate how classes encapsulate data and code:

class Lizard: #class declaration
def __init__(self, name): #class constructor (code)
self.name = name #attribute (data)

def set_name(self, name): #method declaration (code)
self.name = name #method implementation (code)


The first line declares the class and specifies the class name, which in this case is Lizard.

The second line defines a special method called the class constructor. Class constructors are called when a new instance of the class is created. As parameters, we have self and name.

The self parameter gives us the ability to create attribute values that are stored or encapsulated within the object. When we call this constructor or any of the other methods, we don't pass the self parameter. Python does this for us automatically.

Argument values for any other parameter are arbitrarily passed by the caller, and these passed values that come in to the method can be used in a calculation or saved and accessed later using self.

After we're done with the constructor, we can create any number of specialized methods like this one here that allows a caller to change the name value that was stored in self. All we have to do here is call the method and pass a new value for the name. Let's see this in action.

> lizard = Lizard('deep')
> print(lizard.name)
deep

> lizard.set_name('lizard')
> print(lizard.name)
lizard


We create an object instance of the class by specifying the class name and passing the constructor arguments. The constructor will receive these arguments and the constructor code will run saving the passed name.

We can then access the name and print it, and also call the set_name() method to change the name. Multiple of these Lizard instances can exist inside a program, and each one will contain its own data.

From an object oriented standpoint, the important part about this setup is that the attributes and the methods are organized and contained within an object.

Let's switch gears now and look at how object oriented programming fits in with PyTorch.

### PyTorch’s torch.nn package

To build neural networks in PyTorch, we use the torch.nn package, which is PyTorch’s neural network (nn) library. We typically import the package like so:

import torch.nn as nn


This allows us to access neural network package using the nn alias. So from now on, if we say nn, we mean torch.nn. PyTorch’s neural network library contains all of the typical components needed to build neural networks.

The primary component we'll need to build a neural network is a layer, and so, as we might expect, PyTorch's neural network library contains classes that aid us in constructing layers.

#### PyTorch's nn.Module class

As we know, deep neural networks are built using multiple layers. This is what makes the network deep. Each layer in a neural network has two primary components:

• A transformation (code)
• A collection of weights (data)

Like many things in life, this fact makes layers great candidates to be represented as objects using OOP. OOP is short for object oriented programming.

In fact, this is the case with PyTorch. Within the nn package, there is a class called Module, and it is the base class for all of neural network modules which includes layers.

This means that all of the layers in PyTorch extend the nn.Module class and inherit all of PyTorch’s built-in functionality within the nn.Module class. In OOP this concept is known as inheritance.

Even neural networks extend the nn.Module class. This makes sense because neural networks themselves can be thought of as one big layer (if needed, let that sink in over time).

Neural networks and layers in PyTorch extend the nn.Module class. This means that we must extend the nn.Module class when building a new layer or neural network in PyTorch.

#### PyTorch nn.Modules have a forward() method

When we pass a tensor to our network as input, the tensor flows forward though each layer transformation until the tensor reaches the output layer. This process of a tensor flowing forward though the network is known as a forward pass.

The tensor input is passed forward though the network.

Each layer has its own transformation (code) and the tensor passes forward through each layer. The composition of all the individual layer forward passes defines the overall forward pass transformation for the network.

The goal of the overall transformation is to transform or map the input to the correct prediction output class, and during the training process, the layer weights (data) are updated in such a way that cause the mapping to adjust to make the output closer to the correct prediction.

What this all means is that, every PyTorch nn.Module has a forward() method, and so when we are building layers and networks, we must provide an implementation of the forward() method. The forward method is the actual transformation.

#### PyTorch’s nn.functional package

When we implement the forward() method of our nn.Module subclass, we will typically use functions from the nn.functional package. This package provides us with many neural network operations that we can use for building layers. In fact, many of the nn.Module layer classes use nn.functional functions to perform their operations.

The nn.functional package contains methods that subclasses of nn.Module use for implementing their forward() functions. Later, we see an example of this by looking at the PyTorch source code of the nn.Conv2d convolutional layer class.

### Building a neural network in PyTorch

We now have enough information to provide an outline for building neural networks in PyTorch. The steps are as follows:

Short version:

1. Extend the nn.Module base class.
2. Define layers as class attributes.
3. Implement the forward() method.

More detailed version:

1. Create a neural network class that extends the nn.Module base class.
2. In the class constructor, define the network’s layers as class attributes using pre-built layers from torch.nn.
3. Use the network’s layer attributes as well as operations from the nn.functional API to define the network’s forward pass.

#### Extending PyTorch’s nn.Module class

Like we did with the Lizard class example, let’s create a simple class to represent a neural network.

class Network:
def __init__(self):
self.layer = None

def forward(self, t):
t = self.layer(t)
return t


This gives us a simple network class that has a single dummy layer inside the constructor and a dummy implementation for the forward function.

The implementation for the forward() function takes in a tensor t and transforms it using the dummy layer. After the tensor is transformed, the new tensor is returned.

This is a good start, but the class hasn’t yet extended the nn.Module class. To make our Network class extend nn.Module, we must do two additional things:

1. Specify the nn.Module class in parentheses on line 1.
2. Insert a call to the super class constructor on line 3 inside the constructor.

This gives us:

class Network(nn.Module): # line 1
def __init__(self):
super().__init__() # line 3
self.layer = None

def forward(self, t):
t = self.layer(t)
return t


These changes transform our simple neural network into a PyTorch neural network because we are now extending PyTorch's nn.Module base class.

With this, we are done! Now we have a Network class that has all of the functionality of the PyTorch nn.Module class.

#### Define the network’s layers as class attributes

At the moment, our Network class has a single dummy layer as an attribute. Let’s replace this now with some real layers that come pre-built for us from PyTorch's nn library. We’re building a CNN, so the two types of layers we'll use are linear layers and convolutional layers.

class Network(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5)
self.conv2 = nn.Conv2d(in_channels=6, out_channels=12, kernel_size=5)

self.fc1 = nn.Linear(in_features=12 * 4 * 4, out_features=120)
self.fc2 = nn.Linear(in_features=120, out_features=60)
self.out = nn.Linear(in_features=60, out_features=10)

def forward(self, t):
# implement the forward pass
return t


Alright. At this point, we have a Python class called Network that extends PyTorch’s nn.Module class. Inside of our Network class, we have five layers that are defined as attributes. We have two convolutional layers, self.conv1 and self.conv2, and three linear layers, self.fc1, self.fc2, self.out.

We used the abbreviation fc in fc1 and fc2 because linear layers are also called fully connected layers. They also have a third name that we may hear sometimes called dense. So linear, dense, and fully connected are all ways to refer to the same type of layer. PyTorch uses the word linear, hence the nn.Linear class name.

We used the name out for the last linear layer because the last layer in the network is the output layer.

### Wrapping up

We should now have a good idea about how to get started building neural networks in PyTorch using the torch.nn library. In the next post we'll investigate the different types of parameters of our layers and gain an understanding of how they are chosen. I'll see you in the next one.

### quiz

expand_more chevron_left

### resources

expand_more chevron_left

expand_more chevron_left