【问题标题】:Target array shape different to expected output using Tensorflow使用 Tensorflow 的目标数组形状与预期输出不同
【发布时间】:2019-11-16 15:01:45
【问题描述】:

我正在尝试制作一个 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()

不胜感激,已尝试修复一个小时。

【问题讨论】:

    标签: python tensorflow keras


    【解决方案1】:

    您需要在创建模型时取消Flatten图层。基本上,这层图层所做的就是它需要一个4D输入(batch_size, height, width, num_filters)并将其展开到2D ONE (batch_size, height * width * num_filters)中。这是需要获得所需的输出形状。

    【讨论】:

      【解决方案2】:

      您必须使模型输出与标签的形状相同。

      也许最简单的解决方案是确保模型以这些层结束:

      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'))
      

      这似乎可以为您提供所需的输出形状?

      【讨论】:

        【解决方案3】:

        create_model(self) 的输出层之前取消注释flatten 层,conv 层不适用于一维张量/数组,因此您可以获得正确形状的输出层添加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)的模型。

        也请以后使用activation作为层参数。

        【讨论】:

          【解决方案4】:

          使用model.summary() 检查模型的输出形状。如果没有注释掉的 Flatten() 图层,图层的形状将保留图像的原始尺寸,输出图层的形状为 (None, 6, 6, 10)

          你这里要做的大致是:

          1. 以(batch_size、img 宽度、img 高度、通道)的形状开始
          2. 使用卷积通过过滤器检测图像中的模式
          3. 使用最大池化减少 img 的宽度和高度
          4. 然后 Flatten() 图像的尺寸,以便您最终得到一组特征而不是(宽度、高度、特征)。
          5. 与您的班级相匹配。

          注释掉的代码执行第 4 步;当你移除 Flatten() 层时,你最终会得到一组错误的尺寸。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-01-14
            • 1970-01-01
            • 2019-09-21
            • 2021-01-09
            • 2019-10-29
            • 2020-03-08
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多