masterthesis/src/twomartens/masterthesis/weights.py

93 lines
3.9 KiB
Python

# -*- coding: utf-8 -*-
#
# Copyright 2019 Jim Martens
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Functionality to modify weights.
Functions:
subsample_ssd(ssd_weights_file): sub-samples the weights of the SSD network
"""
import shutil
import h5py
import math
import numpy as np
from twomartens.masterthesis.ssd_keras.misc_utils import tensor_sampling_utils
def subsample_ssd(ssd_weights_file: str, subsampled_weights_file: str) -> None:
"""
Sub-samples the weights of the SSD 300 network.
Args:
ssd_weights_file: file path for the SSD weights file
subsampled_weights_file: file path for file with sub-sampled weights
"""
shutil.copy(ssd_weights_file, subsampled_weights_file)
with h5py.File(subsampled_weights_file) as weights_destination_file:
classifier_names = ["conv4_3_norm_mbox_conf",
"fc7_mbox_conf",
"conv6_2_mbox_conf",
"conv7_2_mbox_conf",
"conv8_2_mbox_conf",
"conv9_2_mbox_conf"]
n_classes_source = 81
classes_of_interest = [i for i in range(61)] # first 60 classes are kept plus background
for name in classifier_names:
# Get the trained weights for this layer from the source HDF5 weights file.
kernel = weights_destination_file[name][name]['kernel:0'].value
bias = weights_destination_file[name][name]['bias:0'].value
# Get the shape of the kernel. We're interested in sub-sampling
# the last dimension, 'o'.
height, width, in_channels, out_channels = kernel.shape
subsampling_indices = []
for i in range(int(math.floor(out_channels / n_classes_source))):
indices = np.array(classes_of_interest) + i * n_classes_source
subsampling_indices.append(indices)
subsampling_indices = list(np.concatenate(subsampling_indices))
# Sub-sample the kernel and bias.
# The `sample_tensors()` function used below provides extensive
# documentation, so don't hesitate to read it if you want to know
# what exactly is going on here.
new_kernel, new_bias = tensor_sampling_utils.sample_tensors(
weights_list=[kernel, bias],
sampling_instructions=[height, width, in_channels, subsampling_indices],
axes=[[3]],
# The one bias dimension corresponds to the last kernel dimension.
init=['gaussian', 'zeros'],
mean=0.0,
stddev=0.005
)
# Delete the old weights from the destination file.
del weights_destination_file[name][name]['kernel:0']
del weights_destination_file[name][name]['bias:0']
# Create new data sets for the sub-sampled weights.
weights_destination_file[name][name].create_dataset(name='kernel:0', data=new_kernel)
weights_destination_file[name][name].create_dataset(name='bias:0', data=new_bias)
if __name__ == "__main__":
weights_file = "data/weights/ssd/VGG_coco_SSD_300x300_iter_400000.h5"
weights_destination_file = "data/weights/ssd/VGG_coco_SSD_300x300_iter_400000_subsampled.h5"
subsample_ssd(weights_file, weights_destination_file)