'Acc always around 0.5 by using binary neural network with Tensorflow

import pandas as pd
import numpy as np
import PIL
import PIL.Image
import cv2
import tensorflow as tf
Reading Image Data
file_dirs = ["./Positive", "./Negative"]

def read_image_data(file_dir):
    files = []
    for i in range(20000):
        img_no = "%05d"% (i+1) 
        img_dir = file_dir + "/" + img_no + ".jpg"
        img = cv2.imread(img_dir,cv2.IMREAD_GRAYSCALE)
        if img is not None:
            files.append(img)
            continue
        img_dir = file_dir + "/" + img_no + "_1" + ".jpg"
        img = cv2.imread(img_dir,cv2.IMREAD_GRAYSCALE)
        files.append(img)
    return np.array(files)
pos = read_image_data(file_dirs[0])
neg = read_image_data(file_dirs[1])

print(type(pos[0])) # <class 'numpy.ndarray'>
print(pos.shape[0]) # 20000
print(pos[0].shape) # 227,227

pos_label = np.array([np.float32(1),np.float32(0)])
neg_label = np.array([np.float32(0),np.float32(1)])
pos_labels = np.array([pos_label for i in range(20000)]) # [1,0],[1,0], ...
neg_labels = np.array([neg_label for i in range(20000)]) # [0,1],[0,1], ...

# combine two pos and neg to one dataset
x = np.concatenate((pos,neg))
y = np.concatenate((pos_labels,neg_labels))
  
# Preprocessing
# expand dims
x = np.expand_dims(x, axis=3)
print(x.shape) # (40000,227,227,1)

def shuffle(dataset, labels, NUM_SAMPLES):
    np.random.seed(10)
    random_list = np.arange(NUM_SAMPLES)
    np.random.shuffle(random_list)
    return dataset[random_list], labels[random_list], random_list

# rate = percentage of training data in the dataset
def data_split(x, y, rate, NUM_SAMPLES):
    rate = int(rate*NUM_SAMPLES)
    x_train = x[:rate]
    x_test = x[rate:]
    y_train = y[:rate]
    y_test = y[rate:]
    return x_train, x_test, y_train, y_test

# shuffle and split into train and validation datasets
x_shuffled, y_shuffled, random_list = shuffle(x, y, x.shape[0])
x_train, x_test, y_train, y_test = data_split(x_shuffled, y_shuffled, 0.8, x.shape[0])

# normalization
x_train, x_test, y_train, y_test = x_train/255.0, x_test/255.0, y_train, y_test 

def get_model(IMG_WIDTH, IMG_HEIGHT, NUM_CATEGORIES):
    model = tf.keras.models.Sequential()
    model.add(tf.keras.layers.Conv2D(filters=16, kernel_size=(3,3), padding='valid', input_shape=(IMG_WIDTH, IMG_HEIGHT,1), activation="relu"))
    model.add(tf.keras.layers.AvgPool2D(pool_size=(2,2)))
    model.add(tf.keras.layers.Conv2D(filters=32, kernel_size=(3,3), padding='valid', activation="tanh"))
    model.add(tf.keras.layers.AvgPool2D(pool_size=(2,2)))
    model.add(tf.keras.layers.Dropout(0.2))
    model.add(tf.keras.layers.Conv2D(filters=64, kernel_size=(3,3), padding='valid', activation="tanh"))
    model.add(tf.keras.layers.AvgPool2D(pool_size=(2,2)))
    model.add(tf.keras.layers.Dropout(0.2))
    model.add(tf.keras.layers.Conv2D(filters=64, kernel_size=(3,3), padding='valid', activation="sigmoid"))
    model.add(tf.keras.layers.AvgPool2D(pool_size=(2,2)))
    model.add(tf.keras.layers.Flatten())
    model.add(tf.keras.layers.Dense(NUM_CATEGORIES*16, activation='relu'))
    model.add(tf.keras.layers.Dense(NUM_CATEGORIES*8, activation='relu'))
    model.add(tf.keras.layers.Dense(NUM_CATEGORIES, activation='softmax'))
    
    opt = tf.keras.optimizers.Adam(learning_rate=0.1)
    model.compile(optimizer=opt, loss='binary_crossentropy', metrics=['accuracy'])
    return model

model = get_model(227,227,2)

model.summary()

Model: "sequential_5"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_20 (Conv2D)           (None, 225, 225, 16)      448       
_________________________________________________________________
average_pooling2d_20 (Averag (None, 112, 112, 16)      0         
_________________________________________________________________
conv2d_21 (Conv2D)           (None, 110, 110, 32)      4640      
_________________________________________________________________
average_pooling2d_21 (Averag (None, 55, 55, 32)        0         
_________________________________________________________________
dropout_10 (Dropout)         (None, 55, 55, 32)        0         
_________________________________________________________________
conv2d_22 (Conv2D)           (None, 53, 53, 64)        18496     
_________________________________________________________________
average_pooling2d_22 (Averag (None, 26, 26, 64)        0         
_________________________________________________________________
dropout_11 (Dropout)         (None, 26, 26, 64)        0         
_________________________________________________________________
conv2d_23 (Conv2D)           (None, 24, 24, 64)        36928     
_________________________________________________________________
average_pooling2d_23 (Averag (None, 12, 12, 64)        0         
_________________________________________________________________
flatten_5 (Flatten)          (None, 9216)              0         
_________________________________________________________________
dense_15 (Dense)             (None, 32)                294944    
_________________________________________________________________
dense_16 (Dense)             (None, 16)                528       
_________________________________________________________________
dense_17 (Dense)             (None, 2)                 34        
=================================================================
Total params: 356,018
Trainable params: 356,018
Non-trainable params: 0
_________________________________________________________________
model.fit(x_train, y_train, epochs=5)
model.evaluate(x_test, y_test, verbose=2)
Epoch 1/5
1000/1000 [==============================] - 16s 16ms/step - loss: 3.0167 - accuracy: 0.5013
Epoch 2/5
1000/1000 [==============================] - 15s 15ms/step - loss: 0.6963 - accuracy: 0.4942
Epoch 3/5
1000/1000 [==============================] - 15s 15ms/step - loss: 0.6953 - accuracy: 0.5016
Epoch 4/5
1000/1000 [==============================] - 15s 15ms/step - loss: 0.6957 - accuracy: 0.4999
Epoch 5/5
 679/1000 [===================>..........] - ETA: 5s - loss: 0.6947 - accuracy: 0.4983

Hi. I'm quite new to tensorflow.

I want to build a CNN for classifying photos with surface crack and photos without surface crack.

Why does my model always show a result of acc:0.5?

Even I have tried different learning rate, different activation function, different types of output such as one-hot encoding and sparse categories (0 or 1) increasing the width and the depth of the network, number of neuron = 1 in the last dense layer with sigmoid, it also shows the same result.



Solution 1:[1]

You may need to make a few changes in your code for better accuracy as below:

  • Change all the activation = 'relu' except in the last dense layer.
  • Remove all the dropout layers from the model.
  • Keep the default learning_rate=0.001 for Adam optimizer.
  • Use sigmoid activation function in last layer as this model is for Binary Classification and you are using 'Binary Crossentropy' loss function while compiling the model

Please check this below updated code:

def get_model(IMG_WIDTH, IMG_HEIGHT,NUM_CATEGORIES):

    model = tf.keras.models.Sequential()
    model.add(tf.keras.layers.Conv2D(filters=16, kernel_size=(3,3), padding='valid', input_shape=(IMG_WIDTH, IMG_HEIGHT,1), activation="relu"))
    model.add(tf.keras.layers.AvgPool2D(pool_size=(2,2)))
    model.add(tf.keras.layers.Conv2D(filters=32, kernel_size=(3,3), padding='valid', activation="relu"))
    model.add(tf.keras.layers.AvgPool2D(pool_size=(2,2)))
    model.add(tf.keras.layers.Conv2D(filters=64, kernel_size=(3,3), padding='valid', activation="relu"))
    model.add(tf.keras.layers.AvgPool2D(pool_size=(2,2)))   
    model.add(tf.keras.layers.Conv2D(filters=64, kernel_size=(3,3), padding='valid', activation="relu"))
    model.add(tf.keras.layers.AvgPool2D(pool_size=(2,2)))
    model.add(tf.keras.layers.Flatten())
    model.add(tf.keras.layers.Dense(NUM_CATEGORIES*32, activation='relu'))
    model.add(tf.keras.layers.Dense(NUM_CATEGORIES*32, activation='relu'))   
    model.add(tf.keras.layers.Dense(1, activation='sigmoid'))   
    opt = tf.keras.optimizers.Adam(learning_rate=0.001)
    model.compile(optimizer=opt, loss='binary_crossentropy', metrics=['accuracy'])
    return model

model = get_model(227,227,2)

model.summary()

model.fit(train_dataset,validation_data=validation_dataset, epochs=10)

Output:

Epoch 1/10
63/63 [==============================] - 9s 118ms/step - loss: 1.9775 - accuracy: 0.5405 - val_loss: 0.6941 - val_accuracy: 0.5710
Epoch 2/10
63/63 [==============================] - 8s 119ms/step - loss: 0.6599 - accuracy: 0.6175 - val_loss: 0.6715 - val_accuracy: 0.6020
Epoch 3/10
63/63 [==============================] - 5s 75ms/step - loss: 0.6303 - accuracy: 0.6470 - val_loss: 0.6673 - val_accuracy: 0.6310
Epoch 4/10
63/63 [==============================] - 5s 74ms/step - loss: 0.6029 - accuracy: 0.6775 - val_loss: 0.7275 - val_accuracy: 0.5780
Epoch 5/10
63/63 [==============================] - 5s 73ms/step - loss: 0.5639 - accuracy: 0.7080 - val_loss: 0.6710 - val_accuracy: 0.6490
Epoch 6/10
63/63 [==============================] - 5s 73ms/step - loss: 0.5356 - accuracy: 0.7325 - val_loss: 0.8324 - val_accuracy: 0.6200
Epoch 7/10
63/63 [==============================] - 5s 73ms/step - loss: 0.5034 - accuracy: 0.7500 - val_loss: 0.7696 - val_accuracy: 0.6430
Epoch 8/10
63/63 [==============================] - 5s 74ms/step - loss: 0.4664 - accuracy: 0.7790 - val_loss: 0.7539 - val_accuracy: 0.6530
Epoch 9/10
63/63 [==============================] - 5s 73ms/step - loss: 0.4004 - accuracy: 0.8105 - val_loss: 0.7225 - val_accuracy: 0.6570
Epoch 10/10
63/63 [==============================] - 5s 76ms/step - loss: 0.3409 - accuracy: 0.8455 - val_loss: 0.7910 - val_accuracy: 0.6510

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1