【问题标题】:Invalid argument error tensorflow dataset无效参数错误张量流数据集
【发布时间】:2023-04-02 00:58:02
【问题描述】:

我正在尝试创建一个模型,该模型拍摄两张图像(一张紧接着一张)并对其进行训练,以便它可以预测相机在两张图像之间移动了多少。我使用一个较小的模型,一次处理一张图像,然后将两个输出连接到一个较大的模型中。

我尝试对其进行测试,模型编译得很好,但是当我调用 fit() 时它崩溃并给我一个无效的参数错误。

Epoch 1/5
2021-10-11 11:41:23.993854: I tensorflow/compiler/mlir/mlir_graph_optimization_pass.cc:185] None of the MLIR Optimization Passes are enabled (registered 2)
2021-10-11 11:41:28.606390: I tensorflow/stream_executor/cuda/cuda_dnn.cc:369] Loaded cuDNN version 8200
      7/Unknown - 18s 81ms/step - loss: 63.80682021-10-11 11:41:41.279014: W tensorflow/core/framework/op_kernel.cc:1692] OP_REQUIRES failed at transpose_op.cc:143 : Invalid argument: transpose expects a vector of size 3. But input(1) is a vector of size 4
2021-10-11 11:41:41.279317: W tensorflow/core/framework/op_kernel.cc:1692] OP_REQUIRES failed at transpose_op.cc:143 : Invalid argument: transpose expects a vector of size 3. But input(1) is a vector of size 4
Traceback (most recent call last):
  File "d:/.../Deep Sight/deep_sight.py", line 155, in <module>
    main()
  File "d:/.../Deep Sight/deep_sight.py", line 150, in main
    final_model.fit(train_data, epochs=5)
  File "C:\Users\...\AppData\Local\Programs\Python\Python37\lib\site-packages\keras\engine\training.py", line 1184, in fit
    tmp_logs = self.train_function(iterator)
  File "C:\Users\...\AppData\Local\Programs\Python\Python37\lib\site-packages\tensorflow\python\eager\def_function.py", line 885, in __call__
    result = self._call(*args, **kwds)
  File "C:\Users\...\AppData\Local\Programs\Python\Python37\lib\site-packages\tensorflow\python\eager\def_function.py", line 917, in _call
    return self._stateless_fn(*args, **kwds)  # pylint: disable=not-callable
  File "C:\Users\...\AppData\Local\Programs\Python\Python37\lib\site-packages\tensorflow\python\eager\function.py", line 3040, in __call__
    filtered_flat_args, captured_inputs=graph_function.captured_inputs)  # pylint: disable=protected-access
  File "C:\Users\...\AppData\Local\Programs\Python\Python37\lib\site-packages\tensorflow\python\eager\function.py", line 1964, in _call_flat
    ctx, args, cancellation_manager=cancellation_manager))
  File "C:\Users\...\AppData\Local\Programs\Python\Python37\lib\site-packages\tensorflow\python\eager\function.py", line 596, in call
    ctx=ctx)
  File "C:\Users\...\AppData\Local\Programs\Python\Python37\lib\site-packages\tensorflow\python\eager\execute.py", line 60, in quick_execute
    inputs, attrs, num_outputs)
tensorflow.python.framework.errors_impl.InvalidArgumentError: 2 root error(s) found.
  (0) Invalid argument:  transpose expects a vector of size 3. But input(1) is a vector of size 4
         [[{{node gradient_tape/model_1/model/conv2d/Conv2D/Conv2DBackpropFilter-0-TransposeNHWCToNCHW-LayoutOptimizer}}]]
         [[Func/mean_squared_error/cond/then/_0/input/_29/_48]]
  (1) Invalid argument:  transpose expects a vector of size 3. But input(1) is a vector of size 4
         [[{{node gradient_tape/model_1/model/conv2d/Conv2D/Conv2DBackpropFilter-0-TransposeNHWCToNCHW-LayoutOptimizer}}]]
0 successful operations.
0 derived errors ignored. [Op:__inference_train_function_3137]

Function call stack:
train_function -> train_function

按照我的数据集中的定义,我的批量大小是 32。我相信这与我使用 tf.Datasets 的方式有关。以前,我只是将所有数据加载到内存中,模型运行得很好。但是,因为我的数据集现在要大得多,所以我转而使用 tf.Datasets 来输入数据。这要求我将 2 张图像一起输入到一个张量中作为输入。它还需要我添加 tf.split 和挤压方法来分离模型内的图像。

train_data的形状是一个嵌套结构,如下: (批次:32,特征:[2, 128, 128, 3],标签:标量(两幅图像之间的垂直移动))

def load_data(image_files):
    image_file, image_file2 = bytes.decode(image_files.numpy()[0]), bytes.decode(image_files.numpy()[1])
    # Extract number of png file
    run_folder = image_file[:image_file.rfind('\\')][:-6]
    pic_number = int(image_file[image_file.rfind('\\')+1:image_file.find('.')])

    # Grab the y positions for the indicated pictures, then find their difference
    with open(run_folder+"\\yPos.txt", 'r') as yPosFile:
        for _ in range(pic_number):
            yPosFile.readline()
        oldY = float(yPosFile.readline())
        dY = float(yPosFile.readline()) - oldY

    # Load in the images from their file names, and strip the Alpha value from the RGBA values. It's always 255, so we don't need that extra data.
    image = imageio.imread(image_file)
    # Scale the RGB data down to between 0-1 so that the model has an easier time creating weights.
    return image[:, :, :-1]/255, imageio.imread(image_file2)[:, :, :-1]/255, dY


# Takes the list of output from the load_data function (which must be wrapped in tf.py_function)
# and outputs the data in the nested structure necessary for training, which the map function can process.
# Unfortunately, the py_function cannot output nested data structures, so we have to do a little wrapping here.
def load_data_wrapper(image_files):
    image, image2, dY = tf.py_function(load_data, [image_files], [tf.float32, tf.float32, tf.float32])
    return ([image, image2], dY)


# Takes dataset like [0, 1, 2, 3, 4]
# and converts it to: [[0,1],[1,2],[2,3],[3,4]]
def prep_dataset(dtst):
    # First repeat individual elements, then print those repeated elements after each other
    dtst = dtst.interleave(lambda x: tf.data.Dataset.from_tensors(x).repeat(2), cycle_length=2, block_length=2)
    # Skip the first element so that numbers are paired with the next greatest in the sequence with the batch function. 
    return dtst.skip(1).batch(2, drop_remainder=True) #.take_while(lambda x: tf.squeeze(tf.greater(tf.shape(x), 1)))


def tf_load_data():
    runs = os.listdir("Data")
    image_datasets = None

    for run in runs:
        image_dataset = tf.data.Dataset.list_files("Data/"+run+"/photos/?.png", shuffle=False).apply(prep_dataset)
        image_dataset = image_dataset.map(load_data_wrapper, num_parallel_calls=tf.data.experimental.AUTOTUNE)
        if image_datasets == None:
            image_datasets = image_dataset
        else:
            image_datasets = image_datasets.concatenate(image_dataset)

    #print(image_datasets)

    image_datasets = image_datasets.shuffle(buffer_size=int(599*25/32)).batch(32)

    # for data in image_datasets.take(1):
    #     print(data)

    return image_datasets


def main():
    # Create model

    # Start with smaller model that processes the two images in the same way.
    single_image_input = keras.Input(shape=(128,128,3))

    image = layers.Conv2D(64, (3,3))(single_image_input)
    image = layers.LeakyReLU()(image)
    image = layers.BatchNormalization()(image)
    # Run through MaxPool2D to help the algorithm identify features in different areas of the image.
    # Has the effect of downsampling and cutting the dimensions in half.
    image = layers.MaxPool2D()(image)

    image = layers.Conv2D(128, (3, 3))(image)
    image = layers.LeakyReLU()(image)
    image = layers.BatchNormalization()(image)
    image = layers.Dropout(.3)(image)

    image_model = keras.Model(single_image_input, image)
    
    # Create larger model
    image_inputs = keras.Input(shape=(2,128,128,3))

    first_image, second_image = tf.split(image_inputs, num_or_size_splits=2, axis=1)
    first_image, second_image = tf.squeeze(first_image), tf.squeeze(second_image)

    image_outputs = [image_model(first_image), image_model(second_image)]
    model = layers.Concatenate()(image_outputs)

    model = layers.Flatten()(model)

    model = layers.Dense(128)(model)
    model = layers.LeakyReLU()(model)
    model = layers.BatchNormalization()(model)
    model = layers.Dropout(.3)(model)

    # Output is change in y-position of drone
    out_layer = layers.Dense(1, activation='linear')(model)

    final_model = keras.Model(image_inputs, out_layer)
    final_model.compile(loss="mse", optimizer=optimizers.Adam(lr=0.0003, beta_1=0.7))

    image_model.summary()

    final_model.summary()


    #Preprocess data
    print("Loading and processing data...")
    train_data = tf_load_data()

    #Train model
    final_model.fit(train_data, epochs=5)



if __name__ == "__main__":
    main()
    #tf_load_data()

这是我的完整代码文件和我正在使用的数据示例,以防万一:Data

【问题讨论】:

  • 您需要为这两个图像创建两个Input 层。不要使用tf.squeezetf.split,因为它们不可区分。
  • 我确认完整模型在合成数据上运行良好,问题似乎出在数据集上。您能否分享数据或告诉我们在哪里可以找到它进行测试?
  • @ShubhamPanchal 我尝试使用两个Input 层而不是拆分,但是模型在完成编译之前抛出一个错误,说我只提供了一个输入张量。它似乎将我的数据集解释为一个形状为 (2, 128, 128, 3) 的张量,而不是两个形状为 (128, 128, 3) 的张量。
  • 对我之前评论的小修正。当我调用 fit() 期望 2 个输入但接收到一个时,它会出错。另外,我在帖子中提供了我的一些数据的链接。

标签: python tensorflow keras


【解决方案1】:

下面是使用 Keras 的 Sequence 类的代码。代码非常简单,并且可以正常工作。我知道 tf.datasets 更有吸引力,但是你在做复杂的操作。

class DataGenerator(tf.keras.utils.Sequence):
def __init__(self, datadir, batch_size=32, shuffle=True):
    # 'Initialization'
    self.datdir = datadir
    self.yposdir = datadir
    self.batch_size = batch_size
    self.shuffle = shuffle
    
    # read Y positions
    with open(os.path.join(datadir, 'yPos.txt'), 'r') as f:
        yData = [float(s) for s in f.readlines()]
    self.yData = np.array(yData)
    print(self.yData.shape)

    self.photofiles = glob.glob(os.path.join(datadir, 'photos', '*'))
    print(len(self.photofiles))
    # get image size
    image0 = np.array(imageio.imread(self.photofiles[0]))
    self.xsize, self.ysize, _ = image0.shape
    print(self.xsize)
    print(self.ysize)
    
    n_samples = len(self.photofiles)
    self.set_len = n_samples-1
    self.indexes = range(self.set_len)

    if self.shuffle == True:
        self.indexes = random.sample(range(self.set_len), k=self.set_len)
    
def __len__(self):
    return self.set_len//self.batch_size

def __getitem__(self, index):
    # Generate indexes of the batch
    indexes = self.indexes[index*self.batch_size:(index+1)*self.batch_size]
    
    ypos = np.zeros((self.batch_size,), dtype='float32')
    image_concat_pair_batch = np.zeros((self.batch_size, 2, self.xsize, self.ysize, 3), dtype='float32')
    
    for count, ind in enumerate(indexes):
        # get images
        curr_image = imageio.imread(self.photofiles[ind])
        next_image = imageio.imread(self.photofiles[ind+1])
        # get positions
        curr_ypos = self.yData[ind]
        new_ypos = self.yData[ind+1]
        # diff
        ypos[count] = new_ypos-curr_ypos
        # expand axis
        curr_image = np.array(curr_image)[np.newaxis, :, :, :-1]
        next_image = np.array(next_image)[np.newaxis, :, :, :-1]
        # concatenat image pairs
        image_concat = np.concatenate((curr_image, next_image), axis=0)/255.
        # store
        image_concat_pair_batch[count] = image_concat
    
    return tf.convert_to_tensor(image_concat_pair_batch, dtype=tf.dtypes.float32), tf.convert_to_tensor(ypos, dtype=tf.dtypes.float32)

def on_epoch_end(self):
    if self.shuffle == True:
        self.indexes = random.sample(range(self.set_len), k=self.set_len)

【讨论】:

  • 谢谢@elbe!我什至不知道 Keras 序列的存在!这对我需要的非常有用!我稍微修改了您提供的代码,因为我的数据比我提供的样本大,但现在可以了!
猜你喜欢
  • 2018-08-23
  • 2018-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-10
  • 2019-05-22
相关资源
最近更新 更多