keras 如何将图层输出用作后续图层的参数

0sgqnhkj  于 2022-11-13  发布在  其他
关注(0)|答案(2)|浏览(191)

我需要添加一个Cropping2D层,其中左和右裁剪参数由之前层的输出动态确定。也就是说,left_crop和right_crop参数在编码时是未知的。但是,我似乎无法访问模型中之前Tensor的值。下面是我的代码:

  1. input1 = Input(name='dirty', shape=(IMG_HEIGHT, None, 1), dtype='float32')
  2. input2 = Input(name='x0', shape=(), dtype='int32')
  3. input3 = Input(name='x1', shape=(), dtype='int32')
  4. # Encoder
  5. conv1 = Conv2D(48, kernel_size=(3, 3), activation='relu', padding='same', name='conv1')(input1)
  6. pool1 = MaxPooling2D(pool_size=(2, 2), strides=(2, 2), name='pool1')(conv1)
  7. conv2 = Conv2D(64, kernel_size=(3, 3), activation='relu', padding='same', name='conv2')(pool1)
  8. # Decoder
  9. deconv2 = Conv2DTranspose(48, kernel_size=(3, 3), activation='relu', padding='same', name='deconv2')(conv2)
  10. depool1 = UpSampling2D(size=(2, 2), name='depool1')(deconv2)
  11. output1 = Conv2DTranspose(1, kernel_size=(3, 3), activation='relu', padding='same', name='clean')(depool1)
  12. _, _, width, _ = K.int_shape(output1)
  13. left = K.eval(input2)
  14. right = width - K.eval(input3)
  15. output2 = Cropping2D(name='clean_snippet', cropping=((0, 0), (left, right)))(output1)

这会产生下列错误:

  1. Traceback (most recent call last):
  2. File "test.py", line 81, in <module>
  3. left = K.eval(input2)
  4. File "/Users/garnet/Library/Python/3.8/lib/python/site-packages/keras/backend.py", line 1632, in eval
  5. return get_value(to_dense(x))
  6. File "/Users/garnet/Library/Python/3.8/lib/python/site-packages/keras/backend.py", line 4208, in get_value
  7. return x.numpy()
  8. AttributeError: 'KerasTensor' object has no attribute 'numpy'

我在Keras 2.10.0中使用TF 2.10.0。我在启用和不启用急切模式的情况下都试过了。我的问题是关于我上面代码中“HERE'S THE AREA IN QUESTION...”注解后面的四行。我如何访问以前的图层值,并将它们用作Cropping2D()的 * 参数 *(而不是输入图层)。有什么想法吗?
以下是我的完整代码:

  1. import tensorflow as tf
  2. import cv2
  3. import random
  4. import os
  5. import numpy as np
  6. from tensorflow.keras import backend as K
  7. from tensorflow.keras.models import Model
  8. from tensorflow.keras.optimizers import SGD
  9. from tensorflow.keras.layers import Conv2D, Conv2DTranspose, MaxPooling2D, Cropping2D, UpSampling2D, Input
  10. from tensorflow.keras import losses
  11. SNIPPET_WIDTH = 40
  12. IMG_HEIGHT = 60
  13. def get_data(paths):
  14. for path in paths:
  15. clean = cv2.imread(path.decode('utf-8'), cv2.IMREAD_GRAYSCALE)
  16. h, w = clean.shape
  17. dirty = cv2.blur(clean, (random.randint(1, 5), random.randint(1, 5)))
  18. x0 = random.randint(0, w - SNIPPET_WIDTH)
  19. x1 = x0 + SNIPPET_WIDTH
  20. y0 = 0
  21. y1 = h - 1
  22. clean_snippet = clean[y0:y1, x0:x1]
  23. dirty[y0:y1, x0:x1] = 0 # masked out region
  24. dirty = (256. - dirty.astype(np.float32)) / 255.
  25. dirty = tf.convert_to_tensor(np.expand_dims(dirty, axis=2))
  26. x0 = tf.convert_to_tensor(x0)
  27. x1 = tf.convert_to_tensor(x1)
  28. clean = (256. - clean.astype(np.float32)) / 255.
  29. clean = tf.convert_to_tensor(np.expand_dims(clean, axis=2))
  30. clean_snippet = (256. - clean_snippet.astype(np.float32)) / 255.
  31. clean_snippet = tf.convert_to_tensor(np.expand_dims(clean_snippet, axis=2))
  32. yield {'dirty': dirty, 'x0': x0, 'x1': x1}, {'clean': clean, 'clean_snippet': clean_snippet}
  33. train_directory = 'data/training/'
  34. files = os.listdir(train_directory)
  35. paths = []
  36. for f in files:
  37. filename = os.fsdecode(f)
  38. paths.append(train_directory + filename)
  39. train_ds = tf.data.Dataset.from_generator(get_data, args=[paths], output_signature=(
  40. {
  41. 'dirty': tf.TensorSpec(shape=(IMG_HEIGHT, None, 1), dtype=tf.float32),
  42. 'x0': tf.TensorSpec(shape=(), dtype=tf.int32),
  43. 'x1': tf.TensorSpec(shape=(), dtype=tf.int32)
  44. },
  45. {
  46. 'clean': tf.TensorSpec(shape=(IMG_HEIGHT, None, 1), dtype=tf.float32),
  47. 'clean_snippet': tf.TensorSpec(shape=(IMG_HEIGHT, None, 1), dtype=tf.float32)
  48. }
  49. ))
  50. bucket_sizes = [400, 500, 600, 700, 800]
  51. bucket_batch_sizes = [16, 16, 16, 16, 16, 16]
  52. train_ds = train_ds.bucket_by_sequence_length(element_length_func=lambda x, y: tf.shape(y['clean'])[1],
  53. bucket_boundaries=bucket_sizes, bucket_batch_sizes=bucket_batch_sizes)
  54. input1 = Input(name='dirty', shape=(IMG_HEIGHT, None, 1), dtype='float32')
  55. input2 = Input(name='x0', shape=(), dtype='int32')
  56. input3 = Input(name='x1', shape=(), dtype='int32')
  57. # Encoder
  58. conv1 = Conv2D(48, kernel_size=(3, 3), activation='relu', padding='same', name='conv1')(input1)
  59. pool1 = MaxPooling2D(pool_size=(2, 2), strides=(2, 2), name='pool1')(conv1)
  60. conv2 = Conv2D(64, kernel_size=(3, 3), activation='relu', padding='same', name='conv2')(pool1)
  61. # Decoder
  62. deconv2 = Conv2DTranspose(48, kernel_size=(3, 3), activation='relu', padding='same', name='deconv2')(conv2)
  63. depool1 = UpSampling2D(size=(2, 2), name='depool1')(deconv2)
  64. output1 = Conv2DTranspose(1, kernel_size=(3, 3), activation='relu', padding='same', name='clean')(depool1)
  65. # HERE'S THE AREA IN QUESTION...
  66. _, _, width, _ = K.int_shape(output1)
  67. left = K.eval(input2)
  68. right = width - K.eval(input3)
  69. output2 = Cropping2D(name='clean_snippet', cropping=((0, 0), (left, right)))(output1)
  70. # ...END AREA IN QUESTION
  71. model = Model(inputs=[input1, input2, input3], outputs=[output1, output2])
  72. optimizer = SGD(lr=0.02, decay=1e-6, momentum=0.9, nesterov=True, clipnorm=5)
  73. loss_fcns = {'clean': losses.MeanAbsoluteError(), 'clean_snippet': losses.MeanAbsoluteError()}
  74. model.compile(loss=losses.MeanAbsoluteError(), optimizer=optimizer, metrics=['acc'])
  75. model.fit(x=train_ds, y=None, epochs=1000, shuffle=True, verbose=1)
ajsxfq5m

ajsxfq5m1#

以下是受@药香点评启发的工作方案:

  1. import tensorflow as tf
  2. import cv2
  3. import random
  4. import os
  5. import numpy as np
  6. from tensorflow.keras.models import Model
  7. from tensorflow.keras.optimizers import SGD
  8. from tensorflow.keras.layers import Conv2D, Conv2DTranspose, MaxPooling2D, Cropping2D, UpSampling2D, Input, Multiply
  9. from tensorflow.keras import losses
  10. SNIPPET_WIDTH = 40
  11. IMG_HEIGHT = 60
  12. def normalize(img):
  13. return np.expand_dims((256. - img.astype(np.float32)) / 255., axis=2)
  14. def get_data(paths):
  15. for path in paths:
  16. clean = cv2.imread(path.decode('utf-8'), cv2.IMREAD_GRAYSCALE)
  17. h, w = clean.shape
  18. dirty = cv2.blur(clean, (random.randint(1, 5), random.randint(1, 5)))
  19. x0 = random.randint(0, w - SNIPPET_WIDTH)
  20. x1 = x0 + SNIPPET_WIDTH
  21. y0 = 0
  22. y1 = h - 1
  23. dirty[y0:y1, x0:x1] = 0 # masked out region
  24. dirty = normalize(dirty)
  25. clean = normalize(clean)
  26. mask = np.zeros((h, w, 1), dtype=np.float32)
  27. mask[:, x0:x1, :] = 1.0
  28. clean_snippet = clean * mask
  29. clean = tf.convert_to_tensor(clean)
  30. dirty = tf.convert_to_tensor(dirty)
  31. mask = tf.convert_to_tensor(mask)
  32. clean_snippet = tf.convert_to_tensor(clean_snippet)
  33. yield {'dirty': dirty, 'mask': mask}, {'clean': clean, 'clean_snippet': clean_snippet}
  34. train_directory = 'data/training/'
  35. files = os.listdir(train_directory)
  36. paths = []
  37. for f in files:
  38. filename = os.fsdecode(f)
  39. paths.append(train_directory + filename)
  40. train_ds = tf.data.Dataset.from_generator(get_data, args=[paths], output_signature=(
  41. {
  42. 'dirty': tf.TensorSpec(shape=(IMG_HEIGHT, None, 1), dtype=tf.float32),
  43. 'mask': tf.TensorSpec(shape=(IMG_HEIGHT, None, 1), dtype=tf.float32)
  44. },
  45. {
  46. 'clean': tf.TensorSpec(shape=(IMG_HEIGHT, None, 1), dtype=tf.float32),
  47. 'clean_snippet': tf.TensorSpec(shape=(IMG_HEIGHT, None, 1), dtype=tf.float32)
  48. }
  49. ))
  50. bucket_sizes = [400, 500, 600, 700, 800]
  51. bucket_batch_sizes = [16, 16, 16, 16, 16, 16]
  52. train_ds = train_ds.bucket_by_sequence_length(element_length_func=lambda x, y: tf.shape(y['clean'])[1],
  53. bucket_boundaries=bucket_sizes, bucket_batch_sizes=bucket_batch_sizes)
  54. input1 = Input(name='dirty', shape=(IMG_HEIGHT, None, 1), dtype='float32')
  55. input2 = Input(name='mask', shape=(IMG_HEIGHT, None, 1), dtype='float32')
  56. # Encoder
  57. conv1 = Conv2D(48, kernel_size=(3, 3), activation='relu', padding='same', name='conv1')(input1)
  58. pool1 = MaxPooling2D(pool_size=(2, 2), strides=(2, 2), name='pool1')(conv1)
  59. conv2 = Conv2D(64, kernel_size=(3, 3), activation='relu', padding='same', name='conv2')(pool1)
  60. # Decoder
  61. deconv2 = Conv2DTranspose(48, kernel_size=(3, 3), activation='relu', padding='same', name='deconv2')(conv2)
  62. depool1 = UpSampling2D(size=(2, 2), name='depool1')(deconv2)
  63. output1 = Conv2DTranspose(1, kernel_size=(3, 3), activation='relu', padding='same', name='clean')(depool1)
  64. output2 = Multiply(name='clean_snippet')([output1, input2])
  65. model = Model(inputs=[input1, input2], outputs=[output1, output2])
  66. optimizer = SGD(lr=0.02, decay=1e-6, momentum=0.9, nesterov=True, clipnorm=5)
  67. loss_fcns = {'clean': losses.MeanAbsoluteError(), 'clean_snippet': losses.MeanAbsoluteError()}
  68. model.compile(loss=loss_fcns, optimizer=optimizer, metrics=['acc'])
  69. model.fit(x=train_ds, y=None, epochs=1000, shuffle=True, verbose=1)
展开查看全部
oaxa6hgo

oaxa6hgo2#

这是一个典型的bug,它会在图形模式下弹出。当你运行这段代码时,它并没有真正运行代码,但Tensorflow会对python代码进行自检,并将其编译成一个在GPU上运行良好的图形。有些你认为你可以在Python中完成的事情,在编译后你就无法完成了。
在这种情况下,Tensor形状必须在执行过程中固定,因此在训练过程中不能具有动态输出形状。
我不会在模型中裁剪,而是将你要裁剪的像素清零;在训练图像的数据集中,不会动态调整图像大小,而是动态调整,然后补零,以匹配图像大小(和异常位置)。地面真实值中的零像素和硬编码零的MAE将为零。
然后删除k. eval。你不再需要它了--你可以直接用tf ops用input 2和input 3构建掩码。注意tf ops需要整个批处理,不像Keras层,你不能循环,所以你需要矢量化。你可以用tf.sequence_mask来完成。

相关问题