今天太长姿势了,什么叫懂了也写不出代码说的不就是我吗,就那么几行代码居然叽叽歪歪写了一个小时。

首先exercise要实现的是softmax的cost function和gradient,如下图:

(1)

(2)

(3)

下面就来仔细分析怎么不借助for循环高效的实现上面三个函数。

首先P是一个关键,因为在J和梯度中都出现了,所以现在实现P。

可以看到theta和X的乘积是一个十分重要的量,因为在分子分母中都出现了,所以首先计算假设h=exp(θTX),那么h(k,i)就是exp(θ(k)T*x(i))的值了,实际就是计算样本i标签为k的概率,当然是没归一化的。这一句的代码十分简单(为何不支持matlab的代码?有种被歧视了的赶脚=。=):

h = exp(theta' * X);

此时要注意的一点是虽然有10个分类,但是通过ufldl的讲解我们知道有一个参数是多余的,更直观的理解就是如果得到了x(i)取前9类的概率,那么取第10类的概率直接用1减去前9类的概率和就得到了,所以theat矩阵是9行,而不是10行。我们得到的h也是9行,和公式里面K=10不一样,所以我们给h加上1行1,至于为什么是1,接下来就知道了。

h = [h;ones(1,m)];

接下来就可以计算P了,我们计算一个矩阵P,使得P(k,i)表示上述公式2的值。可以看到公式2里面的分子就是上面计算过的h(k,i)的值,而分母就是h的第i列的值相加。这里就可以借助bsxfun函数实现:

p = bsxfun(@rdivide,h,sum(h));
logp = log2(p);

bsxfun函数是一个十分高效的函数,上述第一个参数@rdivide表示对h中的每个值做“右除”除法,sum(h)就是上面分析出来的P的分母值,是一个行向量1*m(m是总样本数),即(sum(h))(i)表示h的第i列相加的值,这样bsxfun函数就会自动对h的每一行的每一个元素,都除以sum(h)这一个行向量的对应位置的值。

接下来就可以计算cost function J了。借助sub2ind这个函数实现。ufldl上有对这个函数的解释,这里大概总结以下:对于矩阵A,I=sub2ind(size(A), 1:size(A,1), y);执行后I中存放所有index为(1,y(1)),(2,y(2)),(3,y(3)),...(size(A,1),y(size(A,1)))的元素的index,所以A(I)就是这些元素实际的值了。对于cost function J,我们需要把logp中所有(k,i)位置上的值都拿出来,其中k是x(i)的ground truth的标签,所以我们可以这么写sub2ind函数:

index = sub2ind(size(logp),y,[1:m]);

再把index里面元素在logp中对应的值加起来就是cost function J了:

f = -sum(logp(index));

最后解释一下为什么要给h最后一行补1,我们知道如果h(10,i)接近1,说明分类器认为x(i)取第10类的概率大;如果h(10,i)接近0,说明x(i)分类器不太可能取第10类,如果是其他值,说明分类器“自信度”不高,我们不用考虑。我们只要考虑h(10,i)为1的情况,因为我们只要保证从logp中取(k,i)位置上的元素时候,在h(k,i)位置上接近1的元素(k,i)在logp中被取出来,其他位置上的1并不会给最终的梯度带来影响,因为它们不会被取出来,所以在最初的h的最后一行,即使x(i)不属于第k类,我们把h(k,i)置为1,也不会对后面的运算造成影响。但如果x(i)确实属于第k类,我们把h(k,i)置为1,就保证了这部分误差会被计算到最终的误差J中。


以上计算了cost function J的值,接下来计算梯度g:

首先我们知道上面计算出来的P是一个k*m的矩阵(k是类的数目,m是样本的数量),P(k,i)表示样本x(i)属于第k类的概率,公式3中重要的是怎么求出一个k*m的矩阵yk,使得yk(k,i)表示x(i)是否属于第k类,如果属于,yk(k,i)=1;否则yk(k,i)=0;也就是公式3中减号前面的项,可以用如下代码实现:

 yk = full(sparse(y,1:m,1));

full,sparse函数是非常神奇的。假设我们有一个矩阵A=[1,2,4],那么  full(sparse(A,1:3,1));就生成了如下的一个矩阵:

1     0     0
0 1 0
0 0 0
0 0 1

一般来说如果A是一个1*m的矩阵,那么full(sparse(A,1:m,1))就生成了一个(max(A),m)的矩阵,这个矩阵中(A(i),i)上的元素为1,其他元素都为0。这样我们用

 yk = full(sparse(y,1:m,1));

就可以得到上面要求的yk。

不过呢,y里面是有10个类标的,所以yk其实是一个10*m的矩阵,前面说了,我们只要知道一个样本x为前9类的样本的概率就可以了,所以我们其实只需要yk的前9行,所以要对yk进行一个截短,同样对上面的p也做一个,因为其实p的最后一行是我们手动加上去的,并且在公式3中yk要和p相减,我们需要保证p和yk的维度match。

yk = yk(1:num_classes-1,:);
p = p(1:num_classes-1,:);

最后就可以根据公式3计算梯度了

g = -X * (yk-p)';

就这么三个公式,想用代码高效的实现就这么困难,有时候不光要关注idea,更要关注idea的实现。我实现的第一个版本准确率只有87%,这个版本有92%,有时候真的不知道是算法不好,还是实现不好,所以会码是非常重要的!

最后上下结果,总共迭代了232次:

完整的代码可以在我的github上看到。

参考:

【1】http://blog.csdn.net/lingerlanlan/article/details/38425929

【2】http://ufldl.stanford.edu/tutorial/supervised/SoftmaxRegression/

【ufldl tutorial】Softmax Regression的更多相关文章

  1. 【ufldl tutorial】Convolution and Pooling

    卷积的实现: 对于每幅图像,每个filter,首先从W中取出对应的filter: filter = squeeze(W(:,:,filterNum)); 接下来startercode里面将filter ...

  2. emacs 新手笔记(一) —— 阅读【emacs tutorial】

    ilocker:关注 Android 安全(新入行,0基础) QQ: 2597294287 [emacs tutorial]是熟悉 emacs 的入门资料.一共几十个命令,不需硬记,勤练即可. 翻页命 ...

  3. 【深度学习】softmax回归——原理、one-hot编码、结构和运算、交叉熵损失

    1. softmax回归是分类问题 回归(Regression)是用于预测某个值为"多少"的问题,如房屋的价格.患者住院的天数等. 分类(Classification)不是问&qu ...

  4. 深度学习 Deep Learning UFLDL 最新Tutorial 学习笔记 5:Softmax Regression

    Softmax Regression Tutorial地址:http://ufldl.stanford.edu/tutorial/supervised/SoftmaxRegression/ 从本节開始 ...

  5. 【DeepLearning】Exercise:Softmax Regression

    Exercise:Softmax Regression 习题的链接:Exercise:Softmax Regression softmaxCost.m function [cost, grad] = ...

  6. 【TensorFlow-windows】(一)实现Softmax Regression进行手写数字识别(mnist)

    博文主要内容有: 1.softmax regression的TensorFlow实现代码(教科书级的代码注释) 2.该实现中的函数总结 平台: 1.windows 10 64位 2.Anaconda3 ...

  7. 【UFLDL】Exercise: Convolutional Neural Network

    这个exercise需要完成cnn中的forward pass,cost,error和gradient的计算.需要弄清楚每一层的以上四个步骤的原理,并且要充分利用matlab的矩阵运算.大概把过程总结 ...

  8. ufldl学习笔记和编程作业:Softmax Regression(softmax回报)

    ufldl学习笔记与编程作业:Softmax Regression(softmax回归) ufldl出了新教程.感觉比之前的好,从基础讲起.系统清晰,又有编程实践. 在deep learning高质量 ...

  9. ufldl学习笔记与编程作业:Softmax Regression(vectorization加速)

    ufldl学习笔记与编程作业:Softmax Regression(vectorization加速) ufldl出了新教程,感觉比之前的好.从基础讲起.系统清晰,又有编程实践. 在deep learn ...

随机推荐

  1. Fishnet(暴力POJ 1408)

    Fishnet Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 1911   Accepted: 1227 Descripti ...

  2. EditorWindow窗口大小锁死后没有边框的解决方法

    var window = GetWindow(typeof(MyWindow), true); window.minSize = , ); window.maxSize = window.minSiz ...

  3. poj 2420,模拟退火算法,费马点

    题目链接:http://poj.org/problem?id=2420 题意:给n个点,找出一个点,使这个点到其他所有点的距离之和最小,也就是求费马点. 参考链接:http://www.cnblogs ...

  4. 如何快捷输入函数上方的注释代码(Summary)

    写完类或函数(注意必须写完,不然出现的信息会不完整)后,在其上方空行输入/**,然后回车,就可以为其添加Summary.    

  5. profile、bashrc、bash_profile之间的区别和联系

    /etc/profile:此文件为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行.并从/etc/profile.d目录的配置文件中搜集shell的设置. 英文描述为: # /etc/pr ...

  6. J2EE开发规范

    J2EE开发规范一 JAVA编码规范1 命名规范1.1 包命名 包名称必须全部用小写. 命名方式:业务领域名.公司名.项目名.模块名 如com.yr.xxx.dao.1.2 类命名类名以英文单词取 ...

  7. Duilib将UI资源文件打包到exe教程

    转载:http://www.voidcn.com/blog/w839687571/article/p-6001921.html 转载:http://www.voidcn.com/blog/x35698 ...

  8. 1-NPM

    什么是NPM NPM是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题. 常见的使用场景有以下几种: 允许用户从NPM服务器下载别人编写的第三方包到本地使用. 允许用户从N ...

  9. MTK+Android编译

    1. 修改recovery代码 比如mediatek\custom\itek82_wet_kk\recovery\inc\cust_keys.h ./mk r k ./mk recoveryimage ...

  10. HDU 4441 Queue Sequence(splay)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4441 题意:一个数列,三种操作:(1)插入:找到没在当前数列中的最小的正整数i,将其插在位置p之后,并 ...