将二进制分类转换为多标签?

时间:2020-06-15 13:08:04

标签: python image tensorflow classification

我正在尝试将我的二进制图像分类模型转换为多标签,并且NumPy数组显示错误 期望值二维值有人可以帮助我编辑 代码。

我尝试使用multilabelBinazier,但我很走运,这里有人可以帮助我吗?

errors#用法

# python train.py --dataset dataset

# import the necessary packages
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.applications import VGG16
from tensorflow.keras.layers import AveragePooling2D
from tensorflow.keras.layers import Dropout
from tensorflow.keras.layers import Flatten
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import Input
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.utils import to_categorical
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
from imutils import paths
import matplotlib.pyplot as plt
import numpy as np
import argparse
import cv2
import os

# construct the argument parser and parse the arguments

# initialize the initial learning rate, number of epochs to train for,
# and batch size
INIT_LR = 1e-3
EPOCHS = 40
BS = 66

# grab the list of images in our dataset directory, then initialize
# the list of data (i.e., images) and class images
print("[INFO] loading images...")
imagePaths = list(paths.list_images('/content/drive/My Drive/testset/'))
data = []
labels = []

# loop over the image paths
for imagePath in imagePaths:
    # extract the class label from the filename
    label = imagePath.split(os.path.sep)[-2]

    # load the image, swap color channels, and resize it to be a fixed
    # 224x224 pixels while ignoring aspect ratio
    image = cv2.imread(imagePath)
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    image = cv2.resize(image, (224, 224))

    # update the data and labels lists, respectively
    data.append(image)
    labels.append(label)

# convert the data and labels to NumPy arrays while scaling the pixel
# intensities to the range [0, 255]
data = np.array(data) / 255.0
labels = np.array(labels)

# perform one-hot encoding on the labels
lb = LabelBinarizer()
labels = lb.fit_transform(labels)
labels = to_categorical(labels)

# partition the data into training and testing splits using 80% of
# the data for training and the remaining 20% for testing
(trainX, testX, trainY, testY) = train_test_split(data, labels,
    test_size=0.20, stratify=labels, random_state=42)

# initialize the training data augmentation object
trainAug = ImageDataGenerator(
    rotation_range=15,
    fill_mode="nearest")

# load the VGG16 network, ensuring the head FC layer sets are left
# off
baseModel = VGG16(weights="imagenet", include_top=False,
    input_tensor=Input(shape=(224, 224, 3)))

# construct the head of the model that will be placed on top of the
# the base model
headModel = baseModel.output
headModel = AveragePooling2D(pool_size=(4, 4))(headModel)
headModel = Flatten(name="flatten")(headModel)
headModel = Dense(64, activation="relu")(headModel)
headModel = Dropout(0.5)(headModel)
headModel = Dense(2, activation="softmax")(headModel)

# place the head FC model on top of the base model (this will become
# the actual model we will train)
model = Model(inputs=baseModel.input, outputs=headModel)

# loop over all layers in the base model and freeze them so they will
# *not* be updated during the first training process
for layer in baseModel.layers:
    layer.trainable = False

# compile our model
print("[INFO] compiling model...")
opt = Adam(lr=INIT_LR, decay=INIT_LR / EPOCHS)
model.compile(loss="binary_crossentropy", optimizer=opt, metrics=["accuracy"])

# train the head of the network
print("[INFO] training head...")
H = model.fit(
    trainAug.flow(trainX, trainY, batch_size=BS),
    steps_per_epoch=len(trainX) // BS,
    validation_data=(testX, testY),
    validation_steps=len(testX) // BS,
    epochs=EPOCHS)

# make predictions on the testing set
print("[INFO] evaluating network...")
predIdxs = model.predict(testX, batch_size=BS)

# for each image in the testing set we need to find the index of the
# label with corresponding largest predicted probability
predIdxs = np.argmax(predIdxs, axis=1)

# show a nicely formatted classification report
print(classification_report(testY.argmax(axis=1), predIdxs,
    target_names=lb.classes_))

# compute the confusion matrix and and use it to derive the raw
# accuracy, sensitivity, and specificity
cm = confusion_matrix(testY.argmax(axis=1), predIdxs)
total = sum(sum(cm))
acc = (cm[0, 0] + cm[1, 1]) / total
sensitivity = cm[0, 0] / (cm[0, 0] + cm[0, 1])
specificity = cm[1, 1] / (cm[1, 0] + cm[1, 1])

# show the confusion matrix, accuracy, sensitivity, and specificity
print(cm)
print("acc: {:.4f}".format(acc))
print("sensitivity: {:.4f}".format(sensitivity))
print("specificity: {:.4f}".format(specificity))

# plot the training loss and accuracy
N = EPOCHS
plt.style.use("ggplot")
plt.figure()
plt.plot(np.arange(0, N), H.history["loss"], label="train_loss")
plt.plot(np.arange(0, N), H.history["val_loss"], label="val_loss")
plt.plot(np.arange(0, N), H.history["accuracy"], label="train_acc")
plt.plot(np.arange(0, N), H.history["val_accuracy"], label="val_acc")
plt.title("Training Loss and Accuracy on COVID-19 Dataset")
plt.xlabel("Epoch #")
plt.ylabel("Loss/Accuracy")
plt.legend(loc="lower left")
plt.savefig("plot.png")

# serialize the model to disk
print("[INFO] saving COVID-19 detector model...")
model.save('/content/drive/My Drive/setcovid/model.h5', )

3 个答案:

答案 0 :(得分:1)

取决于标签的预处理方式

有三点

1. 第一个:标签形状

观察标签形状。从您的代码中,我猜测您的标签形状必须像(5000,)这样的一维,您可以使用labels.shape看到它。 要使其成为二维,请使用

labels = np.expand_dims(labels,axis=1)


2. 第二个:最后一个致密层中的单元

您已经在最后dense层2中使用了单位数,因此基本上它是一个多类分类,其行为类似于二进制分类。我建议如果您要进行二进制分类,请在最后的dense层使用1个单位并激活softmax以外的其他位置。如果您的数据集具有3个或3个以上的类,请使用dense图层以及输出类的数量和softmax的激活。但在这种情况下,标签应为one hot encoded

3. 第三项:更改损失功能

如果您仍要使用2单位输出作为最后一个密集层。将损失函数从binary_crossentropy更改为categorical_crossentropy

答案 1 :(得分:0)

取决于您的TF版本,但是如果您的输入是生成器,则也许应该使用fit_generator(https://www.tensorflow.org/api_docs/python/tf/keras/Model#fit_generator)方法而不是model.fit。

还要检查前面提到的答案

答案 2 :(得分:0)

我认为您错了

  1. 将numpy数组列表转换为单个numpy数组,您可以使用

    data = np.stack( data, axis=0 )/255

    data = np.concatenate( data, axis=0 )#它会返回形状(bath_size,dim_height * dim_width,通道),然后对数据进行整形

    data.reshape(bath_size, dim_height, dim_width, channel)

    data = np.vstack(data)/255.0

    another answer

  2. 使用lb.fit_transform(labels)后,您无需使用to_categorical(labels)

  3. 不清楚,您想要什么,多标签或多类别?这是不同的。如果要更改为多标签的情况,binary_crossentropy是解决方案之一。但是您会混淆准确性(默认)作为度量标准,这在多标签中是错误的,您可以将准确性计算用于多标签分类。并且不要在最终激活输出中使用softmax,请使用Sigmoid。或者,如果其多类标签的标签是一种热编码,则将损失更改为categorical_crossentropy;如果标签上的标签不是数字,则将损失更改为sparse_categorical_crossentropy。

  4. 如果以前对其进行过二进制图像分类,则输出模型必须为1(1或0)而不是2

希望这个答案成为您的解决方案