“tuple”对象没有属性“rank”

问题描述 投票:0回答:1

这是一个 FabricNet 示例实现(官方代码)。正如研究论文中所述,输入图像尺寸为 120x120x3。我尝试了下面的代码,但它抛出错误“tuple”对象没有属性“rank”。这是输入形状的打印结果:第0层输入形状:(None, 8, 8, 728)。它显然是一个元组,但模型需要一个张量。同一问题的答案之一提到使用 tf.constant(res) 将其转换为 Numpy 数组。但它随后抛出错误;

A KerasTensor is symbolic; it's a placeholder for a shape or dtype. It doesn't have any actual numerical value. You cannot convert it to a NumPy array.
import cv2
import numpy as np
from sklearn.model_selection import train_test_split
import tensorflow as tf
from tensorflow.python.keras.layers import *
import matplotlib.pyplot as plt

def load_data_from_txt(txt_file, image_size=(120, 120)):
    image_paths = []
    labels = []
    
    with open(txt_file, 'r') as f:
        for line in f:
            path, label = line.strip().split(', ')
            image_paths.append(path)
            labels.append(int(label))
    
    images = []
    for path in image_paths:
        try:
            img = cv2.imread(path)
            if img is None:
                print(f"Warning: Unable to read image at {path}")
                continue
            img = cv2.resize(img, image_size)  # Resize to desired size
            images.append(img)
        except Exception as e:
            print(f"Error processing {path}: {e}")
            continue
    
    if len(images) == 0:
        raise ValueError("No images were loaded. Check the file paths.")
    
    images = np.array(images, dtype=np.float32) / 255.0  # Normalize images
    labels = np.array(labels[:len(images)])  # Ensure labels match the number of loaded images
    
    return images, labels

# Load data
x_data, y_data = load_data_from_txt('FISR.txt')
print(f"x_data shape: {x_data.shape}")

# Split data into training and testing sets
x_train, x_test, y_train, y_test = train_test_split(x_data, y_data, test_size=0.25, stratify=y_data)

# One-hot encode labels
num_classes = 7 

y_train = tf.one_hot(np.squeeze(y_train), depth=7).numpy()
y_test = tf.one_hot(np.squeeze(y_test), depth=7).numpy()

def parser(tok, id, cls):
    ''' 
    SepConv: S,f,k,s
    MaxPool: P,s
    ReLU   : R
    Dropout: D
    '''
    print(f"Parsing token: {tok}")
 
    if tok[0] == 'S':
        filters, ks, stride = list(map(int, tok[1:].split(',')))
        print(f"Creating SeparableConv2D with filters={filters}, kernel_size={ks}, strides={stride}")

        return SeparableConv2D(filters=filters, kernel_size=ks, strides=stride, padding='same', name=f'sepconv2d_d{id}_c{cls}')
    
    elif tok[0] == 'P':
        print(f"Creating MaxPool2D with pool_size={int(tok[1:])}")
        return MaxPool2D(pool_size=int(tok[1:]), name=f'MaxPool2D_d{id}_c{cls}')
    
    elif tok[0] == 'R':
        print("Creating ReLU")
        return ReLU(name=f'ReLU_d{id}_c{cls}')
    
    elif tok[0] == 'D':
        print("Creating Dropout with rate=0.1")
        return Dropout(0.1, name=f'dropout_d{id}_c{cls}')
    
    elif tok[0] == 'N':
        print("Creating BatchNormalization")
        return BatchNormalization()
    else:
        print('Invalid')


# How to define ensemble structure:
# S: SeparableConv2D, follows by filter, kernel, and stride 
#    example: S64,3,2
# P: MaxPool, followed by pool size
#    example: P2
# R: ReLU activation
# D: Dropout, defaults to 0.1 drop
#
# A full example: 'S8,3,2_R_D_S8,3,2_R_D'
# The network is as follows:
#    SeparableConv2D(filters=8, kernel_size=3, strides=2)
#    ReLU()
#    Dropout(0.1)
#    SeparableConv2D(filters=8, kernel_size=3, strides=2)
#    ReLU()
#    Dropout(0.1)


ensemble_structure = ['S64,3,2_R_D_S64,3,2_R_D',
                      'S32,3,2_R_D_S64,3,2_R_D',
                      'S16,3,2_R_D_S32,3,2_R_D', 
                      'S8,3,2_R_D_S8,3,2_R_D',
                      'S4,3,2_S16,3,2']


def Xception_block(input_shape, classes,
                   activation='sigmoid',
                   flows=7, 
                   ensemble='S4,3,2_S16,3,2',
                   loss='binary_crossentropy',
                   learning_rate=0.001,
                   weights='imagenet'):

    '''
    input_shape : input shape of image
    classes     : number of classes 
    breakindex  : number of xception block-flows to be used 
    ensemble    : the default ensemble model to be followed for each class
    '''

    assert flows > 0 and flows < 10, "The number of flows should be between [1-9]"
    assert loss in ['binary_crossentropy', 'categorical_crossentropy'], "loss can be either 'binary_crossentropy' or 'categorical_crossentropy'"

    tf.keras.backend.clear_session()
    breakindex = [36, 46, 56, 66, 76, 86, 96, 106, 116]
    
    input_img = tf.keras.Input(input_shape, name='input')
    base_model = tf.keras.applications.Xception(input_tensor=input_img, 
                                                include_top=False, 
                                                weights=weights)
    
    totLayers = len(base_model.layers)
    # for i in range(totLayers):
    #     base_model.layers[i+1]._name += '_head'

    # Last index of the head CNN
    comb_out = base_model.layers[breakindex[flows-1]].output
    #base_model.layers[breakindex[flows-1]]._name += '_lastcom'

    seps = []
    if ensemble != '':
        esets = ensemble.split('_')
        print('esets:', esets)
    else:
        esets = None

    for seg in range(classes):
        if esets != None:
            res = comb_out
            past = None
            for i, tok in enumerate(esets):
                print(f"Layer {i} type: {tok[0]}")
                print(f"Layer {i} input shape: {res.shape}")
                conv_layer = parser(tok, i, seg)
               
                res = conv_layer(res)
                print(f"Layer {i} output shape: {res.shape}")
                if 'S' in tok and past != None and res.shape[-1] == past.shape[-1]:
                    res = Add()([res, past])
                    print('Residual added')
                if 'S' in tok:
                    past = res
        else:
            res = SeparableConv2D(filters=16, kernel_size=3, 
                                  strides=2, name=f'sepconv2d_d1_c{seg}')(comb_out)
            res = ReLU(name=f'maxpool2d_d1_c{seg}')(res)
            res = SeparableConv2D(filters=8, kernel_size=3, strides=2, name=f'sepconv2d_d2_c{seg}')(res)
            res = ReLU(name=f'maxpool2d_d2_c{seg}')(res)

        res = Flatten(name='flatten_'+str(seg))(res)
        res = Dense(1)(res)
        seps.append(res)
        
    out = Concatenate()(seps)
    out = Activation('sigmoid' if loss=='binary_crossentropy' else 'softmax')(out)    
    model = tf.keras.Model(input_img, out)

    print('Params', model.count_params())

    model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=learning_rate), 
                  loss=loss,
                  metrics=[tf.keras.metrics.CategoricalAccuracy(),
                           tf.keras.metrics.BinaryAccuracy(),
                           tf.keras.metrics.Precision(),
                           tf.keras.metrics.Recall(),
                           tf.keras.metrics.TopKCategoricalAccuracy(),
                           tf.keras.metrics.AUC(num_thresholds=200,
                                                multi_label=True),
                           tf.keras.metrics.TruePositives(),
                           tf.keras.metrics.FalsePositives(),
                           ],
                  )
    
    return model

model = Xception_block(x_train.shape[1:], 7,
                       flows=1, ensemble=ensemble_structure[-1],
                       loss='categorical_crossentropy')

model.summary()

#tf.keras.utils.plot_model(model, to_file="model.png",show_shapes=True, 
#                          show_layer_names=True, dpi=96)

history = model.fit(x_train, y_train, validation_data=(x_test, y_test), 
                    epochs=10,
                    callbacks=[tf.keras.callbacks.EarlyStopping(monitor='val_loss', 
                                                                patience=3,
                                                                restore_best_weights=True)])

epochs = np.arange(1, len(history.history['loss'])+1)

plt.plot(epochs, history.history['loss'], label='loss')
plt.plot(epochs, history.history['auc'], label='auc')
plt.plot(epochs, history.history['precision'], label='precision')
plt.plot(epochs, history.history['recall'], label='recall')


plt.xlabel('Epochs')
plt.ylabel('Metric')
plt.grid()
plt.legend()
plt.show()

plt.plot(epochs, history.history['val_loss'], label='val_loss')
plt.plot(epochs, history.history['val_auc'], label='val_auc')
plt.plot(epochs, history.history['val_precision'], label='val_precision')
plt.plot(epochs, history.history['val_recall'], label='val_recall')

plt.xlabel('Epochs')
plt.ylabel('Metric')
plt.grid()
plt.legend()
plt.show()

我尝试使用“tf.constant(res)”将第 0 层输入形状转换为 numpy 数组,但它不起作用。所以我删除了那部分。当我运行代码时,它抛出了他的错误;

libpng error: IDAT: CRC error
Warning: Unable to read image at Fabrics/Cotton/1221/im_4.png
x_data shape: (2212, 120, 120, 3)
esets: ['S4,3,2', 'S16,3,2']
Layer 0 type: S
Layer 0 input shape: (None, 8, 8, 728)
Parsing token: S4,3,2
Creating SeparableConv2D with filters=4, kernel_size=3, strides=2
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
File /Users/wadugekaveeshakavindifernando/Documents/fyp/FabricNet/fabricnet.py:209
    193     model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=learning_rate), 
    194                   loss=loss,
    195                   metrics=[tf.keras.metrics.CategoricalAccuracy(),
   (...)
    204                            ],
    205                   )
    207     return model
--> 209 model = Xception_block(x_train.shape[1:], 7,
    210                        flows=1, ensemble=ensemble_structure[-1],
    211                        loss='categorical_crossentropy')
    213 model.summary()
    215 #tf.keras.utils.plot_model(model, to_file="model.png",show_shapes=True, 
    216 #                          show_layer_names=True, dpi=96)

File /Users/wadugekaveeshakavindifernando/Documents/fyp/FabricNet/fabricnet.py:169
    166 print(f"Layer {i} input shape: {res.shape}")
    167 conv_layer = parser(tok, i, seg)
--> 169 res = conv_layer(res)
    170 print(f"Layer {i} output shape: {res.shape}")
    171 if 'S' in tok and past != None and res.shape[-1] == past.shape[-1]:

File /Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/tensorflow/python/keras/engine/base_layer.py:1026, in Layer.__call__(self, *args, **kwargs)
...
    231                      ', found ndim=' + str(ndim) +
    232                      '. Full shape received: ' +
    233                      str(tuple(shape)))

AttributeError: 'tuple' object has no attribute 'rank'
python keras tensorflow2.0 tensor tf.keras
1个回答
0
投票

给出错误的代码行是“from tensorflow.python.keras.layers import *”。删除 python 并仅使用“from tensorflow.keras.layers import *”对我有用。出现此问题是因为 Xception 模型层输出的数据类型与集成模型所需的参数数据类型不匹配。

© www.soinside.com 2019 - 2024. All rights reserved.