支持向量机原理参考: 1.支持向量机(SVM)的分析及python实现(高赞,通俗易懂,sklearn各种实现) 2.SVM 支持向量机算法原理(详细总结)和python代码实现(进阶详细理论)
SMO算法参考: 序列最小优化算法SMO及代码实现
python实现:
import numpy as np
import random
class SimpleSMO(object):
def __init__(self,x,y,b,c,tolerance,max_iter):
self.x = x
self.y = y
self.b = b
self.c = c
self.max_iter = max_iter
self.tolerance = tolerance
self.alpha = np.zeros((self.x.shape[0],1))
def g(self,x_i):
return np.sum(self.alpha * self.y.reshape(-1, 1) * (np.dot(self.x,x_i.T).reshape(-1,1))) + self.b
def Error(self,x_i,y_i):
return self.g(x_i) - y_i
def SelectJ(self,i):
j = i
while (j==i):
j = int(random.uniform(0,self.x.shape[0]))
return j
def Kernal(self,m,n):
return self.x[m].dot(self.x[n].T)
def Optimization(self):
iter = 0
while (iter < self.max_iter):
alphaPairsChanged = 0
for i in range(self.alpha.size):
E_i = self.Error(self.x[i],self.y[i])
if (y[i] * E_i < -self.tolerance and self.alpha[i] < self.c ) or (y[i] * E_i > self.tolerance and self.alpha[i] > 0 ):
j = self.SelectJ(i)
E_j = self.Error(self.x[j],self.y[j])
alpha_i_old = self.alpha[i].copy()
alpha_j_old = self.alpha[j].copy()
if (self.y[i] != self.y[j]):
L = max(0,alpha_j_old-alpha_i_old)
H = min(self.c,self.c + alpha_j_old - alpha_i_old)
else:
L = max(0,alpha_j_old + alpha_i_old - self.c)
H = min(self.c,alpha_j_old + alpha_i_old)
if L == H:
print("L=H")
continue
eta = 2 * self.Kernal(i,j)-self.Kernal(i,i)-self.Kernal(j,j)
if eta>= 0:
print("eta>=0")
continue
alpha_j_new_unc = alpha_j_old - y[j]*(E_i-E_j)/eta
self.alpha[j] = np.clip(alpha_j_new_unc,L,H)
if abs(self.alpha[j]-alpha_j_old) < 0.00001:
print("j not moving enough")
continue
self.alpha[i] += self.y[i]*self.y[j]*(alpha_j_old-self.alpha[j])
b_i_new = self.b - E_i -y[i]*self.Kernal(i,i)*(self.alpha[i]-alpha_i_old) - y[j]*self.Kernal(j,i)*(self.alpha[j]-alpha_j_old)
b_j_new = self.b - E_j -y[i]*self.Kernal(i,j)*(self.alpha[i]-alpha_i_old) - y[j]*self.Kernal(j,j)*(self.alpha[j]-alpha_j_old)
if (self.alpha[i]>0 and self.alpha[i]<self.c):
self.b = b_i_new
elif (self.alpha[j]>0 and self.alpha[j]<self.c):
self.b = b_j_new
else:
self.b = (b_i_new + b_j_new)/2
alphaPairsChanged += 1
print("External loop: %d; Internal loop i :%d; alphaPairsChanged :%d" % (iter,i,alphaPairsChanged))
if (alphaPairsChanged == 0):
iter += 1
else:
iter = 0
print("Iteration number : %d" % iter)
if __name__ == '__main__':
x = np.array([[4,2], [3,3], [8,-2], [2,-4], [8,1]])
y = np.array([-1,-1,1,-1,1])
smo = SimpleSMO(x,y,0,0.6,0.001,10)
smo.Optimization()
C++实现:
#include <iostream>
#include <vector>
#include <ctime>
#include <algorithm>
class SimpleSMO
{
public:
SimpleSMO(std::vector<std::vector<float>> x, std::vector<float> y, float b, float c, float tolerance, int max_iter)
{
m_x = x;
m_y = y;
m_b = b;
m_c = c;
m_tolerance = tolerance;
m_max_iter = max_iter;
m_alpha.resize(m_x.size());
}
float g(std::vector<float> x_i)
{
std::vector<float> tmp_vec(m_x.size(), 0);
for (size_t i = 0; i < m_x.size(); i++)
{
for (size_t j = 0; j < m_x[0].size(); j++)
{
tmp_vec[i] += m_x[i][j] * x_i[j];
}
}
float tmp_val = 0;
for (size_t i = 0; i < tmp_vec.size(); i++)
{
tmp_val += tmp_vec[i] * m_y[i];
}
float sum = 0;
for (size_t i = 0; i < m_alpha.size(); i++)
{
sum += tmp_val*m_alpha[i];
}
return sum + m_b;
}
float Error(std::vector<float> x_i, float y_i)
{
return g(x_i) - y_i;
}
int SelectJ(int i)
{
srand((unsigned)time(NULL));
int j = i;
while (j == i)
{
j = rand() % m_x.size();
}
return j;
}
float Kernal(int m, int n)
{
float ret = 0;
for (size_t i = 0; i < m_x[0].size(); i++)
{
ret += m_x[m][i] * m_x[n][i];
}
return ret;
}
void Optimization()
{
int iter = 0;
while (iter < m_max_iter)
{
int alphaPairsChanged = 0;
for (size_t i = 0; i < m_alpha.size(); i++)
{
float E_i = Error(m_x[i], m_y[i]);
if ((m_y[i] * E_i < -m_tolerance && m_alpha[i] < m_c) || (m_y[i] * E_i > m_tolerance && m_alpha[i] > 0))
{
int j = SelectJ(i);
float E_j = Error(m_x[j], m_y[j]);
float alpha_i_old = m_alpha[i];
float alpha_j_old = m_alpha[j];
float L, H;
if (m_y[i] != m_y[j])
{
L = std::max(0.0f, alpha_j_old - alpha_i_old);
H = std::min(m_c, m_c + alpha_j_old - alpha_i_old);
}
else {
L = std::max(0.0f, alpha_j_old + alpha_i_old - m_c);
H = std::min(m_c, alpha_j_old + alpha_i_old);
}
if (L == H)
{
std::cout << "L=H" << std::endl;
continue;
}
float eta = 2 * Kernal(i, j) - Kernal(i, i) - Kernal(j, j);
if (eta >= 0)
{
std::cout << "eta>=0" << std::endl;
continue;
}
float alpha_j_new_unc = alpha_j_old - m_y[j] * (E_i - E_j) / eta;
if (alpha_j_new_unc < L)
m_alpha[j] = L;
else if (alpha_j_new_unc > H)
m_alpha[j] = H;
else
m_alpha[j] = alpha_j_new_unc;
if (fabs(m_alpha[j] - alpha_j_old) < 0.00001)
{
std::cout << "j not moving enough" << std::endl;
continue;
}
m_alpha[i] += m_y[i] * m_y[j] * (alpha_j_old - m_alpha[j]);
float b_i_new = m_b - E_i - m_y[i] * Kernal(i, i)*(m_alpha[i] - alpha_i_old) - m_y[j] * Kernal(j, i)*(m_alpha[j] - alpha_j_old);
float b_j_new = m_b - E_j - m_y[i] * Kernal(i, j)*(m_alpha[i] - alpha_i_old) - m_y[j] * Kernal(j, j)*(m_alpha[j] - alpha_j_old);
if (m_alpha[i] > 0 && m_alpha[i] < m_c)
m_b = b_i_new;
else if (m_alpha[j] > 0 && m_alpha[j] < m_c)
m_b = b_j_new;
else
m_b = (b_i_new + b_j_new) / 2.0;
alphaPairsChanged += 1;
std::cout << "External loop: " << iter << "; Internal loop i :" << i << "; alphaPairsChanged:" << alphaPairsChanged << std::endl;
}
}
if (alphaPairsChanged == 0)
iter += 1;
else
iter = 0;
std::cout << "Iteration number: " << iter << std::endl;
}
}
private:
std::vector<std::vector<float>> m_x;
std::vector<float> m_y;
float m_b;
float m_c;
float m_tolerance;
int m_max_iter;
std::vector<float> m_alpha;
};
int main(int argc, char* argv[])
{
std::vector<std::vector<float>> x = { { 4,2 },{ 3,3 },{ 8,-2 },{ 2,-4 }, { 8,1 } };
std::vector<float> y = { -1, -1, 1, -1, 1 };
SimpleSMO smo = SimpleSMO(x, y, 0, 0.6, 0.001, 10);
smo.Optimization();
system("pause");
return EXIT_SUCCESS;
}
|