web-dev-qa-db-ja.com

さまざまなサイズの画像を使用したTensorflow畳み込みニューラルネットワーク

画像内の個々のピクセルを分類できるディープCNNを作成しようとしています。 this 紙から取った下の画像からアーキテクチャを複製しています。この論文では、任意のサイズの入力が可能になるようにデコンボリューションが使用されると述べられています。これは下の画像で見ることができます。

Githubリポジトリ

enter image description here

現在、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
10
Devin Haslam

動的プレースホルダー

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