forked from yosinski/deep-visualization-toolbox
-
Notifications
You must be signed in to change notification settings - Fork 6
/
settings_misc.py
300 lines (233 loc) · 11.2 KB
/
settings_misc.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
import os,sys,inspect
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0,parentdir)
import cPickle as pickle
from caffevis.caffevis_helper import set_mean
from caffe_misc import layer_name_to_top_name, get_max_data_extent
from misc import mkdir_p
def deduce_calculated_settings_without_network(settings):
set_calculated_siamese_network_format(settings)
set_calculated_channel_swap(settings)
read_network_dag(settings)
def deduce_calculated_settings_with_network(settings, net):
set_calculated_is_gray_model(settings, net)
set_calculated_image_dims(settings, net)
def set_calculated_is_gray_model(settings, net):
if settings.is_gray_model is not None:
settings._calculated_is_gray_model = settings.is_gray_model
else:
input_shape = net.blobs[net.inputs[0]].data.shape
channels = input_shape[1]
if channels == 1:
settings._calculated_is_gray_model = True
elif channels == 2 and settings.is_siamese:
settings._calculated_is_gray_model = True
elif channels == 3:
settings._calculated_is_gray_model = False
elif channels == 6 and settings.is_siamese:
settings._calculated_is_gray_model = False
else:
settings._calculated_is_gray_model = None
def set_calculated_image_dims(settings, net):
if settings.caffe_net_image_dims is not None:
settings._calculated_image_dims = settings.caffe_net_image_dims
else:
input_shape = net.blobs[net.inputs[0]].data.shape
settings._calculated_image_dims = input_shape[2:4]
def set_calculated_siamese_network_format(settings):
settings._calculated_siamese_network_format = 'normal'
for layer_def in settings.layers_list:
if layer_def['format'] != 'normal':
settings._calculated_siamese_network_format = layer_def['format']
return
def set_calculated_channel_swap(settings):
if settings.caffe_net_channel_swap is not None:
settings._calculated_channel_swap = settings.caffe_net_channel_swap
else:
if settings.is_siamese and settings.siamese_input_mode == 'concat_channelwise':
settings._calculated_channel_swap = (2, 1, 0, 5, 4, 3)
else:
settings._calculated_channel_swap = (2, 1, 0)
def process_network_proto(settings):
settings._processed_deploy_prototxt = settings.caffevis_deploy_prototxt + ".processed_by_deepvis"
# check if force_backwards is missing
found_force_backwards = False
with open(settings.caffevis_deploy_prototxt, 'r') as proto_file:
for line in proto_file:
fields = line.strip().split()
if len(fields) == 2 and fields[0] == 'force_backward:' and fields[1] == 'true':
found_force_backwards = True
break
# write file, adding force_backward if needed
with open(settings.caffevis_deploy_prototxt, 'r') as proto_file:
with open(settings._processed_deploy_prototxt, 'w') as new_proto_file:
if not found_force_backwards:
new_proto_file.write('force_backward: true\n')
for line in proto_file:
new_proto_file.write(line)
# run upgrade tool on new file name (same output file)
upgrade_tool_command_line = settings.caffevis_caffe_root + '/build/tools/upgrade_net_proto_text.bin ' + settings._processed_deploy_prototxt + ' ' + settings._processed_deploy_prototxt
os.system(upgrade_tool_command_line)
return
def load_network(settings):
# Set the mode to CPU or GPU. Note: in the latest Caffe
# versions, there is one Caffe object *per thread*, so the
# mode must be set per thread! Here we set the mode for the
# main thread; it is also separately set in CaffeProcThread.
sys.path.insert(0, os.path.join(settings.caffevis_caffe_root, 'python'))
import caffe
if settings.caffevis_mode_gpu:
caffe.set_mode_gpu()
caffe.set_device(settings.caffevis_gpu_id)
print 'Loaded caffe in GPU mode, using device', settings.caffevis_gpu_id
else:
caffe.set_mode_cpu()
print 'Loaded caffe in CPU mode'
process_network_proto(settings)
deduce_calculated_settings_without_network(settings)
net = caffe.Classifier(
settings._processed_deploy_prototxt,
settings.caffevis_network_weights,
image_dims=settings.caffe_net_image_dims,
mean=None, # Set to None for now, assign later
input_scale=settings.caffe_net_input_scale,
raw_scale=settings.caffe_net_raw_scale,
channel_swap=settings._calculated_channel_swap)
deduce_calculated_settings_with_network(settings, net)
if settings.caffe_net_transpose:
net.transformer.set_transpose(net.inputs[0], settings.caffe_net_transpose)
data_mean = set_mean(settings.caffevis_data_mean, settings.generate_channelwise_mean, net)
return net, data_mean
class LayerRecord:
def __init__(self, layer_def):
self.layer_def = layer_def
self.name = layer_def.name
self.type = layer_def.type
# keep filter, stride and pad
if layer_def.type == 'Convolution':
self.filter = list(layer_def.convolution_param.kernel_size)
if len(self.filter) == 1:
self.filter *= 2
self.pad = list(layer_def.convolution_param.pad)
if len(self.pad) == 0:
self.pad = [0, 0]
elif len(self.pad) == 1:
self.pad *= 2
self.stride = list(layer_def.convolution_param.stride)
if len(self.stride) == 0:
self.stride = [1, 1]
elif len(self.stride) == 1:
self.stride *= 2
elif layer_def.type == 'Pooling':
self.filter = [layer_def.pooling_param.kernel_size]
if len(self.filter) == 1:
self.filter *= 2
self.pad = [layer_def.pooling_param.pad]
if len(self.pad) == 0:
self.pad = [0, 0]
elif len(self.pad) == 1:
self.pad *= 2
self.stride = [layer_def.pooling_param.stride]
if len(self.stride) == 0:
self.stride = [1, 1]
elif len(self.stride) == 1:
self.stride *= 2
else:
self.filter = [0, 0]
self.pad = [0, 0]
self.stride = [1, 1]
# keep tops
self.tops = list(layer_def.top)
# keep bottoms
self.bottoms = list(layer_def.bottom)
# list of parent layers
self.parents = []
# list of child layers
self.children = []
pass
def read_network_dag(settings):
from caffe.proto import caffe_pb2
from google.protobuf import text_format
# load prototxt file
network_def = caffe_pb2.NetParameter()
with open(settings._processed_deploy_prototxt, 'r') as proto_file:
text_format.Merge(str(proto_file.read()), network_def)
# map layer name to layer record
layer_name_to_record = dict()
for layer_def in network_def.layer:
if (len(layer_def.include) == 0) or (caffe_pb2.TEST in [item.phase for item in layer_def.include]):
layer_name_to_record[layer_def.name] = LayerRecord(layer_def)
top_to_layers = dict()
for layer in network_def.layer:
# no specific phase, or TEST phase is specifically asked for
if (len(layer.include) == 0) or (caffe_pb2.TEST in [item.phase for item in layer.include]):
for top in layer.top:
if top not in top_to_layers:
top_to_layers[top] = list()
top_to_layers[top].append(layer.name)
# find parents and children of all layers
for child_layer_name in layer_name_to_record.keys():
child_layer_def = layer_name_to_record[child_layer_name]
for bottom in child_layer_def.bottoms:
for parent_layer_name in top_to_layers[bottom]:
if parent_layer_name in layer_name_to_record:
parent_layer_def = layer_name_to_record[parent_layer_name]
if parent_layer_def not in child_layer_def.parents:
child_layer_def.parents.append(parent_layer_def)
if child_layer_def not in parent_layer_def.children:
parent_layer_def.children.append(child_layer_def)
# update filter, strid, pad for maxout "structures"
for layer_name in layer_name_to_record.keys():
layer_def = layer_name_to_record[layer_name]
if layer_def.type == 'Eltwise' and \
len(layer_def.parents) == 1 and \
layer_def.parents[0].type == 'Slice' and \
len(layer_def.parents[0].parents) == 1 and \
layer_def.parents[0].parents[0].type in ['Convolution', 'InnerProduct']:
layer_def.filter = layer_def.parents[0].parents[0].filter
layer_def.stride = layer_def.parents[0].parents[0].stride
layer_def.pad = layer_def.parents[0].parents[0].pad
# keep helper variables in settings
settings._network_def = network_def
settings._layer_name_to_record = layer_name_to_record
return
def _get_receptive_fields_cache_filename(settings):
return os.path.join(settings.caffevis_outputs_dir, 'receptive_fields_cache.pickled')
def get_receptive_field(settings, net, layer_name):
# flag which indicates whether the dictionary was changed hence we need to write it to cache
should_save_to_cache = False
# check if dictionary exists
if not hasattr(settings, '_receptive_field_per_layer'):
# if it doesn't, try load it from file
receptive_fields_cache_filename = _get_receptive_fields_cache_filename(settings)
if os.path.isfile(receptive_fields_cache_filename):
try:
with open(receptive_fields_cache_filename, 'rb') as receptive_fields_cache_file:
settings._receptive_field_per_layer = pickle.load(receptive_fields_cache_file)
except:
settings._receptive_field_per_layer = dict()
should_save_to_cache = True
else:
settings._receptive_field_per_layer = dict()
should_save_to_cache = True
# calculate lazy
if not settings._receptive_field_per_layer.has_key(layer_name):
print "Calculating receptive fields for layer %s" % (layer_name)
top_name = layer_name_to_top_name(net, layer_name)
if top_name is not None:
blob = net.blobs[top_name].data
is_spatial = (len(blob.shape) == 4)
layer_receptive_field = get_max_data_extent(net, settings, layer_name, is_spatial)
settings._receptive_field_per_layer[layer_name] = layer_receptive_field
should_save_to_cache = True
if should_save_to_cache:
try:
receptive_fields_cache_filename = _get_receptive_fields_cache_filename(settings)
mkdir_p(settings.caffevis_outputs_dir)
with open(receptive_fields_cache_filename, 'wb') as receptive_fields_cache_file:
pickle.dump(settings._receptive_field_per_layer, receptive_fields_cache_file, -1)
except IOError:
# ignore problems in cache saving
pass
return settings._receptive_field_per_layer[layer_name]