AttributeError: 在使用自定义生成器的 Keras 模型上调用 fit 时,'tuple' 对象没有属性 'rank' [英] AttributeError: 'tuple' object has no attribute 'rank' when calling fit on a Keras model with custom generator

查看:25
本文介绍了AttributeError: 在使用自定义生成器的 Keras 模型上调用 fit 时,'tuple' 对象没有属性 'rank'的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想构建一个具有两个输入的神经网络:用于图像数据和数字数据.所以我为此编写了自定义数据生成器.trainvalidation 数据帧包含 11 列:

I want to build a Neural Network with two inputs: for image data and for numeric data. So I wrote custom data generator for that. The train and validation dataframes contain 11 columns:

  1. image_name — 图像的路径;
  2. 9 个数字特征;
  3. target — 项目的类(最后一列).
  1. image_name — path to the image;
  2. 9 numeric features;
  3. target — class for the item (last column).

自定义生成器的代码(基于这个答案):

The code for custom generator (based on this answer):

target_size = (224, 224)
batch_size = 1

train_datagen = ImageDataGenerator(
    rescale=1./255,
    rotation_range=20,
    width_shift_range=0.2,
    height_shift_range=0.2,
    horizontal_flip=True)

val_datagen = ImageDataGenerator(rescale=1./255)

train_generator = train_datagen.flow_from_dataframe(
    train,
    x_col='image_name',
    y_col=train.columns[1:],
    target_size=target_size,
    batch_size=batch_size,
    shuffle=True,
    class_mode='raw')

validation_generator = val_datagen.flow_from_dataframe(
    validation,
    x_col='image_name',
    y_col=validation.columns[1:],
    target_size=target_size,
    shuffle=False,
    batch_size=batch_size,
    class_mode='raw')

def train_generator_func():
    count = 0
    while True:
        if count == len(train.index):
            train_generator.reset()
            break
        count += 1
        data = train_generator.next()
        
        imgs = []
        cols = []
        targets = []
        
        for k in range(batch_size):
            imgs.append(data[0][k])
            cols.append(data[1][k][:-1])
            targets.append(data[1][k][-1])
            
        yield [imgs, cols], targets
        
def validation_generator_func():
    count = 0
    while True:
        if count == len(validation.index):
            validation_generator.reset()
            break
        count += 1
        data = validation_generator.next()
                
        imgs = []
        cols = []
        targets = []
        
        for k in range(batch_size):
            imgs.append(data[0][k])
            cols.append(data[1][k][:-1])
            targets.append(data[1][k][-1])
            
        yield [imgs, cols], targets

模型构建:

def mlp_model(dim):
    model = Sequential()
    model.add(Dense(8, input_dim=dim, activation="relu"))
    model.add(Dense(4, activation="relu"))
    return model


def vgg16_model():
    model = VGG16(weights='imagenet', include_top=False, input_shape=target_size+(3,))
    x=Flatten()(model.output)
    output=Dense(1,activation='sigmoid')(x) # because we have to predict the AUC
    model=Model(model.input,output)
    return model


def concatenated_model(cnn, mlp):
    combinedInput = concatenate([cnn.output, mlp.output])
    x = Dense(4, activation="relu")(combinedInput)
    x = Dense(1, activation="sigmoid")(x)    
    model = Model(inputs=[cnn.input, mlp.input], outputs=x)
    return model


def focal_loss(alpha=0.25,gamma=2.0):
    def focal_crossentropy(y_true, y_pred):
        bce = K.binary_crossentropy(y_true, y_pred)
        
        y_pred = K.clip(y_pred, K.epsilon(), 1.- K.epsilon())
        p_t = (y_true*y_pred) + ((1-y_true)*(1-y_pred))
        
        alpha_factor = 1
        modulating_factor = 1

        alpha_factor = y_true*alpha + ((1-alpha)*(1-y_true))
        modulating_factor = K.pow((1-p_t), gamma)

        # compute the final loss and return
        return K.mean(alpha_factor*modulating_factor*bce, axis=-1)
    return focal_crossentropy

cnn = vgg16_model()
mlp = mlp_model(9)

model = concatenated_model(cnn, mlp)

opt = Adam(lr=1e-5)
model.compile(loss=focal_loss(), metrics=[tf.keras.metrics.AUC()],optimizer=opt)

nb_epochs = 2
nb_train_steps = train.shape[0]//batch_size
nb_val_steps = validation.shape[0]//batch_size

model.fit(
    train_generator_func(),
    steps_per_epoch=nb_train_steps,
    epochs=nb_epochs,
    validation_data=validation_generator_func(),
    validation_steps=nb_val_steps)

并且拟合不适用于错误消息:

And fitting doesn't work with error message:

AttributeError                            Traceback (most recent call last)
<ipython-input-53-253849fd34d6> in <module>
      9     epochs=nb_epochs,
     10     validation_data=validation_generator_func(),
---> 11     validation_steps=nb_val_steps)

d:pyenvkeras-gpulibsite-packages	ensorflowpythonkerasengine	raining.py in _method_wrapper(self, *args, **kwargs)
    106   def _method_wrapper(self, *args, **kwargs):
    107     if not self._in_multi_worker_mode():  # pylint: disable=protected-access
--> 108       return method(self, *args, **kwargs)
    109 
    110     # Running inside `run_distribute_coordinator` already.

d:pyenvkeras-gpulibsite-packages	ensorflowpythonkerasengine	raining.py in fit(self, x, y, batch_size, epochs, verbose, callbacks, validation_split, validation_data, shuffle, class_weight, sample_weight, initial_epoch, steps_per_epoch, validation_steps, validation_batch_size, validation_freq, max_queue_size, workers, use_multiprocessing)
   1061           use_multiprocessing=use_multiprocessing,
   1062           model=self,
-> 1063           steps_per_execution=self._steps_per_execution)
   1064 
   1065       # Container that configures and calls `tf.keras.Callback`s.

d:pyenvkeras-gpulibsite-packages	ensorflowpythonkerasenginedata_adapter.py in __init__(self, x, y, sample_weight, batch_size, steps_per_epoch, initial_epoch, epochs, shuffle, class_weight, max_queue_size, workers, use_multiprocessing, model, steps_per_execution)
   1108         use_multiprocessing=use_multiprocessing,
   1109         distribution_strategy=ds_context.get_strategy(),
-> 1110         model=model)
   1111 
   1112     strategy = ds_context.get_strategy()

d:pyenvkeras-gpulibsite-packages	ensorflowpythonkerasenginedata_adapter.py in __init__(self, x, y, sample_weights, workers, use_multiprocessing, max_queue_size, model, **kwargs)
    796       return tensor_shape.TensorShape([None for _ in shape.as_list()])
    797 
--> 798     output_shapes = nest.map_structure(_get_dynamic_shape, peek)
    799     output_types = nest.map_structure(lambda t: t.dtype, peek)
    800 

d:pyenvkeras-gpulibsite-packages	ensorflowpythonutil
est.py in map_structure(func, *structure, **kwargs)
    633 
    634   return pack_sequence_as(
--> 635       structure[0], [func(*x) for x in entries],
    636       expand_composites=expand_composites)
    637 

d:pyenvkeras-gpulibsite-packages	ensorflowpythonutil
est.py in <listcomp>(.0)
    633 
    634   return pack_sequence_as(
--> 635       structure[0], [func(*x) for x in entries],
    636       expand_composites=expand_composites)
    637 

d:pyenvkeras-gpulibsite-packages	ensorflowpythonkerasenginedata_adapter.py in _get_dynamic_shape(t)
    792       shape = t.shape
    793       # Unknown number of dimensions, `as_list` cannot be called.
--> 794       if shape.rank is None:
    795         return shape
    796       return tensor_shape.TensorShape([None for _ in shape.as_list()])

AttributeError: 'tuple' object has no attribute 'rank'

所以我尝试查看 Keras 源代码,但没有成功.

So I tried to look at Keras sources but without any success.

如果我使用修改后的 train_generatorvalidation_generator(y_col='target' 而不是 y_col=train.columns[1:]) 一切正常.

If I use modified train_generator and validation_generator (y_col='target' instead of y_col=train.columns[1:]) everything works fine.

推荐答案

您需要将训练和验证生成器返回的所有单个对象转换为 Numpy 数组:

You need to convert all the individual objects returned by both the training and validation generators to Numpy arrays:

    yield [np.array(imgs), np.array(cols)], np.array(targets)

或者,一个更简单、更有效的解决方案是根本不迭代数据批次;相反,我们可以利用这些对象在 ImageDataGenerator 返回时已经是 Numpy 数组的事实,所以我们可以这样写:

Alternatively, a simpler and much more efficient solution is to not iterate over the data batch at all; instead, we can take advantage of the fact that these objects are already Numpy arrays when returned by ImageDataGenerator, so we can write:

    imgs = data[0]
    cols = data[1][:,:-1]
    targets = data[1][:,-1:]
    yield [imgs, cols], targets

这篇关于AttributeError: 在使用自定义生成器的 Keras 模型上调用 fit 时,'tuple' 对象没有属性 'rank'的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆