Перейти к содержимому
Compvision.ru
mrgloom

kmeans и MNIST dataset

Recommended Posts

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

именно хочется найти какие то взаимосвязи.

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

потом интересно посмотреть на центр кластеров, это как я понимаю усредненное изображение по кластеру, наверно можно ввести еще такое понятие как дисперсия внутри кластера, чтобы посмотреть сильно ли различаются сэмплы в кластере.

вот такой результат получился если взять максимальный размер пространсва 28*28.

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

кстати можно найти базис размерности n, а проецировать на размерность k (k<n), т.е. на k первых максимальных?

image.png

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

вообще если выбрать не целевое кол-во кластеров, а большее, то получается что то более осмысленное, как бы подкластеры.

на самом деле ведь по такому подходу можно наглядно оценивать хорошо ли выбран вектор признаков.

единственное пока не очень понятно как сливать подкластеры в целевые кластеры и как можно скажем так отфильтровать шумные сэмплы?

image.png

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Что касается проецирования, то Вы же всегда находите все собственные числа и векторы.

Смысл PCA именно в том и есть, чтобы делать репроекцию на векторы с максимальными собственными числами, это и есть уменьшение размерности.

По поводу k-means и тому подобного:

http://charlotte.ucsd.edu/users/elkan/cikm02.pdf

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

попробовал на 10к данных knn, потом решил на тех же данных проверить как работает и мне выдало все лишь 963 правильных ответа из 10к.

это нормально?

void do_knn()

{

	//первая часть тренировка

	//читаем данные

    vector<Mat> db;

	read_data("C:/MNIST/10k_images.bin",db);

    int rows=db[0].rows;

    int cols=db[0].cols;


	//читаем лэйблы

	vector<unsigned char> vec_labels;

	read_labels("C:/MNIST/10k_labels.bin",vec_labels);


	//приводим исходные данные к нужным матрицам

	int total = rows*cols;

	Mat trainData(total, db.size(), CV_32FC1);

    for(int i = 0; i < db.size(); i++)

    {

        Mat X = trainData.col(i);

        db[i].reshape(1, total).col(0).convertTo(X, CV_32FC1, 1/255.);

    }

	Mat trainClasses(vec_labels);

	trainClasses.convertTo(trainClasses,CV_32FC1, 1/255.);


	int k=32;//можно варьировать

	Mat t= trainData.t();

	CvMat trainData_= t;

	CvMat trainClasses_= trainClasses;

	CvKNearest knn(&trainData_,&trainClasses_, 0, false, k);


	int c_tottal=0;

	int c_good=0;

	for(int i = 0; i < db.size(); ++i)

    {

		Mat t=db[i].reshape(1,1);

		t.convertTo(t,CV_32FC1, 1/255.);

		CvMat sample= t;


		CvMat* currentLabel= cvCreateMat( 1, 1, CV_32FC1);

		knn.find_nearest(&sample, k, currentLabel);


		if(255*currentLabel->data.fl[0]==vec_labels[i])

			c_good++;


		c_tottal++;

		int g=0;

	}


	cout<<c_good;

	cout<<c_tottal;

}

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Такой же результат был бы если просто вслепую выбирать ответ. (вероятность 1/10)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

дело было в параметре k в find_nearest, почему то если его поставить таким же как при обучении =32, то получается плохой результат, попробовал =5 и норм ~97%(правда на той же самой выборке).Если выбрать =1 то на той же самой выборке получим 100%.

какое k оптимально для обучения и поиска опять же непонятно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

кстати я тут подумал вот о чём приминительно к нахождению лиц.

если мы находим лица с помощью хаара, то нам надо иметь примеры положительные и отрицательные.

что если мы имеем довольно много фотографий людей(один вариант простой как на паспорт или другой вариант сложнее в "натуральной среде обитания")

и пытаемся найти какую либо зависимость в данных, выделяя из изображения какие либо высоуровневые или низкоуровневые признаки.

т.е. алгоритм нам как бы сам найдет "примеры" через похожести в данных, а мы уже на последней стадии сможем проверить эти данные на адекватность.

имеет ли такой подход право на существование?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Я думаю тут что то близкое к проблеме обнаружения аномалий. (Anomaly Detection).

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

как можно отобразить это на 2д? (т.е. чтобы похожие элементы были близко, а не похожие не близко)

я попробовал спроецировать через PCA на 2 компоненты, но это получилось что то не то.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Вообще PCA должен работать, и его для таких вещей часто применяют.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

ну у меня получилось нечто такое

http://forum.vingrad.ru/act-Attach/type/post/id-2497082.html

рамка в один пиксель вокруг изображения почти заполнена.

а хотелось бы

http://homepage.tudelft.nl/19j49/t-SNE_files/mnist_large.jpg

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Мне не дают посмотреть что у Вас получилось, у меня выдает по первым векторам такое:

Вот три вида (проекции на плоскости, задаваемые парами векторов (v0,v1),(v0,v2) и (v1,v2)):

post-1-0-21837500-1340400567_thumb.png post-1-0-90373700-1340400582_thumb.png post-1-0-69661200-1340400593_thumb.png

#include <iostream>
#include <vector>
#include <stdio.h>
#include "opencv2/core/core.hpp"
#include "opencv2/core/gpumat.hpp"
#include "opencv2/core/opengl_interop.hpp"
#include "opencv2/gpu/gpu.hpp"
#include "opencv2/ml/ml.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/contrib/contrib.hpp"
#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "fstream"
#include "iostream"
using namespace std;
using namespace cv;

inline void endian_swap(unsigned short& x)
{
x = (x>>8) |
(x<<8);
}

inline void endian_swap(unsigned int& x)
{
x = (x>>24) |
((x<<8) & 0x00FF0000) |
((x>>8) & 0x0000FF00) |
(x<<24);
}

// __int64 for MSVC, "long long" for gcc
inline void endian_swap(unsigned __int64& x)
{
x = (x>>56) |
((x<<40) & 0x00FF000000000000) |
((x<<24) & 0x0000FF0000000000) |
((x<<8) & 0x000000FF00000000) |
((x>>8) & 0x00000000FF000000) |
((x>>24) & 0x0000000000FF0000) |
((x>>40) & 0x000000000000FF00) |
(x<<56);
}

void read_mnist_labels(vector<unsigned char>& vec_lbl)
{
//vector<Mat> vec_img;
ifstream file;

file.open("C:/MNIST/train-labels.idx1-ubyte",ifstream::in | ifstream::binary);
if (file.is_open())
{
unsigned int magic_number=0;
unsigned int number_of_labels=0;
file.read((char*)&magic_number,sizeof(magic_number)); //если перевернуть то будет 2051
endian_swap(magic_number);
file.read((char*)&number_of_labels,sizeof(number_of_labels));//если перевернуть будет 10к
endian_swap(number_of_labels);

cout << "magic_number=" << magic_number << endl;
cout << "number_of_labels=" << number_of_labels << endl;

for(int i=0;i<number_of_labels;++i)
{
unsigned char t_ch=0;
file.read((char*)&t_ch,sizeof(t_ch));
vec_lbl.push_back(t_ch);
}
}
}

void read_mnist(vector<Mat>& vec_img)
{
//vector<Mat> vec_img;
ifstream file;

file.open("C:/MNIST/train-images.idx3-ubyte",ifstream::in | ifstream::binary);
//file.open("C:/MNIST/t10k-images.idx3-ubyte",ifstream::in | ifstream::binary);
if (file.is_open())
{
unsigned int magic_number=0;
unsigned int number_of_images=0;
unsigned int n_rows=0;
unsigned int n_cols=0;
file.read((char*)&magic_number,sizeof(magic_number)); //если перевернуть то будет 2051
endian_swap(magic_number);
file.read((char*)&number_of_images,sizeof(number_of_images));//если перевернуть будет 10к
endian_swap(number_of_images);
file.read((char*)&n_rows,sizeof(n_rows));
endian_swap(n_rows);
file.read((char*)&n_cols,sizeof(n_cols));
endian_swap(n_cols);
cout << "magic_number=" << magic_number << endl;
cout << "n_rows=" << n_rows << endl;
cout << "n_cols=" << n_cols << endl;
cout << "number_of_images=" << number_of_images << endl;

for(int i=0;i<number_of_images;++i)
{
Mat temp(n_rows,n_cols,CV_8UC1);
for(int r=0;r<n_rows;++r)
{
for(int c=0;c<n_cols;++c)
{
unsigned char t_ch=0;
file.read((char*)&t_ch,sizeof(t_ch));
//тут идет запись матрицы 28х28 в вектор
temp.at<unsigned char>(r,c)= t_ch; //возможно можно как то быстрее копировать построчно?
}
}
vec_img.push_back(temp);
}
}

}
//-----------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------
void calc_PCA(vector<Mat>& db,int numPrincipalComponents,Mat& EigVec,Mat& Mean)
{
int total = db[0].rows * db[0].cols;

int rows=db[0].rows;
int cols=db[0].cols;

Mat mat(total, db.size(), CV_32FC1);

for(int i = 0; i < db.size(); i++)
{
Mat X = mat.col(i);
db[i].reshape(1, total).col(0).convertTo(X, CV_32FC1, 1/255.);
}

EigVec=Mat(numPrincipalComponents,total,CV_32FC1);
// do pca
PCA pca(mat, Mat(), CV_PCA_DATA_AS_COL, numPrincipalComponents);

Mat imgDst;
imgDst.create( rows, cols*numPrincipalComponents, CV_32FC1 );
imgDst=0;

pca.mean.copyTo(Mean);

for(int i=0;i<numPrincipalComponents;++i)
{
Mat temp=(pca.eigenvectors.row(i));
normalize(temp,temp); // Это и есть собственный вектор
temp.copyTo(EigVec.row(i));
// ---------------------------------------------------
// Этот кусок нужен для того, чтобы были видны картинки
// ---------------------------------------------------
double m,M;
minMaxLoc(temp,&m,&M);
if((M-m)!=0)
{
temp-=m;
temp/=(M-m);
temp*=255.0;
}
temp=temp.reshape(1, rows);
temp.copyTo(imgDst(Rect(i*cols,0,cols,rows)));
// ---------------------------------------------------
}
imwrite("result.png", imgDst);
int f=0;
}


CvScalar random_color(CvRNG* rng)
{
int color = cvRandInt(rng);
return CV_RGB(color&255, (color>>8)&255, (color>>16)&255);
}


//-----------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------
int main( int argc, char** argv )
{
const int NumVectors=3;
vector<Mat> MNIST;
read_mnist(MNIST);

vector<unsigned char> MNIST_L;
read_mnist_labels(MNIST_L);

int rows=MNIST[0].rows;
int cols=MNIST[0].cols;
// ---------------------------------------------------
// Составили картинку из 100 первых изображений
// ---------------------------------------------------
Mat imgDst;
imgDst.create( 10*rows, 10*cols, CV_8UC1 );
imgDst=0;
for(int i=0;i<10;i++)
{
for(int j=0;j<10;j++)
{
MNIST[i+j*10].copyTo(imgDst(Rect(i*cols,j*rows,cols,rows)));
}
}
imshow("result",imgDst);
// ---------------------------------------------------
// Посчитаем собственные векторы возьмем NumVectors с
// максимальными собственными числами
// ---------------------------------------------------
Mat EigVec,mean,result,repared;
calc_PCA(MNIST,NumVectors,EigVec,mean);
// ---------------------------------------------------
// Спроецируем 10 первых цифр на собственные векторы
// получаем координаты этих цифр в NumVectors мерном пространстве
// а затем восстановим их по этим проекциям.
// ---------------------------------------------------
for(int i=0; i<10; i++)
{
// Спроецируем на собственные векторы
cv::PCAProject(MNIST[i].reshape(1, rows*cols),mean,EigVec,result);
cout << result << endl;

// Восстановим по их NumVectors проекциям на собственные оси.
cv::PCABackProject(result,mean,EigVec,repared);

// переведем обратно в прямоугольный вид
// и выведем в файл
repared=repared.reshape(1, rows);
char str[100];
sprintf(str,"repared_%d.png",i);
imwrite(str,repared);

}
vector<float> x;
vector<float> y;
for(int i=0; i<60000; i++)
{
// Спроецируем на собственные векторы
cv::PCAProject(MNIST[i].reshape(1, rows*cols),mean,EigVec,result);
y.push_back(result.at<float>(1));
x.push_back(result.at<float>(2));
}
pair<vector<float>::iterator,vector<float>::iterator> ylimits = minmax_element(y.begin(),y.end());
pair<vector<float>::iterator,vector<float>::iterator> xlimits = minmax_element(x.begin(),x.end());

float w=*xlimits.second-*xlimits.first;
float h=*ylimits.second-*ylimits.first;
Mat imacl(Size(w/5,h/5),CV_8UC3);
cout<< "h=" << h << " w=" << w << endl;
imacl=0;

CvRNG rng(35435345);

CvScalar Colors[256];
for (int i=0;i<256;i++)
{
Colors[i]=random_color(&rng);
}

for(int i=0; i<10; i++)
{
rectangle(imacl,Point(i*10,0),Point(i*10+10,10),Colors[i],-1);
}

for(int i=0; i<x.size(); i++)
{
int X=(x[i]-*xlimits.first)/5;
int Y=(y[i]-*ylimits.first)/5;
imacl.at<Vec3b>(Y,X)[0]=Colors[MNIST_L[i]].val[0];
imacl.at<Vec3b>(Y,X)[1]=Colors[MNIST_L[i]].val[1];
imacl.at<Vec3b>(Y,X)[2]=Colors[MNIST_L[i]].val[2];
}
imshow("imacl",imacl);
x.clear();
y.clear();
waitKey(0);
return 0;
}[/code]

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Кстати, вот здесь точно то, что использовано для получения той картинки :

http://homepage.tudelft.nl/19j49/t-SNE.html

Плюс к тому Isomap:

http://isomap.stanford.edu/

И хорошая статейка:

http://axon.cs.byu.edu/Dan/678/miscellaneous/Manifold.example.pdf

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Вот три вида (проекции на плоскости, задаваемые парами векторов (v0,v1),(v0,v2) и (v1,v2)):

не понял это вы 3Д проецировали на 3 разных плоскости в 2Д?

Кстати, вот здесь точно то, что использовано для получения той картинки :

http://homepage.tude...9j49/t-SNE.html

Плюс к тому Isomap:

http://isomap.stanford.edu/

это то все понятно, но боюсь если не знать как этим пользоваться ничего не выйдет.

пока наверно можно хотя бы в матлабе поиграться с PCA и проецировать в 3Д, там кстати его крутить можно?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Это opencv-шное 2Д, просто разные пары осей беру по X и Y.

Можно и в 3д построить (OpenGL) или записать координаты и в матлаб закинуть, там крутить можно.

Иногда строю такие вещи в Asymptote качественный вывод (много разных форматов) получается, причем можно 3д в pdf встраивать.

Вот в этом куске цифры менял:

y.push_back(result.at<float>(1));
x.push_back(result.at<float>(2));[/code]

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

пытаюсь воспользоваться этой программой(которая похоже оказалась довольно глючной)

http://mldemos.epfl.ch/

в хелпе написано

Importing data

Generating data in MLDemos is done in three different ways: by manually drawing samples, by projecting image data through PCA (via the Projection panel), or by loading external data.

The data format used by the software is ascii-based and contains on the first line the # of samples followed by # of dimensions (only the first 2 dimensions are used in the software). The file then contains #samples lines with the coordinates of each sample followed by a class number (0 ... 255) and a flag (0-3) that allows to determine whether a sample is unused or in the training, validation or test sets.

a concrete example would be

4 2

0.10 0.11 0 0

0.14 0.91 0 0

0.43 0.74 1 0

0.28 0.34 1 0

which presents 4 two-dimensional samples, two from class 0 and one from class 1.

When the file is saved from MLDemos, the software adds the current algorithm parameters (provided an algorithm was selected), which can be useful for demonstration purposes. If no such information is present, the default algorithm parameters are selected. You should be able to convert your own data to this format with any script.

пробую простейший пример

4 2

0.10 0.11 0 0

0.14 0.91 0 0

0.43 0.74 1 0

0.28 0.34 1 0

thumb.png

thumb.png

thumb.png

thumb.png

пробую пример где размерность >2, хотя даже для простейшего примера =2 нормально не работает.

thumb.png

thumb.png

thumb.png

даже название классов отображается как то не так

thumb.png

вообщем такое ощущение, что либо я что то не так делаю, либо программа вообще не пригодна для данных размерности >2

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Вообще - то она для размерности 2 и есть.

Если больше, то попробуйте язык R (ML-сообщество почему то его очень любит).

http://www.r-project.org/

IDE здесь:

http://rstudio.org/

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

ну вопервых там написано

by projecting image data through PCA (via the Projection panel)
откуда же там предполагается брать многомерные данные? а во вторых он даже для 2-мерного случая неправильно загружает(во всяком случае 1 лишнюю строку+ неправильно отображение названий классов)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Насчет строки, там нет лишнего cr lf в конце файла ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

нет я так тоже пробовал, может там должно быть не cr lf, а что то другое?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

А, ну так там же вначале количество строк и размерность данных указывается (можно попробовать поменять 8 на 7).

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

попробовал, такое ощущение, что программе всё равно какое первое число, грузит всё так же, хоть 0 ставь.

хотя может быть что то в реестре что то прописалось и теперь из-за этого глюки.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

я кстати ваш код так до конца и не понял переписал по своему

Вот в этом куске цифры менял:

y.push_back(result.at<float>(1));

x.push_back(result.at<float>(2));

ну так numPrincipalComponents было ровно 3?

Mat imacl(Size(w/5,h/5),CV_8UC3);

почему делим на 5? я наоборот умножал.

for(int i=0; i<10; i++)

{

rectangle(imacl,Point(i*10,0),Point(i*10+10,10),Colors,-1);

}

не понял что делает.

void project_to_2D()

{

	//читаем данные

    vector<Mat> db;

	read_data("C:/ICP/MNIST/60k_images.bin",db);


	//читаем лэйблы (нужно для окраски точек)

	vector<unsigned char> MNIST_L;

	read_labels("C:/ICP/MNIST/60k_labels.bin",MNIST_L);


	int total = db[0].rows * db[0].cols;

	int numPrincipalComponents=2; //проецируем на 2Д

    int rows=db[0].rows;

    int cols=db[0].cols;


    Mat mat(total, db.size(), CV_32FC1);


	//составляем всё в общию матрицу

    for(int i = 0; i < db.size(); i++)

    {

        Mat X = mat.col(i);

        db[i].reshape(1, total).col(0).convertTo(X, CV_32FC1, 1/255.);

    }


    // do pca

    PCA pca(mat, Mat(), CV_PCA_DATA_AS_COL, numPrincipalComponents);


	//теперь должны спроецировать наши входные данные на наш новый базис

	//проецируем

	vector<float> x;

    vector<float> y;

	for(int i=0;i<db.size();++i)

	{

		Mat temp;

		Mat res;

		db[i].reshape(1, rows*cols).convertTo(temp,CV_32FC1,1./255);

		pca.project(temp,res);

		x.push_back(res.at<float>(0));

		y.push_back(res.at<float>(1));

	}


	//подготавливаем изображение под отрисовку

	float min_x,max_x,min_y,max_y;

	minmax_element(min_x, max_x, x);

	minmax_element(min_y, max_y, y);

	float w=max_x-min_x;

    float h=max_y-min_y;

    Mat imacl(Size(w*200,h*200),CV_8UC3);

    imacl=0;


	CvRNG rng(35435345);


    CvScalar Colors[256];

    for (int i=0;i<256;i++)

    {

            Colors[i]=random_color(&rng);

    }


    for(int i=0; i<x.size(); i++) 

    {

            int X=(x[i]-min_x)*200;

            int Y=(y[i]-min_y)*200;

			if(X>=(int)(w*200))

				X= w*200-1;

			if(Y>=(int)(h*200)) 

				Y= h*200-1;

            imacl.at<Vec3b>(Y,X)[0]=Colors[MNIST_L[i]].val[0];

            imacl.at<Vec3b>(Y,X)[1]=Colors[MNIST_L[i]].val[1];

            imacl.at<Vec3b>(Y,X)[2]=Colors[MNIST_L[i]].val[2];

    }

	imwrite("clusters_label_data.png",imacl); 

}

получилось вот что, вроде то же самое, но всё таки хочется куда то это выгружать, чтобы можно было увеличивать уменьшать в риалтайме и были написаны легенды или даже сами знаки.

thumb.png

thumb.png

по улучшению можно придумать только поменять вектор признаков или поменять PCA на что либо более сложное.

но с другой стороны как это всё оценивать? только на глаз?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

y.push_back(result.at<float>(1));
x.push_back(result.at<float>(2));[/code] Здесь второй собственный вектор совмещается с осью Y, а третий с X. На 5 делил, потому что в экран не помещалось.
[code]for(int i=0; i<10; i++)
{
rectangle(imacl,Point(i*10,0),Point(i*10+10,10),Colors[i],-1);
}

Легенду рисует в верхнем углу :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

//преобразуем через LBP (надо не просто преобразовать, а гистограммы посчитать)

	vector<Mat> db_lbp(db.size());

	for(int i=0;i<db.size();++i)

	{

		lbp::OLBP(db[i],db_lbp[i]);

	}

	db= db_lbp;//

попробовал Local Binary Patterns, но ничего хорошего не выдало, видимо надо посчитать гистограммы, но я пока не понял как.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте учётную запись или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать учётную запись

Зарегистрируйтесь для создания учётной записи. Это просто!

Зарегистрировать учётную запись

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу

×