2017-02-11 1 views
6

Предположим, у меня есть простой MLPГрадиент сети весов выход WRT, который удерживает другой выход постоянного

enter image description here

И у меня есть градиент некоторой функции потерь относительно выходного слоя, чтобы получить G = [0, -1] (т. Е. Увеличение второй выходной переменной уменьшает функцию потерь).

Если я возьму градиент G по моим сетевым параметрам и применил градиентное приличное обновление веса, то вторая выходная переменная должна увеличиться, но ничего не сказано о первой выходной переменной, а масштабированное приложение градиента будет почти конечно, измените выходную переменную (увеличивайте ее или уменьшите ее)

Как я могу изменить функцию потерь или любые вычисления градиента, чтобы гарантировать, что первый выход не изменится?

ответ

1

Обновление: непонятый вопрос. Это новый ответ.

Для этого вам необходимо обновить соединения между скрытым слоем и вторым выходным блоком, а также сохранить между скрытым слоем и первым выходным блоком.

Первый подход - ввести два набора переменных: один для соединений между скрытым слоем и первым блоком вывода, один для остальных. Затем вы можете объединить их с помощью tf.stack и передать var_list, чтобы получить соответствующие производные. Это как (Только для иллюстрации Не тестировался Используйте с осторожностью.).:

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]) 

Другой подход заключается в использовании маски. Это проще реализовать и более гибко, когда вы работаете с некоторыми фреймворками (скажем, slim, Keras и т. Д.), И я порекомендую этот путь. Идея скрыть первый блок вывода функции потерь, не меняя второй выходной блок. Это можно сделать с помощью двоичной переменной: умножьте что-нибудь на 1, если вы хотите сохранить ее, и умножьте ее на 0, чтобы удалить ее. Вот код:

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() 

======================= Ниже старый ответ ========== ====================

Чтобы получить производные по различные переменные, вы можете передать var_list, чтобы решить, какую переменную нужно обновить. Вот пример:

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

Как насчет установки 'обучаемый = false' [Variable] (https://www.tensorflow.org/versions/r0.12/api_docs/python/state_ops/variables) – xxi

+0

это это не одно и то же - проблема в том, что на оба выхода влияет изменение веса - применение градиента вывода по отношению к весам приводит к изменению обоих выходов, но мы хотим, чтобы градиент каким-то образом учитывал тот факт, что один выход должен оставаться постоянным после этапа градиента – Robert

+0

@ Robert О, я вижу. Я неправильно понял ваш вопрос. Я уточню свой ответ. – soloice

Смежные вопросы