Точность CNN не является точной

#python #tensorflow #machine-learning #keras #conv-neural-network

Вопрос:

У меня есть cnn, который выглядит так

 import pandas as pd
import numpy as np
import cv2
import matplotlib.pyplot as plt
from tensorflow.keras.layers import *
from tensorflow.keras.models import *
import random
import pickle
df = pd.read_csv('minor/age_gender.csv')
image_list = []
labels = []
image_labels = []
print(df.shape[0])
for x in range(df.shape[0]):
    png = np.fromstring(df.iloc[x]['pixels'], dtype=int, sep=' ').reshape((48,48,1))
    png = png/250.0
    age = df.iloc[x]['age']
    
    minor=None
    if int(age)<18:
        #print(2)
        minor =1
    else:

        minor = 0
    image_labels.append((png,minor))
young = []
old = []
for png,minor in image_labels:
    if minor==1:
        young.append((png,minor))
    else:
        old.append((png,minor))
pickle.dump(young,open('minor/young.pickle','wb'))
print('saved')
input()
young = young[:min(len(young),len(old))]
old = old[:min(len(young),len(old))]
print(len(young))
input()
image_labels = old young
print(image_labels)
input()
random.shuffle(image_labels)
for png,minor in image_labels:
    image_list.append(png)
    print(minor)
    labels.append(minor)
    
image_list=np.array(image_list)
labels = np.array(labels)
print(image_list.shape)
#imag_list = image_list.reshape(-1,48,48,1)
print(image_list.shape)

def model2():
    inputs = Input((None,None,1))
    x = Conv2D(128,(5,5),input_shape = (48,48,1),padding='same')(inputs)
 
    x= BatchNormalization()(x)
    x = Activation('relu')(x)
    x = Conv2D(64,(5,5),padding='same')(x)
    
    x= BatchNormalization()(x)
    x = Activation('relu')(x)

    x= BatchNormalization()(x)
    x = Activation('relu')(x)
    x = Conv2D(1,(5,5),padding='same')(x)
    x=GlobalMaxPooling2D()(x)
    outputs = Activation('sigmoid')(x)
    model = Model(inputs=inputs,outputs=outputs)
    model.compile('adam','binary_crossentropy',metrics=['accuracy'])
    return model


input()
model = model2()
print(model.summary())
model.fit(image_list,labels,epochs=10,batch_size=32)
model.save('minor/age_detection6')

 

Когда я запускаю его, я получаю журнал эпохи, выглядящий так

 Epoch 1/10
265/265 [==============================] - 40s 148ms/step - loss: 0.6445 - accuracy: 0.6447
Epoch 2/10
265/265 [==============================] - 37s 139ms/step - loss: 0.4422 - accuracy: 0.7994
Epoch 3/10
265/265 [==============================] - 37s 138ms/step - loss: 0.4186 - accuracy: 0.8168
Epoch 4/10
265/265 [==============================] - 37s 138ms/step - loss: 0.3720 - accuracy: 0.8381
Epoch 5/10
265/265 [==============================] - 37s 138ms/step - loss: 0.3559 - accuracy: 0.8517
Epoch 6/10
265/265 [==============================] - 39s 149ms/step - loss: 0.3487 - accuracy: 0.8564
Epoch 7/10
265/265 [==============================] - 40s 151ms/step - loss: 0.3341 - accuracy: 0.8597
Epoch 8/10
265/265 [==============================] - 37s 139ms/step - loss: 0.3252 - accuracy: 0.8699
Epoch 9/10
265/265 [==============================] - 37s 139ms/step - loss: 0.3084 - accuracy: 0.8765
Epoch 10/10
265/265 [==============================] - 37s 138ms/step - loss: 0.3074 - accuracy: 0.8746

 

До этого момента все было хорошо. Существует довольно высокая точность. Вот тут-то все и становится странным. В следующем коде

 import cv2
import numpy as np
from tensorflow.keras.models import load_model
import pandas as pd
import pickle
from tqdm import tqdm
model = load_model('minor/age_detection6')
df = pd.read_csv('minor/age_gender.csv')
image_list = []
labels = []

print(df.shape[0])
for x in range(df.shape[0]):
    png = np.fromstring(df.iloc[x]['pixels'], dtype=int, sep=' ').reshape((48,48,1))
    png = png/250.0
    age = df.iloc[x]['age']
    
    minor=None
    if int(age)<18:
        minor =1
    else:
        minor = 0
    image_list.append(png)
    labels.append(minor)
print(labels.index(1))
input()
image2 = cv2.imread('minor/kid.png')
print(image2.shape)
image2 = cv2.cvtColor(image2,cv2.COLOR_BGR2GRAY)
print(image2.shape)
image = image_list[0]
print(labels[0])
image = image/255.0
image = np.reshape(image,(1,image.shape[0],image.shape[1],1))
image2 = image2/255.0
image2 = np.reshape(image2,(1,image2.shape[0],image2.shape[1],1))
print(image2.shape)
input()
valu = 0
predictions=model.predict(image)
print(predictions)
for items in predictions:
    for item in items:
        valu =item
valu = int(valu/predictions.shape[0])
print(valu)
print(labels[0])
young = pickle.load(open('minor/young.pickle','rb'))
print('no')
score = 0
for png,minor in tqdm(young):
    score  = int(model.predict(png)[0][0])
print(score/len(young))


 

Я делаю кучу фотографий несовершеннолетних(некоторые из которых были изучены моделью), но при прогнозировании всех из них вероятность успеха составляет 0%. Однако для несовершеннолетних это 100%. Мои данные были перетасованы и выровнены, поэтому я недоумеваю, почему это происходит. Любая помощь будет признательна.

Комментарии:

1. НЕ УВЕРЕН, но почему ваш вывод-это просто активация сигмовидной железы. Разве так не должно быть outputs = Dense(1, activation='sigmoid')(x) ?

2. @AdarshWase, Тогда это не был бы полностью подключенный CNN. Весь смысл проекта заключается в создании FCN

3. Это не совсем верно, поскольку плотный слой эквивалентен слою свертки 1×1.

Ответ №1:

Как правило, при двоичном прогнозировании вы устанавливаете пороговое значение, с помощью которого вы разделяете выходные данные на два класса. Вы просто пытаетесь поместить свои выходные данные (число от 0 до 1) в свои классы без порогового значения. Ваше сравнение должно выглядеть примерно так:

 class_1_correct  = np.sum(outputs>=0.5 * class_labels)
class_0_correct  = np.sum(np.abs(1 - outputs<0.5 * class_labels))
 

Это всего лишь пример, и его необходимо будет адаптировать к вашему коду.

Более того, эта часть неверна:

 for png,minor in tqdm(young):
    score  = int(model.predict(png)[0][0])
 

Вы приводите свой сигмоидный вывод к значению int, которое почти всегда будет равно нулю.

То же самое относится и к этому кодексу:

 valu = int(valu/predictions.shape[0])
 

которым, я думаю, ты хочешь быть:

 valu = int(valu/predictions.shape[0]*100)