-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmodel.py
More file actions
205 lines (148 loc) · 5.61 KB
/
Copy pathmodel.py
File metadata and controls
205 lines (148 loc) · 5.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
'''
This file defines the neural network and the loss function.
For popular networks, visit https://pytorch.org/docs/stable/torchvision/models.html
for a tutorial on how to use them. It's not covered here
- All neural networks must inherit the nn.Module class
- All networks must have two defined functions:
`__init__` initializes the class
`forward` defines the forward pass of data through the model
A PyTorch neural network skeleton looks like this:
class My_Network(nn.Module):
def __init__(self, my_other_arguments):
super(My_Network, self).__init__()
# Network *layers* go here
def forward(self, my_batch_data):
# Network *structure/order* goes here
return network_output
PyTorch's torch.nn module has many prebuilt functions that may be useful:
Fully connected layers (nn.Linear)
Convolutional layers (nn.Conv2d)
Pooling layers (nn.MaxPool2d, nn.AvgPool2d)
Dropout layers (nn.Dropout2d)
Activation functions (nn.ReLU, nn.Sigmoid)
Loss functions (nn.MSELoss, nn.CrossEntropyLoss)
Please reference https://pytorch.org/docs/stable/nn.html for all things neural net
'''
import torch
import torch.nn as nn
'''
This is the main network class that defines the layers and structure.
The loss function is *not* a part of the main network
'''
class Example_Network(nn.Module):
def __init__(self, n_blocks = 4, n_channels = 16):
super(Example_Network, self).__init__()
self.conv_in = nn.Conv2d(in_channels = 1,
out_channels = n_channels,
kernel_size = 3,
stride = 1,
padding = 1,
bias = False)
self.inner_convs = self.make_layers(block = Inner_Conv_Block,
n_blocks = n_blocks)
self.conv_out = nn.Conv2d(in_channels = n_channels,
out_channels = 1,
kernel_size = 3,
stride = 1,
padding = 1,
bias = False)
'''
Inner_Conv_Block decreases the spatial resolution of the original image (28x28).
No padding is used for a kernel of size 3x3, so each dimension decreases by 2
for each of the `n_block` convolutions. The variable `output_size` calculates
the output size based on `n_blocks`.
'''
self.output_size = 28 - (2 * n_blocks)
self.inner_fc1 = Inner_Linear_Block(in_features = self.output_size * self.output_size,
out_features = 20)
self.inner_fc2 = Inner_Linear_Block(in_features = 20,
out_features = 10)
self.fc_out = nn.Linear(in_features = 10,
out_features = 10)
self.relu = nn.ReLU()
def forward(self, input):
output = self.relu(self.conv_in(input))
output = self.inner_convs(output)
output = self.relu(self.conv_out(output))
'''
When you switch from convolutions to fully connected layers, PyTorch requires
that the shape of the data be adjusted (flattened).
'''
output = output.view(-1, self.output_size * self.output_size)
output = self.inner_fc1(output)
output = self.inner_fc2(output)
output = self.fc_out(output)
return output
'''
This is a great function that creates many identical layers sequentially.
Here, we will use it to create many Inner_Conv_Block layers in our network.
'''
def make_layers(self, block, n_blocks):
layers = [block()] * n_blocks
return nn.Sequential(*layers)
'''
Inner_Conv_Block contains three layers:
1) Convolution
2) Batch Normalization
3) ReLU Activation
'''
class Inner_Conv_Block(nn.Module):
def __init__(self, n_channels = 16):
super(Inner_Conv_Block, self).__init__()
self.conv = nn.Conv2d(in_channels = n_channels,
out_channels = n_channels,
kernel_size = 3,
stride = 1,
padding = 0,
bias = False)
self.batch_norm = nn.BatchNorm2d(num_features = n_channels)
self.relu = nn.ReLU()
def forward(self, input):
return self.relu(self.batch_norm(self.conv(input)))
'''
Inner_Linear_Block contains three layers:
1) Fully Connected
2) Batch Normalization
3) ReLU Activation
'''
class Inner_Linear_Block(nn.Module):
def __init__(self, in_features, out_features):
super(Inner_Linear_Block, self).__init__()
self.lin = nn.Linear(in_features = in_features,
out_features = out_features)
self.batch_norm = nn.BatchNorm1d(num_features = out_features)
self.relu = nn.ReLU()
def forward(self, input):
return self.relu(self.lin(input))
'''
You don't need a class for the loss function if it's predefined in torch.nn.
This loss function is here as an example for how to do a custom loss function.
Here we use a sigmoid function with the mean squared error.
'''
class Loss_Function(nn.Module):
def __init__(self):
super(Loss_Function, self).__init__()
self.sig = nn.Sigmoid()
self.mse = nn.MSELoss()
def forward(self, prediction, target):
return self.mse(self.sig(prediction), target)
'''
This just checks to make sure that the network works/initializes properly.
'''
if __name__ == '__main__':
# Set the seed for reproducibility
torch.manual_seed(0)
# Example image and class
test_im = torch.zeros((1,1,28,28))
test_class = torch.tensor([[0,0,0,1,0,0,0,0,0,0]],
dtype = torch.float)
# Initialize the network and loss function
net = Example_Network()
loss = Loss_Function()
# Forward pass without keeping track of the gradient
with torch.no_grad():
net_output = net(test_im)
net_loss = loss(net_output, test_class)
print(net_output)
print(net_loss)
###