画像内の個々のピクセルを分類できるディープCNNを作成しようとしています。 this 紙から取った下の画像からアーキテクチャを複製しています。この論文では、任意のサイズの入力が可能になるようにデコンボリューションが使用されると述べられています。これは下の画像で見ることができます。
現在、32x32x7のサイズの画像を受け入れるようにモデルをハードコーディングしていますが、任意のサイズの入力を受け入れたいと思います。 可変サイズの入力を受け入れるには、コードにどのような変更を加える必要がありますか?
x = tf.placeholder(tf.float32, shape=[None, 32*32*7])
y_ = tf.placeholder(tf.float32, shape=[None, 32*32*7, 3])
...
DeConnv1 = tf.nn.conv3d_transpose(layer1, filter = w, output_shape = [1,32,32,7,1], strides = [1,2,2,2,1], padding = 'SAME')
...
final = tf.reshape(final, [1, 32*32*7])
W_final = weight_variable([32*32*7,32*32*7,3])
b_final = bias_variable([32*32*7,3])
final_conv = tf.tensordot(final, W_final, axes=[[1], [1]]) + b_final
Tensorflowでは、プレースホルダーにmultiple動的(別名None
)ディメンションを含めることができます。グラフの作成中はエンジンが正確さを保証できないため、クライアントは正しい入力を提供する責任がありますが、多くの柔軟性を提供します。
だから私はから行きます...
x = tf.placeholder(tf.float32, shape=[None, N*M*P])
y_ = tf.placeholder(tf.float32, shape=[None, N*M*P, 3])
...
x_image = tf.reshape(x, [-1, N, M, P, 1])
に...
# Nearly all dimensions are dynamic
x_image = tf.placeholder(tf.float32, shape=[None, None, None, None, 1])
label = tf.placeholder(tf.float32, shape=[None, None, 3])
とにかく入力を5Dに再形成するつもりなので、最初からx_image
で5Dを使用しないのはなぜですか。この時点で、label
の2番目の次元は任意ですが、promise tensorflowは、x_image
と一致します。
次に、 tf.nn.conv3d_transpose
の良いところは、その出力形状を動的にできることです。したがって、これの代わりに:
# Hard-coded output shape
DeConnv1 = tf.nn.conv3d_transpose(layer1, w, output_shape=[1,32,32,7,1], ...)
... あなたはこれを行うことができます:
# Dynamic output shape
DeConnv1 = tf.nn.conv3d_transpose(layer1, w, output_shape=tf.shape(x_image), ...)
このようにして、転置畳み込みをany imageに適用でき、結果は実行時に実際に渡されたx_image
の形になります。
x_image
の静的形状は(?, ?, ?, ?, 1)
であることに注意してください。
パズルの最後の最も重要な部分は、ネットワーク全体を畳み込みにすることであり、これには最終的な高密度層も含まれます。高密度レイヤー必須その次元を静的に定義します。これにより、ニューラルネットワーク全体が入力画像の次元を修正します。
私たちにとって幸運なことに、Springenbergは、 "Striving for Simplicity:The All Convolutional Net" 紙でFC層をCONV層に置き換える方法を説明しています。 3つの1x1x1
フィルターを使用した畳み込みを使用します( この質問 も参照):
final_conv = conv3d_s1(final, weight_variable([1, 1, 1, 1, 3]))
y = tf.reshape(final_conv, [-1, 3])
final
の寸法がDeConnv1
(およびその他)と同じであることを確認すると、y
が希望の形になります:[-1, N * M * P, 3]
。
ネットワークはかなり大規模ですが、すべてのデコンボリューションは基本的に同じパターンに従うため、概念実証コードを1つのデコンボリューションに簡略化しました。目標は、どのようなネットワークが任意のサイズの画像を処理できるかを示すことです。最後の注意:画像のサイズはさまざまですbetweenバッチですが、1つのバッチ内では同じである必要があります。
完全なコード:
sess = tf.InteractiveSession()
def conv3d_dilation(tempX, tempFilter):
return tf.layers.conv3d(tempX, filters=tempFilter, kernel_size=[3, 3, 1], strides=1, padding='SAME', dilation_rate=2)
def conv3d(tempX, tempW):
return tf.nn.conv3d(tempX, tempW, strides=[1, 2, 2, 2, 1], padding='SAME')
def conv3d_s1(tempX, tempW):
return tf.nn.conv3d(tempX, tempW, strides=[1, 1, 1, 1, 1], padding='SAME')
def weight_variable(shape):
initial = tf.truncated_normal(shape, stddev=0.1)
return tf.Variable(initial)
def bias_variable(shape):
initial = tf.constant(0.1, shape=shape)
return tf.Variable(initial)
def max_pool_3x3(x):
return tf.nn.max_pool3d(x, ksize=[1, 3, 3, 3, 1], strides=[1, 2, 2, 2, 1], padding='SAME')
x_image = tf.placeholder(tf.float32, shape=[None, None, None, None, 1])
label = tf.placeholder(tf.float32, shape=[None, None, 3])
W_conv1 = weight_variable([3, 3, 1, 1, 32])
h_conv1 = conv3d(x_image, W_conv1)
# second convolution
W_conv2 = weight_variable([3, 3, 4, 32, 64])
h_conv2 = conv3d_s1(h_conv1, W_conv2)
# third convolution path 1
W_conv3_A = weight_variable([1, 1, 1, 64, 64])
h_conv3_A = conv3d_s1(h_conv2, W_conv3_A)
# third convolution path 2
W_conv3_B = weight_variable([1, 1, 1, 64, 64])
h_conv3_B = conv3d_s1(h_conv2, W_conv3_B)
# fourth convolution path 1
W_conv4_A = weight_variable([3, 3, 1, 64, 96])
h_conv4_A = conv3d_s1(h_conv3_A, W_conv4_A)
# fourth convolution path 2
W_conv4_B = weight_variable([1, 7, 1, 64, 64])
h_conv4_B = conv3d_s1(h_conv3_B, W_conv4_B)
# fifth convolution path 2
W_conv5_B = weight_variable([1, 7, 1, 64, 64])
h_conv5_B = conv3d_s1(h_conv4_B, W_conv5_B)
# sixth convolution path 2
W_conv6_B = weight_variable([3, 3, 1, 64, 96])
h_conv6_B = conv3d_s1(h_conv5_B, W_conv6_B)
# concatenation
layer1 = tf.concat([h_conv4_A, h_conv6_B], 4)
w = tf.Variable(tf.constant(1., shape=[2, 2, 4, 1, 192]))
DeConnv1 = tf.nn.conv3d_transpose(layer1, filter=w, output_shape=tf.shape(x_image), strides=[1, 2, 2, 2, 1], padding='SAME')
final = DeConnv1
final_conv = conv3d_s1(final, weight_variable([1, 1, 1, 1, 3]))
y = tf.reshape(final_conv, [-1, 3])
cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=label, logits=y))
print('x_image:', x_image)
print('DeConnv1:', DeConnv1)
print('final_conv:', final_conv)
def try_image(N, M, P, B=1):
batch_x = np.random.normal(size=[B, N, M, P, 1])
batch_y = np.ones([B, N * M * P, 3]) / 3.0
deconv_val, final_conv_val, loss = sess.run([DeConnv1, final_conv, cross_entropy],
feed_dict={x_image: batch_x, label: batch_y})
print(deconv_val.shape)
print(final_conv.shape)
print(loss)
print()
tf.global_variables_initializer().run()
try_image(32, 32, 7)
try_image(16, 16, 3)
try_image(16, 16, 3, 2)