Подробное объяснение и практическое применение алгоритма классификации с несколькими метками (Keras)

искусственный интеллект

содержание

Многоуровневая классификация

Как использовать многоуровневую классификацию

Примеры использования нескольких ярлыков

тренироваться

Импорт библиотеки, установка гиперпараметров

Установить глобальные параметры

Создавайте мультиклассовые этикетки

Разделить набор для обучения и набор для проверки

увеличение данных

установить функцию обратного вызова

Настроить модель

Обучите модель и сохраните окончательную модель

распечатать журнал тренировок

Полный код:

контрольная работа


Многоуровневая классификация

Проблема классификации с несколькими метками: классификация с несколькими метками (или классификация с несколькими метками) означает, что образец имеет более одной метки, то есть образец соответствует нескольким меткам.

Как использовать многоуровневую классификацию

При прогнозировании проблемы классификации с несколькими метками, предполагая, что выходные данные скрытого слоя равны [-1.0, 5.0, -0.5, 5.0, -0.5], если используется функция softmax, то выходные данные будут следующими:

z = np.array([-1.0, 5.0, -0.5, 5.0, -0.5])print(Softmax_sim(z)) # 输出为 [ 0.00123281  0.49735104  0.00203256  0.49735104  0.00203256] 

Используя softmax, мы можем четко выбрать метку 2 и метку 4. Но мы должны знать, сколько меток нужно каждой выборке, или выбрать порог вероятности. Это явно не то, что нам нужно, поскольку вероятность того, что выборка принадлежит каждой метке, должна быть независимой.

Для задачи бинарной классификации обычно используемой функцией активации является сигмовидная функция:


ps: Причина, по которой сигмоидальная функция долгое время использовалась как функция активации нейронной сети (сейчас все в основном используют Relu), заключается в том, что производная сигмоидной функции легко вычисляется и может быть выражена сама по себе:


Код Python:

import numpy as np

def Sigmoid_sim(x):
    return  1 /(1+np.exp(-x))

a = np.array([-1.0, 5.0, -0.5, 5.0, -0.5])
print(Sigmoid_sim(a))
#输出为: [ 0.26894142  0.99330715  0.37754067  0.99330715  0.37754067]

 

На данный момент вероятность каждой метки независима. После того, как вся модель построена, самым важным последним шагом является выбор функции потерь для компиляции модели. В классификации с несколькими метками в основном используется функция потерь binary_crossentropy вместо функции потерь categorical_crossentropy, обычно используемой в классификации с несколькими классами. Это может показаться неразумным, но поскольку каждый выходной узел независим, выбирается двоичная потеря, а выход сети моделируется как распределение Бернулли, независимое от каждой метки. Модель для всей многоуровневой классификации:

from keras.models import Model
from keras.layers import Input,Dense

inputs = Input(shape=(10,))
hidden = Dense(units=10,activation='relu')(inputs)
output = Dense(units=5,activation='sigmoid')(hidden)
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

 

多标签使用实例

Мы используем наиболее часто используемый набор данных об одежде для достижения классификации с несколькими метками, а сетевая модель использует ResNet50.

Адрес набора данных: ссылка:disk.baidu.com/is/1EA NX TN WL…

Код извлечения: jo4h

Наш набор данных состоит из5547составлено из картинок из12 Различные виды,включают:

  • black_dress (333 изображения)
  • black_jeans (344 изображения)
  • black_shirt (436 изображений)
  • black_shoe (534 изображения)
  • blue_dress (386 изображений)
  • blue_jeans (356 изображений)
  • blue_shirt (369 изображений)
  • red_dress (384 изображения)
  • red_shirt (332 изображения)
  • red_shoe (486 изображений)
  • white_bag (747 изображений)
  • white_shoe (840 изображений)

Цель нашей сверточной нейронной сети — одновременно предсказывать цвет и категорию одежды. Код написан с использованием Tensorflow 2.0 и выше. Ниже приводится объяснение кода, в котором я реализовал алгоритм:

тренироваться

Импорт библиотеки, установка гиперпараметров

# import the necessary packages

from sklearn.preprocessing import MultiLabelBinarizer
from sklearn.model_selection import train_test_split
from imutils import paths
import tensorflow as tf
import numpy as np
import argparse
import random
import pickle
import cv2
import os
from tensorflow.python.keras.applications.resnet import ResNet50
from tensorflow.keras.optimizers import Adam
from tensorflow.python.keras.callbacks import ModelCheckpoint, ReduceLROnPlateau
from tensorflow.python.keras.preprocessing.image import ImageDataGenerator, img_to_array

# construct the argument parse and parse the arguments

ap = argparse.ArgumentParser()
ap.add_argument("-d", "--dataset", default='../dataset',
                help="path to input dataset (i.e., directory of images)")
ap.add_argument("-m", "--model", default='model.h5',
                help="path to output model")
ap.add_argument("-l", "--labelbin", default='labelbin',
                help="path to output label binarizer")
ap.add_argument("-p", "--plot", type=str, default="plot.png",
                help="path to output accuracy/loss plot")
args = vars(ap.parse_args())

Объяснение гиперпараметров:

  • --dataset: путь к входному набору данных.
  • --model: путь к выходной модели последовательности Keras.
  • --labelbin: путь к бинаризованному объекту для вывода нескольких тегов.
  • --plot: Выходные потери при обучении и правильный путь изображения скорости.

Установить глобальные параметры

EPOCHS = 150

INIT_LR = 1e-3

BS = 16

IMAGE_DIMS = (224, 224, 3)

Скачать данные

print("[INFO] loading images...")

imagePaths = sorted(list(paths.list_images(args["dataset"])))

random.seed(42)

random.shuffle(imagePaths)

# initialize the data and labels

data = []

labels = []

# loop over the input images

for imagePath in imagePaths:

    # load the image, pre-process it, and store it in the data list

    image = cv2.imread(imagePath)

    image = cv2.resize(image, (IMAGE_DIMS[1], IMAGE_DIMS[0]))

    image = img_to_array(image)

    data.append(image)

    # extract set of class labels from the image path and update the

    # labels list

    l = label = imagePath.split(os.path.sep)[-2].split("_")

    labels.append(l)

# scale the raw pixel intensities to the range [0, 1]

data = np.array(data, dtype="float") / 255.0

labels = np.array(labels)

print(labels)

результат операции:

[['red' 'shirt']
['black' 'jeans']
['black' 'shoe']
...
['black' 'dress']
['black' 'shirt']
['white' 'shoe']]

Создавайте мультиклассовые этикетки

print("[INFO] class labels:")

mlb = MultiLabelBinarizer()

labels = mlb.fit_transform(labels)

# loop over each of the possible class labels and show them

for (i, label) in enumerate(mlb.classes_):

print("{}. {}".format(i + 1, label))

print(labels)

Код метки можно получить через подбор MultiLabelBinarizer(). Распечатываем категории и сгенерированные ярлыки. Результаты категорий следующие:

[INFO] class labels:
1. bag
2. black
3. blue
4. dress
5. jeans
6. red
7. shirt
8. shoe
9. white

Вывод лейблов следующий:

[[0 0 0 ... 1 0 0]
[0 1 0 ... 0 0 0]
[0 1 0 ... 0 1 0]
...
[0 1 0 ... 0 0 0]
[0 1 0 ... 1 0 0]
[0 0 0 ... 0 1 1]]

 

Чтобы всем было легче понять этикетки, я использую следующую таблицу для объяснения

  Bag Black Blue Dress Jeans Red Shirt Shoe White
['Красная рубашка'] 0 0 0 0 0 1 1 0 0
['черные' 'джинсы'] 0 1 0 0 1 0 0 0 0
 ['white' 'shoe'] 0 0 0 0 0 0 0 1 1

Затем сохраните модель, обученную MultiLabelBinarizer(), для удобства тестирования. код показывает, как показано ниже:

print("[INFO] serializing label binarizer...")

f = open(args["labelbin"], "wb")

f.write(pickle.dumps(mlb))

f.close()

Разделить набор для обучения и набор для проверки

(trainX, testX, trainY, testY) = train_test_split(data,

                                                  labels, test_size=0.2, random_state=42)

увеличение данных

# construct the image generator for data augmentation

aug = ImageDataGenerator(rotation_range=25, width_shift_range=0.1,

                         height_shift_range=0.1, shear_range=0.2, zoom_range=0.2,

                         horizontal_flip=True, fill_mode="nearest")

установить функцию обратного вызова

checkpointer = ModelCheckpoint(filepath='weights_best_Reset50_model.hdf5',

                               monitor='val_accuracy', verbose=1, save_best_only=True, mode='max')

 

reduce = ReduceLROnPlateau(monitor='val_accuracy', patience=10,

                           verbose=1,

                           factor=0.5,

                           min_lr=1e-6)

Роль контрольной точки состоит в том, чтобы сохранить лучшую обученную модель. уменьшить динамически регулирует скорость обучения.

Настроить модель

model = ResNet50(weights=None, classes=len(mlb.classes_))

optimizer = Adam(lr=INIT_LR)

model.compile(loss="binary_crossentropy", optimizer=optimizer,

              metrics=["accuracy"])

Обучите модель и сохраните окончательную модель

print("[INFO] training network...")

history = model.fit(

    x=aug.flow(trainX, trainY, batch_size=BS),

    validation_data=(testX, testY),

    steps_per_epoch=len(trainX) // BS,

epochs=EPOCHS, callbacks=[checkpointer, reduce], verbose=1)

# save the model to disk

print("[INFO] serializing network...")

model.save(args["model"], save_format="h5")

распечатать журнал тренировок

# plot the training loss and accuracy

loss_trend_graph_path = r"WW_loss.jpg"

acc_trend_graph_path = r"WW_acc.jpg"

import matplotlib.pyplot as plt

 

print("Now,we start drawing the loss and acc trends graph...")

# summarize history for accuracy

fig = plt.figure(1)

plt.plot(history.history["accuracy"])

plt.plot(history.history["val_accuracy"])

plt.title("Model accuracy")

plt.ylabel("accuracy")

plt.xlabel("epoch")

plt.legend(["train", "test"], loc="upper left")

plt.savefig(acc_trend_graph_path)

plt.close(1)

# summarize history for loss

fig = plt.figure(2)

plt.plot(history.history["loss"])

plt.plot(history.history["val_loss"])

plt.title("Model loss")

plt.ylabel("loss")

plt.xlabel("epoch")

plt.legend(["train", "test"], loc="upper left")

plt.savefig(loss_trend_graph_path)

plt.close(2)

print("We are done, everything seems OK...")

Полный код:

# import the necessary packages

from sklearn.preprocessing import MultiLabelBinarizer
from sklearn.model_selection import train_test_split
from imutils import paths
import tensorflow as tf
import numpy as np
import argparse
import random
import pickle
import cv2
import os
from tensorflow.python.keras.applications.resnet import ResNet50
from tensorflow.keras.optimizers import Adam
from tensorflow.python.keras.callbacks import ModelCheckpoint, ReduceLROnPlateau
from tensorflow.python.keras.preprocessing.image import ImageDataGenerator, img_to_array

# construct the argument parse and parse the arguments

ap = argparse.ArgumentParser()
ap.add_argument("-d", "--dataset", default='../dataset',
                help="path to input dataset (i.e., directory of images)")
ap.add_argument("-m", "--model", default='model.h5',
                help="path to output model")
ap.add_argument("-l", "--labelbin", default='labelbin',
                help="path to output label binarizer")
ap.add_argument("-p", "--plot", type=str, default="plot.png",
                help="path to output accuracy/loss plot")
args = vars(ap.parse_args())

# initialize the number of epochs to train for, initial learning rate,
# batch size, and image dimensions
EPOCHS = 150
INIT_LR = 1e-3
BS = 16
IMAGE_DIMS = (224, 224, 3)
# disable eager execution
tf.compat.v1.disable_eager_execution()
# grab the image paths and randomly shuffle them
print("[INFO] loading images...")
imagePaths = sorted(list(paths.list_images(args["dataset"])))
random.seed(42)
random.shuffle(imagePaths)
# initialize the data and labels
data = []
labels = []
# loop over the input images
for imagePath in imagePaths:
    # load the image, pre-process it, and store it in the data list
    image = cv2.imread(imagePath)
    image = cv2.resize(image, (IMAGE_DIMS[1], IMAGE_DIMS[0]))
    image = img_to_array(image)
    data.append(image)
    # extract set of class labels from the image path and update the
    # labels list
    l = label = imagePath.split(os.path.sep)[-2].split("_")
    labels.append(l)
# scale the raw pixel intensities to the range [0, 1]
data = np.array(data, dtype="float") / 255.0
labels = np.array(labels)
print("[INFO] data matrix: {} images ({:.2f}MB)".format(
    len(imagePaths), data.nbytes / (1024 * 1000.0)))
# binarize the labels using scikit-learn's special multi-label
# binarizer implementation
print("[INFO] class labels:")
mlb = MultiLabelBinarizer()
labels = mlb.fit_transform(labels)
# loop over each of the possible class labels and show them
for (i, label) in enumerate(mlb.classes_):
    print("{}. {}".format(i + 1, label))
print(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.2, random_state=42)
print("[INFO] serializing label binarizer...")
f = open(args["labelbin"], "wb")
f.write(pickle.dumps(mlb))
f.close()
# construct the image generator for data augmentation
aug = ImageDataGenerator(rotation_range=25, width_shift_range=0.1,
                         height_shift_range=0.1, shear_range=0.2, zoom_range=0.2,
                         horizontal_flip=True, fill_mode="nearest")

checkpointer = ModelCheckpoint(filepath='weights_best_Reset50_model.hdf5',
                               monitor='val_accuracy', verbose=1, save_best_only=True, mode='max')

reduce = ReduceLROnPlateau(monitor='val_accuracy', patience=10,
                           verbose=1,
                           factor=0.5,
                           min_lr=1e-6)
model = ResNet50(weights=None, classes=len(mlb.classes_))
optimizer = Adam(lr=INIT_LR)
model.compile(loss="binary_crossentropy", optimizer=optimizer,
              metrics=["accuracy"])
# train the network
print("[INFO] training network...")
history = model.fit(
    x=aug.flow(trainX, trainY, batch_size=BS),
    validation_data=(testX, testY),
    steps_per_epoch=len(trainX) // BS,
    epochs=EPOCHS, callbacks=[checkpointer, reduce], verbose=1)
# save the model to disk
print("[INFO] serializing network...")
model.save(args["model"], save_format="h5")
# save the multi-label binarizer to disk

# plot the training loss and accuracy
loss_trend_graph_path = r"WW_loss.jpg"
acc_trend_graph_path = r"WW_acc.jpg"
import matplotlib.pyplot as plt

print("Now,we start drawing the loss and acc trends graph...")
# summarize history for accuracy
fig = plt.figure(1)
plt.plot(history.history["accuracy"])
plt.plot(history.history["val_accuracy"])
plt.title("Model accuracy")
plt.ylabel("accuracy")
plt.xlabel("epoch")
plt.legend(["train", "test"], loc="upper left")
plt.savefig(acc_trend_graph_path)
plt.close(1)
# summarize history for loss
fig = plt.figure(2)
plt.plot(history.history["loss"])
plt.plot(history.history["val_loss"])
plt.title("Model loss")
plt.ylabel("loss")
plt.xlabel("epoch")
plt.legend(["train", "test"], loc="upper left")
plt.savefig(loss_trend_graph_path)
plt.close(2)
print("We are done, everything seems OK...")

контрольная работа

# import the necessary packages
from tensorflow.keras.preprocessing.image import img_to_array
from tensorflow.keras.models import load_model
import numpy as np
import argparse
import imutils
import pickle
import cv2
import os
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-m", "--model", default='weights_best_Reset50_model.hdf5',
	help="path to trained model model")
ap.add_argument("-l", "--labelbin", default='labelbin',
	help="path to label binarizer")
ap.add_argument("-i", "--image", default='../dataset/0.jpg',
	help="path to input image")
args = vars(ap.parse_args())
# load the image
image = cv2.imread(args["image"])
output = imutils.resize(image, width=400)

# pre-process the image for classification
image = cv2.resize(image, (224, 224))
image = image.astype("float") / 255.0
image = img_to_array(image)
image = np.expand_dims(image, axis=0)
# load the trained convolutional neural network and the multi-label
# binarizer
print("[INFO] loading network...")
model = load_model(args["model"])
mlb = pickle.loads(open(args["labelbin"], "rb").read())
# classify the input image then find the indexes of the two class
# labels with the *largest* probability
print("[INFO] classifying image...")
proba = model.predict(image)[0]
idxs = np.argsort(proba)[::-1][:2]
# loop over the indexes of the high confidence class labels
for (i, j) in enumerate(idxs):
	# build the label and draw the label on the image
	label = "{}: {:.2f}%".format(mlb.classes_[j], proba[j] * 100)
	cv2.putText(output, label, (10, (i * 30) + 25),
		cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
# show the probabilities for each of the individual labels
for (label, p) in zip(mlb.classes_, proba):
	print("{}: {:.2f}%".format(label, p * 100))
# show the output image
cv2.imshow("Output", output)
cv2.waitKey(0)

参考文章:

 

keras решает проблему классификации с несколькими метками

blog.CSDN.net/так каждый день/искусство…

Multi-label classification with Keras

woohoo.py изображение search.com/2018/05/07/…