About a month ago I posted here on large scale SVM. The conclusion of my post was that linear SVM is solved problem, mainly due to Pegasos stochastic gradient descent algorithm.
Today I had the pleasure of meeting Shai Shalev-Shwartz, the author of Pegasos. I asked Shai if he can explain to me (namely for dummies.. ) why pegasos is working so well. So this is what I heard. Pegasos is a stochastic gradient descent method. Instead of computing the costly operation of the exact gradient, a random data point is selected, and an approximated gradient is computed, based solely on this data point. The solution method is advancing in random directions, however on expectation, those random directions will lead to the exact global solution.
I asked Shai if he can provide me a simple matlab code that demonstrates the essence of Pegasos. And here is the code I got from him:
% w=pegasos(X,Y,lambda,nepochs)
% Solve the SVM optimization problem without kernels:
% w = argmin lambda w'*w + 1/m * sum(max(0,1-Y.*X*w))
% Input:
% X - matrix of instances (each row is an instance)
% Y - column vector of labels over {+1,-1}
% lambda - scalar
% nepochs - how many times to go over the training set
% Output:
% w - column vector of weights
% Written by Shai Shalev-Shwartz, HUJI
function w=pegasos(X,Y,lambda,nepochs)
[m,d] = size(X);
w = zeros(d,1);
t = 1;
for (i=1:nepochs) % iterations over the full data
for (tau=1:m) % pick a single data point
if (Y(tau)*X(tau,:)*w < 1) % distance of data point
% from separator is to small
% or data point is at the other side of the separator.
% take a step towards the gradient
w = (1-1/t)*w + 1/(lambda*t)*Y(tau)*X(tau,:)';
else
w = (1-1/t)*w;
end
t=t+1; % increment counter
end
end
You must agree with me that this is a very simple and elegant piece of code.
And here are my two stupid questions:
1) Why do we update the gradient with the magic number < 1?
2) Why do we update w even when gradient update is not needed?
Answers I got from Shai:
1) It's either the data point is close to the separator, or that it's far away from the separator but on the wrong side (i.e., if y*w*x is a large negative number).
2) The actual distance from a point x to the separator is |w*x| / (||w|| * ||x||). So, to increase this number we want that both |w*x| will be large and that ||w|| will be small. So, even if we don't update, we always want to shrink ||w||.
Showing posts with label pegasos. Show all posts
Showing posts with label pegasos. Show all posts
Sunday, April 15, 2012
Monday, July 18, 2011
Hearst Machine Learning Challenge - Converting inputs to SVMLight format
After the excitement following our 5th place in KDD CUP 2011 is a little over, I started looking at other interesting problems. The hearst machine learning challenge has some interesting data. About 1M emails are given with 273 sparse features. The task is to classify some validation emails, and decide whether the user has opened the email and if he clicked on the link within the email. The problem is not so easy since the data is highly skewed - most users ignore ad emails
as spam, so the number of positive examples is rather low.
One of the classic ways of solving the classification problem is using SVM (support vector machine). SVMLight is a popular implementation of SVM solver.
Here is a short script I wrote for converting Hearst machine learning challenge data into SVMLight format (and also pegasos format).
as spam, so the number of positive examples is rather low.
One of the classic ways of solving the classification problem is using SVM (support vector machine). SVMLight is a popular implementation of SVM solver.
Here is a short script I wrote for converting Hearst machine learning challenge data into SVMLight format (and also pegasos format).
%function for converting hearst data to svm light format %Input: number - the file number. 1-5 Model files. 6 - validation. % doclick or doopen - one of them should be 1 and the other zero, depends on which target. %Written by Danny Bickson, CMU, July 2011. %This script converts hearst machine learning challenge data into SVMlight format %namely:The script can be actually run in parallel on multicore machine. The way to run it is to execute the following in a Linux shell (optimally if you have 11 cores):... % for example %-1 3:15.4 4:18 19:32 % function []=convert2svm(number,doclick, doopen) assert(number>=1 && number<=6); row_offset = [0 400000 800000 1200000 1600000 0]; rows=[400000 400000 400000 400000 185421 9956]; cols=274; assert(~(doopen && doclick)); assert(doclick || doopen); terms273 = {'Sun', 'Mon','Tue', 'Wed', 'Thu', 'Fri', 'Sat'}; ids = num2cell(1:length(terms273)); dict273 = reshape({terms273{:};ids{:}},2,[]); dict273 = struct(dict273{:}); if (number == 6) fid=fopen('validation.csv','r'); outid=fopen('validation.txt','w'); else fid=fopen(['Modeling_', num2str(number), '.csv'],'r'); if (doclick) outid=fopen(['svm', num2str(number), '.txt'],'w'); else outid=fopen(['2svm', num2str(number), '.txt'],'w'); end end assert(outid~=-1); title=textscan(fid, '%s', 273, 'delimiter', ','); % read title title=title{1}; title{274} = 'date';% field no. 273 is mistakenly parsed into two fields in matlab because of a "," % go over rows tic for j=1:rows(number)-1 if (mod(j,500) == 0) disp(['row ', num2str(j)]); tic for j=1:rows(number)-1 if (mod(j,500) == 0) disp(['row ', num2str(j)]); toc end a=textscan(fid, '%s', 274,'delimiter', ','); a=a{1}; for i=1:cols if (i == 1|| i == 2) %handle target if ((doclick&&i==1) || (doopen&&i==2)) if (number == 6) fprintf(outid,'%d ', -1); %target is unknown, write -1 as a placeholder else fprintf(outid,'%d ', (2*strcmp(a{i},'Y'))-1); end end elseif (~strcmp(a{i} ,''))%if feature is non zero val=a{i}; if (i == 73) % translate field of the type A01, B03, J05, etc. quickly into a number val = val(1)*26+val(3); elseif (i==273) val = val(2:end); %remove quatation mark val = dict273.(val); elseif (i==274) % translate date into a number val = datenum(a{274}); else if (length(val) == 1) val = uint8(val); elseif (sum(isletter(val))==0) % string is all digits, translate to double val = str2double(val); else val = sum(uint8(val));%translate a string into a number, using sun of chars, can use more fancy methods here end end fprintf(outid, '%d:%f ', i-2, val); % remove two from field number since first two fields are targets end end fprintf(outid, '\n'); end fclose(fid); fclose(outid); end
for i in `seq 1 1 6` do matlab -r "convert2svm($i,1,0)" & matlab -r "convert2svm($i,0,1)" & doneThe resulting files are svm1.txt -> svm5.txt (using first target - open email), files 2svm1.txt -> 2svm5.txt (using second target - click email) and the validation.txt file. Next you can merge the files using the command
cat svm1.txt > total.txt for i in `seq 2 1 5` do cat svm$i.txt >> total.txt done
Subscribe to:
Posts (Atom)