【问题标题】:Failed to convert a NumPy array to a Tensor (Unsupported object type numpy.ndarray) on ImageDataGenerator in Keras无法在 Keras 的 ImageDataGenerator 上将 NumPy 数组转换为张量(不支持的对象类型 numpy.ndarray)
【发布时间】:2021-09-20 01:09:57
【问题描述】:

我在 Keras 中有以下简单的图像数据生成器:

 import tensorflow as tf
 import numpy as np
 import cv2

 class My_Custom_Generator(tf.keras.utils.Sequence) :

 def __init__(self, image_filenames, labels, batch_size) :
     self.image_filenames = image_filenames
     self.labels = labels
     self.batch_size = batch_size  

 def __len__(self) :
    return (np.ceil(len(self.image_filenames) / float(self.batch_size))).astype(np.int)


def __getitem__(self, idx) :
    batch_x = self.image_filenames[idx * self.batch_size : (idx+1) * self.batch_size]
    batch_y = self.labels[idx * self.batch_size : (idx+1) * self.batch_size]

   
    return np.array([
        cv2.imread(file_name).astype(np.int)
           for file_name in batch_x])/255.0, np.array(batch_y) 

很简单,我给它一个图像名称和标签列表,它所做的只是返回由cv2 读取的图像,以及我定义的用于使用 GPU 的批次中的标签。

我的问题是我怎么称呼它,这让我很头疼。

from sklearn.model_selection import GridSearchCV 
from statistics import mode
from sklearn.metrics import roc_auc_score, average_precision_score, accuracy_score, f1_score, precision_score, recall_score
import pickle
from sklearn.metrics import plot_confusion_matrix
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from tensorflow.keras.applications import Xception
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Activation, Flatten
from tensorflow.keras.callbacks import ModelCheckpoint, ReduceLROnPlateau, EarlyStopping
from tensorflow.keras.layers import Conv2D, MaxPooling2D
from tensorflow.keras.utils import to_categorical
import tensorflow as tf
from tensorflow.keras.layers import Input
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adamax
from tensorflow.keras.models import model_from_json
from mycustomgenerator import My_Custom_Generator
from sklearn.utils import shuffle

#This function returns me a vector of labels according to a list of image names
def return_classes_by_name(image_path):

    class_image_vector=[]

    for i in range(0,image_path.shape[0]):
        image_name=image_path[i]
    
        if("RAW_" in image_name):
            class_image_vector.append(0)
        if("GAN_" in image_name):
            class_image_vector.append(1)
     return np.array(class_image_vector)

#So, the rest of the code is where my nightmare is

#Load all names first
print("Loading dataset names")
filenames=np.genfromtxt("dataset_printscan.csv", dtype=str)

print("getting classes (labels) from names")
y=return_classes_by_name(filenames)
   
print("Organizing intro training, validation and testing")
#Before split, we shuffle
filenames_shuffled, y_shuffled = shuffle(filenames, y)   
    
#Now we have the files names of train, test and validation
x_train, x_test, y_train, y_test = train_test_split(filenames_shuffled, y_shuffled, test_size=0.5, random_state=42)

x_train,x_validation,y_train,y_validation=train_test_split(x_train, y_train, test_size=0.3, random_state=42)

num_classes=2    
#For now, I just want to train the network, no test
y_train = to_categorical(y_train, num_classes)
y_validation = to_categorical(y_validation, num_classes)
            
print("Setting up the network")
#Parameters for network training
batch_size = 16
epochs=10

#calling the generator
#pleae be aware that x_train and x_validation are image paths that should be read by the generator in batches and send to the gpu    
my_training_batch_generator = My_Custom_Generator(x_train, y_train, batch_size)
my_validation_batch_generator = My_Custom_Generator(x_validation, y_validation, batch_size)

adamax = Adamax(lr=0.01)

weights_file="weights/mymodel.h5"

#An approach to learning rate reducing through training
lr_reducer= ReduceLROnPlateau(monitor='val_loss', factor=np.sqrt(0.1), cooldown=0, patience=2, min_lr=0.5e-6)

#An approach to stop training before the whole epochs are processed
early_stopper=EarlyStopping(monitor='val_accuracy', min_delta=0.01,patience=3,restore_best_weights=True,verbose=1)

#Policy to save weights
model_checkpoint= ModelCheckpoint(weights_file, monitor="val_accuracy", save_best_only=True, save_weights_only=True,mode='auto')
#callbacks
callbacks=[lr_reducer,early_stopper,model_checkpoint]

print("Compiling the network")
#Load model and prepare it for fine tuning
baseModel = Xception(weights=None, include_top=False, input_tensor=Input(shape=(299, 299, 3)))
            
headModel = baseModel.output
headModel = Flatten(name="flatten")(headModel)
headModel = Dense(512, activation="relu")(headModel)
headModel = Dropout(0.5)(headModel)
headModel = Dense(num_classes, activation="softmax")(headModel)
    
# place the head FC model on top of the base model (this will become
# the actual model we will train)
model = Model(inputs=baseModel.input, outputs=headModel)
        
model.compile(loss="binary_crossentropy", optimizer=adam, metrics=["accuracy"])
print("[INFO] training...")
    
#Here is my problem

H=model.fit(my_training_batch_generator, steps_per_epoch = int(x_train.shape[0] // batch_size), validation_data = my_validation_batch_generator, validation_steps = int(x_validation.shape[0] // batch_size), callbacks=callbacks, epochs=epochs)

最大的问题是生成器已经应该读取批量大小(16 张图像),读取它们,然后返回 GPU,但这是我得到的:

File "xception.py", line 150, in <module>
    H=model.fit(my_training_batch_generator, steps_per_epoch = int(x_train.shape[0] // batch_size), validation_data = my_validation_batch_generator, validation_steps = int(x_validation.shape[0] // batch_size), callbacks=callbacks, epochs=epochs)
  File "/home/anselmo/.local/lib/python3.8/site-packages/tensorflow/python/keras/engine/training.py", line 108, in _method_wrapper
    return method(self, *args, **kwargs)
  File "/home/anselmo/.local/lib/python3.8/site-packages/tensorflow/python/keras/engine/training.py", line 1049, in fit
    data_handler = data_adapter.DataHandler(
  File "/home/anselmo/.local/lib/python3.8/site-packages/tensorflow/python/keras/engine/data_adapter.py", line 1105, in __init__
    self._adapter = adapter_cls(
  File "/home/anselmo/.local/lib/python3.8/site-packages/tensorflow/python/keras/engine/data_adapter.py", line 909, in __init__
    super(KerasSequenceAdapter, self).__init__(
  File "/home/anselmo/.local/lib/python3.8/site-packages/tensorflow/python/keras/engine/data_adapter.py", line 788, in __init__
    peek = _process_tensorlike(peek)
  File "/home/anselmo/.local/lib/python3.8/site-packages/tensorflow/python/keras/engine/data_adapter.py", line 1021, in _process_tensorlike
    inputs = nest.map_structure(_convert_numpy_and_scipy, inputs)
  File "/home/anselmo/.local/lib/python3.8/site-packages/tensorflow/python/util/nest.py", line 635, in map_structure
    structure[0], [func(*x) for x in entries],
  File "/home/anselmo/.local/lib/python3.8/site-packages/tensorflow/python/util/nest.py", line 635, in <listcomp>
    structure[0], [func(*x) for x in entries],
  File "/home/anselmo/.local/lib/python3.8/site-packages/tensorflow/python/keras/engine/data_adapter.py", line 1016, in _convert_numpy_and_scipy
    return ops.convert_to_tensor(x, dtype=dtype)
  File "/home/anselmo/.local/lib/python3.8/site-packages/tensorflow/python/framework/ops.py", line 1499, in convert_to_tensor
    ret = conversion_func(value, dtype=dtype, name=name, as_ref=as_ref)
  File "/home/anselmo/.local/lib/python3.8/site-packages/tensorflow/python/framework/tensor_conversion_registry.py", line 52, in _default_conversion_function
    return constant_op.constant(value, dtype, name=name)
  File "/home/anselmo/.local/lib/python3.8/site-packages/tensorflow/python/framework/constant_op.py", line 263, in constant
    return _constant_impl(value, dtype, shape, name, verify_shape=False,
  File "/home/anselmo/.local/lib/python3.8/site-packages/tensorflow/python/framework/constant_op.py", line 275, in _constant_impl
    return _constant_eager_impl(ctx, value, dtype, shape, verify_shape)
  File "/home/anselmo/.local/lib/python3.8/site-packages/tensorflow/python/framework/constant_op.py", line 300, in _constant_eager_impl
    t = convert_to_eager_tensor(value, ctx, dtype)
  File "/home/anselmo/.local/lib/python3.8/site-packages/tensorflow/python/framework/constant_op.py", line 98, in convert_to_eager_tensor
    return ops.EagerTensor(value, ctx.device_name, dtype)
ValueError: Failed to convert a NumPy array to a Tensor (Unsupported object type numpy.ndarray).

我的错误是什么?

【问题讨论】:

  • 这个文件My_Custom_Generator有什么内容?可能您应该在生成器中将数据转换为 float32,如下所示:x_train=np.array(x_train).astype(np.float32)
  • 确保您尝试转换为Tensor(或传递给tensor 函数)的数组(或列表)是数字dtype。如果源是多个形状不同的数组,则该数组将是 object dtype(并且可能是 1d)。

标签: python python-3.x numpy tensorflow keras


【解决方案1】:

我已成功重现错误。

My_Custom_Generator.__getitem__ 中的np.array([cv2.imread(file_name).astype(np.int) for file_name in batch_x]) 行没有创建多维数组,而是创建了一个带有dtype=np.object 的数组时,就会出现错误,这只是一个数组列表。

当列表中数组的形状(即图像的形状)不相同时会发生这种情况,如下例所示。

np.array([np.zeros((4, 4, 3)), np.zeros((5, 5, 3))])
>>> array([array([[[0., 0., 0.], ..., [0., 0., 0.]]]),
           array([[[0., 0., 0.], ..., [0., 0., 0.]]])], dtype=object)

运行示例中的代码,可以看到以下弃用警告:VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences(这是一个列表或元组的列表或元组或具有不同长度的 ndarray 或形状)已弃用。如果您打算这样做,则必须在创建 ndarray 时指定“dtype=object”。 np.array([np.zeros((4, 4, 3)), np.zeros((5, 5, 3))]).

一般来说,通过函数np.array将数组堆叠在一个列表中并不是一个好习惯,建议使用np.stack,它可以提前捕获此类错误。

np.array([cv2.imread(file_name).astype(np.int) for file_name in batch_x]) 替换为np.stack([cv2.imread(file_name).astype(np.int) for file_name in batch_x], axis=0),您应该会看到更有意义的错误堆栈跟踪。

总而言之,要解决问题,您应该检查图像的形状以找到破坏代码的图像。

【讨论】:

    猜你喜欢
    • 2020-07-05
    • 2021-04-25
    • 2022-01-10
    • 1970-01-01
    • 1970-01-01
    • 2020-10-15
    • 2021-04-18
    • 2021-10-11
    • 2020-11-22
    相关资源
    最近更新 更多