Softmax回归
Reference:
http://ufldl.stanford.edu/wiki/index.php/Softmax_regression
http://deeplearning.net/tutorial/logreg.html
起源:Logistic的二类分类
Softmax回归是Logistic回归的泛化版本,用于解决线性多类(K类)的分类问题。
Logistic回归可以看作是Softmax回归在K=2时的特例。Softmax函数即是K分类版的Logistc函数。
裸Softmax回归的效果很差,因为没有隐层结构,归根还是是线性回归。所以在深度学习里,Softmax则通常作为MLP的输出层。
即,将BP网络和Softmax结合起来,取BP网络的隐层映射机制、Softmax的多分类机制,加以组合形成新的MLP架构。
这么做的原因就是,传统BP网络的输出层是个多神经元的自行设计接口层,比如常见的log2(K)方法,转多分类需要麻烦的编码。
但实际上,隐层(可看作是input)到输出层的映射原理等效于Softmax,既然Softmax拥有概率取分类的方法,何必再用低效的编码方法?
Part I 如何从2类转化为K类?
解决方案是引入K组(W、b)参数,即有K个分隔超平面,选择maxP(Y=j|xi,θ,b)作为最终分类即可。
由于存在K组参数,原来的h(θ)=sigmoid(Inner)将从单个值,变成一个大小为K的向量。
Part II 变化的目标函数
Logistic的目标函数: J(θ)=∑mi=1(1−y(i))log(1−hθ(xi)+yilog(hθ(x(i)))
在Softmax里,由于hθ(x(i)已经变成了向量,所以不能再使用。
实际上,在Logistic的推导里,hθ(x(i))只是偶然而已,P(y=0|x;θ)=h(θ)。
即P(y|x;θ))才是真正的概率分布函数,上述情况只是二项分布的特例。由于y的取值变成的K类,所以新的K项分布概率密度分布表示如下:
P(y(i)=j|x;θ)=eWjXi∑kl=1eWlXi
且定义1{ yi=j}=(yi==j)?1:0
则 J(θ)=∑mi=1∑lj=01{ yi=j}logeWjXi∑kl=1eWlXi
仔细观察,其实就是hθ(x(i))这个向量根据y(i)情况抽取的单个值而已,这就是Logistic函数的修改版本——Softmax函数
梯度变成:∂J(θj)∂θj=∑mi=1x(i)(1{ yi=j}−P(y(i)=j|x;θj)),j=1,2....k
可以使用梯度上升算法了(下降算法也可,即取均值加上负号,变成负对数似然函数):
θnewj=θnewj+α∂J(θj)∂θj,j=1,2....k
Part III C++代码与实现
#include "cstdio" #include "iostream" #include "fstream" #include "vector" #include "sstream" #include "string" #include "math.h" using namespace std; #define N 500 #define delta 0.0001 #define alpha 0.1 #define cin fin #define K 2 #define Dim dataSet[0].feature.size() struct Data { vectorfeature; int y; Data(vector feature,int y):feature(feature),y(y) {} }; struct Parament { vector w; double b; Parament() {} Parament(vector w,double b):w(w),b(b) {} }; vector dataSet; vector parament; void read() { ifstream fin("fullTrain.txt"); double fea;int cls; string line; while(getline(cin,line)) { stringstream sin(line); vector feature; while(sin>>fea) feature.push_back(fea); cls=feature.back();feature.pop_back(); dataSet.push_back(Data(feature,cls)); } for(int i=0;i (Dim,0.0),0.0)); } double calcInner(Parament param,Data data) { double ret=0.0; for(int i=0;i feature; while(sin>>fea) feature.push_back(fea); cls=feature.back();feature.pop_back(); int bestClass=-1;double bestP=-1; for(int i=1;i<=K;i++) { double p=calcProb(i,Data(feature,cls)); if(p>bestP) {bestP=p;bestClass=i;} } cout<<"Test:"<<++no<<" origin:"< delta) { objLW=newLW; gradient(iter); newLW=calcLW(); iter++; //if(iter%5==0) cout<<"iter: "<
#include "cstdio" #include "iostream" #include "fstream" #include "vector" #include "sstream" #include "string" #include "math.h" using namespace std; #define N 500 #define delta 0.0001 #define alpha 0.1 #define cin fin #define K 2 #define Dim dataSet[0].feature.size() struct Data { vectorfeature; int y; Data(vector feature,int y):feature(feature),y(y) {} }; struct Parament { vector w; double b; Parament() {} Parament(vector w,double b):w(w),b(b) {} }; vector dataSet; vector parament; void read() { ifstream fin("fullTrain.txt"); double fea;int cls; string line; while(getline(cin,line)) { stringstream sin(line); vector feature; while(sin>>fea) feature.push_back(fea); cls=feature.back();feature.pop_back(); dataSet.push_back(Data(feature,cls)); } for(int i=0;i (Dim,0.0),0.0)); } double calcInner(Parament param,Data data) { double ret=0.0; for(int i=0;i feature; while(sin>>fea) feature.push_back(fea); cls=feature.back();feature.pop_back(); int bestClass=-1;double bestP=-1; for(int i=1;i<=K;i++) { double p=calcProb(i,Data(feature,cls)); if(p>bestP) {bestP=p;bestClass=i;} } cout<<"Test:"<<++no<<" origin:"< delta) { objLW=newLW; gradient(iter); newLW=calcLW(); iter++; //if(iter%5==0) cout<<"iter: "<
Part IV 测试
使用Iris鸢尾花数据集:http://archive.ics.uci.edu/ml/datasets/Iris,是三类分类问题
该数据集的第三组数据是非线性的,若K=3训练,则因为非线性数据扰乱,错误率很大。
若K=2,则代码等效于Logistic回归,错误率相近。