tensorflow
Matematik bakom 2D-upplösning med avancerade exempel i TF
Sök…
Introduktion
2D-upplösning beräknas på liknande sätt som man skulle beräkna 1D-upplösning : du glider din kärna över ingången, beräknar de elementvisa multiplikationerna och summerar dem. Men istället för att din kärna / input är en matris, här är de matriser.
Ingen stoppning, steg = 1
Detta är det mest grundläggande exemplet med de enklaste beräkningarna. Låt oss anta att din input
och kernel
är:
När du din kärna får du följande utgång: , som beräknas på följande sätt:
- 14 = 4 * 1 + 3 * 0 + 1 * 1 + 2 * 2 + 1 * 1 + 0 * 0 + 1 * 0 + 2 * 0 + 4 * 1
- 6 = 3 * 1 + 1 * 0 + 0 * 1 + 1 * 2 + 0 * 1 + 1 * 0 + 2 * 0 + 4 * 0 + 1 * 1
- 6 = 2 * 1 + 1 * 0 + 0 * 1 + 1 * 2 + 2 * 1 + 4 * 0 + 3 * 0 + 1 * 0 + 0 * 1
- 12 = 1 * 1 + 0 * 0 + 1 * 1 + 2 * 2 + 4 * 1 + 1 * 0 + 1 * 0 + 0 * 0 + 2 * 1
TFs konv2d- funktion beräknar rullningar i partier och använder ett något annat format. För en ingång är det [batch, in_height, in_width, in_channels]
för kärnan är det [filter_height, filter_width, in_channels, out_channels]
. Så vi måste lämna uppgifterna i rätt format:
import tensorflow as tf
k = tf.constant([
[1, 0, 1],
[2, 1, 0],
[0, 0, 1]
], dtype=tf.float32, name='k')
i = tf.constant([
[4, 3, 1, 0],
[2, 1, 0, 1],
[1, 2, 4, 1],
[3, 1, 0, 2]
], dtype=tf.float32, name='i')
kernel = tf.reshape(k, [3, 3, 1, 1], name='kernel')
image = tf.reshape(i, [1, 4, 4, 1], name='image')
Därefter beräknas upplösningen med:
res = tf.squeeze(tf.nn.conv2d(image, kernel, [1, 1, 1, 1], "VALID"))
# VALID means no padding
with tf.Session() as sess:
print sess.run(res)
Och kommer att motsvara den vi beräknade för hand.
Viss stoppning, steg = 1
Polstring är bara ett fint namn på att berätta: omge din matematik med något konstant. I de flesta fall är konstanten noll och det är därför folk kallar det noll stoppning. Så om du vill använda en stoppning av 1 i vår ursprungliga ingång (kolla det första exemplet med padding=0, strides=1
) kommer matrisen att se ut så här:
För att beräkna värdena på upplösningen gör du samma glidning. Lägg märke till att i vårt fall många värden i mitten inte behöver beräknas om (de kommer att vara samma som i föregående exempel. Jag kommer inte heller att visa alla beräkningar här, eftersom idén är rak framåt. Resultatet är:
var
- 5 = 0 * 1 + 0 * 0 + 0 * 1 + 0 * 2 + 4 * 1 + 3 * 0 + 0 * 0 + 0 * 1 + 1 * 1
- ...
- 6 = 4 * 1 + 1 * 0 + 0 * 1 + 0 * 2 + 2 * 1 + 0 * 0 + 0 * 0 + 0 * 0 + 0 * 1
TF stöder inte en godtycklig polstring i konv2d- funktionen, så om du behöver lite stoppning som inte stöds, använd tf.pad () . Lyckligtvis för vår inmatning kommer vadderingen "SAME" att vara lika med vadderingen = 1. Så vi behöver ändra nästan ingenting i vårt tidigare exempel:
res = tf.squeeze(tf.nn.conv2d(image, kernel, [1, 1, 1, 1], "SAME"))
# 'SAME' makes sure that our output has the same size as input and
# uses appropriate padding. In our case it is 1.
with tf.Session() as sess:
print sess.run(res)
Du kan verifiera att svaret kommer att vara detsamma som beräknas för hand.
Polstring och steg (det vanligaste fallet)
Nu kommer vi att tillämpa en stegvis upplösning på vårt tidigare beskrivna vadderade exempel och beräkna upplösningen där p = 1, s = 2
Tidigare när vi använde strides = 1
flyttades vårt skjutfönster med 1 position, med strides = s
flyttar det sig efter s
positioner (du måste beräkna s^2
element mindre. Men i vårt fall kan vi ta en genväg och inte utföra några beräkningar alls. Eftersom vi redan beräknar värdena för s = 1
, i vårt fall kan vi bara ta tag i varje andra element.
Så om lösningen är fallet med s = 1
var
vid s = 2
kommer det att vara:
Kontrollera värdena 14, 2, 12, 6 i den föregående matrisen. Den enda förändringen vi behöver utföra i vår kod är att ändra steg från 1 till 2 för bredd och höjdimension (2-nd, 3-rd).
res = tf.squeeze(tf.nn.conv2d(image, kernel, [1, 2, 2, 1], "SAME"))
with tf.Session() as sess:
print sess.run(res)
Förresten, det finns inget som hindrar oss från att använda olika steg för olika dimensioner.