首页 文章

ValueError:检查目标时出错:预期activation_6有形状(None,2)但得到形状的数组(5760,1)

提问于
浏览
0

我正在尝试使用8个类来适应卷积神经网络(在Keras中)的Python代码来处理2个类 . 我的问题是我收到以下错误消息:

ValueError:检查目标时出错:预期activation_6具有形状(None,2)但是具有形状的数组(5760,1) .

我的模型如下(没有缩进问题):

class MiniVGGNet:
    @staticmethod
    def build(width, height, depth, classes):
    # initialize the model along with the input shape to be
    # "channels last" and the channels dimension itself
    model = Sequential()
    inputShape = (height, width, depth)
    chanDim = -1

    # if we are using "channels first", update the input shape
    # and channels dimension
    if K.image_data_format() == "channels_first":
        inputShape = (depth, height, width)
        chanDim = 1

    # first CONV => RELU => CONV => RELU => POOL layer set
    model.add(Conv2D(32, (3, 3), padding="same",
        input_shape=inputShape))
    model.add(Activation("relu"))
    model.add(BatchNormalization(axis=chanDim))
    model.add(Conv2D(32, (3, 3), padding="same"))
    model.add(Activation("relu"))
    model.add(BatchNormalization(axis=chanDim))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Dropout(0.25))

    # second CONV => RELU => CONV => RELU => POOL layer set
    model.add(Conv2D(64, (3, 3), padding="same"))
    model.add(Activation("relu"))
    model.add(BatchNormalization(axis=chanDim))
    model.add(Conv2D(64, (3, 3), padding="same"))
    model.add(Activation("relu"))
    model.add(BatchNormalization(axis=chanDim))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Dropout(0.25))

    # first (and only) set of FC => RELU layers
    model.add(Flatten())
    model.add(Dense(512))
    model.add(Activation("relu"))
    model.add(BatchNormalization())
    model.add(Dropout(0.5))

    # softmax classifier
    model.add(Dense(classes))
    model.add(Activation("softmax"))

    # return the constructed network architecture
    return model

其中classes = 2,inputShape =(32,32,3) .

我知道我的错误与我的类/使用binary_crossentropy有关,并且发生在下面的model.fit行中,但是无法弄清楚它为什么有问题,或者如何修复它 .

通过将上面的model.add(Dense(classes))更改为model.add(Dense(classes-1)),我可以获得要训练的模型,但是我的标签大小和target_names不匹配,我只有一个类别,一切被归类为 .

# import the necessary packages
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from pyimagesearch.nn.conv import MiniVGGNet
from pyimagesearch.preprocessing import ImageToArrayPreprocessor
from pyimagesearch.preprocessing import SimplePreprocessor
from pyimagesearch.datasets import SimpleDatasetLoader
from keras.optimizers import SGD
#from keras.datasets import cifar10
from imutils import paths
import matplotlib.pyplot as plt
import numpy as np
import argparse

# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-d", "--dataset", required=True,
    help="path to input dataset")
ap.add_argument("-o", "--output", required=True,
    help="path to the output loss/accuracy plot")
args = vars(ap.parse_args())

# grab the list of images that we'll be describing
print("[INFO] loading images...")
imagePaths = list(paths.list_images(args["dataset"]))

# initialize the image preprocessors
sp = SimplePreprocessor(32, 32)
iap = ImageToArrayPreprocessor()

# load the dataset from disk then scale the raw pixel intensities
# to the range [0, 1]
sdl = SimpleDatasetLoader(preprocessors=[sp, iap])
(data, labels) = sdl.load(imagePaths, verbose=500)
data = data.astype("float") / 255.0

# partition the data into training and testing splits using 75% of
# the data for training and the remaining 25% for testing
(trainX, testX, trainY, testY) = train_test_split(data, labels,
    test_size=0.25, random_state=42)

# convert the labels from integers to vectors
trainY = LabelBinarizer().fit_transform(trainY)
testY = LabelBinarizer().fit_transform(testY)

# initialize the label names for the items dataset
labelNames = ["mint", "used"]

# initialize the optimizer and model
print("[INFO] compiling model...")
opt = SGD(lr=0.01, decay=0.01 / 10, momentum=0.9, nesterov=True)
model = MiniVGGNet.build(width=32, height=32, depth=3, classes=2)
model.compile(loss="binary_crossentropy", optimizer=opt,
    metrics=["accuracy"])

# train the network
print("[INFO] training network...")
H = model.fit(trainX, trainY, validation_data=(testX, testY),
    batch_size=64, epochs=10, verbose=1)
print ("Made it past training")

# evaluate the network
print("[INFO] evaluating network...")
predictions = model.predict(testX, batch_size=64)
print(classification_report(testY.argmax(axis=1),
    predictions.argmax(axis=1), target_names=labelNames))

# plot the training loss and accuracy
plt.style.use("ggplot")
plt.figure()
plt.plot(np.arange(0, 10), H.history["loss"], label="train_loss")
plt.plot(np.arange(0, 10), H.history["val_loss"], label="val_loss")
plt.plot(np.arange(0, 10), H.history["acc"], label="train_acc")
plt.plot(np.arange(0, 10), H.history["val_acc"], label="val_acc")
plt.title("Training Loss and Accuracy on items dataset")
plt.xlabel("Epoch #")
plt.ylabel("Loss/Accuracy")
plt.legend()
plt.savefig(args["output"])

我已经看过这些问题,但无法根据回答来解决这个问题 .

Stackoverflow Question 1

Stackoverflow Question 2

Stackoverflow Question 3

我会非常感谢任何建议或帮助,因为我花了最近几天的时间 .

2 回答

  • 0

    我认为问题在于使用 LabelBinarizer .

    从这个例子:

    >>> lb = preprocessing.LabelBinarizer()
    >>> lb.fit_transform(['yes', 'no', 'no', 'yes'])
    array([[1],
           [0],
           [0],
           [1]])
    

    我认为你的转换输出具有相同的格式,i . 即单个 10 编码"is new"或"is used" .

    如果你的问题只是要求在这两个类之间进行分类,那么这种格式是可取的,因为它包含所有信息并且使用的空间比替代方案少,i . 即 [1,0], [0,1], [0,1], [1,0] .

    因此,使用 classes = 1 是正确的,输出应该是一个浮点数,表示网络对第一类中的样本的置信度 . 由于这些值必须总和为1,因此通过从1减去可以很容易地推断出它在第二类中的概率 .

    您需要将 softmax 替换为任何其他激活,因为单个值上的softmax始终返回1.我不完全确定具有单值结果的 binary_crossentropy 的行为,并且您可能想要尝试 mean_squared_error 作为丢失 .

    如果您希望扩展模型以涵盖两个以上的类,则需要将目标矢量转换为One-hot编码 . 我相信来自 LabelBinarizerinverse_transform 会做到这一点,尽管那似乎是一种相当迂回的方式来实现目标 . 我看到sklearn也有 OneHotEncoder ,这可能是更合适的替代品 .

    注意:您可以更轻松地为任何图层指定激活功能,例如:

    Dense(36, activation='relu')
    

    这可能有助于将代码保持在可管理的大小 .

  • 1

    Matt的评论是完全正确的,因为问题在于使用LabelBinarizer,这个提示让我得到了一个解决方案,它不需要我放弃使用softmax,或者更改最后一层以使class = 1.对于后代和其他人来说,这里是我改变的代码部分以及我如何能够避免LabelBinarizer:

    from keras.utils import np_utils
    from sklearn.preprocessing import LabelEncoder    
    
    # load the dataset from disk then scale the raw pixel intensities
    # to the range [0,1]
    sp = SimplePreprocessor (32, 32)
    iap = ImageToArrayPreprocessor()
    
    # encode the labels, converting them from strings to integers
    le=LabelEncoder()
    labels = le.fit_transform(labels)
    
    data = data.astype("float") / 255.0
    labels = np_utils.to_categorical(labels,2)
    
    # partition the data into training and testing splits using 75% of
    # the data for training and the remaining 25% for testing
    ....
    

相关问题