Files

193 lines
6.3 KiB
Python
Executable File

#!/bin/python
import numpy as np
import torch
import torch.nn as nn
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# Use the formula:
# [(W-K+2P)/S] + 1
# where:
# W: Is the input volume size for each dimension
# K: Is the kernel size
# P: Is the padding
# S: Is the stride
def CalcConvFormula(W, K, P, S):
return int(np.floor(((W - K + 2 * P) / S) + 1))
# https://stackoverflow.com/questions/53580088/calculate-the-output-size-in-convolution-layer
# Calculate the output shape after applying a convolution
def CalcConvOutShape(in_shape, kernel_size, padding, stride, out_filters):
# Multiple options for different kernel shapes
if type(kernel_size) == int:
out_shape = [CalcConvFormula(in_shape[i], kernel_size, padding, stride) for i in range(2)]
else:
out_shape = [CalcConvFormula(in_shape[i], kernel_size[i], padding, stride) for i in range(2)]
return (out_shape[0], out_shape[1], out_filters) # , batch_size... but not necessary.
class CNN(nn.Module):
def __init__(self
, in_features
, out_features
, conv_filters
, conv_kernel_size
, conv_strides
, conv_pad
, actv_func
, max_pool_kernels
, max_pool_strides
, l1=120
, l2=84
, MLP=None
, pre_module_list=None
, use_dropout=False
, use_batch_norm=False
, device="cpu"
):
super(CNN, self).__init__()
# Gerneral model Properties
self.in_features = in_features
self.out_features = out_features
# Convolution operations
self.conv_filters = conv_filters
self.conv_kernel_size = conv_kernel_size
self.conv_strides = conv_strides
self.conv_pad = conv_pad
# Convolution Activiations
self.actv_func = actv_func
# Max Pools
self.max_pool_kernels = max_pool_kernels
self.max_pool_strides = max_pool_strides
# Regularization
self.use_dropout = use_dropout
self.use_batch_norm = use_batch_norm
# Tunable parameters
self.l1 = l1
self.l2 = l2
# Number of conv/pool/act/batch_norm/dropout layers we add
self.n_conv_layers = len(self.conv_filters)
# Create the module list
if pre_module_list:
self.module_list = pre_module_list
else:
self.module_list = nn.ModuleList()
self.shape_list = []
self.shape_list.append(self.in_features)
self.build_()
# Send to gpu
self.device = device
self.to(self.device)
def build_(self):
# Track shape
cur_shape = self.GetCurShape()
for i in range(self.n_conv_layers):
if i == 0:
if len(self.in_features) == 2:
in_channels = 1
else:
in_channels = self.in_features[2]
else:
in_channels = self.conv_filters[i - 1]
cur_shape = CalcConvOutShape(cur_shape, self.conv_kernel_size[i], self.conv_pad[i], self.conv_strides[i],
self.conv_filters[i])
self.shape_list.append(cur_shape)
conv = nn.Conv2d(in_channels=in_channels,
out_channels=self.conv_filters[i],
kernel_size=self.conv_kernel_size[i],
padding=self.conv_pad[i],
stride=self.conv_strides[i]
)
self.module_list.append(conv)
if self.use_batch_norm:
self.module_list.append(nn.BatchNorm2d(cur_shape[2]))
if self.use_dropout:
self.module_list.append(nn.Dropout(p=0.15))
# Add the Activation function
if self.actv_func[i]:
self.module_list.append(GetActivation(name=self.actv_func[i]))
if self.max_pool_kernels:
if self.max_pool_kernels[i]:
self.module_list.append(nn.MaxPool2d(self.max_pool_kernels[i], stride=self.max_pool_strides[i]))
cur_shape = CalcConvOutShape(cur_shape, self.max_pool_kernels[i], 0, self.max_pool_strides[i],
cur_shape[2])
self.shape_list.append(cur_shape)
# # Adding MLP
s = self.GetCurShape()
in_features = s[0] * s[1] * s[2]
self.module_list.append(nn.Linear(in_features, self.l1))
self.module_list.append(nn.ReLU())
self.module_list.append(nn.Linear(self.l1, self.l2))
self.module_list.append(nn.ReLU())
self.module_list.append(nn.Linear(self.l2, self.out_features))
def forward(self, x):
j = 0
for i, module in enumerate(self.module_list):
if isinstance(module, nn.Linear) and j == 0:
x = torch.flatten(x.float(), start_dim=1)
j = 1
x = module(x)
return x
def GetCurShape(self):
return self.shape_list[-1]
def GetCNN(l1=120, l2=84):
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
cnn = CNN(in_features=(32, 32, 3),
out_features=10,
conv_filters=[32, 32, 64, 64], # , 128, 256, 512
conv_kernel_size=[3, 3, 3, 3], # ,3,3,1
conv_strides=[1, 1, 1, 1], # ,1,1,1
conv_pad=[0, 0, 0, 0, 0, 0, 0],
actv_func=["relu", "relu", "relu", "relu"], # , "relu", "relu", "relu"
max_pool_kernels=[None, (2, 2), None, (2, 2)], # , None, None, None
max_pool_strides=[None, 2, None, 2], # , None,None, None
l1=l1,
l2=l2,
use_dropout=False,
use_batch_norm=True, # False
device=device
)
return cnn
def GetActivation(name="relu"):
if name == "relu":
return nn.ReLU()
elif name == "leakyrelu":
return nn.LeakyReLU()
elif name == "Sigmoid":
return nn.Sigmoid()
elif name == "Tanh":
return nn.Tanh()
elif name == "Identity":
return nn.Identity()
else:
return nn.ReLU()