Этот проект состоит из реализации алгоритма кластеризации в распределенной среде и отображения результатов в блокноте Python. В частности, я использовал очень популярный набор данных MNIST в Apache Spark, используя библиотеку машинного обучения MLlib.

Apache Spark позволяет использовать массивные наборы данных в нескольких кластерах, но для простоты я просто буду использовать стандартный MNIST вместо EMNIST или MNIST8M на своей единственной машине. Другой момент заключается в том, что результаты простых неконтролируемых K-средних далеко не сопоставимы с более продвинутыми контролируемыми методами.

Набор данных (доступный по адресу http://yann.lecun.com/exdb/mnist/) содержит изображения рукописных чисел в формате 28x28, центрированные по их центру масс. Самым первым этапом предварительной обработки может быть масштабирование изображения с использованием ограничительной рамки фактического числа. Я представлю лишь базовую реализацию стандартного подхода, в дальнейшем буду дорабатывать.

Для набора данных требуется просто проанализировать фактическое значение пикселя и преобразовать его в Double. Реализация K-Means Spark MLlib требует RDD векторного типа, который мы можем обеспечить сопоставлением, а также на предыдущем шаге.

// Load data    
val data = sc.textFile("src/main/resources/mnist_test.csv")     
var lines = data.map(l => Vectors.dense(l.split(",").map(_.toDouble))).cache()

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

Фактическое обучение данных также требует максимального количества итераций, но с относительно небольшими наборами данных, такими как MNIST, я просто обращаюсь к большему числу, поскольку оно будет сходиться довольно быстро.

var clusters = KMeans.train(lines, 10, maxIteration);

Из-за случайной инициализации K-средних у вас могут быть разные результаты с точки зрения среднего расстояния / вычислительной стоимости. Вы можете захотеть/нужно сохранить ваши центроиды и вашу модель.

printToFile(new File("target/clusters")) { p => p.println(clusters.clusterCenters.mkString("\n")) 
}
clusters.save(sc, "target/model")

Сохранение центров кластеров создаст для каждого центра вектор с той же размерностью, что и входные векторы, которые мы предоставили модели. (784x1)

Я использовал блокнот Python для построения результатов. Мы можем визуализировать наши центроиды в форме 784x1, масштабированные до изображения 28x28, используя выбранный язык или библиотеку. Я использовал матплотлиб.

with open(r'KMeansMNIST\target\clusters', 'r') as f:
    for line in f:
        tmp = []
        line = re.sub('[\[\]]', '', line)
        for item in line.split(','):
            tmp.append(float(item))
        images.append(tmp)
def drawDigit(digit):
    image = np.array(digit)
    plt.figure()
    digit = plt.imshow(image.reshape(28,28))
    digit.set_cmap('gray_r')
    plt.show()

В результате получаются такие центроиды:

Здесь вы можете найти исходный код кода Apache Spark и блокнота Python: https://github.com/hichameyessou/KMeansMNIST