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个分隔超平面,选择$max P(Y=j|x^{i},\theta,b)$作为最终分类即可。

由于存在K组参数,原来的$h(\theta)=sigmoid(Inner)$将从单个值,变成一个大小为K的向量。

Part II  变化的目标函数

Logistic的目标函数: $J(\theta)=\sum_{i=1}^{m}(1-y^{(i)})log(1-h_{\theta}(x^{i})+y^{i}log(h_{\theta}(x^{(i)}))$

在Softmax里,由于$h_{\theta}(x^{(i)}$已经变成了向量,所以不能再使用。

实际上,在Logistic的推导里,$h_{\theta}(x^{(i)})$只是偶然而已,$P(y=0|x;\theta)=h(\theta)$。

即$P(y|x;\theta))$才是真正的概率分布函数,上述情况只是二项分布的特例。由于y的取值变成的K类,所以新的K项分布概率密度分布表示如下:

$P(y^{(i)}=j|x;\theta)=\frac{e^{W_{j}X^{i}}}{\sum_{l=1}^{k}e^{W_{l}X^{i}}}$

且定义$1\{y_{i}=j\}=(y_{i}==j)?1:0$

则  $J(\theta)=\sum_{i=1}^{m}\sum_{j=0}^{l}1\{y_{i}=j\}log\frac{e^{W_{j}X^{i}}}{\sum_{l=1}^{k}e^{W_{l}X^{i}}}$

仔细观察,其实就是$h_{\theta}(x^{(i)})$这个向量根据$y^{(i)}$情况抽取的单个值而已,这就是Logistic函数的修改版本——Softmax函数

梯度变成:$\frac{\partial J(\theta_{j})}{\partial \theta_{j}}=\sum_{i=1}^{m}x^{(i)}(1\{y_{i}=j\}-P(y^{(i)}=j|x;\theta_{j})),j=1,2....k$

可以使用梯度上升算法了(下降算法也可,即取均值加上负号,变成负对数似然函数):

$\theta_{j}^{new}=\theta_{j}^{new}+\alpha\frac{\partial J(\theta_{j})}{\partial \theta_{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
{
vector<double> feature;
int y;
Data(vector<double> feature,int y):feature(feature),y(y) {}
};
struct Parament
{
vector<double> w;
double b;
Parament() {}
Parament(vector<double> w,double b):w(w),b(b) {}
};
vector<Data> dataSet;
vector<Parament> parament;
void read()
{
ifstream fin("fullTrain.txt");
double fea;int cls;
string line;
while(getline(cin,line))
{
stringstream sin(line);
vector<double> feature;
while(sin>>fea) feature.push_back(fea);
cls=feature.back();feature.pop_back();
dataSet.push_back(Data(feature,cls));
}
for(int i=;i<K;i++) parament.push_back(Parament(vector<double>(Dim,0.0),0.0));
}
double calcInner(Parament param,Data data)
{
double ret=0.0;
for(int i=;i<data.feature.size();i++) ret+=(param.w[i]*data.feature[i]);
return ret+param.b;
}
double calcProb(int j,Data data)
{
double ret=0.0,spec=0.0;
for(int l=;l<=K;l++)
{
double tmp=exp(calcInner(parament[l-],data));
if(l==j) spec=tmp;
ret+=tmp;
}
return spec/ret;
}
double calcLW()
{
double ret=0.0;
for(int i=;i<dataSet.size();i++)
{
double prob=calcProb(dataSet[i].y,dataSet[i]);
ret+=log(prob);
}
return ret;
}
void gradient(int iter)
{
/*batch (logistic)
for(int i=0;i<param.w.size();i++)
{
double ret=0.0;
for(int j=0;j<dataSet.size();j++)
{
double ALPHA=(double)0.1/(iter+j+1)+0.1;
ret+=ALPHA*(dataSet[j].y-sigmoid(param,dataSet[j]))*dataSet[j].feature[i];
}
param.w[i]+=ret;
}
for(int i=0;i<dataSet.size();i++) ret+=alpha*(dataSet[i].y-sigmoid(param,dataSet[i]));
*/
//random
for(int j=;j<dataSet.size();j++)
{
double ret=0.0,prob=0.0;
double ALPHA=(double)0.1/(iter+j+)+0.1;
for(int k=;k<=K;k++)
{
prob=((dataSet[j].y==k?:)-calcProb(k,dataSet[j]));
for(int i=;i<Dim;i++) parament[k-].w[i]+=ALPHA*prob*dataSet[j].feature[i];
parament[k-].b+=ALPHA*prob;
}
}
}
void classify()
{
ifstream fin("fullTest.txt");
double fea;int cls,no=;
string line;
while(getline(cin,line))
{
stringstream sin(line);
vector<double> feature;
while(sin>>fea) feature.push_back(fea);
cls=feature.back();feature.pop_back();
int bestClass=-;double bestP=-;
for(int i=;i<=K;i++)
{
double p=calcProb(i,Data(feature,cls));
if(p>bestP) {bestP=p;bestClass=i;}
}
cout<<"Test:"<<++no<<" origin:"<<cls<<" classify:"<<bestClass<<endl;
}
}
void mainProcess()
{
double objLW=calcLW(),newLW;
int iter=;
gradient(iter);
newLW=calcLW();
while(fabs(newLW-objLW)>delta)
{
objLW=newLW;
gradient(iter);
newLW=calcLW();
iter++;
//if(iter%5==0) cout<<"iter: "<<iter<<" target value: "<<newLW<<endl;
}
cout<<endl<<endl;
}
int main()
{
read();
mainProcess();
classify();
}

Softmax

Part IV  测试

使用Iris鸢尾花数据集:http://archive.ics.uci.edu/ml/datasets/Iris,是三类分类问题

该数据集的第三组数据是非线性的,若K=3训练,则因为非线性数据扰乱,错误率很大。

若K=2,则代码等效于Logistic回归,错误率相近。

Softmax回归的更多相关文章

  1. Softmax回归(Softmax Regression)

    转载请注明出处:http://www.cnblogs.com/BYRans/ 多分类问题 在一个多分类问题中,因变量y有k个取值,即.例如在邮件分类问题中,我们要把邮件分为垃圾邮件.个人邮件.工作邮件 ...

  2. DeepLearning之路(二)SoftMax回归

    Softmax回归   1. softmax回归模型 softmax回归模型是logistic回归模型在多分类问题上的扩展(logistic回归解决的是二分类问题). 对于训练集,有. 对于给定的测试 ...

  3. Machine Learning 学习笔记 (3) —— 泊松回归与Softmax回归

    本系列文章允许转载,转载请保留全文! [请先阅读][说明&总目录]http://www.cnblogs.com/tbcaaa8/p/4415055.html 1. 泊松回归 (Poisson ...

  4. Softmax 回归原理介绍

    考虑一个多分类问题,即预测变量y可以取k个离散值中的任何一个.比如一个邮件分类系统将邮件分为私人邮件,工作邮件和垃圾邮件.由于y仍然是一个离散值,只是相对于二分类的逻辑回归多了一些类别.下面将根据多项 ...

  5. UFLDL教程(四)之Softmax回归

    关于Andrew Ng的machine learning课程中,有一章专门讲解逻辑回归(Logistic回归),具体课程笔记见另一篇文章. 下面,对Logistic回归做一个简单的小结: 给定一个待分 ...

  6. 机器学习 —— 基础整理(五)线性回归;二项Logistic回归;Softmax回归及其梯度推导;广义线性模型

    本文简单整理了以下内容: (一)线性回归 (二)二分类:二项Logistic回归 (三)多分类:Softmax回归 (四)广义线性模型 闲话:二项Logistic回归是我去年入门机器学习时学的第一个模 ...

  7. LR多分类推广 - Softmax回归*

    LR是一个传统的二分类模型,它也可以用于多分类任务,其基本思想是:将多分类任务拆分成若干个二分类任务,然后对每个二分类任务训练一个模型,最后将多个模型的结果进行集成以获得最终的分类结果.一般来说,可以 ...

  8. Logistic回归(逻辑回归)和softmax回归

    一.Logistic回归 Logistic回归(Logistic Regression,简称LR)是一种常用的处理二类分类问题的模型. 在二类分类问题中,把因变量y可能属于的两个类分别称为负类和正类, ...

  9. 手写数字识别 ----Softmax回归模型官方案例注释(基于Tensorflow,Python)

    # 手写数字识别 ----Softmax回归模型 # regression import os import tensorflow as tf from tensorflow.examples.tut ...

随机推荐

  1. CSS知识回顾--读《CSS 那些事儿》笔记

    由于之前有了解过CSS的相关知识,有了一定的基础,所以读起<CSS 那些事儿>不是很有难度,况且我现在读起来时,CSS3和HTML5比较流行,这里只是记录一些CSS知识记录,不做详细铺开, ...

  2. php中session锁--如何防止阻塞请求(译)

    现代浏览器限制到一个host并发连接的数量一般为4或6.这意味着,如果您的web页面加载几十个来自同一个host的assert file(js.图像.css)时,由于并发数的限制,会产生排队.同样甚至 ...

  3. PHP中判断变量为空的几种方法

    判断变量为空,在许多场合都会用到,同时自己和许多新手一样也经常会犯一些错误, 所以自己整理了一下PHP中一些常用的.判断变量为空的方法. 1. isset功能:判断变量是否被初始化本函数用来测试变量是 ...

  4. jvm

    -Xms128m表示JVM Heap(堆内存)最小尺寸128MB,初始分配-Xmx512m表示JVM Heap(堆内存)最大允许的尺寸256MB,按需分配. 说明:如果-Xmx不指定或者指定偏小,应用 ...

  5. vtkMapper

    本文只是整理了该网页的内容:http://www.cnblogs.com/lizhengjin/archive/2009/08/16/1547340.html vtkMapper是一个抽象类,指定了几 ...

  6. [Kerberos] User Ticket Management

    Kerberos客户端常用命令包括 kinit, klist, kdestroy, and kpasswd,用户使用这些命令管理自己的 ticket. 此外,每台运行Kerberos的机器应该都配置/ ...

  7. JavaScript获取浏览器高度和宽度值(documentElement,clientHeight,offsetHeight,scrollHeight,scrollTop,offsetParent,offsetY,innerHeight)

    IE中: document.body.clientWidth ==> BODY对象宽度 document.body.clientHeight ==> BODY对象高度 document.d ...

  8. Linux date命令详解

    1.显示时间 date命令可以按照指定格式显示日期,只键入date则以默认格式显示当前时间.如下: 如果需要以指定的格式显示日期,可以使用“+”开头的字符串指定其格式,详细格式如下: %n : 下一行 ...

  9. Node.js入门学习笔记(三)

    基于事件驱动的回调 这个问题不好回答,不过这是Node.js原生的工作方式.它是事件驱动的,这也是它为什么这么快的原因.你可以花一点时间阅读一下Felix Geisendörfer的大作 Unders ...

  10. 编程之美读书笔记之 -寻找出现次数为1的ID的问题

    问题描述: 在一张表里面保存了N个ID,有N-1个ID是出现了两次的,只有一个ID只出现了一次,现在要你把这个ID找出来.如果是两个呢?   解法一: 我们先来解决一个的.假如ID的值的范围是1-k, ...