Компьютерное зрение. Машинное обучение без нейронных сетей (scikit-learn)

В качестве простейшей иллюстрации рассмотрим классификацию датасета 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')

Несмотря на то, что для идеального классификатора эта матрица является диагональной, в нашем случае наблюдаются выбросы ложных срабатываний, что говорит о «не идеальности» классификатора.

На основе этого примера, должно быть понятно, как использовать классические методы из библиотеки. Вы можете попробовать обучить классификатор самостоятельно, а также попробовать поработать с другими датасетами.

Colaboratory Jupiter Notebook

Компьютерное зрение. Машинное обучение без нейронных сетей (scikit-learn): 2 комментария

  1. Уведомление: Компьютерное зрение. Введение | Digiratory

  2. Уведомление: Компьютерное зрение. Машиное обучение с использовнием нейронных сетей (Keras) | Digiratory

Добавить комментарий