in c2/tools/extract_features.py [0:0]
def ExtractFeatures(args):
if args.gpus is not None:
gpus = [int(x) for x in args.gpus.split(',')]
num_gpus = len(gpus)
else:
gpus = range(args.num_gpus)
num_gpus = args.num_gpus
if num_gpus > 0:
log.info("Running on GPUs: {}".format(gpus))
else:
log.info("Running on CPU")
my_arg_scope = {
'order': 'NCHW',
'use_cudnn': True,
'cudnn_exhaustive_search': True
}
model = cnn.CNNModelHelper(
name="Extract Features",
**my_arg_scope
)
video_input_args = dict(
batch_size=args.batch_size,
clip_per_video=args.clip_per_video,
decode_type=args.decode_type,
length_rgb=args.clip_length_rgb,
sampling_rate_rgb=args.sampling_rate_rgb,
scale_h=args.scale_h,
scale_w=args.scale_w,
crop_size=args.crop_size,
video_res_type=args.video_res_type,
short_edge=min(args.scale_h, args.scale_w),
num_decode_threads=args.num_decode_threads,
do_multi_label=args.multi_label,
num_of_class=args.num_labels,
random_mirror=False,
random_crop=False,
input_type=args.input_type,
length_of=args.clip_length_of,
sampling_rate_of=args.sampling_rate_of,
frame_gap_of=args.frame_gap_of,
do_flow_aggregation=args.do_flow_aggregation,
flow_data_type=args.flow_data_type,
get_rgb=(args.input_type == 0 or args.input_type >= 3),
get_optical_flow=(args.input_type == 1 or args.input_type >= 4),
get_logmels=(args.input_type >= 2),
get_video_id=args.get_video_id,
get_start_frame=args.get_start_frame,
use_local_file=args.use_local_file,
crop_per_clip=args.crop_per_clip,
)
reader_args = dict(
name="extract_features" + '_reader',
input_data=args.test_data,
)
reader, num_examples = reader_utils.create_data_reader(
model,
**reader_args
)
def input_fn(model):
model_helper.AddVideoInput(
model,
reader,
**video_input_args)
def create_model_ops(model, loss_scale):
return model_builder.build_model(
model=model,
model_name=args.model_name,
model_depth=args.model_depth,
num_labels=args.num_labels,
batch_size=args.batch_size,
num_channels=args.num_channels,
crop_size=args.crop_size,
clip_length=(
args.clip_length_of if args.input_type == 1
else args.clip_length_rgb
),
loss_scale=loss_scale,
is_test=1,
multi_label=args.multi_label,
channel_multiplier=args.channel_multiplier,
bottleneck_multiplier=args.bottleneck_multiplier,
use_dropout=args.use_dropout,
use_convolutional_pred=args.use_convolutional_pred,
use_pool1=args.use_pool1,
)
if num_gpus > 0:
data_parallel_model.Parallelize_GPU(
model,
input_builder_fun=input_fn,
forward_pass_builder_fun=create_model_ops,
param_update_builder_fun=None, # 'None' since we aren't training
devices=gpus,
optimize_gradient_memory=True,
)
else:
model._device_type = caffe2_pb2.CPU
model._devices = [0]
device_opt = core.DeviceOption(model._device_type, 0)
with core.DeviceScope(device_opt):
# Because our loaded models are named with "gpu_x", keep the naming for now.
# TODO: Save model using `data_parallel_model.ExtractPredictorNet`
# to extract the model for "gpu_0". It also renames
# the input and output blobs by stripping the "gpu_x/" prefix
with core.NameScope("{}_{}".format("gpu", 0)):
input_fn(model)
create_model_ops(model, 1.0)
workspace.RunNetOnce(model.param_init_net)
workspace.CreateNet(model.net)
if args.db_type == 'pickle':
model_loader.LoadModelFromPickleFile(model, args.load_model_path)
elif args.db_type == 'minidb':
if num_gpus > 0:
model_helper.LoadModel(args.load_model_path, args.db_type)
else:
with core.DeviceScope(core.DeviceOption(caffe2_pb2.CPU, 0)):
model_helper.LoadModel(args.load_model_path, args.db_type)
else:
log.warning("Unsupported db_type: {}".format(args.db_type))
data_parallel_model.FinalizeAfterCheckpoint(model)
def fetchActivations(model, outputs, num_iterations):
all_activations = {}
for counter in range(num_iterations):
workspace.RunNet(model.net.Proto().name)
num_devices = 1 # default for cpu
if num_gpus > 0:
num_devices = num_gpus
for g in range(num_devices):
for output_name in outputs:
blob_name = 'gpu_{}/'.format(g) + output_name
activations = workspace.FetchBlob(blob_name)
if output_name not in all_activations:
all_activations[output_name] = []
all_activations[output_name].append(activations)
if counter % 20 == 0:
log.info('{}/{} iterations'.format(counter, num_iterations))
# each key holds a list of activations obtained from each minibatch.
# we now concatenate these lists to get the final arrays.
# concatenating during the loop requires a realloc and can get slow.
for key in all_activations:
all_activations[key] = np.concatenate(all_activations[key])
return all_activations
outputs = [name.strip() for name in args.features.split(',')]
assert len(outputs) > 0
if args.num_iterations > 0:
num_iterations = args.num_iterations
else:
if num_gpus > 0:
examples_per_iteration = args.batch_size * num_gpus
else:
examples_per_iteration = args.batch_size
num_iterations = int(num_examples / examples_per_iteration)
activations = fetchActivations(model, outputs, num_iterations)
# saving extracted features
for index in range(len(outputs)):
log.info(
"Read '{}' with shape {}".format(
outputs[index],
activations[outputs[index]].shape
)
)
if args.output_path:
output_path = args.output_path
else:
output_path = os.path.dirname(args.test_data) + '/features.pickle'
log.info('Writing to {}'.format(output_path))
if args.save_h5:
with h5py.File(output_path, 'w') as handle:
for name, activation in activations.items():
handle.create_dataset(name, data=activation)
else:
with open(output_path, 'wb') as handle:
pickle.dump(activations, handle)
# perform sanity check
if args.sanity_check == 1: # check clip accuracy
assert args.multi_label == 0
clip_acc = 0
softmax = activations['softmax']
label = activations['label']
for i in range(len(softmax)):
sorted_preds = \
np.argsort(softmax[i])
sorted_preds[:] = sorted_preds[::-1]
if sorted_preds[0] == label[i]:
clip_acc += 1
log.info('Sanity check --- clip accuracy: {}'.format(
clip_acc / len(softmax))
)
elif args.sanity_check == 2: # check auc
assert args.multi_label == 1
prob = activations['prob']
label = activations['label']
mean_auc, mean_ap, mean_wap, _ = metric.mean_ap_metric(prob, label)
log.info('Sanity check --- AUC: {}, mAP: {}, mWAP: {}'.format(
mean_auc, mean_ap, mean_wap)
)