forked from WaqasSultani/AnomalyDetectionCVPR2018
-
Notifications
You must be signed in to change notification settings - Fork 0
/
TrainingAnomalyDetector_public.py
318 lines (245 loc) · 11.7 KB
/
TrainingAnomalyDetector_public.py
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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, TimeDistributedDense ,LSTM,Reshape
from keras.regularizers import l2
from keras.optimizers import SGD,adam, Adagrad
from scipy.io import loadmat, savemat
from keras.models import model_from_json
import theano.tensor as T
import theano
import csv
import ConfigParser
import collections
import time
import csv
import os
from os import listdir
import skimage.transform
from skimage import color
from os.path import isfile, join
import numpy as np
import numpy
from datetime import datetime
import path
from os.path import basename
import glob
import theano.sandbox
theano.sandbox.cuda.use('gpu0')
print("Create Model")
model = Sequential()
model.add(Dense(512, input_dim=4096,init='glorot_normal',W_regularizer=l2(0.001),activation='relu'))
model.add(Dropout(0.6))
model.add(Dense(32,init='glorot_normal',W_regularizer=l2(0.001)))
model.add(Dropout(0.6))
model.add(Dense(1,init='glorot_normal',W_regularizer=l2(0.001),activation='sigmoid'))
def load_model(json_path): # Function to load the model
model = model_from_json(open(json_path).read())
return model
def load_weights(model, weight_path): # Function to load the model weights
dict2 = loadmat(weight_path)
dict = conv_dict(dict2)
i = 0
for layer in model.layers:
weights = dict[str(i)]
layer.set_weights(weights)
i += 1
return model
def conv_dict(dict2):
i = 0
dict = {}
for i in range(len(dict2)):
if str(i) in dict2:
if dict2[str(i)].shape == (0, 0):
dict[str(i)] = dict2[str(i)]
else:
weights = dict2[str(i)][0]
weights2 = []
for weight in weights:
if weight.shape in [(1, x) for x in range(0, 5000)]:
weights2.append(weight[0])
else:
weights2.append(weight)
dict[str(i)] = weights2
return dict
def save_model(model, json_path, weight_path): # Function to save the model
json_string = model.to_json()
open(json_path, 'w').write(json_string)
dict = {}
i = 0
for layer in model.layers:
weights = layer.get_weights()
my_list = np.zeros(len(weights), dtype=np.object)
my_list[:] = weights
dict[str(i)] = my_list
i += 1
savemat(weight_path, dict)
# Load Training Dataset
def load_dataset_Train_batch(AbnormalPath, NormalPath):
# print("Loading training batch")
batchsize=60 # Each batch contain 60 videos.
n_exp=batchsize/2 # Number of abnormal and normal videos
Num_abnormal = 810 # Total number of abnormal videos in Training Dataset.
Num_Normal = 800 # Total number of Normal videos in Training Dataset.
# We assume the features of abnormal videos and normal videos are located in two different folders.
Abnor_list_iter = np.random.permutation(Num_abnormal)
Abnor_list_iter = Abnor_list_iter[Num_abnormal-n_exp:] # Indexes for randomly selected Abnormal Videos
Norm_list_iter = np.random.permutation(Num_Normal)
Norm_list_iter = Norm_list_iter[Num_Normal-n_exp:] # Indexes for randomly selected Normal Videos
AllVideos_Path = AbnormalPath
def listdir_nohidden(AllVideos_Path): # To ignore hidden files
file_dir_extension = os.path.join(AllVideos_Path, '*_C.txt')
for f in glob.glob(file_dir_extension):
if not f.startswith('.'):
yield os.path.basename(f)
All_Videos=sorted(listdir_nohidden(AllVideos_Path))
All_Videos.sort()
AllFeatures = [] # To store C3D features of a batch
print("Loading Abnormal videos Features...")
Video_count=-1
for iv in Abnor_list_iter:
Video_count=Video_count+1
VideoPath = os.path.join(AllVideos_Path, All_Videos[iv])
f = open(VideoPath, "r")
words = f.read().split()
num_feat = len(words) / 4096
# Number of features per video to be loaded. In our case num_feat=32, as we divide the video into 32 segments. Note that
# we have already computed C3D features for the whole video and divide the video features into 32 segments. Please see Save_C3DFeatures_32Segments.m as well
count = -1;
VideoFeatues = []
for feat in xrange(0, num_feat):
feat_row1 = np.float32(words[feat * 4096:feat * 4096 + 4096])
count = count + 1
if count == 0:
VideoFeatues = feat_row1
if count > 0:
VideoFeatues = np.vstack((VideoFeatues, feat_row1))
if Video_count == 0:
AllFeatures = VideoFeatues
if Video_count > 0:
AllFeatures = np.vstack((AllFeatures, VideoFeatues))
print(" Abnormal Features loaded")
print("Loading Normal videos...")
AllVideos_Path = NormalPath
def listdir_nohidden(AllVideos_Path): # To ignore hidden files
file_dir_extension = os.path.join(AllVideos_Path, '*_C.txt')
for f in glob.glob(file_dir_extension):
if not f.startswith('.'):
yield os.path.basename(f)
All_Videos = sorted(listdir_nohidden(AllVideos_Path))
All_Videos.sort()
for iv in Norm_list_iter:
VideoPath = os.path.join(AllVideos_Path, All_Videos[iv])
f = open(VideoPath, "r")
words = f.read().split()
feat_row1 = np.array([])
num_feat = len(words) /4096 # Number of features to be loaded. In our case num_feat=32, as we divide the video into 32 segments.
count = -1;
VideoFeatues = []
for feat in xrange(0, num_feat):
feat_row1 = np.float32(words[feat * 4096:feat * 4096 + 4096])
count = count + 1
if count == 0:
VideoFeatues = feat_row1
if count > 0:
VideoFeatues = np.vstack((VideoFeatues, feat_row1))
feat_row1 = []
AllFeatures = np.vstack((AllFeatures, VideoFeatues))
print("Features loaded")
AllLabels = np.zeros(32*batchsize, dtype='uint8')
th_loop1=n_exp*32
th_loop2=n_exp*32-1
for iv in xrange(0, 32*batchsize):
if iv< th_loop1:
AllLabels[iv] = int(0) # All instances of abnormal videos are labeled 0. This will be used in custom_objective to keep track of normal and abnormal videos indexes.
if iv > th_loop2:
AllLabels[iv] = int(1) # All instances of Normal videos are labeled 1. This will be used in custom_objective to keep track of normal and abnormal videos indexes.
# print("ALLabels loaded")
return AllFeatures,AllLabels
def custom_objective(y_true, y_pred):
'Custom Objective function'
y_true = T.flatten(y_true)
y_pred = T.flatten(y_pred)
n_seg = 32 # Because we have 32 segments per video.
nvid = 60
n_exp = nvid / 2
Num_d=32*nvid
sub_max = T.ones_like(y_pred) # sub_max represents the highest scoring instants in bags (videos).
sub_sum_labels = T.ones_like(y_true) # It is used to sum the labels in order to distinguish between normal and abnormal videos.
sub_sum_l1=T.ones_like(y_true) # For holding the concatenation of summation of scores in the bag.
sub_l2 = T.ones_like(y_true) # For holding the concatenation of L2 of score in the bag.
for ii in xrange(0, nvid, 1):
# For Labels
mm = y_true[ii * n_seg:ii * n_seg + n_seg]
sub_sum_labels = T.concatenate([sub_sum_labels, T.stack(T.sum(mm))]) # Just to keep track of abnormal and normal vidoes
# For Features scores
Feat_Score = y_pred[ii * n_seg:ii * n_seg + n_seg]
sub_max = T.concatenate([sub_max, T.stack(T.max(Feat_Score))]) # Keep the maximum score of scores of all instances in a Bag (video)
sub_sum_l1 = T.concatenate([sub_sum_l1, T.stack(T.sum(Feat_Score))]) # Keep the sum of scores of all instances in a Bag (video)
z1 = T.ones_like(Feat_Score)
z2 = T.concatenate([z1, Feat_Score])
z3 = T.concatenate([Feat_Score, z1])
z_22 = z2[31:]
z_44 = z3[:33]
z = z_22 - z_44
z = z[1:32]
z = T.sum(T.sqr(z))
sub_l2 = T.concatenate([sub_l2, T.stack(z)])
# sub_max[Num_d:] means include all elements after Num_d.
# AllLabels =[2 , 4, 3 ,9 ,6 ,12,7 ,18 ,9 ,14]
# z=x[4:]
#[ 6. 12. 7. 18. 9. 14.]
sub_score = sub_max[Num_d:] # We need this step since we have used T.ones_like
F_labels = sub_sum_labels[Num_d:] # We need this step since we have used T.ones_like
# F_labels contains integer 32 for normal video and 0 for abnormal videos. This because of labeling done at the end of "load_dataset_Train_batch"
# AllLabels =[2 , 4, 3 ,9 ,6 ,12,7 ,18 ,9 ,14]
# z=x[:4]
# [ 2 4 3 9]... This shows 0 to 3 elements
sub_sum_l1 = sub_sum_l1[Num_d:] # We need this step since we have used T.ones_like
sub_sum_l1 = sub_sum_l1[:n_exp]
sub_l2 = sub_l2[Num_d:] # We need this step since we have used T.ones_like
sub_l2 = sub_l2[:n_exp]
indx_nor = theano.tensor.eq(F_labels, 32).nonzero()[0] # Index of normal videos: Since we labeled 1 for each of 32 segments of normal videos F_labels=32 for normal video
indx_abn = theano.tensor.eq(F_labels, 0).nonzero()[0]
n_Nor=n_exp
Sub_Nor = sub_score[indx_nor] # Maximum Score for each of abnormal video
Sub_Abn = sub_score[indx_abn] # Maximum Score for each of normal video
z = T.ones_like(y_true)
for ii in xrange(0, n_Nor, 1):
sub_z = T.maximum(1 - Sub_Abn + Sub_Nor[ii], 0)
z = T.concatenate([z, T.stack(T.sum(sub_z))])
z = z[Num_d:] # We need this step since we have used T.ones_like
z = T.mean(z, axis=-1) + 0.00008*T.sum(sub_sum_l1) + 0.00008*T.sum(sub_l2) # Final Loss f
return z
adagrad=Adagrad(lr=0.01, epsilon=1e-08)
model.compile(loss=custom_objective, optimizer=adagrad)
print("Starting training...")
AllClassPath='/newdata/UCF_Anomaly_Dataset/Dataset/CVPR_Data/C3D_Features_Txt/Train/'
# AllClassPath contains C3D features (.txt file) of each video. Each text file contains 32 features, each of 4096 dimension
output_dir='/newdata/UCF_Anomaly_Dataset/Dataset/CVPR_Data/Trained_Models/TrainedModel_MIL_C3D/'
# Output_dir is the directory where you want to save trained weights
weights_path = output_dir + 'weights.mat'
# weights.mat are the model weights that you will get after (or during) that training
model_path = output_dir + 'model.json'
if not os.path.exists(output_dir):
os.makedirs(output_dir)
All_class_files= listdir(AllClassPath)
All_class_files.sort()
loss_graph =[]
num_iters = 20000
total_iterations = 0
batchsize=60
time_before = datetime.now()
for it_num in range(num_iters):
AbnormalPath = os.path.join(AllClassPath, All_class_files[0]) # Path of abnormal already computed C3D features
NormalPath = os.path.join(AllClassPath, All_class_files[1]) # Path of Normal already computed C3D features
inputs, targets=load_dataset_Train_batch(AbnormalPath, NormalPath) # Load normal and abnormal video C3D features
batch_loss =model.train_on_batch(inputs, targets)
loss_graph = np.hstack((loss_graph, batch_loss))
total_iterations += 1
if total_iterations % 20 == 1:
print "These iteration=" + str(total_iterations) + ") took: " + str(datetime.now() - time_before) + ", with loss of " + str(batch_loss)
iteration_path = output_dir + 'Iterations_graph_' + str(total_iterations) + '.mat'
savemat(iteration_path, dict(loss_graph=loss_graph))
if total_iterations % 1000 == 0: # Save the model at every 1000th iterations.
weights_path = output_dir + 'weightsAnomalyL1L2_' + str(total_iterations) + '.mat'
save_model(model, model_path, weights_path)
save_model(model, model_path, weights_path)