Я пытаюсь сделать CNN (все еще новичок). При попытке соответствовать модели я получаю эту ошибку:

ValueError: Целевой массив с формой (10000, 10) был передан для вывода формы (None, 6, 6, 10) при использовании в качестве потерь categorical_crossentropy. Эта потеря предполагает, что цели будут иметь ту же форму, что и выходные данные.

Форма меток = (10000, 10) Форма данных изображения = (10000, 32, 32, 3)

Код:

import pickle
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import (Dense, Dropout, Activation, Flatten, 
                                     Conv2D, MaxPooling2D)
from tensorflow.keras.callbacks import TensorBoard
from keras.utils import to_categorical
import numpy as np
import time

MODEL_NAME = f"_________{int(time.time())}"
BATCH_SIZE = 64

class ConvolutionalNetwork():
    '''
    A convolutional neural network to be used to classify images
    from the CIFAR-10 dataset.
    '''

    def __init__(self):
        '''
        self.training_images -- a 10000x3072 numpy array of uint8s. Each 
                                a row of the array stores a 32x32 colour image. 
                                The first 1024 entries contain the red channel 
                                values, the next 1024 the green, and the final 
                                1024 the blue. The image is stored in row-major 
                                order, so that the first 32 entries of the array are the red channel values of the first row of the image.
        self.training_labels -- a list of 10000 numbers in the range 0-9. 
                                The number at index I indicates the label 
                                of the ith image in the array data.
        '''
        # List of image categories
        self.label_names = (self.unpickle("cifar-10-batches-py/batches.meta",
                            encoding='utf-8')['label_names'])

        self.training_data = self.unpickle("cifar-10-batches-py/data_batch_1")
        self.training_images = self.training_data[b'data']
        self.training_labels = self.training_data[b'labels']

        # Reshaping the images + scaling 
        self.shape_images()  

        # Converts labels to one-hot
        self.training_labels = np.array(to_categorical(self.training_labels))

        self.create_model()

        self.tensorboard = TensorBoard(log_dir=f'logs/{MODEL_NAME}')

    def unpickle(self, file, encoding='bytes'):
        '''
        Unpickles the dataset files.
        '''
        with open(file, 'rb') as fo:
            training_dict = pickle.load(fo, encoding=encoding)
        return training_dict

    def shape_images(self):
        '''
        Reshapes the images and scales by 255.
        '''
        images = list()
        for d in self.training_images:
            image = np.zeros((32,32,3), dtype=np.uint8)
            image[...,0] = np.reshape(d[:1024], (32,32)) # Red channel
            image[...,1] = np.reshape(d[1024:2048], (32,32)) # Green channel
            image[...,2] = np.reshape(d[2048:], (32,32)) # Blue channel
            images.append(image)

        for i in range(len(images)):
            images[i] = images[i]/255

        images = np.array(images)
        self.training_images = images
        print(self.training_images.shape)

    def create_model(self):
        '''
        Creating the ConvNet model.
        '''
        self.model = Sequential()
        self.model.add(Conv2D(64, (3, 3), input_shape=self.training_images.shape[1:]))
        self.model.add(Activation("relu"))
        self.model.add(MaxPooling2D(pool_size=(2,2)))

        self.model.add(Conv2D(64, (3,3)))
        self.model.add(Activation("relu"))
        self.model.add(MaxPooling2D(pool_size=(2,2)))

        # self.model.add(Flatten())
        # self.model.add(Dense(64))
        # self.model.add(Activation('relu'))

        self.model.add(Dense(10))
        self.model.add(Activation(activation='softmax'))

        self.model.compile(loss="categorical_crossentropy", optimizer="adam", 
                           metrics=['accuracy'])

    def train(self):
        '''
        Fits the model.
        '''
        print(self.training_images.shape)
        print(self.training_labels.shape)
        self.model.fit(self.training_images, self.training_labels, batch_size=BATCH_SIZE, 
                       validation_split=0.1, epochs=5, callbacks=[self.tensorboard])


network = ConvolutionalNetwork()
network.train()

Был бы признателен за помощь, пытались исправить в течение часа.

5
Joeyboy 6 Июл 2019 в 10:42

4 ответа

Вы должны привести свою модель в ту же форму, что и ваши метки.

Возможно, самым простым решением было бы убедиться, что модель заканчивается этими слоями:

model.add(Flatten())
## possibly an extra dense layer or 2 with 'relu' activation
model.add(Dense(10, activation=`softmax`))

Это один из самых распространенных «окончаний» модели категоризации и, возможно, самый простой для понимания.

Непонятно, почему вы закомментировали этот раздел:

# self.model.add(Flatten())
# self.model.add(Dense(64))
# self.model.add(Activation('relu'))

Что может дать вам необходимую форму вывода?

1
Stewart_R 6 Июл 2019 в 08:11

Вам необходимо раскомментировать слой Flatten при создании модели. По сути, этот слой делает то, что он принимает четырехмерный вход (batch_size, height, width, num_filters) и разворачивает его в двухмерный (batch_size, height * width * num_filters). Это необходимо, чтобы получить желаемую выходную форму.

2
Djib2011 6 Июл 2019 в 08:00

Используйте model.summary(), чтобы проверить выходные формы вашей модели. Без закомментированного слоя Flatten () формы ваших слоев сохраняют исходные размеры изображения, а форма выходного слоя - (None, 6, 6, 10).

Что вы хотите сделать здесь примерно:

  1. начать с формы (batch_size, img width, img heigh, channel)
  2. использовать свертки, чтобы обнаружить шаблоны через изображение, применяя фильтр
  3. уменьшить ширину и высоту изображения с максимальным объединением
  4. затем Flatten () размеры изображения, так что вместо (ширина, высота, элементы) вы получите только набор элементов.
  5. сопоставить с вашими классами.

Закомментированный код выполняет шаг 4; Когда вы удаляете слой Flatten (), вы получаете неправильный набор размеров в конце.

1
Pedro Marques 6 Июл 2019 в 08:06

Снимите комментарий с выравнивающего слоя перед вашим выходным слоем в create_model(self), слои конвоя не будут работать с одномерными тензорами / массивами, и поэтому вы получите выходной слой правильной формы, добавив Flatten() слой прямо перед выходным слоем, вот так:

def create_model(self):
        '''
        Creating the ConvNet model.
        '''
        self.model = Sequential()
        self.model.add(Conv2D(64, (3, 3), input_shape=self.training_images.shape[1:]), activation='relu')
        #self.model.add(Activation("relu"))
        self.model.add(MaxPooling2D(pool_size=(2,2)))

        self.model.add(Conv2D(64, (3,3), activation='relu'))
        #self.model.add(Activation("relu"))
        self.model.add(MaxPooling2D(pool_size=(2,2)))

        # self.model.add(Dense(64))
        # self.model.add(Activation('relu'))
        self.model.add(Flatten())

        self.model.add(Dense(10, activation='softmax'))
        #self.model.add(Activation(activation='softmax'))

        self.model.compile(loss="categorical_crossentropy", optimizer="adam", 
                           metrics=['accuracy'])

        print ('model output shape:', self.model.output_shape)#prints out the output shape of your model

Приведенный выше код даст вам модель с выходной формой (None, 10).

Также, пожалуйста, используйте активацию в качестве параметра слоя в будущем.

1
BPDESILVA 6 Июл 2019 в 09:01