В качестве простейшей иллюстрации рассмотрим классификацию датасета MNIST двумя подходами, и. заодно, познакомимся с двумя инструментами.
Датасет MNIST представляет собой набор из 70000 изображений рукописных цифр от 0 до 9, который делится на 60000 обучающих изображений и 10000 тестовых. Подробное его описание и он сам доступены по адресу https://www.openml.org/d/554.
Цифры были нормализованы по размеру и центрированы на изображении фиксированного размера. Исходные черно-белые изображения из NIST были нормализованы по размеру, чтобы поместиться в поле размером 20×20 пикселей при сохранении их соотношения сторон. После нормализации изображения сглажены, вследствие чего содержат уровни серого. Полученные изображения центрированы в поле 28×28 путем вычисления центра масс пикселей и перемещения изображения таким образом, чтобы расположить эту точку в центре.
Когда-то этот датасет был одним из соревновательных датасетов для научных исследований в области классификации изображений, однако, на данный момент современными средствами и методами точность классификации приблизилась к 100%, а датасет получил роль учебного и является хорошей базой для первых шагов в машинном обучении.
Одним из наиболее известных фреймворков для машинного обучения с использованием классических методов является scikit-learn.
Загрузка датасета
Так как решение любой задачи машинного обучения начинается с датасета (в случае с кластеризацией его размечать нет необходимости, так как это обучение без учителя).
Scikit-learn содержит несколько датасетов, однако, выбранного нами, mnist в их числе нет, поэтому воспользуемся другим его инструментом — загрузчиком из репозитория openml.
from sklearn.datasets import fetch_openml
# Загружаем данные из https://www.openml.org/d/554
X, y = fetch_openml('mnist_784', version=1, return_X_y=True)
Загруженный датасет содержит в одном массиве и обучающие и тестовые данные, потому необходимо их разделить.
В 3-й строке производится разделение датасетана обучающую часть размером 60000 элементов и тестовую размером 10000 элементов.
в 4 и 5 строках из-за особенностей представления лейблов в датасете (они предствлены текстовым значением) производим преобразование к целочисленному типу.
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=60000, test_size=10000)
y_train = y_train.astype(int)
y_test = y_test.astype(int)
print("Train shape:", X_train.shape)
print("Test shape:", X_test.shape)
Для проверки получим изображения нескольких цифр, используемых для обучения:
В 6й строке для вывода изображение производится преобразование вектора значений в массив 28×28. Подобные преобразования (в обе строны) достаточно часто встречаются при работе с датасетами.
import matplotlib.pyplot as plt
for i in range(5):
plt.subplot(2, 5, i + 1)
plt.axis('off')
plt.imshow(X_train[i].reshape(28,28), cmap=plt.cm.gray_r, interpolation='nearest')
plt.title('Training: {}'.format(y_train[i]))
Так как датасет содержит уже предобработанные и нормализованные изображения, эти шаги можно пропустить и перейти непосредственно к классификатору.
Обучение классификатора
В качестве примера воспользуемся методом опорных векторов. Не будем вдаваться в подробности метода, т.к. это заслуживает отдельной статьи, однако если кратко, то метод опорных векторов пытается найти такую функцию которая разделит данные на классы, в том числе с использование отражения данных в пространство с более высокой размерностью.
Вообще говоря, при создании классификатора есть достаточно большое количество параметров, которые являются гиперпараметрами и должны настраиваться исследователем, что несколько затрудняет задачу, однако оставим их подбор на совести читателя и воспользуемся значениями по умолчанию.
Подробности о классификаторе SVC в составе scikit-learn в мануале. Из-за того, что рассматриваемый датасет слишком велик для метода SVC, используем его модификацию с помощью метода стохастического градиентного спуска SGDClassifier, который по умолчанию использует метод опорных векторов.
В рассматриваемом коде используются параметры по умолчанию, вы же можете попробовать улучшить результат путем изменения гиперпараметров.
from sklearn import linear_model
# Создадим классификатор: метод опорных векторов
classifier = linear_model.SGDClassifier(loss='hinge',
penalty='l2',
alpha=0.0001,
l1_ratio=0.15,
fit_intercept=True,
max_iter=1000,
tol=0.001,
shuffle=True,
verbose=0,
epsilon=0.1,
n_jobs=None,
random_state=None,
learning_rate='optimal',
eta0=0.0,
power_t=0.5,
early_stopping=False,
validation_fraction=0.1,
n_iter_no_change=5,
class_weight=None,
warm_start=False,
average=False)
# Обучим классификатор
classifier.fit(X_train, y_train)
Когда процесс обучения закончится (а в некоторых случаях он может быть достаточно длительным) выполним визуализацию и проверку на тестовых данных. Для этого воспользуемся confusion matrix — которые являются одним из мощнейших инструментов визуализации и анализа качества многоклассовых классификаторов.
Визуализация результатов обучения
Используемая библиотека не содержит штатных методов грфического вывода confusion matrix, однако воспользуемся реализацией из примера
from sklearn.metrics import confusion_matrix
from sklearn.utils.multiclass import unique_labels
def plot_confusion_matrix(y_true, y_pred, classes,
normalize=False,
title=None,
cmap=plt.cm.Blues):
"""
This function prints and plots the confusion matrix.
Normalization can be applied by setting `normalize=True`.
"""
if not title:
if normalize:
title = 'Normalized confusion matrix'
else:
title = 'Confusion matrix, without normalization'
# Compute confusion matrix
cm = confusion_matrix(y_true, y_pred)
# Only use the labels that appear in the data
classes = classes[unique_labels(y_true, y_pred)]
if normalize:
cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
print("Normalized confusion matrix")
else:
print('Confusion matrix, without normalization')
print(cm)
fig, ax = plt.subplots()
im = ax.imshow(cm, interpolation='nearest', cmap=cmap)
ax.figure.colorbar(im, ax=ax)
# We want to show all ticks...
ax.set(xticks=np.arange(cm.shape[1]),
yticks=np.arange(cm.shape[0]),
# ... and label them with the respective list entries
xticklabels=classes, yticklabels=classes,
title=title,
ylabel='True label',
xlabel='Predicted label')
# Rotate the tick labels and set their alignment.
plt.setp(ax.get_xticklabels(), rotation=45, ha="right",
rotation_mode="anchor")
# Loop over data dimensions and create text annotations.
fmt = '.2f' if normalize else 'd'
thresh = cm.max() / 2.
for i in range(cm.shape[0]):
for j in range(cm.shape[1]):
ax.text(j, i, format(cm[i, j], fmt),
ha="center", va="center",
color="white" if cm[i, j] > thresh else "black")
fig.tight_layout()
return ax
Далее для удобства созданим вектора ожидаемых и предсказанных значений. Для получения предсказания классификатор нужно возпользоваться методом predict объекта обученного классификатора.
expected = y_test
predicted = classifier.predict(X_test)
Теперь, после того, как получены ожидаемые и предсказанные значения, построим confusion matrix.
import numpy as np
class_names = np.array(["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"])
# Plot non-normalized confusion matrix
plot_confusion_matrix(expected, predicted, classes=class_names,
title='Confusion matrix, without normalization')
Несмотря на то, что для идеального классификатора эта матрица является диагональной, в нашем случае наблюдаются выбросы ложных срабатываний, что говорит о «не идеальности» классификатора.
На основе этого примера, должно быть понятно, как использовать классические методы из библиотеки. Вы можете попробовать обучить классификатор самостоятельно, а также попробовать поработать с другими датасетами.
Уведомление: Компьютерное зрение. Введение | Digiratory
Уведомление: Компьютерное зрение. Машиное обучение с использовнием нейронных сетей (Keras) | Digiratory