Search code examples
replacekeraskeras-layeractivationactivation-function

keras custom activation to drop under certain conditions


I am trying to drop the values less than 1 and greater than -1 in my custom activation like below.

def ScoreActivationFromSigmoid(x, target_min=1, target_max=9) :
    condition = K.tf.logical_and(K.tf.less(x, 1), K.tf.greater(x, -1))
    case_true = K.tf.reshape(K.tf.zeros([x.shape[1] * x.shape[2]], tf.float32), shape=(K.tf.shape(x)[0], x.shape[1], x.shape[2]))
    case_false = x
    changed_x = K.tf.where(condition, case_true, case_false)

    activated_x = K.sigmoid(changed_x)
    score = activated_x * (target_max - target_min) + target_min
    return  score

the data type has 3 dimensions: batch_size x sequence_length x number of features.

But I got this error

nvalidArgumentError: Inputs to operation activation_51/Select of type Select must have the same size and shape.  Input 0: [1028,300,64] != input 1: [1,300,64]
     [[{{node activation_51/Select}} = Select[T=DT_FLOAT, _class=["loc:@training_88/Adam/gradients/activation_51/Select_grad/Select_1"], _device="/job:localhost/replica:0/task:0/device:GPU:0"](activation_51/LogicalAnd, activation_51/Reshape, dense_243/add)]]
     [[{{node metrics_92/acc/Mean_1/_9371}} = _Recv[client_terminated=false, recv_device="/job:localhost/replica:0/task:0/device:CPU:0", send_device="/job:localhost/replica:0/task:0/device:GPU:0", send_device_incarnation=1, tensor_name="edge_473_metrics_92/acc/Mean_1", tensor_type=DT_FLOAT, _device="/job:localhost/replica:0/task:0/device:CPU:0"]()]]

I understand what the problem is; custom activation function cannot find the proper batch size of inputs. But I don't know how to control them.

Can anyone fix this or suggest other methods to replace some of the element values in some conditions?


Solution

  • The error message I got when running your code is:

    ValueError: Cannot reshape a tensor with 19200 elements to shape [1028,300,64] (19737600 elements) for 'Reshape_8' (op: 'Reshape') with input shapes: [19200], [3] and with input tensors computed as partial shapes: input[1] = [1028,300,64].

    And the problem should be that you cannot reshape a tensor of shape [x.shape[1] * x.shape[2]] to (K.tf.shape(x)[0], x.shape[1], x.shape[2]). This is because their element counts are different.

    So the solution is just creating a zero array in right shape. This line:

    case_true = K.tf.reshape(K.tf.zeros([x.shape[1] * x.shape[2]], tf.float32), shape=(K.tf.shape(x)[0], x.shape[1], x.shape[2]))
    

    should be replace with:

    case_true = K.tf.reshape(K.tf.zeros([x.shape[0] * x.shape[1] * x.shape[2]], K.tf.float32), shape=(K.tf.shape(x)[0], x.shape[1], x.shape[2]))
    

    or using K.tf.zeros_like:

    case_true = K.tf.zeros_like(x)
    

    Workable code:

    import keras.backend as K
    import numpy as np
    
    def ScoreActivationFromSigmoid(x, target_min=1, target_max=9) :
        condition = K.tf.logical_and(K.tf.less(x, 1), K.tf.greater(x, -1))
        case_true = K.tf.zeros_like(x)
        case_false = x
        changed_x = K.tf.where(condition, case_true, case_false)
    
        activated_x = K.tf.sigmoid(changed_x)
        score = activated_x * (target_max - target_min) + target_min
        return  score
    
    with K.tf.Session() as sess:
        x = K.tf.placeholder(K.tf.float32, shape=(1028, 300, 64), name='x')
        score = sess.run(ScoreActivationFromSigmoid(x), feed_dict={'x:0':np.random.randn(1028, 300, 64)})
    
    print(score)