2017-02-11 12 views
6

Załóżmy mam prosty MLPGradient wyjście wrt ciężarami sieciowych, które posiada innego wyjścia stały

enter image description here

I mam gradient jakiejś funkcji straty w stosunku do warstwy wyjściowej do uzyskania G = [0, -1] (czyli zwiększenie drugiej zmiennej wyjściowej zmniejsza funkcję straty).

Jeśli przyjmę gradient G w odniesieniu do moich parametrów sieci i zastosuję aktualizację przyzwoitej gradientu, druga zmienna wyjściowa powinna wzrosnąć, ale nic nie jest powiedziane o pierwszej zmiennej wyjściowej, a skalowana aplikacja gradientu będzie prawie równa na pewno zmień zmienną wyjściową (zwiększając ją lub zmniejszając)

Jak mogę zmodyfikować funkcję utraty lub jakiekolwiek obliczenia gradientowe, aby upewnić się, że pierwsze wyjście nie zmieni się?

Odpowiedz

1

Aktualizacja: źle zrozumiałem pytanie. To jest nowa odpowiedź.

W tym celu należy aktualizować połączenia tylko między warstwą ukrytą a drugą jednostką wyjściową, zachowując jednocześnie nienaruszone połączenia między warstwą ukrytą a pierwszą jednostką wyjściową.

Pierwsze podejście polega na wprowadzeniu dwóch zestawów zmiennych: jeden dla połączeń pomiędzy warstwą ukrytą a pierwszą jednostką wyjściową, a drugą dla pozostałych. Następnie możesz połączyć je za pomocą tf.stack i przekazać var_list, aby uzyskać odpowiednie pochodne. To jak (Tylko dla ilustracji nie testowano używać z rozwagą..):

out1 = tf.matmul(hidden, W_h_to_out1) + b_h_to_out1 
out2 = tf.matmul(hidden, W_h_to_out2) + b_h_to_out2 
out = tf.stack([out1, out2]) 
out = tf.transpose(tf.reshape(out, [2, -1])) 
loss = some_function_of(out) 
optimizer = tf.train.GradientDescentOptimizer(0.1) 
train_op_second_unit = optimizer.minimize(loss, var_list=[W_h_to_out2, b_h_to_out2]) 

Innym podejściem jest użycie maski. Jest to łatwiejsze do wdrożenia i bardziej elastyczne podczas pracy z niektórymi frameworkami (np. Slim, Keras itp.) I polecam w ten sposób. Pomysł, aby ukryć pierwszą jednostkę wyjściową do funkcji utraty, a jednocześnie nie zmieniać drugiej jednostki wyjściowej. Można to zrobić za pomocą zmiennej binarnej: pomnóż coś przez 1, jeśli chcesz ją zachować, i pomnóż ją przez 0, aby ją upuścić. Oto kod:

import tensorflow as tf 
import numpy as np 

# let's make our tiny dataset: (x, y) pairs, where x = (x1, x2, x3), y = (y1, y2), 
# and y1 = x1+x2+x3, y2 = x1^2+x2^2+x3^2 

# n_sample data points 
n_sample = 8 
data_x = np.random.random((n_sample, 3)) 
data_y = np.zeros((n_sample, 2)) 
data_y[:, 0] += np.sum(data_x, axis=1) 
data_y[:, 1] += np.sum(data_x**2, axis=1) 
data_y += 0.01 * np.random.random((n_sample, 2)) # add some noise 


# build graph 
# suppose we have a network of shape [3, 4, 2], i.e.: one hidden layer of size 4. 

x = tf.placeholder(tf.float32, shape=[None, 3], name='x') 
y = tf.placeholder(tf.float32, shape=[None, 2], name='y') 
mask = tf.placeholder(tf.float32, shape=[None, 2], name='mask') 

W1 = tf.Variable(tf.random_normal(shape=[3, 4], stddev=0.1), name='W1') 
b1 = tf.Variable(tf.random_normal(shape=[4], stddev=0.1), name='b1') 
hidden = tf.nn.sigmoid(tf.matmul(x, W1) + b1) 
W2 = tf.Variable(tf.random_normal(shape=[4, 2], stddev=0.1), name='W2') 
b2 = tf.Variable(tf.random_normal(shape=[2], stddev=0.1), name='b2') 
out = tf.matmul(hidden, W2) + b2 
loss = tf.reduce_mean(tf.square(out - y)) 

# multiply out by mask, thus out[0] is "invisible" to loss, and its gradient will not be propagated 
masked_out = mask * out 
loss2 = tf.reduce_mean(tf.square(masked_out - y)) 

optimizer = tf.train.GradientDescentOptimizer(0.1) 
train_op_all = optimizer.minimize(loss) # update all variables in the network 
train_op12 = optimizer.minimize(loss, var_list=[W2, b2]) # update hidden -> output layer 
train_op2 = optimizer.minimize(loss2, var_list=[W2, b2]) # update hidden -> second output unit 


sess = tf.InteractiveSession() 
sess.run(tf.global_variables_initializer()) 
mask_out1 = np.zeros((n_sample, 2)) 
mask_out1[:, 1] += 1.0 
# print(mask_out1) 
print(sess.run([hidden, out, loss, loss2], feed_dict={x: data_x, y: data_y, mask: mask_out1})) 

# In this case, only out2 is updated. You see the loss and loss2 decreases. 
sess.run(train_op2, feed_dict={x: data_x, y:data_y, mask: mask_out1}) 
print(sess.run([hidden, out, loss, loss2], feed_dict={x: data_x, y:data_y, mask: mask_out1})) 

# In this case, both out1 and out2 is updated. You see the loss and loss2 decreases. 
sess.run(train_op12, feed_dict={x: data_x, y:data_y, mask: mask_out1}) 
print(sess.run([hidden, out, loss, loss2], feed_dict={x: data_x, y:data_y, mask: mask_out1})) 

# In this case, everything is updated. You see the loss and loss2 decreases. 
sess.run(train_op_all, feed_dict={x: data_x, y:data_y, mask: mask_out1}) 
print(sess.run([hidden, out, loss, loss2], feed_dict={x: data_x, y:data_y, mask: mask_out1})) 
sess.close() 

======================= Poniżej znajduje się stary odpowiedź ========== ====================

Aby uzyskać instrumenty pochodne różne zmienne, można przekazać var_list, aby zdecydować, którą zmienną zaktualizować. Oto przykład:

import tensorflow as tf 
import numpy as np 

# let's make our tiny dataset: (x, y) pairs, where x = (x1, x2, x3), y = (y1, y2), 
# and y1 = x1+x2+x3, y2 = x1^2+x2^2+x3^2 

# n_sample data points 
n_sample = 8 
data_x = np.random.random((n_sample, 3)) 
data_y = np.zeros((n_sample, 2)) 
data_y[:, 0] += np.sum(data_x, axis=1) 
data_y[:, 1] += np.sum(data_x**2, axis=1) 
data_y += 0.01 * np.random.random((n_sample, 2)) # add some noise 


# build graph 
# suppose we have a network of shape [3, 4, 2], i.e.: one hidden layer of size 4. 

x = tf.placeholder(tf.float32, shape=[None, 3], name='x') 
y = tf.placeholder(tf.float32, shape=[None, 2], name='y') 

W1 = tf.Variable(tf.random_normal(shape=[3, 4], stddev=0.1), name='W1') 
b1 = tf.Variable(tf.random_normal(shape=[4], stddev=0.1), name='b1') 
hidden = tf.nn.sigmoid(tf.matmul(x, W1) + b1) 
W2 = tf.Variable(tf.random_normal(shape=[4, 2], stddev=0.1), name='W2') 
b2 = tf.Variable(tf.random_normal(shape=[2], stddev=0.1), name='b2') 
out = tf.matmul(hidden, W2) + b2 

loss = tf.reduce_mean(tf.square(out - y)) 
optimizer = tf.train.GradientDescentOptimizer(0.1) 
# You can pass a variable list to decide which variable(s) to minimize. 
train_op_second_layer = optimizer.minimize(loss, var_list=[W2, b2]) 
# If there is no var_list, all variables will be updated. 
train_op_all = optimizer.minimize(loss) 

sess = tf.InteractiveSession() 
sess.run(tf.global_variables_initializer()) 
print(sess.run([W1, b1, W2, b2, loss], feed_dict={x: data_x, y:data_y})) 

# In this case, only W2 and b2 are updated. You see the loss decreases. 
sess.run(train_op_second_layer, feed_dict={x: data_x, y:data_y}) 
print(sess.run([W1, b1, W2, b2, loss], feed_dict={x: data_x, y:data_y})) 

# In this case, all variables are updated. You see the loss decreases. 
sess.run(train_op_all, feed_dict={x: data_x, y:data_y}) 
print(sess.run([W1, b1, W2, b2, loss], feed_dict={x: data_x, y:data_y})) 
sess.close() 
+0

Jak o ustawienie 'wyszkolić = FALSE, [zmienna] (https://www.tensorflow.org/versions/r0.12/api_docs/python/state_ops/variables) – xxi

+0

to to nie to samo - problem polega na tym, że na oba wyjścia wpływa zmiana wagi - zastosowanie gradientu wyjścia w odniesieniu do ciężarów indukuje zmianę obu wyników, ale chcemy, aby gradient w jakiś sposób tłumaczył fakt, że wyjście powinno pozostać niezmienione po kroku gradientu – Robert

+0

@Robert Och, widzę. Źle zrozumiałem twoje pytanie. Zaktualizuję moją odpowiedź. – soloice