代码之家  ›  专栏  ›  技术社区  ›  Nathan

CNN准确性没有提高

  •  0
  • Nathan  · 技术社区  · 2 年前

    之前我试图建立一个通用的CNN,可以做图像分类。我在扑克牌上测试过,效果很好。我现在正试图修改输入和输出管道,以便它可以进行对象定位(返回类和边界框数据)。我不知道为什么,但这个模特不会训练。准确性不会提高。Rn模型有两个输出节点:分类器头(用于图像类)和回归器头(用于BBox)。如果我将回归头修改为具有0个单位(强制它只在类上训练,而不是在Bbox上训练),则分类器头的精度会提高。所有其他修改超参数的尝试都没有明显的效果。

    有问题的代码:

    import tensorflow as tf
    from tensorflow.keras.preprocessing.image import ImageDataGenerator
    from tensorflow import keras
    from tensorflow.keras import layers
    from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint
    import random
    import numpy as np
    import matplotlib.pyplot as plt
    
    batch_size = 32
    img_shape = 150
    class_size = 52
    shuffle_val = 200000
    
    checkpoint_path = "D:\Python\Datasets\Playing Cards\My Generated DataSet\Checkpoints\weights-improvement-{epoch:02d}-{val_accuracy:.4f}.hdf5"
    
    train_ds = tf.data.Dataset.list_files('D:\Python\Datasets\Playing Cards\Misc\Images with Black BG\Training\*\*', shuffle = False)
    
    train_ds = train_ds.shuffle(shuffle_val) #accepts shuffle buffer
    
    for i in train_ds.take(10):
        print(i) #prints x number of the paths read. Used to confirm if shuffling is done properly.
    
    
    print("\n\n Training ds len: ", len(train_ds))
    
    
    def get_train_Bbox(train_file_path):
    
        mylabel = tf.strings.split(train_file_path, os.sep)[-1] #returns entire file name
        t_x1 = tf.strings.to_number(tf.strings.split(mylabel, ",")[2], tf.int32)
        t_y1 = tf.strings.to_number(tf.strings.split(mylabel, ",")[3], tf.int32)
        t_x2 = tf.strings.to_number(tf.strings.split(mylabel, ",")[4], tf.int32)
        t_y2 = tf.strings.to_number(tf.strings.split(mylabel, ",")[5], tf.int32)
        
        return t_x1, t_y1, t_x2, t_y2
    
    
    
    
    def get_label(training_file_path):
    
        label = tf.strings.split(training_file_path, os.sep)[-1]
        label_class = (tf.strings.split(label, ",")[-2])
        label = label_class
        label = tf.strings.to_number(label, tf.int32) 
        label = tf.one_hot(label, class_size)
    
        print("from label function,num of classes:", len(label))
        print("Label shape after one-hot encoding:", label.shape)
    
        return label
    
    
    
    def process_image(training_file_path):
    
        label = get_label(training_file_path)
        img = tf.io.read_file(training_file_path)
        img = tf.image.decode_jpeg(img)
        img = tf.image.resize(img, (img_shape,img_shape))
        img = tf.image.random_brightness(img, 0.2)
        train_img = img/255
    
        t_x1, t_y1, t_x2, t_y2 = get_train_Bbox(training_file_path)
        print("Label shape after processing image:", label.shape)
        return train_img, {'classifier_head': label, 'regressor_head': (t_x1, t_y1, t_x2, t_y2)}
        
    
    train_ds = train_ds.map(process_image)
    
    train_ds = train_ds.batch(batch_size)
    
    for img, label in train_ds.take(1):
        print("Training: ", label)
    
    
    
    
    valid_ds = tf.data.Dataset.list_files('D:\Python\Datasets\Playing Cards\Misc\Images with Black BG\Validating\*\*', shuffle = False) 
    
    print("Len of Valid ds:", len(valid_ds))
    
    def get_valid_label(valid_file_path):
    
        valid_label = tf.strings.split(valid_file_path, os.sep)[-1]
        valid_label_class = (tf.strings.split(valid_label, ",")[-2])
        valid_label = valid_label_class
        valid_label = tf.strings.to_number(valid_label, tf.int32)
        valid_label = tf.one_hot(valid_label, class_size) #review this later
        print("Validation Label shape after one-hot encoding:", valid_label.shape)
        return valid_label
    
    
    
    
    def get_valid_Bbox(valid_file_path):
    
        v_label = tf.strings.split(valid_file_path, os.sep)[-1] #returns entire file name
        v_x1 = tf.strings.to_number(tf.strings.split(v_label, ",")[2], tf.int32)
        v_y1 = tf.strings.to_number(tf.strings.split(v_label, ",")[3], tf.int32)
        v_x2 = tf.strings.to_number(tf.strings.split(v_label, ",")[4], tf.int32)
        v_y2 = tf.strings.to_number(tf.strings.split(v_label, ",")[5], tf.int32)
        
        return v_x1, v_y1, v_x2, v_y2
    
    
    
    def process_valid_image(valid_file_path):
        valid_label = get_valid_label(valid_file_path)
        valid_img = tf.io.read_file(valid_file_path) #read the actual image file ie. the array
        valid_img = tf.image.decode_jpeg(valid_img)
        valid_img = tf.image.resize(valid_img, (img_shape,img_shape))
        valid_img = valid_img/255
    
        v_x1, v_y1, v_x2, v_y2 = get_train_Bbox(valid_file_path)
    
        print("Valid Label shape after processing image:", valid_label.shape)
    
        return valid_img, {'classifier_head': valid_label, 'regressor_head': (v_x1, v_y1, v_x2, v_y2)}
    
    
    valid_ds = valid_ds.map(process_valid_image, num_parallel_calls=tf.data.AUTOTUNE) 
    valid_ds = valid_ds.batch(batch_size)
    
    
    for img, label in valid_ds.take(1):
        print("Valid: ", label)
    
    
    
    
    def build_feature_extractor(inputs):
    
    
        x = tf.keras.layers.Conv2D(32, (3,3), activation = "relu", input_shape=(img_shape,img_shape,3), padding = "same")(inputs)
        x = tf.keras.layers.MaxPooling2D(2,2)(x)
    
        x = tf.keras.layers.Conv2D(64, (3,3), activation = "relu", input_shape=(img_shape,img_shape,3), padding = "same")(x)
        x = tf.keras.layers.MaxPooling2D(2,2)(x)
    
    
        x = tf.keras.layers.Conv2D(128, (3,3), activation = "relu", input_shape=(img_shape,img_shape,3), padding = "same")(x)
        x = tf.keras.layers.MaxPooling2D(2,2)(x)
    
        x = tf.keras.layers.Conv2D(512, (3,3), activation = "relu", input_shape=(img_shape,img_shape,3), padding = "same")(x)
        x = tf.keras.layers.MaxPooling2D(2,2)(x)
    
        return x
    
    
    
    def build_model_adaptor(inputs):
    
        x = tf.keras.layers.Flatten()(inputs)
        x = tf.keras.layers.Dense(512, activation= "relu")(x)
        x = tf.keras.layers.Dropout(0.5)(x)
        x = tf.keras.layers.Dense(128, activation= "relu")(x)
        x = tf.keras.layers.Dense(64, activation= "relu")(x)
        
        return x
    
        
    def build_classifier_head(inputs):
    
        return tf.keras.layers.Dense(52, activation= "softmax", name = 'classifier_head')(inputs)
    
    
    def build_regressor_head(inputs):
        return tf.keras.layers.Dense(4, name = 'regressor_head')(inputs)
    
    
    def build_model(inputs):
    
        feature_extractor = build_feature_extractor(inputs)
        model_adaptor = build_model_adaptor(feature_extractor)
        classification_head = build_classifier_head(model_adaptor)
        regressor_head = build_regressor_head(model_adaptor)
    
        model = tf.keras.Model(inputs = inputs, outputs = [classification_head, regressor_head])
    
        model.compile(optimizer = 'adam', loss = {'classifier_head' : 'categorical_crossentropy', 'regressor_head' : 'mse'}, metrics = {'classifier_head' : 'accuracy', 'regressor_head' : 'mse'})
    
        return model
    
    
    model = build_model(tf.keras.layers.Input(shape=(img_shape, img_shape, 3,)))
    
    
    
    model.summary()
    
    
    epochs=25
    
    
    history = model.fit(train_ds,steps_per_epoch=int(np.ceil(26000 / float(batch_size))), epochs=epochs,validation_data=valid_ds, validation_steps=int(np.ceil(6500 / float(batch_size))))````
    
    
    
    
    I've changed the kernel sizes, batch sizes, image sizes, epochs, number of layers. Attempted to change the loss from categorical cross entrophy to sparce categorical cross entrophy.
    
    NB. The image data that is being used for training has already been augmented prior to being imported into the code. In the code I am just applying some extra brightness adjustments. 
    
    0 回复  |  直到 2 年前