drsaikirant88 commited on
Commit
f9c83e1
1 Parent(s): 3a5accc

Upload darknet.py

Browse files
Files changed (1) hide show
  1. darknet.py +322 -0
darknet.py ADDED
@@ -0,0 +1,322 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # PyTorch implementation of Darknet
2
+ # This is a custom, hard-coded version of darknet with
3
+ # YOLOv3 implementation for openimages database. This
4
+ # was written to test viability of implementing YOLO
5
+ # for face detection followed by emotion / sentiment
6
+ # analysis.
7
+ #
8
+ # Configuration, weights and data are hardcoded.
9
+ # Additional options include, ability to create
10
+ # subset of data with faces exracted for labelling.
11
+ #
12
+ # Author : Saikiran Tharimena
13
+ # Co-Authors: Kjetil Marinius Sjulsen, Juan Carlos Calvet Lopez
14
+ # Project : Emotion / Sentiment Detection from news images
15
+ # Date : 12 September 2022
16
+ # Version : v0.1
17
+ #
18
+ # (C) Schibsted ASA
19
+
20
+ # Libraries
21
+ import torch
22
+ import torch.nn as nn
23
+ import torch.nn.functional as F
24
+ from torch.autograd import Variable
25
+ import numpy as np
26
+ from utils import *
27
+
28
+
29
+ def parse_cfg(cfgfile):
30
+ """
31
+ Takes a configuration file
32
+
33
+ Returns a list of blocks. Each blocks describes a block in the neural
34
+ network to be built. Block is represented as a dictionary in the list
35
+
36
+ """
37
+
38
+ file = open(cfgfile, 'r')
39
+ lines = file.read().split('\n') # store the lines in a list
40
+ lines = [x for x in lines if len(x) > 0] # get read of the empty lines
41
+ lines = [x for x in lines if x[0] != '#'] # get rid of comments
42
+ lines = [x.rstrip().lstrip() for x in lines] # get rid of fringe whitespaces
43
+
44
+ block = {}
45
+ blocks = []
46
+
47
+ for line in lines:
48
+ if line[0] == "[": # This marks the start of a new block
49
+ if len(block) != 0: # If block is not empty, implies it is storing values of previous block.
50
+ blocks.append(block) # add it the blocks list
51
+ block = {} # re-init the block
52
+ block["type"] = line[1:-1].rstrip()
53
+ else:
54
+ key,value = line.split("=")
55
+ block[key.rstrip()] = value.lstrip()
56
+ blocks.append(block)
57
+
58
+ return blocks
59
+
60
+
61
+ class EmptyLayer(nn.Module):
62
+ def __init__(self):
63
+ super(EmptyLayer, self).__init__()
64
+
65
+
66
+ class DetectionLayer(nn.Module):
67
+ def __init__(self, anchors):
68
+ super(DetectionLayer, self).__init__()
69
+ self.anchors = anchors
70
+
71
+
72
+ def create_modules(blocks):
73
+ net_info = blocks[0] #Captures the information about the input and pre-processing
74
+ module_list = nn.ModuleList()
75
+ prev_filters = 3
76
+ output_filters = []
77
+
78
+ for index, x in enumerate(blocks[1:]):
79
+ module = nn.Sequential()
80
+
81
+ #check the type of block
82
+ #create a new module for the block
83
+ #append to module_list
84
+
85
+ #If it's a convolutional layer
86
+ if (x["type"] == "convolutional"):
87
+ #Get the info about the layer
88
+ activation = x["activation"]
89
+ try:
90
+ batch_normalize = int(x["batch_normalize"])
91
+ bias = False
92
+ except:
93
+ batch_normalize = 0
94
+ bias = True
95
+
96
+ filters= int(x["filters"])
97
+ padding = int(x["pad"])
98
+ kernel_size = int(x["size"])
99
+ stride = int(x["stride"])
100
+
101
+ if padding:
102
+ pad = (kernel_size - 1) // 2
103
+ else:
104
+ pad = 0
105
+
106
+ #Add the convolutional layer
107
+ conv = nn.Conv2d(prev_filters, filters, kernel_size, stride, pad, bias = bias)
108
+ module.add_module("conv_{0}".format(index), conv)
109
+
110
+ #Add the Batch Norm Layer
111
+ if batch_normalize:
112
+ bn = nn.BatchNorm2d(filters)
113
+ module.add_module("batch_norm_{0}".format(index), bn)
114
+
115
+ #Check the activation.
116
+ #It is either Linear or a Leaky ReLU for YOLO
117
+ if activation == "leaky":
118
+ activn = nn.LeakyReLU(0.1, inplace = True)
119
+ module.add_module("leaky_{0}".format(index), activn)
120
+
121
+ #If it's an upsampling layer
122
+ #We use Bilinear2dUpsampling
123
+ elif (x["type"] == "upsample"):
124
+ stride = int(x["stride"])
125
+ upsample = nn.Upsample(scale_factor = 2, mode = "nearest")
126
+ module.add_module("upsample_{}".format(index), upsample)
127
+
128
+ #If it is a route layer
129
+ elif (x["type"] == "route"):
130
+ x["layers"] = x["layers"].split(',')
131
+ #Start of a route
132
+ start = int(x["layers"][0])
133
+ #end, if there exists one.
134
+ try:
135
+ end = int(x["layers"][1])
136
+ except:
137
+ end = 0
138
+ #Positive anotation
139
+ if start > 0:
140
+ start = start - index
141
+ if end > 0:
142
+ end = end - index
143
+ route = EmptyLayer()
144
+ module.add_module("route_{0}".format(index), route)
145
+ if end < 0:
146
+ filters = output_filters[index + start] + output_filters[index + end]
147
+ else:
148
+ filters= output_filters[index + start]
149
+
150
+ #shortcut corresponds to skip connection
151
+ elif x["type"] == "shortcut":
152
+ shortcut = EmptyLayer()
153
+ module.add_module("shortcut_{}".format(index), shortcut)
154
+
155
+ #Yolo is the detection layer
156
+ elif x["type"] == "yolo":
157
+ mask = x["mask"].split(",")
158
+ mask = [int(x) for x in mask]
159
+
160
+ anchors = x["anchors"].split(",")
161
+ anchors = [int(a) for a in anchors]
162
+ anchors = [(anchors[i], anchors[i+1]) for i in range(0, len(anchors),2)]
163
+ anchors = [anchors[i] for i in mask]
164
+
165
+ detection = DetectionLayer(anchors)
166
+ module.add_module("Detection_{}".format(index), detection)
167
+
168
+ module_list.append(module)
169
+ prev_filters = filters
170
+ output_filters.append(filters)
171
+
172
+ return (net_info, module_list)
173
+
174
+ class Darknet(nn.Module):
175
+ def __init__(self, cfgfile):
176
+ super(Darknet, self).__init__()
177
+ self.blocks = parse_cfg(cfgfile)
178
+ self.net_info, self.module_list = create_modules(self.blocks)
179
+
180
+ def forward(self, x, CUDA):
181
+ modules = self.blocks[1:]
182
+ outputs = {} #We cache the outputs for the route layer
183
+
184
+ write = 0
185
+ for i, module in enumerate(modules):
186
+ module_type = (module["type"])
187
+
188
+ if module_type == "convolutional" or module_type == "upsample":
189
+ x = self.module_list[i](x)
190
+
191
+ elif module_type == "route":
192
+ layers = module["layers"]
193
+ layers = [int(a) for a in layers]
194
+
195
+ if (layers[0]) > 0:
196
+ layers[0] = layers[0] - i
197
+
198
+ if len(layers) == 1:
199
+ x = outputs[i + (layers[0])]
200
+
201
+ else:
202
+ if (layers[1]) > 0:
203
+ layers[1] = layers[1] - i
204
+
205
+ map1 = outputs[i + layers[0]]
206
+ map2 = outputs[i + layers[1]]
207
+ x = torch.cat((map1, map2), 1)
208
+
209
+
210
+ elif module_type == "shortcut":
211
+ from_ = int(module["from"])
212
+ x = outputs[i-1] + outputs[i+from_]
213
+
214
+ elif module_type == 'yolo':
215
+ anchors = self.module_list[i][0].anchors
216
+ #Get the input dimensions
217
+ inp_dim = int (self.net_info["height"])
218
+
219
+ #Get the number of classes
220
+ num_classes = int (module["classes"])
221
+
222
+ #Transform
223
+ x = x.data
224
+ x = predict_transform(x, inp_dim, anchors, num_classes, CUDA)
225
+ if not write: #if no collector has been intialised.
226
+ detections = x
227
+ write = 1
228
+
229
+ else:
230
+ detections = torch.cat((detections, x), 1)
231
+
232
+ outputs[i] = x
233
+
234
+ return detections
235
+
236
+
237
+ def load_weights(self, weightfile):
238
+ #Open the weights file
239
+ fp = open(weightfile, "rb")
240
+
241
+ #The first 5 values are header information
242
+ # 1. Major version number
243
+ # 2. Minor Version Number
244
+ # 3. Subversion number
245
+ # 4,5. Images seen by the network (during training)
246
+ header = np.fromfile(fp, dtype = np.int32, count = 5)
247
+ self.header = torch.from_numpy(header)
248
+ self.seen = self.header[3]
249
+
250
+ weights = np.fromfile(fp, dtype = np.float32)
251
+
252
+ ptr = 0
253
+ for i in range(len(self.module_list)):
254
+ module_type = self.blocks[i + 1]["type"]
255
+
256
+ #If module_type is convolutional load weights
257
+ #Otherwise ignore.
258
+
259
+ if module_type == "convolutional":
260
+ model = self.module_list[i]
261
+ try:
262
+ batch_normalize = int(self.blocks[i+1]["batch_normalize"])
263
+ except:
264
+ batch_normalize = 0
265
+
266
+ conv = model[0]
267
+
268
+
269
+ if (batch_normalize):
270
+ bn = model[1]
271
+
272
+ #Get the number of weights of Batch Norm Layer
273
+ num_bn_biases = bn.bias.numel()
274
+
275
+ #Load the weights
276
+ bn_biases = torch.from_numpy(weights[ptr:ptr + num_bn_biases])
277
+ ptr += num_bn_biases
278
+
279
+ bn_weights = torch.from_numpy(weights[ptr: ptr + num_bn_biases])
280
+ ptr += num_bn_biases
281
+
282
+ bn_running_mean = torch.from_numpy(weights[ptr: ptr + num_bn_biases])
283
+ ptr += num_bn_biases
284
+
285
+ bn_running_var = torch.from_numpy(weights[ptr: ptr + num_bn_biases])
286
+ ptr += num_bn_biases
287
+
288
+ #Cast the loaded weights into dims of model weights.
289
+ bn_biases = bn_biases.view_as(bn.bias.data)
290
+ bn_weights = bn_weights.view_as(bn.weight.data)
291
+ bn_running_mean = bn_running_mean.view_as(bn.running_mean)
292
+ bn_running_var = bn_running_var.view_as(bn.running_var)
293
+
294
+ #Copy the data to model
295
+ bn.bias.data.copy_(bn_biases)
296
+ bn.weight.data.copy_(bn_weights)
297
+ bn.running_mean.copy_(bn_running_mean)
298
+ bn.running_var.copy_(bn_running_var)
299
+
300
+ else:
301
+ #Number of biases
302
+ num_biases = conv.bias.numel()
303
+
304
+ #Load the weights
305
+ conv_biases = torch.from_numpy(weights[ptr: ptr + num_biases])
306
+ ptr = ptr + num_biases
307
+
308
+ #reshape the loaded weights according to the dims of the model weights
309
+ conv_biases = conv_biases.view_as(conv.bias.data)
310
+
311
+ #Finally copy the data
312
+ conv.bias.data.copy_(conv_biases)
313
+
314
+ #Let us load the weights for the Convolutional layers
315
+ num_weights = conv.weight.numel()
316
+
317
+ #Do the same as above for weights
318
+ conv_weights = torch.from_numpy(weights[ptr:ptr+num_weights])
319
+ ptr = ptr + num_weights
320
+
321
+ conv_weights = conv_weights.view_as(conv.weight.data)
322
+ conv.weight.data.copy_(conv_weights)