当我用 keras 训练网络时,为什么我预测的形状不准确?

When i train a network with keras, why are the shape of my predictions not accurate?

我是 tensorflow keras 训练模型来分类图像是 a 还是 b。我有 20,000 张随机生成的图像用于训练(一半 a,一半 b)。 example of a image example of b image

首先我导入必要的包

import tensorflow
from matplotlib import pyplot as plt
import cv2
from matplotlib import pyplot as plt
import random
from tensorflow.keras import models 
from tensorflow.keras import layers 
import numpy as np

在那之后,我从我的文件夹中加载图像,并处理它们,将它们变成只有 0 和 1 的数组,将它们与适当的标签一起保存,如果图像是 a,则为 1,如果图像是 a,则为 0图像是a b。完成后,我将它们放在一个列表中并随机播放列表。

a_letters = []
b_letters = []

folder_path_a = 'C:/path/to/folder/'
folder_path_b = 'C:/path/to/folder/'

count = 0
while count < 10000:
    path = folder_path_a + f'a{count}.png'
    img = cv2.imread(path)
    gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    for row_number, row in enumerate(gray_image):
        for column_number, column in enumerate(row):
            if gray_image[row_number][column_number] > 50:
                gray_image[row_number][column_number] = 1
            else:
                gray_image[row_number][column_number] = 0
    #gray_image = np.expand_dims(gray_image, axis=2)
    image_and_label = [gray_image, 1]
    a_letters.append(image_and_label)
    count = count + 1

    
count = 0    
while count < 10000:
    path = folder_path_b + f'b{count}.png'
    img = cv2.imread(path)
    gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    for row_number, row in enumerate(gray_image):
        for column_number, column in enumerate(row):
            if gray_image[row_number][column_number] > 50:
                gray_image[row_number][column_number] = 1
            else:
                gray_image[row_number][column_number] = 0
    # gray_image = np.expand_dims(gray_image, axis=2)
    image_and_label = [gray_image, 0]
    b_letters.append(image_and_label)    
    count = count + 1    

    
unified_list = a_letters + b_letters
random.shuffle(unified_list)

接下来,我将标签和图像分离到它们自己的列表中,并将它们拆分为训练数据和验证数据。

images = []
labels = []

for image, label in unified_list:
    images.append(image)
    labels.append(float(label))

x_train = images[:15000]
y_train = labels[:15000]

x_val = images[15000:]
y_val = labels[15000:]

然后我将列表转换成 numpy 数组,并扩展标签的维度(之前,我尝试训练模型,我得到一个错误,说 logits 和标签需要是相同的维度,所以我扩展了标签的尺寸,使它们与图像的尺寸相同)

x_train_array = np.asarray(x_train)
y_train_array = np.asarray(y_train)

x_val_array = np.asarray(x_val)
y_val_array = np.asarray(y_val)

y_train_array = np.expand_dims(y_train_array, axis =1)
y_val_array = np.expand_dims(y_val_array, axis = 1)

接下来,我构建模型并对其进行训练:

model = models.Sequential()
model.add(layers.Dense(512, activation='relu', input_shape=(169,191,)))
model.add(layers.Dense(150, activation='relu'))
model.add(layers.Dense(250, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))

model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['accuracy'])

model.fit(x_train_array, y_train_array, epochs=10, batch_size=500, validation_data=(x_val_array, y_val_array))

以下是模型摘要: model summary

当我尝试使用此代码对我的模型进行预测时:

predictions = model.predict(x_val_array)

我得到 predictions.shape 的 (5000, 169, 1)。似乎不是每张图片得到一个预测,而是得到 169?我已经研究了一段时间,但似乎无法弄明白。

形状 169 来自输入图像的宽度。

它被继承是因为如果你添加一个密集层,它只连接到前一个张量的一个维度。

您可以尝试的第一件事是展平图像:

扁平化

model = models.Sequential()
model.add(layers.Flatten(input_shape = (169,191,)))
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(150, activation='relu'))
model.add(layers.Dense(250, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
model.summary()
model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['accuracy'])
predictions = model.predict(example)
predictions.shape
Model: "sequential_12"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 flatten_7 (Flatten)         (None, 32279)             0         
                                                                 
 dense_40 (Dense)            (None, 512)               16527360  
                                                                 
 dense_41 (Dense)            (None, 150)               76950     
                                                                 
 dense_42 (Dense)            (None, 250)               37750     
                                                                 
 dense_43 (Dense)            (None, 1)                 251       
                                                                 
=================================================================
Total params: 16,642,311
Trainable params: 16,642,311
Non-trainable params: 0
_________________________________________________________________
(50, 1)

但是,不推荐这样做,因为与它可能传达的信息相比,模型太大了。该模型有 18M 个参数,计算效率非常低。我宁愿将 ResNet-18 用于 15M 参数模型。

否则,您可以利用卷积层。 这是一个例子:

model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(169,191,1)))
model.add(layers.Conv2D(32, (3, 3), activation='relu'))
model.add(layers.MaxPool2D(pool_size=(4, 4)))
model.add(layers.Conv2D(32, (3, 3), activation='relu'))
model.add(layers.Conv2D(32, (3, 3), activation='relu'))
model.add(layers.MaxPool2D(pool_size=(4, 4)))
model.add(layers.Flatten())
model.add(layers.Dense(150, activation='relu'))
model.add(layers.Dense(250, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
model.summary()
model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['accuracy'])
predictions = model.predict(example)
predictions.shape
Model: "sequential_17"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 conv2d_24 (Conv2D)          (None, 167, 189, 32)      320       
                                                                 
 conv2d_25 (Conv2D)          (None, 165, 187, 32)      9248      
                                                                 
 max_pooling2d_9 (MaxPooling  (None, 41, 46, 32)       0         
 2D)                                                             
                                                                 
 conv2d_26 (Conv2D)          (None, 39, 44, 32)        9248      
                                                                 
 conv2d_27 (Conv2D)          (None, 37, 42, 32)        9248      
                                                                 
 max_pooling2d_10 (MaxPoolin  (None, 9, 10, 32)        0         
 g2D)                                                            
                                                                 
 flatten_12 (Flatten)        (None, 2880)              0         
                                                                 
 dense_56 (Dense)            (None, 150)               432150    
                                                                 
 dense_57 (Dense)            (None, 250)               37750     
                                                                 
 dense_58 (Dense)            (None, 1)                 251       
                                                                 
=================================================================
Total params: 498,215
Trainable params: 498,215
Non-trainable params: 0
_________________________________________________________________
(50, 1)

小了30倍,但是性能会好很多,因为卷积层擅长提取特征。