Участник:Gkhazeeva/Нечеткий алгоритм C средних
![]() | Эта работа прошла предварительную проверку Дата последней правки страницы: 19.12.2016 Данная работа соответствует формальным критериям. Проверено Coctic. |
Нечеткий алгоритм C средних | |
Последовательный алгоритм | |
Последовательная сложность | O(c^2 Mn_{iter} + cMdn_{iter}), n_{iter} - количество итераций |
Объём входных данных | M*d, [количество наблюдений * размерность] |
Объём выходных данных | M*c, [количество наблюдений * количество кластеров] |
Параллельный алгоритм | |
Высота ярусно-параллельной формы | O(cdn_{iter} + c^2n_{iter}) |
Ширина ярусно-параллельной формы | O (M) |
Авторы : Гелана Хазеева (1.3; 1.5; 1.6; 1.7; 2.4; 2.7), Павел Юшин (1.1; 1.2; 1.4; 1.8; 1.9; 1.10)
Содержание
- 1 Свойства и структура алгоритмов
- 1.1 Общее описание алгоритма
- 1.2 Математическое описание алгоритма [2]
- 1.3 Вычислительное ядро алгоритма
- 1.4 Макроструктура алгоритма
- 1.5 Схема реализации последовательного алгоритма
- 1.6 Последовательная сложность алгоритма
- 1.7 Информационный граф
- 1.8 Ресурс параллелизма алгоритма
- 1.9 Входные и выходные данные алгоритма
- 1.10 Свойства алгоритма
- 2 Программная реализация алгоритма
- 2.1 Особенности реализации последовательного алгоритма
- 2.2 Локальность данных и вычислений
- 2.3 Возможные способы и особенности параллельной реализации алгоритма
- 2.4 Масштабируемость алгоритма и его реализации
- 2.5 Динамические характеристики и эффективность реализации алгоритма
- 2.6 Выводы для классов архитектур
- 2.7 Существующие реализации алгоритма
- 3 Литература
1 Свойства и структура алгоритмов
1.1 Общее описание алгоритма
Кластеризация - это объединение объектов в группы (кластеры) на основе схожести признаков для объектов одной группы и отличий между группами. Нечеткий алгоритм C Средних (Fuzzy C-means, FCM) - алгоритм кластеризации, позволяющий объектам принадлежать с различной степенью нескольким кластерам одновременно. Впервые алгоритм был предложен J.C. Dunn в 1973 [1]. Нечеткое разбиение позволяет просто решить проблему определения кластера для объектов, расположенных на границе - им назначают степени принадлежностей равные 0.5.
Входные данные алгоритма: набор векторов, которые следует кластеризовать.
Параметры алгоритма: c - количество кластеров;m \gt = 1 - параметр, определяющий нечеткость кластеров ( при m = 1 разбиение является четким, с увеличением параметра m растет степень "размазанности" объектов по кластерам); \varepsilon - параметр останова алгоритма.
Выходные данные: матрица вероятностей принадлежности векторов кластерам.
Краткое описание алгоритма:
- Задать параметры алгоритма.
- Сгенерировать случайную матрицу принадлежностей векторов кластерам (матрицу нечеткого разбиения).
- Повторить следующие шаги до тех пор, пока расстояние между матрицами нечеткого разбиения на этом и предыдущем шаге алгоритма не будет отличаться менее, чем на параметр останова.
- Рассчитать центры кластеров.
- Рассчитать расстояние между объектами и центрами кластеров.
- Пересчитать элементы матрицы нечеткого разбиения.
1.2 Математическое описание алгоритма [2]
Пусть W = w_{ij} \in[0,1],\; i = 1, ..., M, \; j = 1, ..., c - матрица разбиения, где w_{i,j} - степень принадлежности объекта i к кластеру j; c - количество кластеров, M - количество векторов, X_i - набор входных векторов размерности d.
В качестве нормы предлагается максимум-норма: ||W|| = \max_{i,j} |w_{i,j}|
При этом элементы матрицы должны удовлетворять условиям:
- \sum_{j = 1}^c w_{ij} = 1, i = 1, ..., M (1)
- 0 \lt \sum_{i = 1}^M w_{ij} \lt M, j = 1, ..., c (2)
Тогда алгоритм принимает следующий вид:
1) Задаем параметры алгоритма: c - количество кластеров; m \gt = 1 - экспоненциальный вес, определяющий нечеткость кластеров; \varepsilon \gt 0 - параметр останова алгоритма.
2) Генерируем случайным образом матрицу нечеткого разбиения с учетом условий (1) и (2)
3) Рассчитываем центроиды (центры кластеров): V_j = {{\sum_{i=1}^M w_{ij}^m * X_i} \over {\sum_{i=1}^M w_{ij}^m}}, j = 1, ..., c
4) Рассчитываем расстояния между объектами X и центроидами:
D_{ij} = {||X_i - V_j||}, i = 1,...,M; j = 1,...,c
5) Пересчет элементов матрицы разбиения:
при D_{ij} \gt 0 : w_{ij} = {{1}\over {{ (\sum_{k=1}^c {{D_{ij}}\over{D_{ik}}} ) }^{2/(m-1)}}}, j = 1,...,c
при D_{ij} =0 : w_{ij} = \delta_{ij}, j = 1,...,c, где \delta_{ij} - символ Кронекера
6) Если || F - F^{*} || \lt \varepsilon , где F^{*} - матрица нечеткого разбиения предыдущей итерации, то идем далее, иначе возвращаемся на пункт 3.
7) Конец.
1.3 Вычислительное ядро алгоритма
Вычислительным ядром алгоритма являются следующие пункты:
- Поиск V_j - расчет центроидов (пункт 3 алгоритма)
- Нахождение D_{ij} - расстояний между объектами (пункт 4 алгоритма)
- Пересчет w_{ij} - элементов матрицы разбиения (пункт 5 алгоритма)
1.4 Макроструктура алгоритма
Основные шаги при реализации алгоритма
- Генерация случайной матрицы размера M*c, проверка условий
- Расчет центроидов – по сути, скалярное произведение с нормировкой
- Расчет расстояний – в общепринятом случае является скалярным произведением
- Пересчет матрицы – по сути, скалярное произведение
- Проверка условий останова – вычисление нормы
1.5 Схема реализации последовательного алгоритма
float ** FuzzyCMeans (float** X, c, m, eps){ n = X.size(); r = X[0].size(); centers = generateZeroFill(c, r) Wprev = genetateRandFill(n, c); W = Wprev; while (true){ // обновляем центры кластеров for (int i=0; i<c; i++){ float * num = new float [](); float den = 0; for (int j=0; j<n; j++){ num += pow(W[j][i], m) * X[j]; den+=pow(W[j][i], m); } centers[i] = num / den; } //обновляем вероятности W и считаем расстояние между матрицами W и Wprev float max_diff = 0; for (int i=0; i<n; i++) for (int j=0; j<c; j++){ total = 0; for (int m=0; m<с; m++) total += pow(distance(X[i], centers[j]) / distance(X[i], centers[m]), 2/(m-1)); W[i][j] = 1/total; max_diff = max(abs(Wprev[i][j]-W[i][j]), max_diff); Wprev[i][j] = W[i][j]; } if (max_diff < eps): break; } return W; }
1.6 Последовательная сложность алгоритма
Последовательная сложность алгоритма состоит из сложности каждой итерации умноженной на их количество n_{iter} . Так как число итераций заранее неизвестно и зависит от входных параметров, рассмотрим сложность на каждой итерации. Наибольшую сложность представляет собой пересчет матрицы, сложность которого O(c^2 M) (по сравнению со сложностью O(cMd) расчета расстояний, вычисления центроидов и проверки условия останова). Итого общая сложность алгоритма O(c^2 Mn_{iter} + cMdn_{iter}). Так как обычно n \gt \gt c , то в этом случае сложность O(c^2 Mn_{iter} ).
1.7 Информационный граф
Информационный граф представлен на рисунке ниже.
Первый ярус состоит из n_{p} параллельных процессов, между которыми равномерно распределены M операций 1, 2, совершаемых в цикле c раз для каждого кластера.
Операция 1: w_{ij}^m, где j - номер итерации в цикле, i - номер параллельной ветви.
Операция 2: w_{ij}^m*X_i
Здесь j - номер итерации в цикле, i - номер параллельной ветви.
На выходе из каждой ветки получаем вектор размера 1 x c и матрицу размера d x c. Далее совершаем поэлементное сложение векторов и матриц соответственно, а затем делим каждый столбец в матрице на соответствующий элемент в векторе.
Второй ярус состоит из n_{p} параллельных процессов, между которыми равномерно распределены M операций 3, 4, 5 также совершаемых в цикле c раз.
Операция 3: обновление значения w_{ij} по указанной в разделе 1.2 в пункте 5 формуле.
Операция 4: maximum = max(|w_{ij} - w_{ij}^{prev}|, maximum).
Операция 5: w_{ij}^{prev} = w_{ij}.
Здесь j - номер итерации в цикле, i - номер параллельной ветви.
На выходе из каждой ветки получаем число maximum. Далее находим максимальное значение из полученных величин для каждой ветки. Затем проверяем условие останова алгоритма.
1.8 Ресурс параллелизма алгоритма
На первом ярусе происходит O(cdn_{iter}) операций, на втором - O(c^2n_{iter}) , итого высота ЯПФ алгоритма O(cdn_{iter} + c^2n_{iter}) . Ширина ярусно-параллельной формы алгоритма равна O(M) . Иерархическая структура параллелизма подробно описана в п.1.7.
В алгоритме не возникает скошенного параллелизма.
1.9 Входные и выходные данные алгоритма
- Входные данные алгоритма: набор векторов x_i размерности d, где i = 1,...,M; M - количество векторов.
- Объем входных данных: M*d , [количество наблюдений * размерность].
- Выходные данные алгоритма: матрица вероятностей принадлежности векторов кластерам M на c.
- Объем выходных данных: M*c , [количество наблюдений * количество кластеров].
1.10 Свойства алгоритма
- Соотношение последовательной и параллельной сложности: M
- Вычислительная мощность: {dc^2n_{iter} } \over {c+d}.
- Устойчивость: алгоритм не является устойчивым, поэтому существует много исследований о том, как первоначально выбрать параметры кластеризации.
- Сбалансированность: в данном алгоритме операция умножения доминирует над операцией сложения. Операции между параллельными ветвями сбалансированы.
- Детерминированность: алгоритм не является детерминированным, так как матрица нечеткого разбиение генерируется произвольно.
- Степень исхода вершины информационного графа (для одной итерации): 2. Если выходные данные пошли на следующую итерацию: 3.
2 Программная реализация алгоритма
2.1 Особенности реализации последовательного алгоритма
2.2 Локальность данных и вычислений
2.3 Возможные способы и особенности параллельной реализации алгоритма
2.4 Масштабируемость алгоритма и его реализации
Проведём исследование масштабируемости параллельной реализации нечеткого алгоритма С-средних. Исследование проводилось на суперкомпьютере "Ломоносов"[3] Суперкомпьютерного комплекса Московского университета. Была исследована собственная параллельная реализация алгоритма, написанная на языке C++ с использованием стандарта MPI. Сборка программы производилась при помощи компилятора компании Intel версии 13.1.0 с использованием библиотеки intelMPI версии 4.1.0 . Расчеты проводились в разделе test на узлах со следующими характеристиками: количество GPU - 0, количество ядер - 8 ядер архитектуры x86, количество памяти - 12 Гб.
Набор и границы значений изменяемых параметров запуска реализации алгоритма:
- число процессоров [1 : 128];
- размер матрицы [10000 : 80000].
В результате проведённых экспериментов был получен следующий диапазон эффективности реализации алгоритма:
- минимальная эффективность реализации 0,33%;
- максимальная эффективность реализации 9,4%.
На следующих рисунках приведены графики производительности и эффективности выбранной реализации в зависимости от изменяемых параметров запуска.
Построим оценки масштабируемости выбранной реализации нечеткого алгоритма С-средних:
- По числу процессов: 0.007. При увеличении числа процессов эффективность на рассмотренной области изменений параметров запуска увеличивается.
- По размеру задачи: -0.0016. При увеличении размера задачи эффективность уменьшается.
- По двум направлениям: 0,000077. При рассмотрении увеличения как вычислительной сложности, так и числа процессов на всей рассмотренной области значений эффективность увеличивается, однако скорость увеличения эффективности небольшая.
Была использована следующая реализация алгоритма.
#include <mpi.h> #include <stdio.h> #include <iostream> #include <stdlib.h> #include <math.h> #include <string.h> #include <time.h> using namespace std; double **x; //input matrix of size (n x x_dim) int n; int x_dim; double **centroids; //cluster centroids matrix of size (n_cluster x x_dim) int n_cluster; // number of clusters double **w; //probability matrix of size (n x n_cluster) double **dist; //distances matrix of size (n x n_cluster) double eps; //max error double m; //parameter of algo int max_iter; // max num of iterations double **num; double *den; double *allden; double *err; double *total_err; int rank, size; double ** generateZerosMatrix(int r, int c){ double ** arr = new double* [r]; for (int i = 0; i < r; ++i){ arr[i] = new double[c](); } return arr; } int generate_data() { //generate matrix x = generateZerosMatrix(n, x_dim); centroids = generateZerosMatrix(n_cluster, x_dim); w = generateZerosMatrix(n, n_cluster); dist = generateZerosMatrix(n, n_cluster); num = generateZerosMatrix(n_cluster, x_dim); //generate vectors den = new double [n_cluster](); allden = new double [n_cluster](); //for stopping algorithm err = new double; total_err = new double; srand(time(0)); //initialize w randomly with restrictions for (int i = 0; i < n; ++i){ double sum = 0; for (int j = 0; j < n_cluster; ++j){ w[i][j] = rand(); sum += w[i][j]; } for (int j = 0; j < n_cluster; ++j){ w[i][j] /= sum; } } //initialize x randomly for (int i = 0; i < n; ++i) for (int j = 0; j < x_dim; ++j) x[i][j] = rand(); return 0; } double make_iteration() { // calculate centroids centers for (int i = rank; i < n; i+=size) for (int j = 0; j < n_cluster; ++j){ double mu = pow(w[i][j], m); den[j] += mu; for (int k = 0; k < x_dim; ++k) num[j][k] = mu * x[i][k]; } MPI_Allreduce(den, allden, n_cluster, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); for (int j=0; j < n_cluster; ++j) MPI_Allreduce(num[j], centroids[j], x_dim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); for (int i = 0; i < n_cluster; ++i) for (int j = 0; j < x_dim; ++j) centroids[i][j] /= allden[i]; // calculate distances and probabilities, check stop conditions double err = 0.0; for (int i = rank; i < n; i+=size) for (int j = 0; j < n_cluster; ++j){ for (int k = 0; k < x_dim; ++k) dist[i][j] += (x[i][k] - centroids[j][k]) * (x[i][k] - centroids[j][k]); double w_prev = w[i][j]; for (int k = 0; k < n_cluster; ++k) w[i][j] += dist[i][j] / dist[i][k]; w[i][j] = 1.0 / pow(w[i][j], 1.0 / (m - 1)); err = fmax(err, abs(w_prev - w[i][j])); } return err; } int FCM(){ *total_err = eps+1; int cur_iter = 0; while (cur_iter < max_iter && *total_err > eps){ *err = make_iteration(); MPI_Allreduce(err, total_err, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); cur_iter++; } return cur_iter; } void clearMatrix(double ** matr, int r, int c){ for (int i = 0; i < r; ++i){ delete [] matr[i]; } delete [] matr; } int memory_free(){ clearMatrix(x, n, x_dim); clearMatrix(centroids, n_cluster, x_dim); clearMatrix(w, n_cluster, n); clearMatrix(num, n_cluster, x_dim); clearMatrix(dist, n, n_cluster); delete [] den; delete [] allden; delete err; delete total_err; return 0; } int main(int argc, char **argv){ MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &size); MPI_Comm_rank(MPI_COMM_WORLD, &rank); int n_repeat = strtol(argv[1], NULL, 10); int nx_min = strtol(argv[2], NULL, 10); int nx_max = strtol(argv[3], NULL, 10); int step = strtol(argv[4], NULL, 10); x_dim = strtol(argv[5], NULL, 10); m = strtod(argv[6], NULL); n_cluster = strtol(argv[7], NULL, 10); max_iter = strtol(argv[8], NULL, 10); eps = strtod(argv[9], NULL); //for all input matrix sizes for (n = nx_min; n <= nx_max; n += step){ double start, finish, time_elapsed_iter=0; int total_iterations = 0; //repeat for getting mean value for (int i = 0; i < n_repeat; ++i) { generate_data(); MPI_Barrier(MPI_COMM_WORLD); start = MPI_Wtime(); total_iterations += FCM(); finish = MPI_Wtime(); memory_free(); time_elapsed_iter += (finish-start); } time_elapsed_iter /= total_iterations; if (rank == 0) { cout << n << " " << size << " " << time_elapsed_iter << endl; } } MPI_Finalize(); }
2.5 Динамические характеристики и эффективность реализации алгоритма
2.6 Выводы для классов архитектур
2.7 Существующие реализации алгоритма
- Реализация алгоритма на POSTGRESQL: http://num-meth.srcc.msu.ru/zhurnal/tom_2012/pdf/v13r207.pdf
- Библиотека для MATLAB: http://www.mathworks.com/help/fuzzy/fcm.html (распространяется на коммерческой основе)
3 Литература
- ↑ | J. C. Dunn. A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters. Journal of Cybernetics, volume 3,1973 - Issue 3, pp 32-57
- ↑ | Нейский И.М. Классификация и сравнение методов кластеризации.// Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.
- ↑ Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.