【问题标题】:MobileNetV2 is giving good results during training and validation. But when tested on single images , the results are not matchingMobileNetV2 在训练和验证期间给出了很好的结果。但是在单张图片上测试时,结果不匹配
【发布时间】:2021-12-27 04:24:55
【问题描述】:

我正在尝试在 TensorFlow 中使用 MobileNetV2 实现二进制分类。我有两个文件夹 A 和 B,我正在使用 image_dataset_from_directory 函数将它们分成两个类进行训练。

BATCH_SIZE = 32
IMG_SIZE = (224, 224)
train_directory = "Train_set/"
test_directory = "Test_set/"
train_dataset = image_dataset_from_directory(train_directory, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_SIZE)
validation_dataset = image_dataset_from_directory(test_directory, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_SIZE)

我在将输入传递到网络之前对其进行预处理。

preprocess_input = tf.keras.applications.mobilenet_v2.preprocess_input```

然后我使用代码创建模型:

def alpaca_model(image_shape=IMG_SIZE):
    input_shape = image_shape + (3,)    
    base_model = tf.keras.applications.MobileNetV2(input_shape=input_shape,
                                                   include_top=False, # <== Important!!!!
                                                   weights='imagenet') # From imageNet
    
    # Freeze the base model by making it non trainable
    base_model.trainable = False

    # create the input layer (Same as the imageNetv2 input size)
    inputs = tf.keras.Input(shape=input_shape) 
    
    # data preprocessing using the same weights the model was trained on
    x = preprocess_input(inputs) 
    
    # set training to False to avoid keeping track of statistics in the batch norm layer
    x = base_model(x, training=False) 
    
    # Add the new Binary classification layers
    # use global avg pooling to summarize the info in each channel
    x = tf.keras.layers.GlobalAveragePooling2D()(x) 
    #include dropout with probability of 0.2 to avoid overfitting
    x = tf.keras.layers.Dropout(0.2)(x)
        
    # create a prediction layer with one neuron (as a classifier only needs one)
    prediction_layer = tf.keras.layers.Dense(1, activation="sigmoid")
    
    outputs = prediction_layer(x) 
    model = tf.keras.Model(inputs, outputs)
    
    return model

模型摘要看起来像这样

Model: "model_1"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 input_4 (InputLayer)        [(None, 224, 224, 3)]     0         
                                                                 
 tf.math.truediv_1 (TFOpLamb  (None, 224, 224, 3)      0         
 da)                                                             
                                                                 
 tf.math.subtract_1 (TFOpLam  (None, 224, 224, 3)      0         
 bda)                                                            
                                                                 
 mobilenetv2_1.00_224 (Funct  (None, 7, 7, 1280)       2257984   
 ional)                                                          
                                                                 
 global_average_pooling2d_1   (None, 1280)             0         
 (GlobalAveragePooling2D)                                        
                                                                 
 dropout_1 (Dropout)         (None, 1280)              0         
                                                                 
 dense_1 (Dense)             (None, 1)                 1281      
                                                                 
=================================================================
Total params: 2,259,265
Trainable params: 1,281
Non-trainable params: 2,257,984
_________________________________________________________________

然后使用以下代码编译模型:

loss_function=tf.keras.losses.BinaryCrossentropy()
optimizer = tf.keras.optimizers.Adam(learning_rate=0.01)
metrics=['accuracy', tf.metrics.Recall(), tf.metrics.Precision()]

这些是 model.fit 和 model.evaluate 的统计数据

total_epochs = 5
history_fine = model2.fit(train_dataset, epochs=total_epochs, validation_data=validation_dataset)
Epoch 1/5
54/54 [==============================] - 213s 3s/step - loss: 0.2236 - accuracy: 0.9013 - recall: 0.9149 - precision: 0.8852 - val_loss: 0.0856 - val_accuracy: 0.9887 - val_recall: 0.9950 - val_precision: 0.9803
Epoch 2/5
54/54 [==============================] - 217s 4s/step - loss: 0.0614 - accuracy: 0.9855 - recall: 0.9928 - precision: 0.9776 - val_loss: 0.0439 - val_accuracy: 0.9977 - val_recall: 1.0000 - val_precision: 0.9950
Epoch 3/5
54/54 [==============================] - 216s 4s/step - loss: 0.0316 - accuracy: 0.9948 - recall: 0.9988 - precision: 0.9905 - val_loss: 0.0297 - val_accuracy: 0.9977 - val_recall: 1.0000 - val_precision: 0.9950
Epoch 4/5
54/54 [==============================] - 217s 4s/step - loss: 0.0258 - accuracy: 0.9954 - recall: 1.0000 - precision: 0.9905 - val_loss: 0.0373 - val_accuracy: 0.9910 - val_recall: 0.9850 - val_precision: 0.9949
Epoch 5/5
54/54 [==============================] - 220s 4s/step - loss: 0.0242 - accuracy: 0.9942 - recall: 0.9988 - precision: 0.9893 - val_loss: 0.0225 - val_accuracy: 0.9977 - val_recall: 1.0000 - val_precision: 0.9950

model2.evaluate(validation_dataset)
14/14 [==============================] - 15s 354ms/step - loss: 0.0225 - accuracy: 0.9977 - recall: 1.0000 - precision: 0.9950

统计数据非常好。但是,当我使用相同的验证集并检查文件夹 A 和 B 中单个图片的预测并绘制预测时,这些点似乎不是线性可分的。

A = []
for i in os.listdir("Test_set\A"):
    location = f"Test_set\A\{i}"
    my_image = tf.keras.preprocessing.image.load_img(location, target_size=(224, 224))
    preprocess_input = tf.keras.applications.mobilenet_v2.preprocess_input

    #preprocess the image
    my_image = tf.keras.preprocessing.image.img_to_array(my_image)
    my_image = my_image.reshape((1, my_image.shape[0], my_image.shape[1], 
    my_image.shape[2]))
    my_image = preprocess_input(my_image)

    #make the prediction
    prediction = model2.predict(my_image)
    # print(prediction)
    A.append(float(prediction))
B = []
for i in os.listdir("Test_set\B"):
    location = f"Test_set\B\{i}"
    my_image = tf.keras.preprocessing.image.load_img(location, target_size=(224, 224))
    preprocess_input = tf.keras.applications.mobilenet_v2.preprocess_input

    #preprocess the image
    my_image = tf.keras.preprocessing.image.img_to_array(my_image)
    my_image = my_image.reshape((1, my_image.shape[0], my_image.shape[1], 
    my_image.shape[2]))
    my_image = preprocess_input(my_image)

    #make the prediction
    prediction = model2.predict(my_image)
    # print(prediction)
    B.append(float(prediction))

【问题讨论】:

    标签: python tensorflow machine-learning deep-learning tf.keras


    【解决方案1】:

    既然你有两个类,你应该替换

    prediction_layer = tf.keras.layers.Dense(1, activation="sigmoid")
    

    prediction_layer = tf.keras.layers.Dense(2, activation="softmax")
    

    分类器最后一层的单元数等于类数。

    在此之后,您必须重新训练模型。

    【讨论】:

    • 但是 sigmoid 对于 1 个节点的二进制分类来说已经足够了,对吧?理想情况下,该节点的输出应该是代表两个类的 0 或 1。
    • 我使用了 2 个单位和 softmax,因为如果您注意到这两个数字的总和为 1,即 0.73+0.23 = 1,您将从最后一层获得的输出为 [0.73, 0.27]。所以,基于这个值,softmax 会说输入属于 0 类,因为0.73&gt;0.27。可以使用np.argmax获取数组中最大数的索引值
    猜你喜欢
    • 2017-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-20
    • 2020-07-31
    • 2018-12-08
    • 2020-11-08
    • 1970-01-01
    相关资源
    最近更新 更多