Взвешенная маска / корректировка веса в керасе
Я хочу предоставить маску того же размера, что и входное изображение, и откорректировать веса, извлеченные из изображения, в соответствии с этой маской (аналогично вниманию, но предварительно рассчитанному для каждого входного изображения). Как я могу сделать это с керасом (или тензорным потоком)?
0 ответов
Вопрос
Как я могу добавить еще один векторный слой к изображению, такой как маска, и сделать так, чтобы нейронная сеть учитывала этот новый векторный слой?
Ответ
Краткий ответ - добавить его в качестве другого цветового канала к изображению. Если ваше изображение уже имеет 3 цветовых канала; красный, синий, зеленый, затем добавление еще одного канала с маской 1 и 0 дает нейронной сети гораздо больше информации, которую можно использовать для принятия решений.
Мысленный эксперимент
В качестве мысленного эксперимента давайте рассмотрим MNIST. MNIST изображения имеют размер 28x28. Давайте возьмем 1 изображение, "истинное" изображение и 3 других изображения, "отвлекающие факторы", и сформируем изображение размером 56x56 из 4 изображений размером 28x28. MNIST черно-белый, поэтому он имеет только 1 цветной канал, яркость. Давайте теперь добавим еще один цветной канал, который является маской, 1 в области изображения 56x56, где "истинное" изображение, и 0 в другом месте.
Если мы используем ту же архитектуру, что и обычно, для решения MNIST, вплоть до свертки, мы можем представить, что она может использовать эту новую информацию, чтобы научиться обращать внимание только на "истинную" область и правильно классифицировать изображение.
Пример кода
В этом примере мы пытаемся решить проблему XOR. Мы берем классический XOR, удваиваем вход с шумом и добавляем канал, который равен 1 для отсутствия шума и 0 для шума
# Adapted from https://github.com/panchishin/learn-to-tensorflow/blob/master/solutions/04-xor-2d.py
# -- The xor problem --
x = np.array([[0., 0.], [1., 1.], [1., 0.], [0., 1.]])
y_ = [[1., 0.], [1., 0.], [0., 1.], [0., 1.]]
def makeBatch() :
# Add an additional 2 channels of noise
# either before or after the two real 'x's.
global x
rx = np.random.rand(4,4,2) > 0.5
# set the mask to 0 for all items
rx[:,:,1] = 0
index = int(np.random.random()*3)
rx[:,index:index+2,0] = x
# set the mask to 1 for 'real' values
rx[:,index:index+2,1] = 1
return rx
# -- imports --
import tensorflow as tf
# np.set_printoptions(precision=1) reduces np precision output to 1 digit
np.set_printoptions(precision=2, suppress=True)
# -- induction --
# Layer 0
x0 = tf.placeholder(dtype=tf.float32, shape=[None, 4, 2])
y0 = tf.placeholder(dtype=tf.float32, shape=[None, 2])
# Layer 1
f1 = tf.reshape(x0,shape=[-1,8])
m1 = tf.Variable(tf.random_uniform([8, 9], minval=0.1, maxval=0.9, dtype=tf.float32))
b1 = tf.Variable(tf.random_uniform([9], minval=0.1, maxval=0.9, dtype=tf.float32))
h1 = tf.sigmoid(tf.matmul(f1, m1) + b1)
# Layer 2
m2 = tf.Variable(tf.random_uniform([9, 2], minval=0.1, maxval=0.9, dtype=tf.float32))
b2 = tf.Variable(tf.random_uniform([2], minval=0.1, maxval=0.9, dtype=tf.float32))
y_out = tf.nn.softmax(tf.matmul(h1, m2) + b2)
# -- loss --
# loss : sum of the squares of y0 - y_out
loss = tf.reduce_sum(tf.square(y0 - y_out))
# training step : gradient descent (1.0) to minimize loss
train = tf.train.GradientDescentOptimizer(1.0).minimize(loss)
# -- training --
# run 500 times using all the X and Y
# print out the loss and any other interesting info
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print("\nloss")
for step in range(5000):
sess.run(train, feed_dict={x0: makeBatch(), y0: y_})
if (step + 1) % 1000 == 0:
print(sess.run(loss, feed_dict={x0: makeBatch(), y0: y_}))
results = sess.run([m1, b1, m2, b2, y_out, loss], feed_dict={x0: makeBatch(), y0: y_})
labels = "m1,b1,m2,b2,y_out,loss".split(",")
for label, result in zip(*(labels, results)):
print("")
print(label)
print(result)
print("")
Выход
Мы видим, что сеть правильно решает проблему и дает правильный вывод с высокой степенью достоверности.
y_ (истина) = [[1., 0.], [1., 0.], [0., 1.], [0., 1.]]
y_out
[[0.99 0.01]
[0.99 0.01]
[0.01 0.99]
[0.01 0.99]]
loss
0.00056630466
Подтверждение, что маска что-то делает
Давайте изменим функцию маски, чтобы она была случайной, закомментировав строки, которые устанавливают 0 для шума и 1 для сигнала
def makeBatch() :
global x
rx = np.random.rand(4,4,2) > 0.5
#rx[:,:,1] = 0
index = int(np.random.random()*3)
rx[:,index:index+2,0] = x
#rx[:,index:index+2,1] = 1
return rx
и затем повторно запустите код. Действительно, мы видим, что сеть не может учиться без маски.
y_out
[[0.99 0.01]
[0.76 0.24]
[0.09 0.91]
[0.58 0.42]]
loss
0.8080765
Заключение
Если у вас есть некоторый сигнал и шум на изображении (или другой структуре данных), и вы успешно добавили другой канал (маску), который указывает, где находится сигнал и где находится шум, нейронная сеть может использовать эту маску для фокусировки на сигнале пока еще есть доступ к шуму.