def compute_mask(self, inputs, mask=None): if mask is None: return None if not isinstance(mask, list): raise ValueError('`mask` should be a list.') if not isinstance(inputs, list): raise ValueError('`inputs` should be a list.') if len(mask) != len(inputs): raise ValueError('The lists `inputs` and `mask` ' 'should have the same length.') if all([m is None for m in mask]): return None # Make a list of masks while making sure # the dimensionality of each mask # is the same as the corresponding input. masks = [] for input_i, mask_i in zip(inputs, mask): if mask_i is None: # Input is unmasked. Append all 1s to masks, masks.append(array_ops.ones_like(input_i, dtype='bool')) elif K.ndim(mask_i) < K.ndim(input_i): # Mask is smaller than the input, expand it masks.append(array_ops.expand_dims(mask_i, axis=-1)) else: masks.append(mask_i) concatenated = K.concatenate(masks, axis=self.axis) return K.all(concatenated, axis=-1, keepdims=False)
def weighted(y_true, y_pred, weights, mask=None): """Wrapper function. Arguments: y_true: `y_true` argument of `fn`. y_pred: `y_pred` argument of `fn`. weights: Weights tensor. mask: Mask tensor. Returns: Scalar tensor. """ # score_array has ndim >= 2 score_array = fn(y_true, y_pred) if mask is not None: # Cast the mask to floatX to avoid float64 upcasting in theano mask = math_ops.cast(mask, K.floatx()) # mask should have the same shape as score_array score_array *= mask # the loss per batch should be proportional # to the number of unmasked samples. score_array /= K.mean(mask) # apply sample weighting if weights is not None: # reduce score_array to same ndim as weight array ndim = K.ndim(score_array) weight_ndim = K.ndim(weights) score_array = K.mean(score_array, axis=list(range(weight_ndim, ndim))) score_array *= weights score_array /= K.mean( math_ops.cast(math_ops.not_equal(weights, 0), K.floatx())) return K.mean(score_array)
def compute_weighted_loss(losses, sample_weight=None, reduction=ReductionV2.SUM_OVER_BATCH_SIZE, name=None): """Computes the weighted loss. Args: losses: `Tensor` of shape `[batch_size, d1, ... dN]`. sample_weight: Optional `Tensor` whose rank is either 0, or the same rank as `losses`, or be broadcastable to `losses`. reduction: (Optional) Type of `tf.keras.losses.Reduction` to apply to loss. Default value is `SUM_OVER_BATCH_SIZE`. name: Optional name for the op. Raises: ValueError: If the shape of `sample_weight` is not compatible with `losses`. Returns: Weighted loss `Tensor` of the same type as `losses`. If `reduction` is `NONE`, this has the same shape as `losses`; otherwise, it is scalar. """ ReductionV2.validate(reduction) # If this function is called directly, then we just default 'AUTO' to # 'SUM_OVER_BATCH_SIZE'. Eg. Canned estimator use cases. if reduction == ReductionV2.AUTO: reduction = ReductionV2.SUM_OVER_BATCH_SIZE if sample_weight is None: sample_weight = 1.0 with K.name_scope(name or 'weighted_loss'): # Save the `reduction` argument for loss normalization when distributing # to multiple replicas. Used only for estimator + v1 optimizer flow. ops.get_default_graph()._last_loss_reduction = reduction # pylint: disable=protected-access # Update dimensions of `sample_weight` to match with `losses` if possible. losses, _, sample_weight = squeeze_or_expand_dimensions( losses, None, sample_weight) losses = ops.convert_to_tensor(losses) input_dtype = losses.dtype losses = math_ops.cast(losses, dtypes.float32) sample_weight = math_ops.cast(sample_weight, dtypes.float32) try: # Broadcast weights if possible. sample_weight = weights_broadcast_ops.broadcast_weights( sample_weight, losses) except ValueError: # Reduce values to same ndim as weight array. ndim = K.ndim(losses) weight_ndim = K.ndim(sample_weight) losses = K.mean(losses, axis=list(range(weight_ndim, ndim))) sample_weight.shape.assert_is_compatible_with(losses.shape) weighted_losses = math_ops.multiply(losses, sample_weight) # Apply reduction function to the individual weighted losses. loss = reduce_weighted_loss(weighted_losses, reduction) # Convert the result back to the input type. loss = math_ops.cast(loss, input_dtype) return loss
def compute_weighted_loss(losses, sample_weight=None, reduction=losses_impl.ReductionV2.SUM_OVER_BATCH_SIZE, name=None): """Computes the weighted loss. Args: losses: `Tensor` of shape `[batch_size, d1, ... dN]`. sample_weight: Optional `Tensor` whose rank is either 0, or the same rank as `losses`, or be broadcastable to `losses`. reduction: Type of `tf.losses.Reduction` to apply to loss. Default value is `SUM_OVER_BATCH_SIZE`. name: Optional name for the op. Raises: ValueError: If the shape of `sample_weight` is not compatible with `losses`. Returns: Weighted loss `Tensor` of the same type as `losses`. If `reduction` is `NONE`, this has the same shape as `losses`; otherwise, it is scalar. """ losses_impl.ReductionV2.validate(reduction) if sample_weight is None: sample_weight = 1.0 with ops.name_scope(name, 'weighted_loss', (losses, sample_weight)): # Save the `reduction` argument for loss normalization when distributing # to multiple replicas. # TODO(josh11b): Associate it with the returned op for more precision. ops.get_default_graph()._last_loss_reduction = reduction # pylint: disable=protected-access # Update dimensions of `sample_weight` to match with `losses` if possible. losses, _, sample_weight = squeeze_or_expand_dimensions( losses, None, sample_weight) losses = ops.convert_to_tensor(losses) input_dtype = losses.dtype losses = math_ops.to_float(losses) sample_weight = math_ops.to_float(sample_weight) try: # Broadcast weights if possible. sample_weight = weights_broadcast_ops.broadcast_weights( sample_weight, losses) except ValueError: # Reduce values to same ndim as weight array. ndim = K.ndim(losses) weight_ndim = K.ndim(sample_weight) losses = K.mean(losses, axis=list(range(weight_ndim, ndim))) sample_weight.get_shape().assert_is_compatible_with(losses.get_shape()) weighted_losses = math_ops.multiply(losses, sample_weight) # Apply reduction function to the individual weighted losses. loss = _reduce_weighted_loss(weighted_losses, reduction) # Convert the result back to the input type. loss = math_ops.cast(loss, input_dtype) return loss
def weighted(y_true, y_pred, weights, mask=None): """Wrapper function. Arguments: y_true: `y_true` argument of `fn`. y_pred: `y_pred` argument of `fn`. weights: Weights tensor. mask: Mask tensor. Returns: Scalar tensor. """ # score_array has ndim >= 2 score_array = fn(y_true, y_pred) if mask is not None: mask = math_ops.cast(mask, y_pred.dtype) # Update weights with mask. if weights is None: weights = mask else: # Update shape of weights if possible before adding mask. # Update dimensions of weights to match with mask if possible. mask, _, weights = metrics_module.squeeze_or_expand_dimensions( mask, None, weights) try: # Broadcast weights if possible. weights = weights_broadcast_ops.broadcast_weights(weights, mask) weights *= mask except ValueError: score_array *= mask score_array /= K.mean(mask) # TODO(psv): Handle case when mask and weight shapes are not # compatible. # Apply sample weighting. if weights is not None: # Update dimensions of weights to match with values if possible. score_array, _, weights = metrics_module.squeeze_or_expand_dimensions( score_array, None, weights) try: # Broadcast weights if possible. weights = weights_broadcast_ops.broadcast_weights(weights, score_array) except ValueError: # Reduce values to same ndim as weight array. ndim = K.ndim(score_array) weight_ndim = K.ndim(weights) score_array = K.mean(score_array, axis=list(range(weight_ndim, ndim))) score_array = math_ops.multiply(score_array, weights) score_array = math_ops.reduce_sum(score_array) weights = math_ops.reduce_sum(weights) score_array = metrics_module.safe_div(score_array, weights) return K.mean(score_array)
def compute_weighted_loss(losses, sample_weight=None, reduction=ReductionV2.SUM_OVER_BATCH_SIZE, name=None): """Computes the weighted loss. Args: losses: `Tensor` of shape `[batch_size, d1, ... dN]`. sample_weight: Optional `Tensor` whose rank is either 0, or the same rank as `losses`, or be broadcastable to `losses`. reduction: (Optional) Type of `tf.keras.losses.Reduction` to apply to loss. Default value is `SUM_OVER_BATCH_SIZE`. name: Optional name for the op. Raises: ValueError: If the shape of `sample_weight` is not compatible with `losses`. Returns: Weighted loss `Tensor` of the same type as `losses`. If `reduction` is `NONE`, this has the same shape as `losses`; otherwise, it is scalar. """ ReductionV2.validate(reduction) if sample_weight is None: sample_weight = 1.0 with ops.name_scope(name, 'weighted_loss', (losses, sample_weight)): # Update dimensions of `sample_weight` to match with `losses` if possible. losses, _, sample_weight = squeeze_or_expand_dimensions( losses, None, sample_weight) losses = ops.convert_to_tensor(losses) input_dtype = losses.dtype losses = math_ops.cast(losses, dtypes.float32) sample_weight = math_ops.cast(sample_weight, dtypes.float32) try: # Broadcast weights if possible. sample_weight = weights_broadcast_ops.broadcast_weights( sample_weight, losses) except ValueError: # Reduce values to same ndim as weight array. ndim = K.ndim(losses) weight_ndim = K.ndim(sample_weight) losses = K.mean(losses, axis=list(range(weight_ndim, ndim))) sample_weight.shape.assert_is_compatible_with(losses.shape) weighted_losses = math_ops.multiply(losses, sample_weight) # Apply reduction function to the individual weighted losses. loss = reduce_weighted_loss(weighted_losses, reduction) # Convert the result back to the input type. loss = math_ops.cast(loss, input_dtype) return loss
def call(self, inputs): if (self.data_format == 'channels_first' and K.ndim(inputs) is not None and K.ndim(inputs) > 1): permutation = [0] permutation.extend([i for i in range(2, K.ndim(inputs))]) permutation.append(1) inputs = array_ops.transpose(inputs, perm=permutation) outputs = array_ops.reshape( inputs, (tensor_shape.dimension_value(inputs.shape[0]) or array_ops.shape(inputs)[0], -1)) if not context.executing_eagerly(): outputs.set_shape(self.compute_output_shape(inputs.shape)) return outputs
def softmax(x, axis=-1): """The softmax activation function transforms the outputs so that all values are in range (0, 1) and sum to 1. It is often used as the activation for the last layer of a classification network because the result could be interpreted as a probability distribution. The softmax of x is calculated by exp(x)/tf.reduce_sum(exp(x)). Arguments: x : Input tensor. axis: Integer, axis along which the softmax normalization is applied. Returns: Tensor, output of softmax transformation (all values are non-negative and sum to 1). Raises: ValueError: In case `dim(x) == 1`. """ ndim = K.ndim(x) if ndim == 2: return nn.softmax(x) elif ndim > 2: e = math_ops.exp(x - math_ops.reduce_max(x, axis=axis, keepdims=True)) s = math_ops.reduce_sum(e, axis=axis, keepdims=True) return e / s else: raise ValueError('Cannot apply softmax to a tensor that is 1D. ' 'Received input: %s' % (x,))
def gram_matrix(x): assert K.ndim(x) == 3 if K.image_data_format() == 'channels_first': features = K.batch_flatten(x) else: features = K.batch_flatten(K.permute_dimensions(x, (2, 0, 1))) gram = K.dot(features, K.transpose(features)) return gram
def tv_loss(x): ''' Total variation loss is used to keep the image locally coherent ''' assert K.ndim(x) == 4 a = K.square(x[:, :-1, :-1, :] - x[:, 1:, :-1, :]) b = K.square(x[:, :-1, :-1, :] - x[:, :-1, 1:, :]) return K.sum(a + b, axis=(1, 2, 3))
def style_loss(style_image, target_image, style_masks, target_masks): '''Calculate style loss between style_image and target_image, in all regions. ''' assert 3 == K.ndim(style_image) == K.ndim(target_image) assert 3 == K.ndim(style_masks) == K.ndim(target_masks) loss = K.variable(0) for i in range(nb_labels): if K.image_dim_ordering() == 'th': style_mask = style_masks[i, :, :] target_mask = target_masks[i, :, :] else: style_mask = style_masks[:, :, i] target_mask = target_masks[:, :, i] loss += region_style_weight * region_style_loss( style_image, target_image, style_mask, target_mask) return loss
def call(self, inputs, **kwargs): if K.ndim(inputs[0]) != 3: raise ValueError( "Unexpected inputs dimensions %d, expect to be 3 dimensions" % (K.ndim(inputs))) embeds_vec_list = inputs row = [] col = [] # num_inputs = len(embeds_vec_list) # for i in range(num_inputs - 1): # for j in range(i + 1, num_inputs): # row.append(i) # col.append(j) for r, c in itertools.combinations(embeds_vec_list, 2): row.append(r) col.append(c) #p = tf.concat([embeds_vec_list[idx] for idx in row],axis=1) #q = tf.concat([embeds_vec_list[idx] for idx in col], axis=1) p = tf.concat(row, axis=1) q = tf.concat(col, axis=1) inner_product = p * q bi_interaction = inner_product attention_temp = tf.nn.relu( tf.nn.bias_add( tf.tensordot(bi_interaction, self.attention_W, axes=(-1, 0)), self.attention_b)) # Dense(self.attention_factor,'relu',kernel_regularizer=l2(self.l2_reg_w))(bi_interaction) self.normalized_att_score = tf.nn.softmax(tf.tensordot( attention_temp, self.projection_h, axes=(-1, 0)), dim=1) attention_output = tf.reduce_sum(self.normalized_att_score * bi_interaction, axis=1) attention_output = tf.nn.dropout(attention_output, self.keep_prob, seed=1024) # Dropout(1-self.keep_prob)(attention_output) afm_out = tf.tensordot(attention_output, self.projection_p, axes=(-1, 0)) return afm_out
def call(self, inputs, training=None, **kwargs): # inputs的shape:[batch_size, ] if K.ndim(inputs[0]) != 3: raise ValueError( "Unexpected inputs dimensions %d, expect to be 3 dimensions" % (K.ndim(inputs))) embeds_vec_list = inputs row = [] col = [] # 交叉对 数量: m = num * (num - 1) / 2 for r, c in itertools.combinations(embeds_vec_list, 2): row.append(r) col.append(c) # 把所有 m 个 embed向量 (1 * embed_size) 接起来:(1 * (m * embed_size)) p = tf.concat(row, axis=1) q = tf.concat(col, axis=1) inner_product = p * q # 为什m这里不进行reshape:tf.reshape(inner_product, shape=[-1, embed_size]) # ???可能输入理解有误,继续阅读 bi_interaction = inner_product attention_temp = tf.nn.relu( tf.nn.bias_add( # 这里的tensordot就是 左边矩阵的最后一维 与 右边矩阵的第一维 做矩阵相乘 # attention_W 的 维度 是 (embed_size * attention_factor) tf.tensordot(bi_interaction, self.attention_W, axes=(-1, 0)), self.attention_b)) # Dense(self.attention_factor,'relu',kernel_regularizer=l2(self.l2_reg_w))(bi_interaction) self.normalized_att_score = softmax( # attention_temp 的维度:(交叉数量m, attention_factor) # projection_h 的维度:(attention_factor, 1) tf.tensordot(attention_temp, self.projection_h, axes=(-1, 0)), dim=1) # axis = 1, 最后累加结果保持最外面的维度,这里应该是batch操作??? attention_output = reduce_sum(self.normalized_att_score * bi_interaction, axis=1) attention_output = self.dropout(attention_output, training=training) # training afm_out = self.tensordot([attention_output, self.projection_p]) return afm_out
def call(self, inputs, **kwargs): if K.ndim(inputs) != 3: raise ValueError( "Unexpected inputs dimensions %d, expect to be 3 dimensions" % (K.ndim(inputs))) concated_embeds_value = inputs square_of_sum = tf.square( tf.reduce_sum(concated_embeds_value, axis=1, keep_dims=True)) sum_of_square = tf.reduce_sum(concated_embeds_value * concated_embeds_value, axis=1, keep_dims=True) cross_term = 0.5 * (square_of_sum - sum_of_square) return cross_term
def _softmax(x): """ Softmax that works on ND inputs. """ channel_axis = get_channel_axis(K.ndim(x) - 2) e = K.exp(x - K.max(x, axis=channel_axis, keepdims=True)) s = K.sum(e, axis=channel_axis, keepdims=True) return e / s
def weighted(y_true, y_pred, weights, mask=None): """Wrapper function. Arguments: y_true: `y_true` argument of `fn`. y_pred: `y_pred` argument of `fn`. weights: Weights tensor. mask: Mask tensor. Returns: Scalar tensor. """ # score_array has ndim >= 2 score_array = fn(y_true, y_pred) if mask is not None: # Cast the mask to floatX to avoid float64 upcasting in theano mask = math_ops.cast(mask, K.floatx()) # mask should have the same shape as score_array score_array *= mask # the loss per batch should be proportional # to the number of unmasked samples. score_array /= K.mean(mask) # Apply sample weighting. if weights is not None: # Update dimensions of weights to match with values if possible. score_array, _, weights = metrics_module.squeeze_or_expand_dimensions( score_array, None, weights) try: # Broadcast weights if possible. weights = weights_broadcast_ops.broadcast_weights( weights, score_array) except ValueError: # Reduce values to same ndim as weight array. ndim = K.ndim(score_array) weight_ndim = K.ndim(weights) score_array = K.mean(score_array, axis=list(range(weight_ndim, ndim))) score_array = math_ops.multiply(score_array, weights) score_array = math_ops.reduce_sum(score_array) weights = math_ops.reduce_sum(weights) score_array = metrics_module.safe_div(score_array, weights) return K.mean(score_array)
def weighted(y_true, y_pred, weights, mask=None): """Wrapper function. Arguments: y_true: `y_true` argument of `fn`. y_pred: `y_pred` argument of `fn`. weights: Weights tensor. mask: Mask tensor. Returns: Scalar tensor. """ # score_array has ndim >= 2 score_array = fn(y_true, y_pred) if mask is not None: mask = math_ops.cast(mask, y_pred.dtype) # Update weights with mask. if weights is None: weights = mask else: # Update dimensions of weights to match with mask if possible. mask, _, weights = metrics_module.squeeze_or_expand_dimensions( mask, None, weights) weights *= mask # Apply sample weighting. if weights is not None: # Update dimensions of weights to match with values if possible. score_array, _, weights = metrics_module.squeeze_or_expand_dimensions( score_array, None, weights) try: # Broadcast weights if possible. weights = weights_broadcast_ops.broadcast_weights(weights, score_array) except ValueError: # Reduce values to same ndim as weight array. ndim = K.ndim(score_array) weight_ndim = K.ndim(weights) score_array = K.mean(score_array, axis=list(range(weight_ndim, ndim))) score_array = math_ops.multiply(score_array, weights) score_array = math_ops.reduce_sum(score_array) weights = math_ops.reduce_sum(weights) score_array = metrics_module.safe_div(score_array, weights) return K.mean(score_array)
def _mask_batch(y_true, y_pred, iou_threshold=0.5, mask_size=(28, 28), parallel_iterations=32): if K.ndim(y_pred) == 4: y_pred_shape = tf.shape(y_pred) new_y_pred_shape = [y_pred_shape[0] * y_pred_shape[1], y_pred_shape[2], y_pred_shape[3]] y_pred = tf.reshape(y_pred, new_y_pred_shape) y_true_shape = tf.shape(y_true) new_y_true_shape = [y_true_shape[0] * y_true_shape[1], y_true_shape[2], y_true_shape[3]] y_true = tf.reshape(y_true, new_y_true_shape) # split up the different predicted blobs boxes = y_pred[:, :, :4] masks = y_pred[:, :, 4:] # split up the different blobs annotations = y_true[:, :, :5] width = K.cast(y_true[0, 0, 5], dtype='int32') height = K.cast(y_true[0, 0, 6], dtype='int32') masks_target = y_true[:, :, 7:] # reshape the masks back to their original size masks_target = K.reshape(masks_target, (K.shape(masks_target)[0], K.shape(masks_target)[1], height, width)) masks = K.reshape(masks, (K.shape(masks)[0], K.shape(masks)[1], mask_size[0], mask_size[1], -1)) def _mask(args): boxes = args[0] masks = args[1] annotations = args[2] masks_target = args[3] return compute_mask_loss( boxes, masks, annotations, masks_target, width, height, iou_threshold=iou_threshold, mask_size=mask_size, ) mask_batch_loss = tf.map_fn( _mask, elems=[boxes, masks, annotations, masks_target], dtype=K.floatx(), parallel_iterations=parallel_iterations ) return K.mean(mask_batch_loss)
def total_variation_loss(x): assert K.ndim(x) == 4 a = K.square(x[:, :, 1:, :img_width - 1] - x[:, :, :img_height - 1, :img_width - 1]) b = K.square(x[:, :, :img_height - 1, 1:] - x[:, :, :img_width - 1, :img_height - 1]) #a = K.square(x[:, :, :img_width-1, :img_height-1] - x[:, :, 1:, :img_height-1]) #b = K.square(x[:, :, :img_width-1, :img_height-1] - x[:, :, :img_width-1, 1:]) return K.sum(K.pow(a + b, 1.25))
def call(self, inputs, training=None, **kwargs): if K.ndim(inputs[0]) != 3: raise ValueError( "Unexpected inputs dimensions %d, expect to be 3 dimensions" % (K.ndim(inputs))) inputs = concat_func(inputs, axis=1) Z = reduce_mean( inputs, axis=-1, ) A_1 = tf.nn.relu(self.tensordot([Z, self.W_1])) A_2 = tf.nn.relu(self.tensordot([A_1, self.W_2])) V = tf.multiply(inputs, tf.expand_dims(A_2, axis=2)) return tf.split(V, self.filed_size, axis=1)
def call(self, inputs, **kwargs): if K.ndim(inputs) != 2: raise ValueError( "Unexpected inputs dimensions %d, expect to be 2 dimensions" % (K.ndim(inputs))) x = inputs dim = x.get_shape()[-1] x_0 = K.reshape(x, [-1, dim, 1]) x_l = x_0 for i in range(self.layer_num): dot_ = tf.matmul(x_0, tf.transpose( x_l, [0, 2, 1])) # K.dot(x_0,K.transpose(x_l)) dot_ = K.dot(dot_, self.kernels[i]) #x_l = K.bias_add(dot_+ x_l,self.bias[i]) # K.bias_add(dot_, self.bias) x_l = dot_ + x_l + self.bias[i] #K.reshape(self.bias[i],[1,dim,1]) x_l = K.reshape(x_l, [-1, dim]) return x_l
def _preprocess_symbolic_input(x, data_format, mode): """Preprocesses a tensor encoding a batch of images. Arguments: x: Input tensor, 3D or 4D. data_format: Data format of the image tensor. mode: One of "caffe", "tf" or "torch". - caffe: will convert the images from RGB to BGR, then will zero-center each color channel with respect to the ImageNet dataset, without scaling. - tf: will scale pixels between -1 and 1, sample-wise. - torch: will scale pixels between 0 and 1 and then will normalize each channel with respect to the ImageNet dataset. Returns: Preprocessed tensor. """ global _IMAGENET_MEAN if mode == 'tf': x /= 127.5 x -= 1. return x if mode == 'torch': x /= 255. mean = [0.485, 0.456, 0.406] std = [0.229, 0.224, 0.225] else: if data_format == 'channels_first': # 'RGB'->'BGR' if K.ndim(x) == 3: x = x[::-1, ...] else: x = x[:, ::-1, ...] else: # 'RGB'->'BGR' x = x[..., ::-1] mean = [103.939, 116.779, 123.68] std = None if _IMAGENET_MEAN is None: _IMAGENET_MEAN = constant_op.constant(-np.array(mean), dtype=K.floatx()) # Zero-center by mean pixel if K.dtype(x) != K.dtype(_IMAGENET_MEAN): x = K.bias_add(x, math_ops.cast(_IMAGENET_MEAN, K.dtype(x)), data_format) else: x = K.bias_add(x, _IMAGENET_MEAN, data_format) if std is not None: x /= std return x
def total_variation_loss(x): assert K.ndim(x) == 4 if K.image_data_format() == "channels_first": a = K.square(x[:, :, :img_width - 1, :img_height - 1] - x[:, :, 1:, :img_height - 1]) b = K.square(x[:, :, :img_width - 1, :img_height - 1] - x[:, :, :img_width - 1, 1:]) else: a = K.square(x[:, :img_width - 1, :img_height - 1, :] - x[:, 1:, :img_height - 1, :]) b = K.square(x[:, :img_width - 1, :img_height - 1, :] - x[:, :img_width - 1, 1:, :]) return K.sum(K.pow(a + b, 1.25))
def call(self, inputs, **kwargs): if K.ndim(inputs[0]) != 3: raise ValueError( "Unexpected inputs dimensions %d, expect to be 3 dimensions" % (K.ndim(inputs))) if self.bilinear_type == "all": p = [tf.multiply(tf.tensordot(v_i, self.W, axes=(-1, 0)), v_j) for v_i, v_j in itertools.combinations(inputs, 2)] elif self.bilinear_type == "each": p = [tf.multiply(tf.tensordot(inputs[i], self.W_list[i], axes=(-1, 0)), inputs[j]) for i, j in itertools.combinations(range(len(inputs)), 2)] elif self.bilinear_type == "interaction": p = [tf.multiply(tf.tensordot(v[0], w, axes=(-1, 0)), v[1]) for v, w in zip(itertools.combinations(inputs, 2), self.W_list)] else: raise NotImplementedError return concat_fun(p)
def update_state(self, values, sample_weight=None): """Accumulates statistics for computing the mean. For example, if `values` is [1, 3, 5, 7] then the mean is 4. If the `sample_weight` is specified as [1, 1, 0, 0] then the mean would be 2. Args: values: Per-example value. sample_weight: Optional weighting of each example. Defaults to 1. Returns: Update op. """ values = math_ops.cast(values, self._dtype) if sample_weight is None: num_values = math_ops.cast(array_ops.size(values), self._dtype) else: sample_weight = math_ops.cast(sample_weight, self._dtype) # Update dimensions of weights to match with values if possible. values, _, sample_weight = squeeze_or_expand_dimensions( values, None, sample_weight) try: # Broadcast weights if possible. sample_weight = weights_broadcast_ops.broadcast_weights( sample_weight, values) except ValueError: # Reduce values to same ndim as weight array ndim = K.ndim(values) weight_ndim = K.ndim(sample_weight) values = math_ops.reduce_mean(values, axis=list( range(weight_ndim, ndim))) num_values = math_ops.reduce_sum(sample_weight) values = math_ops.multiply(values, sample_weight) values = math_ops.reduce_sum(values) # Update state variables. Count should be updated only when total is # updated. update_total_op = state_ops.assign_add(self.total, values) with ops.control_dependencies([update_total_op]): update_count_op = state_ops.assign_add(self.count, num_values) return ops.convert_to_tensor(update_count_op)
def weighted(y_true, y_pred, weights, mask=None): """Wrapper function. Arguments: y_true: `y_true` argument of `fn`. y_pred: `y_pred` argument of `fn`. weights: Weights tensor. mask: Mask tensor. Returns: Scalar tensor. """ # score_array has ndim >= 2 score_array = fn(y_true, y_pred) if mask is not None: mask = math_ops.cast(mask, y_pred.dtype) # Update weights with mask. if weights is None: weights = mask else: # Update dimensions of weights to match with mask if possible. mask, _, weights = squeeze_or_expand_dimensions(mask, None, weights) weights *= mask # Apply sample weighting. if weights is not None: # Update dimensions of weights to match with values if possible. score_array, _, weights = squeeze_or_expand_dimensions( score_array, None, weights) try: # Broadcast weights if possible. weights = weights_broadcast_ops.broadcast_weights(weights, score_array) except ValueError: # Reduce values to same ndim as weight array. ndim = K.ndim(score_array) weight_ndim = K.ndim(weights) score_array = K.mean(score_array, axis=list(range(weight_ndim, ndim))) score_array = math_ops.multiply(score_array, weights) score_array = math_ops.reduce_sum(score_array) weights = math_ops.reduce_sum(weights) score_array = math_ops.div_no_nan(score_array, weights) return K.mean(score_array)
def discriminative_instance_loss(y_true, y_pred, delta_v=0.5, delta_d=1.5, gamma=1e-3): """Discriminative loss between an output tensor and a target tensor. Args: y_true: A tensor of the same shape as y_pred. y_pred: A tensor of the vector embedding Returns: tensor: Output tensor. """ def temp_norm(ten, axis=None): if axis is None: axis = 1 if K.image_data_format( ) == 'channels_first' else K.ndim(ten) - 1 return K.sqrt(K.epsilon() + K.sum(K.square(ten), axis=axis)) rank = K.ndim(y_pred) channel_axis = 1 if K.image_data_format() == 'channels_first' else rank - 1 axes = [x for x in list(range(rank)) if x != channel_axis] # Compute variance loss cells_summed = tf.tensordot(y_true, y_pred, axes=[axes, axes]) n_pixels = K.cast(tf.count_nonzero(y_true, axis=axes), dtype=K.floatx()) + K.epsilon() n_pixels_expand = K.expand_dims(n_pixels, axis=1) + K.epsilon() mu = tf.divide(cells_summed, n_pixels_expand) delta_v = K.constant(delta_v, dtype=K.floatx()) mu_tensor = tf.tensordot(y_true, mu, axes=[[channel_axis], [0]]) L_var_1 = y_pred - mu_tensor L_var_2 = K.square(K.relu(temp_norm(L_var_1) - delta_v)) L_var_3 = tf.tensordot(L_var_2, y_true, axes=[axes, axes]) L_var_4 = tf.divide(L_var_3, n_pixels) L_var = K.mean(L_var_4) # Compute distance loss mu_a = K.expand_dims(mu, axis=0) mu_b = K.expand_dims(mu, axis=1) diff_matrix = tf.subtract(mu_b, mu_a) L_dist_1 = temp_norm(diff_matrix) L_dist_2 = K.square( K.relu(K.constant(2 * delta_d, dtype=K.floatx()) - L_dist_1)) diag = K.constant(0, dtype=K.floatx()) * tf.diag_part(L_dist_2) L_dist_3 = tf.matrix_set_diag(L_dist_2, diag) L_dist = K.mean(L_dist_3) # Compute regularization loss L_reg = gamma * temp_norm(mu) L = L_var + L_dist + K.mean(L_reg) return L
def softmax(x, axis=1): ndim = K.ndim(x) if ndim == 2: return K.softmax(x) elif ndim > 2: e = K.exp(x - K.max(x, axis=axis, keepdims=True)) s = K.sum(e, axis=axis, keepdims=True) return e / s else: raise ValueError('Cannot apply softmax to a tensor that is 1D')
def region_style_loss(style_image, target_image, style_mask, target_mask): '''Calculate style loss between style_image and target_image, for one common region specified by their (boolean) masks ''' assert 3 == K.ndim(style_image) == K.ndim(target_image) assert 2 == K.ndim(style_mask) == K.ndim(target_mask) if K.image_dim_ordering() == 'th': masked_style = style_image * style_mask masked_target = target_image * target_mask nb_channels = K.shape(style_image)[0] else: masked_style = K.permute_dimensions(style_image, (2, 0, 1)) * style_mask masked_target = K.permute_dimensions(target_image, (2, 0, 1)) * target_mask nb_channels = K.shape(style_image)[-1] s = gram_matrix(masked_style) / K.mean(style_mask) / nb_channels c = gram_matrix(masked_target) / K.mean(target_mask) / nb_channels return K.mean(K.square(s - c))
def update_state(self, values, sample_weight=None): """Accumulates statistics for computing the mean. For example, if `values` is [1, 3, 5, 7] then the mean is 4. If the `sample_weight` is specified as [1, 1, 0, 0] then the mean would be 2. Args: values: Per-example value. sample_weight: Optional weighting of each example. Defaults to 1. Returns: Update op. """ values = math_ops.cast(values, self._dtype) if sample_weight is None: num_values = math_ops.cast(array_ops.size(values), self._dtype) else: sample_weight = math_ops.cast(sample_weight, self._dtype) # Update dimensions of weights to match with values if possible. values, _, sample_weight = squeeze_or_expand_dimensions( values, None, sample_weight) try: # Broadcast weights if possible. sample_weight = weights_broadcast_ops.broadcast_weights( sample_weight, values) except ValueError: # Reduce values to same ndim as weight array ndim = K.ndim(values) weight_ndim = K.ndim(sample_weight) values = math_ops.reduce_mean( values, axis=list(range(weight_ndim, ndim))) num_values = math_ops.reduce_sum(sample_weight) values = math_ops.multiply(values, sample_weight) values = math_ops.reduce_sum(values) # Update state variables. Count should be updated only when total is # updated. update_total_op = state_ops.assign_add(self.total, values) with ops.control_dependencies([update_total_op]): update_count_op = state_ops.assign_add(self.count, num_values) return ops.convert_to_tensor(update_count_op)
def _preprocess_symbolic_input(x, data_format, mode): """Preprocesses a tensor encoding a batch of images. Arguments: x: Input tensor, 3D or 4D. data_format: Data format of the image tensor. mode: One of "caffe", "tf" or "torch". - caffe: will convert the images from RGB to BGR, then will zero-center each color channel with respect to the ImageNet dataset, without scaling. - tf: will scale pixels between -1 and 1, sample-wise. - torch: will scale pixels between 0 and 1 and then will normalize each channel with respect to the ImageNet dataset. Returns: Preprocessed tensor. """ global _IMAGENET_MEAN if mode == 'tf': x /= 127.5 x -= 1. return x if mode == 'torch': x /= 255. mean = [0.485, 0.456, 0.406] std = [0.229, 0.224, 0.225] else: if data_format == 'channels_first': # 'RGB'->'BGR' if K.ndim(x) == 3: x = x[::-1, ...] else: x = x[:, ::-1, ...] else: # 'RGB'->'BGR' x = x[..., ::-1] mean = [103.939, 116.779, 123.68] std = None if _IMAGENET_MEAN is None: _IMAGENET_MEAN = constant_op.constant(-np.array(mean), dtype=K.floatx()) # Zero-center by mean pixel if K.dtype(x) != K.dtype(_IMAGENET_MEAN): x = K.bias_add(x, math_ops.cast(_IMAGENET_MEAN, K.dtype(x)), data_format) else: x = K.bias_add(x, _IMAGENET_MEAN, data_format) if std is not None: x /= std return x
def local_conv_matmul(inputs, kernel, kernel_mask, output_shape): """Apply N-D convolution with un-shared weights using a single matmul call. This method outputs `inputs . (kernel * kernel_mask)` (with `.` standing for matrix-multiply and `*` for element-wise multiply) and requires a precomputed `kernel_mask` to zero-out weights in `kernel` and hence perform the same operation as a convolution with un-shared (the remaining entries in `kernel`) weights. It also does the necessary reshapes to make `inputs` and `kernel` 2-D and `output` (N+2)-D. Arguments: inputs: (N+2)-D tensor with shape `(batch_size, channels_in, d_in1, ..., d_inN)` or `(batch_size, d_in1, ..., d_inN, channels_in)`. kernel: the unshared weights for N-D convolution, an (N+2)-D tensor of shape: `(d_in1, ..., d_inN, channels_in, d_out2, ..., d_outN, channels_out)` or `(channels_in, d_in1, ..., d_inN, channels_out, d_out2, ..., d_outN)`, with the ordering of channels and spatial dimensions matching that of the input. Each entry is the weight between a particular input and output location, similarly to a fully-connected weight matrix. kernel_mask: a float 0/1 mask tensor of shape: `(d_in1, ..., d_inN, 1, d_out2, ..., d_outN, 1)` or `(1, d_in1, ..., d_inN, 1, d_out2, ..., d_outN)`, with the ordering of singleton and spatial dimensions matching that of the input. Mask represents the connectivity pattern of the layer and is precomputed elsewhere based on layer parameters: stride, padding, and the receptive field shape. output_shape: a tuple of (N+2) elements representing the output shape: `(batch_size, channels_out, d_out1, ..., d_outN)` or `(batch_size, d_out1, ..., d_outN, channels_out)`, with the ordering of channels and spatial dimensions matching that of the input. Returns: Output (N+2)-D tensor with shape `output_shape`. """ inputs_flat = K.reshape(inputs, (K.shape(inputs)[0], -1)) kernel = kernel_mask * kernel kernel = make_2d(kernel, split_dim=K.ndim(kernel) // 2) output_flat = K.math_ops.sparse_matmul(inputs_flat, kernel, b_is_sparse=True) output = K.reshape(output_flat, [ K.shape(output_flat)[0], ] + output_shape.as_list()[1:]) return output
def call(self, inputs): if (self.data_format == 'channels_first' and K.ndim(inputs) is not None and K.ndim(inputs) > 1): permutation = [0] permutation.extend([i for i in range(2, K.ndim(inputs))]) permutation.append(1) inputs = array_ops.transpose(inputs, perm=permutation) input_shape = inputs.shape if input_shape[1:].is_fully_defined(): flattened_dim = tensor_shape.dimension_value( np.prod(input_shape[1:], dtype=int)) outputs = array_ops.reshape(inputs, (-1, flattened_dim)) else: outputs = array_ops.reshape( inputs, (tensor_shape.dimension_value(inputs.shape[0]) or array_ops.shape(inputs)[0], -1)) if not context.executing_eagerly(): outputs.set_shape(self.compute_output_shape(inputs.shape)) return outputs
def call(self, inputs): if self.data_format == 'channels_first': permutation = [0] permutation.extend([i for i in range(2, K.ndim(inputs))]) permutation.append(1) inputs = array_ops.transpose(inputs, perm=permutation) outputs = array_ops.reshape(inputs, (array_ops.shape(inputs)[0], -1)) if not context.executing_eagerly(): outputs.set_shape(self.compute_output_shape(inputs.get_shape())) return outputs
def style_loss(style_image, target_image, style_masks, target_masks): '''Calculate style loss between style_image and target_image, in all regions. ''' assert 3 == K.ndim(style_image) == K.ndim(target_image) assert 3 == K.ndim(style_masks) == K.ndim(target_masks) loss = None for i in range(P.num_labels): if K.image_data_format() == 'channels_first': style_mask = style_masks[i, :, :] target_mask = target_masks[i, :, :] else: style_mask = style_masks[:, :, i] target_mask = target_masks[:, :, i] style_l = region_style_loss(style_image, target_image, style_mask, target_mask) if loss is None: loss = style_l else: loss = tf.add(loss, style_l) return loss
def call(self, inputs,**kwargs): if K.ndim(inputs) !=3 : raise ValueError("Unexpected inputs dimensions %d, expect to be 3 dimensions"% (K.ndim(inputs))) concated_embeds_value = inputs square_of_sum = K.square(K.sum(concated_embeds_value, axis=1, keepdims=True)) sum_of_square = K.sum(concated_embeds_value * concated_embeds_value, axis=1, keepdims=True) cross_term = 0.5*(square_of_sum - sum_of_square) cross_term = K.reshape(cross_term,(-1,inputs.get_shape()[-1])) return cross_term
def region_style_loss(style_image, target_image, style_mask, target_mask): '''Calculate style loss between style_image and target_image, for one common region specified by their (boolean) masks ''' assert 3 == K.ndim(style_image) == K.ndim(target_image) assert 2 == K.ndim(style_mask) == K.ndim(target_mask) if K.image_data_format() == 'channels_first': masked_style = style_image * style_mask masked_target = target_image * target_mask num_channels = K.shape(style_image)[0] else: masked_style = K.permute_dimensions( style_image, (2, 0, 1)) * style_mask masked_target = K.permute_dimensions( target_image, (2, 0, 1)) * target_mask num_channels = K.shape(style_image)[-1] num_channels = K.cast(num_channels, dtype='float32') s = gram_matrix(masked_style) / K.mean(style_mask) / num_channels c = gram_matrix(masked_target) / K.mean(target_mask) / num_channels return K.mean(K.square(s - c))
def call(self, inputs): if self.data_format == 'channels_first': permutation = [0] permutation.extend([i for i in range(2, K.ndim(inputs))]) permutation.append(1) inputs = array_ops.transpose(inputs, perm=permutation) outputs = array_ops.reshape(inputs, (array_ops.shape(inputs)[0], -1)) if not context.executing_eagerly(): outputs.set_shape(self.compute_output_shape(inputs.get_shape())) return outputs
def style_loss(style, combination, mask_path=None, nb_channels=None): assert K.ndim(style) == 3 assert K.ndim(combination) == 3 if content_mask_path is not None: content_mask = K.variable(load_mask(content_mask_path, nb_channels)) combination = combination * K.stop_gradient(content_mask) del content_mask if mask_path is not None: style_mask = K.variable(load_mask(mask_path, nb_channels)) style = style * K.stop_gradient(style_mask) if content_mask_path is None: combination = combination * K.stop_gradient(style_mask) del style_mask S = gram_matrix(style) C = gram_matrix(combination) channels = 3 size = img_width * img_height return K.sum(K.square(S - C)) / (4. * (channels ** 2) * (size ** 2))
def __init__(self, transition_params): """Initialize the CrfDecodeForwardRnnCell. Args: transition_params: 1. A [num_tags, num_tags] matrix of binary potentials. This matrix is expanded into a [1, num_tags, num_tags] in preparation for the broadcast summation occurring within the cell. 2. or a [Batch, num_tags, num_tags] """ if K.ndim(transition_params) == 2: transition_params = array_ops.expand_dims(transition_params, 0) assert K.ndim(transition_params ) == 3, "transition_params should have 2 or 3 dims" self._transition_params = transition_params self._num_tags = tensor_shape.dimension_value( transition_params.shape[1])
def call(self, inputs,**kwargs): if K.ndim(inputs) !=2 : raise ValueError("Unexpected inputs dimensions %d, expect to be 2 dimensions"% (K.ndim(inputs))) x_0 = tf.expand_dims(inputs,axis=2) x_l = x_0 for i in range(self.layer_num): xl_w = tf.tensordot(tf.transpose(x_l,[0,2,1]),self.kernels[i],axes=(-1,0)) dot_ = tf.matmul(x_0,xl_w) x_l = dot_ + x_l + self.bias[i] x_l = tf.squeeze(x_l,axis=2) return x_l
def weighted_focal_loss(y_true, y_pred, n_classes=3, gamma=2., axis=None, from_logits=False): """Focal loss between an output tensor and a target tensor. Automatically computes the class weights from the target image and uses them to weight the cross entropy Args: y_true: A tensor of the same shape as y_pred. y_pred: A tensor resulting from a softmax (unless from_logits is True, in which case y_pred is expected to be the logits). from_logits: Boolean, whether y_pred is the result of a softmax, or is a tensor of logits. Returns: tensor: Output tensor. """ if from_logits: raise Exception('weighted_focal_loss cannot take logits') if axis is None: axis = 1 if K.image_data_format( ) == 'channels_first' else K.ndim(y_pred) - 1 reduce_axis = [x for x in list(range(K.ndim(y_pred))) if x != axis] # scale preds so that the class probas of each sample sum to 1 y_pred = y_pred / K.sum(y_pred, axis=axis, keepdims=True) # manual computation of crossentropy _epsilon = tf.convert_to_tensor(K.epsilon(), y_pred.dtype.base_dtype) y_pred = tf.clip_by_value(y_pred, _epsilon, 1. - _epsilon) y_true_cast = K.cast(y_true, K.floatx()) total_sum = K.sum(y_true_cast) class_sum = K.sum(y_true_cast, axis=reduce_axis, keepdims=True) class_weights = 1.0 / K.cast_to_floatx(n_classes) * tf.divide( total_sum, class_sum + 1.) temp_loss = (K.pow(1. - y_pred, gamma) * K.log(y_pred) * class_weights) focal_loss = -K.sum(y_true * temp_loss, axis=axis) return focal_loss
def local_conv_matmul(inputs, kernel, kernel_mask, output_shape): """Apply N-D convolution with un-shared weights using a single matmul call. This method outputs `inputs . (kernel * kernel_mask)` (with `.` standing for matrix-multiply and `*` for element-wise multiply) and requires a precomputed `kernel_mask` to zero-out weights in `kernel` and hence perform the same operation as a convolution with un-shared (the remaining entries in `kernel`) weights. It also does the necessary reshapes to make `inputs` and `kernel` 2-D and `output` (N+2)-D. Arguments: inputs: (N+2)-D tensor with shape `(batch_size, channels_in, d_in1, ..., d_inN)` or `(batch_size, d_in1, ..., d_inN, channels_in)`. kernel: the unshared weights for N-D convolution, an (N+2)-D tensor of shape: `(d_in1, ..., d_inN, channels_in, d_out2, ..., d_outN, channels_out)` or `(channels_in, d_in1, ..., d_inN, channels_out, d_out2, ..., d_outN)`, with the ordering of channels and spatial dimensions matching that of the input. Each entry is the weight between a particular input and output location, similarly to a fully-connected weight matrix. kernel_mask: a float 0/1 mask tensor of shape: `(d_in1, ..., d_inN, 1, d_out2, ..., d_outN, 1)` or `(1, d_in1, ..., d_inN, 1, d_out2, ..., d_outN)`, with the ordering of singleton and spatial dimensions matching that of the input. Mask represents the connectivity pattern of the layer and is precomputed elsewhere based on layer parameters: stride, padding, and the receptive field shape. output_shape: a tuple of (N+2) elements representing the output shape: `(batch_size, channels_out, d_out1, ..., d_outN)` or `(batch_size, d_out1, ..., d_outN, channels_out)`, with the ordering of channels and spatial dimensions matching that of the input. Returns: Output (N+2)-D tensor with shape `output_shape`. """ inputs_flat = K.reshape(inputs, (K.shape(inputs)[0], -1)) kernel = kernel_mask * kernel kernel = make_2d(kernel, split_dim=K.ndim(kernel) // 2) output_flat = K.math_ops.sparse_matmul(inputs_flat, kernel, b_is_sparse=True) output = K.reshape(output_flat, [K.shape(output_flat)[0],] + output_shape.as_list()[1:]) return output
def _merge_function(self, inputs): if len(inputs) != 2: raise ValueError('A `Dot` layer should be called ' 'on exactly 2 inputs') x1 = inputs[0] x2 = inputs[1] if isinstance(self.axes, int): if self.axes < 0: axes = [self.axes % K.ndim(x1), self.axes % K.ndim(x2)] else: axes = [self.axes] * 2 else: axes = [] for i in range(len(self.axes)): if self.axes[i] < 0: axes.append(self.axes[i] % K.ndim(inputs[i])) else: axes.append(self.axes[i]) if self.normalize: x1 = nn.l2_normalize(x1, axis=axes[0]) x2 = nn.l2_normalize(x2, axis=axes[1]) output = K.batch_dot(x1, x2, axes) return output
def softmax(x, axis=-1): """Softmax activation function. Arguments: x : Tensor. axis: Integer, axis along which the softmax normalization is applied. Returns: Tensor, output of softmax transformation. Raises: ValueError: In case `dim(x) == 1`. """ ndim = K.ndim(x) if ndim == 2: return nn.softmax(x) elif ndim > 2: e = math_ops.exp(x - math_ops.reduce_max(x, axis=axis, keepdims=True)) s = math_ops.reduce_sum(e, axis=axis, keepdims=True) return e / s else: raise ValueError('Cannot apply softmax to a tensor that is 1D')
def call(self, inputs): if not isinstance(inputs, list): raise ValueError('A merge layer should be called ' 'on a list of inputs.') if self._reshape_required: reshaped_inputs = [] input_ndims = list(map(K.ndim, inputs)) if None not in input_ndims: # If ranks of all inputs are available, # we simply expand each of them at axis=1 # until all of them have the same rank. max_ndim = max(input_ndims) for x in inputs: x_ndim = K.ndim(x) for _ in range(max_ndim - x_ndim): x = array_ops.expand_dims(x, axis=1) reshaped_inputs.append(x) return self._merge_function(reshaped_inputs) else: # Transpose all inputs so that batch size is the last dimension. # (batch_size, dim1, dim2, ... ) -> (dim1, dim2, ... , batch_size) transposed = False for x in inputs: x_ndim = K.ndim(x) if x_ndim is None: x_shape = array_ops.shape(x) batch_size = x_shape[0] new_shape = K.concatenate( [x_shape[1:], array_ops.expand_dims(batch_size, axis=-1)]) x_transposed = array_ops.reshape( x, array_ops.stack( [batch_size, math_ops.reduce_prod(x_shape[1:])], axis=0)) x_transposed = array_ops.transpose(x_transposed, perm=(1, 0)) x_transposed = array_ops.reshape(x_transposed, new_shape) reshaped_inputs.append(x_transposed) transposed = True elif x_ndim > 1: dims = list(range(1, x_ndim)) + [0] reshaped_inputs.append(array_ops.transpose(x, perm=dims)) transposed = True else: # We don't transpose inputs if they are 1D vectors or scalars. reshaped_inputs.append(x) y = self._merge_function(reshaped_inputs) y_ndim = K.ndim(y) if transposed: # If inputs have been transposed, we have to transpose the output too. if y_ndim is None: y_shape = array_ops.shape(y) y_ndim = array_ops.shape(y_shape)[0] batch_size = y_shape[y_ndim - 1] new_shape = K.concatenate([ array_ops.expand_dims(batch_size, axis=-1), y_shape[:y_ndim - 1] ]) y = array_ops.reshape(y, (-1, batch_size)) y = array_ops.transpose(y, perm=(1, 0)) y = array_ops.reshape(y, new_shape) elif y_ndim > 1: dims = [y_ndim - 1] + list(range(y_ndim - 1)) y = array_ops.transpose(y, perm=dims) return y else: return self._merge_function(inputs)