Этот проект состоит из реализации алгоритма кластеризации в распределенной среде и отображения результатов в блокноте 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