如何将两个动态尺寸张量相乘

时间:2019-04-22 07:39:13

标签: python tensorflow keras

我想获取每个输入向量之间的距离。但是由于张量流没有直接获取距离的函数,我将公式用作(a+b)^2 = a^2 + 2ab + b^2。但是,由于输入向量的维是动态的(例如[None, 64]),因此我无法正确获得乘法结果。那么如何获得两个动态tensor之间的乘积?

这是我在具有tensorflow背景的keras中使用的代码。

import numpy as np

from keras.layers import Input, Conv2D, LeakyReLU, MaxPooling2D, Flatten, Dense, BatchNormalization, Lambda
from keras.models import Model
from keras import backend as K
from keras.layers import Layer
from keras import backend as K
from keras.engine.topology import Layer
from keras.datasets import mnist
from keras import optimizers
from keras.utils import to_categorical


class MyLayer(Layer):
    def __init__(self, 
                output_dim, 
                distant_parameter = 0.05,
                **kwargs):
        self.output_dim = output_dim
        self.distant_parameter = distant_parameter
        super(MyLayer, self).__init__(**kwargs)

    def build(self, input_shape):
        self.kernel = self.add_weight(name = 'MyKernel', 
                                      shape = (self.output_dim, input_shape[-1]), 
                                      initializer = 'uniform',
                                      trainable = True)
        super(MyLayer, self).build(input_shape)

    def call(self, inputs):
        import tensorflow as tf
        test = True
        outputs = ()

        with tf.variable_scope('pairwise_dist'):
            na = tf.reduce_sum(tf.square(self.kernel), 1)
            nb = tf.reduce_sum(tf.square(inputs), 1)

            # nb cannot be calculated accuracy and the output a [none, none, none, ..., none]

            na = tf.reshape(na, [1, -1])
            nb = tf.reshape(nb, [-1, 1])


            Tul = tf.exp(- self.distant_parameter * tf.sqrt(tf.maximum(nb - 2*tf.matmul(inputs, self.kernel, False, True) + na, 0.0)))  
            SumTul = tf.reduce_sum(Tul, 1)
            SumTul = tf.reshape(SumTul, [-1, 1])
            outputs = tf.divide(Tul, SumTul)

        return outputs

    def compute_output_shape(self, input_shape):
        output_shape = list(input_shape)
        output_shape[-1] = self.output_dim
        #output_shape[-1] = input_shape[0]
        return tuple(output_shape)




def TestModel():
    InpLay = Input(shape=(3, 28, 28))
    Block1 = Conv2D(7, kernel_size=(3, 3),activation='linear', input_shape=(3, 28, 28), padding='same')(InpLay)
    Block1 = LeakyReLU(alpha=0.1)(Block1)
    Block1 = MaxPooling2D((2, 2),padding='same')(Block1)

    Block2 = Conv2D(14, (3, 3), activation='linear',padding='same')(Block1)
    Block2 = LeakyReLU(alpha=0.1)(Block2)
    Block2 = MaxPooling2D(pool_size=(2, 2),padding='same')(Block2)

    Block3 = Conv2D(28, (3, 3), activation='linear',padding='same')(Block2)
    Block3 = LeakyReLU(alpha=0.1)(Block3)
    Block3 = MaxPooling2D(pool_size=(2, 2),padding='same')(Block3)

    Finals = Flatten()(Block3)
    Finals = Dense(64, activation='linear')(Finals)
    Finals = LeakyReLU(alpha=0.1)(Finals)
    Finals = BatchNormalization(axis = -1)(Finals)

    Finals = MyLayer(10)(Finals)

    model = Model(inputs = InpLay, outputs = Finals)
    model.summary()

    return model


def RWTrain():
    #Import MNIST dataset
    (x_train, y_train),(x_test, y_test) = mnist.load_data()
    x_new_train = []

    for i in range(0, len(x_train)):
        x_new_train.append([x_train[i], x_train[i], x_train[i]])

    y_new_train = to_categorical(y_train)
    x_new_train = np.array(x_new_train)
    y_new_train = np.array(y_new_train)

    #Import Model
    model = TestModel()
    sgd = optimizers.SGD(lr=0.02, decay=1e-6, momentum=0.9, nesterov=True)
    #Using Stochastic gradient descent(SGD) for optimizer
    model.compile(loss='categorical_crossentropy', metrics=['accuracy'], optimizer = sgd)

    #Training model
    model.fit(x = x_new_train, y = y_new_train, validation_split=0.1, epochs = 1)
    model.save_weights("./Output/Model.h5")

if __name__ == '__main__':
    import sys
    RWTrain()


1 个答案:

答案 0 :(得分:0)

计算两个张量之间的欧几里得距离非常简单。考虑下面的例子。第一维未知(None),我们计算xy中相应批处理位置中两个张量之间的距离:

import tensorflow as tf

x = tf.placeholder(tf.float32, shape=(None, 2))
y = tf.placeholder(tf.float32, shape=(None, 2))

squared_distance = tf.reduce_sum(tf.square(tf.subtract(x, y)),
                                 axis=1)
distance = tf.sqrt(squared_distance)

with tf.Session() as sess:
  res = sess.run(distance,
                 feed_dict={x:[[1., 1.], [3., 3.]],
                            y:[[2., 2.], [1., 1.]]})
  print('Euclidean distance:')
  print(res) # [1.4142135 2.828427 ] <-- sqrt(2), sqrt(8)
  res = sess.run(squared_distance,
                 feed_dict={x:[[1., 1.], [3., 3.]],
                            y:[[2., 2.], [1., 1.]]})
  print('Squared Euclidean distance:')
  print(res) # [2. 8.]

# Euclidean distance:
# [1.4142135 2.828427 ]
# Squared Euclidean distance:
# [2. 8.]

使用自定义keras图层也是如此:

class DistanceLayer(tf.keras.layers.Layer):
  def __init__(self, distance='euclidean'):
    self.distance = distance

  def __call__(self, x, y):
    distance = tf.reduce_sum(tf.square(tf.subtract(x, y)), axis=1)
    if self.distance == 'euclidean':
      distance = tf.sqrt(distance)
    return distance

distlayer = DistanceLayer()

x = tf.constant([[1., 1.], [3., 3.]])
y = tf.constant([[2., 2.], [1., 1.]])
res = distlayer(x, y)
with tf.Session() as sess:
  print(res.eval()) # [1.4142135 2.828427 ]