Пользовательский слой с Keras: возможно ли иметь выходные нейроны равными 0 на выходе слоя softmax на основе нулей в качестве данных на входном слое? - PullRequest
0 голосов
/ 22 декабря 2018

У меня есть нейронная сеть с 13 выходными нейронами в последнем слое с использованием активации softmax (soft_out).Я также точно знаю, что на основе входных значений некоторые нейроны в выходном слое должны иметь 0 значений.Итак, у меня есть специальный входной слой (inp) из 13 нейронов, каждый из которых имеет значение 0 или 1.

Можно ли каким-то образом форсировать, скажем, выходной нейрон no.3, чтобы иметь значение = 0, если входной нейрон № 3 установлен в 1?

В дополнение к этому он должен действовать как слой softmax, поэтому в конце сумма нейронов должна быть равна 1. Таким образом,выходные строки должны быть исправлены.

Шаги следующие: 1. очистить нейроны soft_out, где нейроны inp == 1 2. вычислить сумму строк в soft_out 3. проверить, в какой строке сумма равна 0 4исправить правильное значение soft_out в строках, где сумма равна 0, с произвольным постоянным значением 5. снова вычислить сумму строк в soft_out 6. проверить, в какой строке сумма равна 0, и установить ее равной 1 7. вернуть soft_out / sum для каждой строки(поэтому настройте вывод так, чтобы сумма = 1 на строку)

При numpy это следующие шаги: INPUT DATA

inp = np.array((5,13))
inp = np.random.choice([0, 1], size=5*13, p=[.5, .5])
inp = inp.reshape(5,13)
soft_out=np.around(np.random.random_sample((5,13)),2)
inp [3,:]=1
inp [4,:]=1
inp [4,12]=0
soft_out[4,12]=0
print ("inp",inp,"\n")
print ("soft_out",soft_out,"\n")

inp [[1 1 0 0 1 1 11 1 1 0 0 0] [0 0 0 0 1 0 0 0 1 1 0 0 1] [1 0 1 1 0 0 0 1 0 0 0 0 1] [1 1 1 1 1 1 1 1 1 1 1 11] [1 1 1 1 1 1 1 1 1 1 1 1 0]]

soft_out [[0,8 0,16 0,42 0,44 0,67 0,39 0,38 0,54 0,75 0,06 0,62 0,67 0,8] [0,87 0,28 0,51 0,92 0,89 0,97 0,1 0,1700,73 0,43 0,84 0,96 0,57] [0,16 0,33 0,62 0,37 0,42 0,54 0,1 0,54 0,92 0,51 0,89 0,86 0,96] [0,53 0,59 0,6 0,63 0,57 0,95 0,41 0,1 0,32 0,81 0,87 0,35 0,16] [0,13 0,57 0,92 0,87 0,82 0,08 0,74 0,78 0,2 0,22 0,64 0,060.]]

#0. find out where inp is set to 1 and to 0
mask_nonzero=np.where(inp != 0 )
print ("mask_nonzero", mask_nonzero,"\n")

mask_zero=np.where(inp == 0 )
print ("mask_zero", mask_zero,"\n")

#1. clear those values where inp is 1
soft_out[mask_nonzero]=0
print ("soft_out", soft_out,"\n")

#2. calculate the sum of the rows
row_sum_soft_out = np.sum(soft_out,axis=-1)
print ("row_sum_soft_out", row_sum_soft_out,"\n")

# 3. reshape in order to find out rows where the sum is zero >> this means that the soft_out values have to be corrected
row_sum_soft_out = row_sum_soft_out.reshape(5,1)
print ("row_sum_soft_out", row_sum_soft_out,"\n")

mask_sum_zero = np.where(row_sum_soft_out == 0 )
soft_out[mask_sum_zero[0]] = 1
print ("soft_out", soft_out,"\n")

print ("mask_sum_zero", mask_sum_zero,"\n")
soft_out[mask_nonzero]=0

# correct soft_out in the rows where sum is 0 to an arbitrary constant value
row_sum_soft_out = np.sum(soft_out,axis=-1)

#5. calculate sum of the rows in soft_out again
mask_sum_zero = np.where(row_sum_soft_out == 0 )

#6. check in which row where the sum is 0 and set it to 1
row_sum_soft_out[mask_sum_zero] = 1

row_sum_soft_out = row_sum_soft_out.reshape(5,1)
#7. return soft_out / sum per each row (so adjust the output to have sum =1 per row)
y = soft_out / row_sum_soft_out
print ("soft_out", y)
print (np.sum(y,axis=-1),"\n")

mask_nonzero (array ([0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2,2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4,4, 4, 4, 4], dtype = int64), массив ([0, 1, 4, 5, 6, 7, 8, 9, 4, 8, 9, 12, 0, 2, 3, 7, 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], dtype = int64))

mask_zero (массив ([0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,2, 2, 2, 2, 2, 2, 4], dtype = int64), массив ([2, 3, 10, 11, 12, 0, 1, 2, 3, 5, 6, 7, 10, 11, 1, 4, 5, 6, 8, 9, 10, 11, 12], dtype = int64))

soft_out [[0.0. 0,42 0,44 0. 0. 0. 0. 0. 0. 0.62 0.67 0.86] [0.87 0.28 0.51 0.92 0. 0.97 0.1 0.17 0. 0. 0.84 0.96 0.] [0.0,33 0,10 0,42 0,54 0,1 0. 0,92 0,51 0,89 0,86 0.] [0.0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [0.0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]]

row_sum_soft_out [3.01 5.62 4.57 0. 0.]

row_sum_soft_out [[3,01] [5,62] [4,57] [0.] [0.]]

soft_out [[0.0. 0,42 0,44 0. 0. 0. 0. 0. 0. 0.62 0.67 0.86] [0.87 0.28 0.51 0.92 0. 0.97 0.1 0.17 0. 0. 0.84 0.96 0.] [0.0,33 0,10 0,42 0,54 0,1 0. 0,92 0,51 0,89 0,86 0.] [1.1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] [1.1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]]

mask_sum_zero (массив ([3, 4], dtype = int64), массив ([0, 0], dtype = int64))

soft_out [[0.0. 0,13953488 0,1461794 0. 0. 0. 0. 0. 0. 0.20598007 0.22259136 0.28571429] [0.15480427 0.04982206 0.09074733 0.16370107 0. 0.17259786 0.01779359 0.03024911 0. 0. 0.14946619 0.17081851 0.] [0.0,07221007 0. 0. 0.09190372 0.11816193 0.02188184 0. 0.20131291 0.11159737 0.19474836 0.18818381 0.] [0.0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.0.] [0.0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]] [1.1. 1. 0. 1.]

Может кто-нибудь помочь с написанием внутреннего слоя KERAS, пожалуйста?

1 Ответ

0 голосов
/ 23 декабря 2018

Я придумал этот код в конце ... нужно изменить форму (shape = (32, 13)) по мере необходимости

from keras import backend as K
import tensorflow as tf
def mask_output2(x):
    # soft_out is the output of the previous softmax layer, shape =(batch_size, 13) in my case
    # inp is the tensor containing 0 and 1-s, where 1 means that the action was already used, shape=(batch_size, 13)
    inp, soft_out = x
    # add a very small value in order to avoid having 0 everywhere
    c = K.constant(0.0000001, dtype='float32', shape=(32, 13))
    y = soft_out + c
    # clear invalid actions' values
    y = Lambda(lambda x: K.switch(K.equal(x[0],0), x[1], K.zeros_like(x[1])))([inp, soft_out])
    y_sum =  K.sum(y, axis=-1)
    # correct sum if it is 0 to avoid dividing by zero
    y_sum_corrected = Lambda(lambda x: K.switch(K.equal(x[0],0), K.ones_like(x[0]), x[0] ))([y_sum])
    # reshape output in order to have sum 1 per row, so first calculate 1/sum
    y_sum_corrected = tf.divide(1,y_sum_corrected)
    # multiply tensor (32,13) with tensor (32)
    y = tf.einsum('ij,i->ij', y, y_sum_corrected)
    return y
...