極限學習機(ELM)算法的matlab與C++實現

極限學習機(ELM)算法的matlab與C++實現

  • 極限學習機的原理 
    極限學習機(Extreme learning machine,ELM)是單隱層神經網絡的算法,其最大特點就是能在保證學習精度的前提下比傳統的學習算法快。其結構如下圖所示: 
    ELM結構圖

對於一個單隱層神經網絡,假設有N個任意的樣本(Xi,ti),其中, 
Xi=[xi1,xi2,xin]TRnti=[ti1,ti2,tim]TRm 
一個有L個隱層節點的單隱層神經網絡可以表示爲: 
i=1Lβih(WiXj+bi)=ojj=1,,N

其中,h(x)爲激活函數, Wi=[wi1,wi2,,win]T 
爲輸入權重,βi爲輸出權重,bi是第個隱層單元的偏置。Wi·Wj表示Wi和Wj的內積。 
單隱層神經網絡學習的目標是使得輸出的誤差最小,可以表示爲: 
j=1Nojtj=0 
即存在βi,Wi和 bi使得 
i=1Lβih(WiXj+bi)=tjj=1,,N 
可以矩陣表示爲: 
Hβ=T 
其中,是H隱層節點的輸出,β爲輸出權重,爲T期望輸出。 

H(W1,,WL,b1,,bL,X1,,XL)=h(W1X1+b1)h(W1XN+b1)h(WLX1+bL)h(WLXN+bL)

β=βT1βTL

T=TT1TTNN×m

傳統的一些基於梯度下降法的算法,可以用來求解這樣的問題,但是基本的基於梯度的學習算法需要在迭代的過程中調整所有參數。而在ELM算法中, 一旦輸入權重Wi和隱層的偏置bi被隨機確定,隱層的輸出矩陣就被唯一確定。訓練單隱層神經網絡可以轉化爲求解一個線性系統Hβ=T。並且輸出權重β可以被確定。 
β=H+T

其中,H+是矩陣H的Moore-Penrose廣義逆。且可證明求得的解的範數是最小的並且唯一。

以一個簡單的二分類爲例,分別用matlab和c++實現。matlab代碼如下:

traindata=load('traindata.txt');
feature=traindata(:,1:2);%特徵
label=traindata(:,3);%標籤
X=feature;
[N,n]=size(X);
L=100;
m=2;%二分類
W=rand(n,L)*2-1;%權重-1到1
b_1=rand(1,L);
b=ones(N,1)*b_1;
H=1./(1+exp(-X*W+b));
temp_T=zeros(N,m);
for i=1:N
    if(label(i)==1)
        temp_T(i,1)=1;
        temp_T(i,2)=0;
    else
        temp_T(i,1)=0;
        temp_T(i,2)=1;
    end
end
T=temp_T*2-1;
beta=pinv(H)*T;

x_1=X(:,1);
x_2=X(:,2);
hold on
for i=1:N
    if(label(i)==1)
        plot(x_1(i),x_2(i),'.g');
    else
        plot(x_1(i),x_2(i),'.r');
    end
end


c++代碼如下,這裏的矩陣運算採用Eigen工具包,最難的地方就是廣義逆矩陣怎麼求,參照網上的資源,代碼如下:

#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <Eigen/Dense>
#include <Eigen/SVD>
using namespace std;
using namespace Eigen;

template<typename _Matrix_Type_>
bool pseudoInverse(const _Matrix_Type_ &a, _Matrix_Type_ &result, double epsilon = std::numeric_limits<typename _Matrix_Type_::Scalar>::epsilon())
{
    Eigen::JacobiSVD< _Matrix_Type_ > svd = a.jacobiSvd(Eigen::ComputeThinU | Eigen::ComputeThinV);
    if (a.rows() < a.cols())
    {
        typename _Matrix_Type_::Scalar tolerance = epsilon * std::max(a.cols(), a.rows()) * svd.singularValues().array().abs()(0);
        result = svd.matrixV() *  (svd.singularValues().array().abs() > tolerance).select(svd.singularValues().array().inverse(), 0).matrix().asDiagonal() * svd.matrixU().adjoint();
    }
//      return false;
    else
    {
        typename _Matrix_Type_::Scalar tolerance = epsilon * std::max(a.cols(), a.rows()) * svd.singularValues().array().abs().maxCoeff();
        //  Eigen::JacobiSVD< _Matrix_Type_ > svd = a.jacobiSvd(Eigen::ComputeThinU | Eigen::ComputeThinV);
        //  typename _Matrix_Type_::Scalar tolerance = epsilon * std::max(a.cols(), a.rows()) * svd.singularValues().array().abs().maxCoeff();
        result = svd.matrixV() * ((svd.singularValues().array().abs() > tolerance).select(svd.singularValues().array().inverse(), 0)).matrix().asDiagonal() * svd.matrixU().adjoint();
    }
    return true;
}

int main()
{
    ifstream trainfile;
    trainfile.open("traindata.txt");
    vector<vector<double>> traindata;
    vector<double> rowdata;
    double temp[3];
    while (!trainfile.eof())
    {
        for (int i = 0; i < 3;i++)
        {
            trainfile >> temp[i];
            rowdata.push_back(temp[i]);
        }
        traindata.push_back(rowdata);
        rowdata.erase(rowdata.begin(), rowdata.end());
    }
    trainfile.close();
    MatrixXd feature(traindata.size(), 2);
    VectorXd label(traindata.size());
    for (int i = 0; i < traindata.size(); i++)
    {
        for (int j = 0; j < 3; j++)
        {
            if (j < 2)
                feature(i,j) = traindata[i][j];
            else
                label(i) = traindata[i][j];
        }
    }
    int L = 50;//隱含層數
    int m = 2;//二分類
    int n = 2;//特徵數
    int N = traindata.size();
    MatrixXd W,b_1,b,R,Tem,H;
    W = MatrixXd::Random(n, L);
    b_1 = (MatrixXd::Random(1, L) + MatrixXd::Ones(1, L)) / 2;
    b = MatrixXd::Ones(N, 1)*b_1;
    R = -feature*W+b;
    Tem = R.array().exp() + 1;
    H = Tem.array().inverse();
    MatrixXd temp_T,T;
    temp_T = MatrixXd::Zero(N, m);
    for (int i = 0; i < N;i++)
    {
        if (label(i)==1)
        {
            temp_T(i, 0) = 1;
            temp_T(i, 1) = 0;
        }
        else
        {
            temp_T(i, 0) = 0;
            temp_T(i, 1) = 1;
        }
    }
    T = temp_T * 2 - MatrixXd::Ones(N, m);
    MatrixXd result(L,N);
    pseudoInverse(H, result);
    MatrixXd beta = result*T;
    MatrixXd output = H*beta;
    for (int i = 0; i < N;i++)
        cout << T(i,0) << " ";
    cout << endl;
    for (int i = 0; i < N; i++)
        cout << output(i,0) << " ";
    return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章