|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"""Auxiliary functions for domain adaptation related losses. |
|
""" |
|
import math |
|
import tensorflow as tf |
|
|
|
|
|
def create_summaries(end_points, prefix='', max_images=3, use_op_name=False): |
|
"""Creates a tf summary per endpoint. |
|
|
|
If the endpoint is a 4 dimensional tensor it displays it as an image |
|
otherwise if it is a two dimensional one it creates a histogram summary. |
|
|
|
Args: |
|
end_points: a dictionary of name, tf tensor pairs. |
|
prefix: an optional string to prefix the summary with. |
|
max_images: the maximum number of images to display per summary. |
|
use_op_name: Use the op name as opposed to the shorter end_points key. |
|
""" |
|
for layer_name in end_points: |
|
if use_op_name: |
|
name = end_points[layer_name].op.name |
|
else: |
|
name = layer_name |
|
if len(end_points[layer_name].get_shape().as_list()) == 4: |
|
|
|
if end_points[layer_name].get_shape().as_list()[-1] == 1 or end_points[ |
|
layer_name].get_shape().as_list()[-1] == 3: |
|
visualization_image = end_points[layer_name] |
|
else: |
|
visualization_image = reshape_feature_maps(end_points[layer_name]) |
|
tf.summary.image( |
|
'{}/{}'.format(prefix, name), |
|
visualization_image, |
|
max_outputs=max_images) |
|
elif len(end_points[layer_name].get_shape().as_list()) == 3: |
|
images = tf.expand_dims(end_points[layer_name], 3) |
|
tf.summary.image( |
|
'{}/{}'.format(prefix, name), |
|
images, |
|
max_outputs=max_images) |
|
elif len(end_points[layer_name].get_shape().as_list()) == 2: |
|
tf.summary.histogram('{}/{}'.format(prefix, name), end_points[layer_name]) |
|
|
|
|
|
def reshape_feature_maps(features_tensor): |
|
"""Reshape activations for tf.summary.image visualization. |
|
|
|
Arguments: |
|
features_tensor: a tensor of activations with a square number of feature |
|
maps, eg 4, 9, 16, etc. |
|
Returns: |
|
A composite image with all the feature maps that can be passed as an |
|
argument to tf.summary.image. |
|
""" |
|
assert len(features_tensor.get_shape().as_list()) == 4 |
|
num_filters = features_tensor.get_shape().as_list()[-1] |
|
assert num_filters > 0 |
|
num_filters_sqrt = math.sqrt(num_filters) |
|
assert num_filters_sqrt.is_integer( |
|
), 'Number of filters should be a square number but got {}'.format( |
|
num_filters) |
|
num_filters_sqrt = int(num_filters_sqrt) |
|
conv_summary = tf.unstack(features_tensor, axis=3) |
|
conv_one_row = tf.concat(axis=2, values=conv_summary[0:num_filters_sqrt]) |
|
ind = 1 |
|
conv_final = conv_one_row |
|
for ind in range(1, num_filters_sqrt): |
|
conv_one_row = tf.concat(axis=2, |
|
values=conv_summary[ |
|
ind * num_filters_sqrt + 0:ind * num_filters_sqrt + num_filters_sqrt]) |
|
conv_final = tf.concat( |
|
axis=1, values=[tf.squeeze(conv_final), tf.squeeze(conv_one_row)]) |
|
conv_final = tf.expand_dims(conv_final, -1) |
|
return conv_final |
|
|
|
|
|
def accuracy(predictions, labels): |
|
"""Calculates the classificaton accuracy. |
|
|
|
Args: |
|
predictions: the predicted values, a tensor whose size matches 'labels'. |
|
labels: the ground truth values, a tensor of any size. |
|
|
|
Returns: |
|
a tensor whose value on evaluation returns the total accuracy. |
|
""" |
|
return tf.reduce_mean(tf.cast(tf.equal(predictions, labels), tf.float32)) |
|
|
|
|
|
def compute_upsample_values(input_tensor, upsample_height, upsample_width): |
|
"""Compute values for an upsampling op (ops.BatchCropAndResize). |
|
|
|
Args: |
|
input_tensor: image tensor with shape [batch, height, width, in_channels] |
|
upsample_height: integer |
|
upsample_width: integer |
|
|
|
Returns: |
|
grid_centers: tensor with shape [batch, 1] |
|
crop_sizes: tensor with shape [batch, 1] |
|
output_height: integer |
|
output_width: integer |
|
""" |
|
batch, input_height, input_width, _ = input_tensor.shape |
|
|
|
height_half = input_height / 2. |
|
width_half = input_width / 2. |
|
grid_centers = tf.constant(batch * [[height_half, width_half]]) |
|
crop_sizes = tf.constant(batch * [[input_height, input_width]]) |
|
output_height = input_height * upsample_height |
|
output_width = input_width * upsample_width |
|
|
|
return grid_centers, tf.to_float(crop_sizes), output_height, output_width |
|
|
|
|
|
def compute_pairwise_distances(x, y): |
|
"""Computes the squared pairwise Euclidean distances between x and y. |
|
|
|
Args: |
|
x: a tensor of shape [num_x_samples, num_features] |
|
y: a tensor of shape [num_y_samples, num_features] |
|
|
|
Returns: |
|
a distance matrix of dimensions [num_x_samples, num_y_samples]. |
|
|
|
Raises: |
|
ValueError: if the inputs do no matched the specified dimensions. |
|
""" |
|
|
|
if not len(x.get_shape()) == len(y.get_shape()) == 2: |
|
raise ValueError('Both inputs should be matrices.') |
|
|
|
if x.get_shape().as_list()[1] != y.get_shape().as_list()[1]: |
|
raise ValueError('The number of features should be the same.') |
|
|
|
norm = lambda x: tf.reduce_sum(tf.square(x), 1) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return tf.transpose(norm(tf.expand_dims(x, 2) - tf.transpose(y))) |
|
|
|
|
|
def gaussian_kernel_matrix(x, y, sigmas): |
|
r"""Computes a Guassian Radial Basis Kernel between the samples of x and y. |
|
|
|
We create a sum of multiple gaussian kernels each having a width sigma_i. |
|
|
|
Args: |
|
x: a tensor of shape [num_samples, num_features] |
|
y: a tensor of shape [num_samples, num_features] |
|
sigmas: a tensor of floats which denote the widths of each of the |
|
gaussians in the kernel. |
|
Returns: |
|
A tensor of shape [num_samples{x}, num_samples{y}] with the RBF kernel. |
|
""" |
|
beta = 1. / (2. * (tf.expand_dims(sigmas, 1))) |
|
|
|
dist = compute_pairwise_distances(x, y) |
|
|
|
s = tf.matmul(beta, tf.reshape(dist, (1, -1))) |
|
|
|
return tf.reshape(tf.reduce_sum(tf.exp(-s), 0), tf.shape(dist)) |
|
|