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

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

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

input1 = Input(name='dirty', shape=(IMG_HEIGHT, None, 1), dtype='float32')
input2 = Input(name='x0', shape=(), dtype='int32')
input3 = Input(name='x1', shape=(), dtype='int32')

# Encoder
conv1 = Conv2D(48, kernel_size=(3, 3), activation='relu', padding='same', name='conv1')(input1)
pool1 = MaxPooling2D(pool_size=(2, 2), strides=(2, 2), name='pool1')(conv1)
conv2 = Conv2D(64, kernel_size=(3, 3), activation='relu', padding='same', name='conv2')(pool1)

# Decoder
deconv2 = Conv2DTranspose(48, kernel_size=(3, 3), activation='relu', padding='same', name='deconv2')(conv2)
depool1 = UpSampling2D(size=(2, 2), name='depool1')(deconv2)
output1 = Conv2DTranspose(1, kernel_size=(3, 3), activation='relu', padding='same', name='clean')(depool1)

_, _, width, _ = K.int_shape(output1)
left = K.eval(input2)
right = width - K.eval(input3)
output2 = Cropping2D(name='clean_snippet', cropping=((0, 0), (left, right)))(output1)

这会产生下列错误:

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

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

import tensorflow as tf
import cv2
import random
import os
import numpy as np

from tensorflow.keras import backend as K

from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import SGD
from tensorflow.keras.layers import Conv2D, Conv2DTranspose, MaxPooling2D, Cropping2D, UpSampling2D, Input
from tensorflow.keras import losses

SNIPPET_WIDTH = 40
IMG_HEIGHT = 60

def get_data(paths):
    for path in paths:
        clean = cv2.imread(path.decode('utf-8'), cv2.IMREAD_GRAYSCALE)
        h, w = clean.shape
        dirty = cv2.blur(clean, (random.randint(1, 5), random.randint(1, 5)))
        x0 = random.randint(0, w - SNIPPET_WIDTH)
        x1 = x0 + SNIPPET_WIDTH
        y0 = 0
        y1 = h - 1
        clean_snippet = clean[y0:y1, x0:x1]
        dirty[y0:y1, x0:x1] = 0  # masked out region
        dirty = (256. - dirty.astype(np.float32)) / 255.
        dirty = tf.convert_to_tensor(np.expand_dims(dirty, axis=2))
        x0 = tf.convert_to_tensor(x0)
        x1 = tf.convert_to_tensor(x1)
        clean = (256. - clean.astype(np.float32)) / 255.
        clean = tf.convert_to_tensor(np.expand_dims(clean, axis=2))
        clean_snippet = (256. - clean_snippet.astype(np.float32)) / 255.
        clean_snippet = tf.convert_to_tensor(np.expand_dims(clean_snippet, axis=2))
        yield {'dirty': dirty, 'x0': x0, 'x1': x1}, {'clean': clean, 'clean_snippet': clean_snippet}

train_directory = 'data/training/'
files = os.listdir(train_directory)
paths = []
for f in files:
    filename = os.fsdecode(f)
    paths.append(train_directory + filename)

train_ds = tf.data.Dataset.from_generator(get_data, args=[paths], output_signature=(
    {
        'dirty': tf.TensorSpec(shape=(IMG_HEIGHT, None, 1), dtype=tf.float32),
        'x0': tf.TensorSpec(shape=(), dtype=tf.int32),
        'x1': tf.TensorSpec(shape=(), dtype=tf.int32)
    },
    {
        'clean': tf.TensorSpec(shape=(IMG_HEIGHT, None, 1), dtype=tf.float32),
        'clean_snippet': tf.TensorSpec(shape=(IMG_HEIGHT, None, 1), dtype=tf.float32)
    }
))

bucket_sizes = [400, 500, 600, 700, 800]
bucket_batch_sizes = [16, 16, 16, 16, 16, 16]

train_ds = train_ds.bucket_by_sequence_length(element_length_func=lambda x, y: tf.shape(y['clean'])[1],
                                              bucket_boundaries=bucket_sizes, bucket_batch_sizes=bucket_batch_sizes)

input1 = Input(name='dirty', shape=(IMG_HEIGHT, None, 1), dtype='float32')
input2 = Input(name='x0', shape=(), dtype='int32')
input3 = Input(name='x1', shape=(), dtype='int32')

# Encoder
conv1 = Conv2D(48, kernel_size=(3, 3), activation='relu', padding='same', name='conv1')(input1)
pool1 = MaxPooling2D(pool_size=(2, 2), strides=(2, 2), name='pool1')(conv1)
conv2 = Conv2D(64, kernel_size=(3, 3), activation='relu', padding='same', name='conv2')(pool1)

# Decoder
deconv2 = Conv2DTranspose(48, kernel_size=(3, 3), activation='relu', padding='same', name='deconv2')(conv2)
depool1 = UpSampling2D(size=(2, 2), name='depool1')(deconv2)
output1 = Conv2DTranspose(1, kernel_size=(3, 3), activation='relu', padding='same', name='clean')(depool1)

# HERE'S THE AREA IN QUESTION...
_, _, width, _ = K.int_shape(output1)
left = K.eval(input2)
right = width - K.eval(input3)
output2 = Cropping2D(name='clean_snippet', cropping=((0, 0), (left, right)))(output1)
# ...END AREA IN QUESTION

model = Model(inputs=[input1, input2, input3], outputs=[output1, output2])
optimizer = SGD(lr=0.02, decay=1e-6, momentum=0.9, nesterov=True, clipnorm=5)
loss_fcns = {'clean': losses.MeanAbsoluteError(), 'clean_snippet': losses.MeanAbsoluteError()}

model.compile(loss=losses.MeanAbsoluteError(), optimizer=optimizer, metrics=['acc'])
model.fit(x=train_ds, y=None, epochs=1000, shuffle=True, verbose=1)
ajsxfq5m

ajsxfq5m1#

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

import tensorflow as tf
import cv2
import random
import os
import numpy as np

from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import SGD
from tensorflow.keras.layers import Conv2D, Conv2DTranspose, MaxPooling2D, Cropping2D, UpSampling2D, Input, Multiply
from tensorflow.keras import losses

SNIPPET_WIDTH = 40
IMG_HEIGHT = 60

def normalize(img):
    return np.expand_dims((256. - img.astype(np.float32)) / 255., axis=2)

def get_data(paths):
    for path in paths:
        clean = cv2.imread(path.decode('utf-8'), cv2.IMREAD_GRAYSCALE)
        h, w = clean.shape
        dirty = cv2.blur(clean, (random.randint(1, 5), random.randint(1, 5)))
        x0 = random.randint(0, w - SNIPPET_WIDTH)
        x1 = x0 + SNIPPET_WIDTH
        y0 = 0
        y1 = h - 1
        dirty[y0:y1, x0:x1] = 0  # masked out region
        dirty = normalize(dirty)
        clean = normalize(clean)
        mask = np.zeros((h, w, 1), dtype=np.float32)
        mask[:, x0:x1, :] = 1.0
        clean_snippet = clean * mask
        clean = tf.convert_to_tensor(clean)
        dirty = tf.convert_to_tensor(dirty)
        mask = tf.convert_to_tensor(mask)
        clean_snippet = tf.convert_to_tensor(clean_snippet)

        yield {'dirty': dirty, 'mask': mask}, {'clean': clean, 'clean_snippet': clean_snippet}

train_directory = 'data/training/'
files = os.listdir(train_directory)
paths = []
for f in files:
    filename = os.fsdecode(f)
    paths.append(train_directory + filename)

train_ds = tf.data.Dataset.from_generator(get_data, args=[paths], output_signature=(
    {
        'dirty': tf.TensorSpec(shape=(IMG_HEIGHT, None, 1), dtype=tf.float32),
        'mask': tf.TensorSpec(shape=(IMG_HEIGHT, None, 1), dtype=tf.float32)
    },
    {
        'clean': tf.TensorSpec(shape=(IMG_HEIGHT, None, 1), dtype=tf.float32),
        'clean_snippet': tf.TensorSpec(shape=(IMG_HEIGHT, None, 1), dtype=tf.float32)
    }
))

bucket_sizes = [400, 500, 600, 700, 800]
bucket_batch_sizes = [16, 16, 16, 16, 16, 16]

train_ds = train_ds.bucket_by_sequence_length(element_length_func=lambda x, y: tf.shape(y['clean'])[1],
                                              bucket_boundaries=bucket_sizes, bucket_batch_sizes=bucket_batch_sizes)

input1 = Input(name='dirty', shape=(IMG_HEIGHT, None, 1), dtype='float32')
input2 = Input(name='mask', shape=(IMG_HEIGHT, None, 1), dtype='float32')

# Encoder
conv1 = Conv2D(48, kernel_size=(3, 3), activation='relu', padding='same', name='conv1')(input1)
pool1 = MaxPooling2D(pool_size=(2, 2), strides=(2, 2), name='pool1')(conv1)
conv2 = Conv2D(64, kernel_size=(3, 3), activation='relu', padding='same', name='conv2')(pool1)

# Decoder
deconv2 = Conv2DTranspose(48, kernel_size=(3, 3), activation='relu', padding='same', name='deconv2')(conv2)
depool1 = UpSampling2D(size=(2, 2), name='depool1')(deconv2)
output1 = Conv2DTranspose(1, kernel_size=(3, 3), activation='relu', padding='same', name='clean')(depool1)
output2 = Multiply(name='clean_snippet')([output1, input2])

model = Model(inputs=[input1, input2], outputs=[output1, output2])
optimizer = SGD(lr=0.02, decay=1e-6, momentum=0.9, nesterov=True, clipnorm=5)
loss_fcns = {'clean': losses.MeanAbsoluteError(), 'clean_snippet': losses.MeanAbsoluteError()}

model.compile(loss=loss_fcns, optimizer=optimizer, metrics=['acc'])
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来完成。

相关问题