SoftMax实际上是Logistic的推广,当分类数为2的时候会退化为Logistic分类

其计算公式和损失函数如下,

梯度如下,

1{条件} 表示True为1,False为0,在下图中亦即对于每个样本只有正确的分类才取1,对于损失函数实际上只有m个表达式(m个样本每个有一个正确的分类)相加,

对于梯度实际上是把我们以前的最后一层和分类层合并了:

  • 第一步则和之前的求法类似,1-概率 & 0-概率组成向量,作为分类层的梯度,对batch数据实现的话就是建立一个(m,k)的01矩阵,直接点乘控制开关,最后求np.sum
  • x的转置乘分类层梯度
  • 全batch数据求和,实际上这在代码实现中和上一步放在了一块

对于单个数据梯度:x.T.dot(y_pred-y),维度是这样的(k,1)*(1,c)=(k,c)

对于成批数据梯度:X.T.dot(y_pred-y),维度是这样的(k,m)*(1,c)=(k,c),只不过结果矩阵的对应位置由x(i,1)*er(1,j)变换为x0(i,1)*er(1,j)+x1(i,1)*er(1,j)... ...正好是对全batch求了个和,所以后面需要除下去

X.T.dot(grad_next)结果是batch梯度累加和,所以需要除以样本数m,这个结论对全部使用本公式的梯度均成立(1,这句话是废话;2,但是几乎全部机器or深度学习算法都需要矩阵乘法,亦即梯度必须使用本公式,所以是很重要的废话)。

L2正则化:lamda*np.sum(W*W)或者lamda*np.sum(W.T.dot(W))均可,实际上就是W各个项的平方和

#计算Error,Cost,Grad
y_dash = self.softmax(X.dot(theta_n)) # 向前传播结果 Y = np.zeros((m,10)) # one-hot编码label矩阵
for i in range(m):
Y[i,y[i]]=1 error = np.sum(Y * np.log(y_dash), axis=1) # 注意,这里是点乘
cost = -np.sum(error, axis=0)
grad = X.T.dot(y_dash-Y) grad_n = grad.ravel()

代码实现:

import numpy as np
import matplotlib.pyplot as plt
import math def scale_n(x):
return x
#return (x-x.mean(axis=0))/(x.std(axis=0)+1e-10) class SoftMaxModel(object):
def __init__(self,alpha=0.06,threhold=0.0005):
self.alpha = alpha # 学习率
self.threhold = threhold # 循环终止阈值
self.num_classes = 10 # 分类数 def setup(self,X):
# 初始化权重矩阵,注意,由于是多分类,所以权重由向量变化为矩阵
# 而且这里面初始化的是flat为1维的矩阵
m, n = X.shape # 400,15
s = math.sqrt(6) / math.sqrt(n+self.num_classes)
theta = np.random.rand(n*(self.num_classes))*2*s-s #[15,1]
return theta def softmax(self,x):
# 先前传播softmax多分类
# 注意输入的x是[batch数目n,类数目m],输出是[batch数目n,类数目m]
e = np.exp(x)
temp = np.sum(e, axis=1,keepdims=True)
return e/temp def get_cost_grad(self,theta,X,y):
m, n = X.shape
theta_n = theta.reshape(n, self.num_classes) #计算Error,Cost,Grad
y_dash = self.softmax(X.dot(theta_n)) # 向前传播结果 Y = np.zeros((m,10)) # one-hot编码label矩阵
for i in range(m):
Y[i,y[i]]=1 error = np.sum(Y * np.log(y_dash), axis=1)
cost = -np.sum(error, axis=0)
grad = X.T.dot(y_dash-Y) grad_n = grad.ravel()
return cost,grad_n def train(self,X,y,max_iter=50, batch_size=200):
m, n = X.shape # 400,15
theta = self.setup(X) #our intial prediction
prev_cost = None
loop_num = 0
n_samples = y.shape[0]
n_batches = n_samples // batch_size
# Stochastic gradient descent with mini-batches
while loop_num < max_iter:
for b in range(n_batches):
batch_begin = b*batch_size
batch_end = batch_begin+batch_size
X_batch = X[batch_begin:batch_end]
Y_batch = y[batch_begin:batch_end] #intial cost
cost,grad = self.get_cost_grad(theta,X_batch,Y_batch) theta = theta- self.alpha * grad/float(batch_size) loop_num+=1
if loop_num%10==0:
print (cost,loop_num)
if prev_cost:
if prev_cost - cost <= self.threhold:
break prev_cost = cost self.theta = theta
print (theta,loop_num) def train_scipy(self,X,y):
m,n = X.shape
import scipy.optimize
options = {'maxiter': 50, 'disp': True}
J = lambda x: self.get_cost_grad(x, X, y)
theta = self.setup(X) result = scipy.optimize.minimize(J, theta, method='L-BFGS-B', jac=True, options=options)
self.theta = result.x def predict(self,X):
m,n = X.shape
theta_n = self.theta.reshape(n, self.num_classes)
a = np.argmax(self.softmax(X.dot(theta_n)),axis=1)
return a def grad_check(self,X,y):
epsilon = 10**-4
m, n = X.shape sum_error=0
N=300 for i in range(N):
theta = self.setup(X)
j = np.random.randint(1,len(theta))
theta1=theta.copy()
theta2=theta.copy()
theta1[j]+=epsilon
theta2[j]-=epsilon cost1,grad1 = self.get_cost_grad(theta1,X,y)
cost2,grad2 = self.get_cost_grad(theta2,X,y)
cost3,grad3 = self.get_cost_grad(theta,X,y) sum_error += np.abs(grad3[j]-(cost1-cost2)/float(2*epsilon))
print ("grad check error is %e\n"%(sum_error/float(N))) if __name__=="__main__": import cPickle, gzip
# Load the dataset
f = gzip.open('mnist.pkl.gz', 'rb')
train_set, valid_set, test_set = cPickle.load(f)
f.close()
train_X = scale_n(train_set[0])
train_y = train_set[1]
test_X = scale_n(test_set[0])
test_y = test_set[1] l_model = SoftMaxModel() l_model.grad_check(test_X[0:200,:],test_y[0:200]) l_model.train_scipy(train_X,train_y) predict_train_y = l_model.predict(train_X)
b = predict_train_y!=train_y error_train = np.sum(b, axis=0)/float(b.size) predict_test_y = l_model.predict(test_X)
b = predict_test_y!=test_y error_test = np.sum(b, axis=0)/float(b.size) print ("Train Error rate = %.4f, \nTest Error rate = %.4f\n"%(error_train,error_test))

这里面有scipy的优化器应用,因为不是重点(暂时没有学习这个库的日程),所以标注出来,需要用优化器优化函数的时候记得有这么回事再深入学习即可:

def train_scipy(self,X,y):
m,n = X.shape
import scipy.optimize
options = {'maxiter': 50, 'disp': True}
J = lambda x: self.get_cost_grad(x, X, y)
theta = self.setup(X) result = scipy.optimize.minimize(J, theta, method='L-BFGS-B', jac=True, options=options)
self.theta = result.x

主要是提供了一些比较复杂的优化算法,而且是一个优化自建目标函数的demo,以后可能有所应用。

『科学计算』通过代码理解SoftMax多分类的更多相关文章

  1. 『科学计算』通过代码理解线性回归&Logistic回归模型

    sklearn线性回归模型 import numpy as np import matplotlib.pyplot as plt from sklearn import linear_model de ...

  2. 『科学计算』可视化二元正态分布&3D科学可视化实战

    二元正态分布可视化本体 由于近来一直再看kaggle的入门书(sklearn入门手册的感觉233),感觉对机器学习的理解加深了不少(实际上就只是调包能力加强了),联想到假期在python科学计算上也算 ...

  3. 『科学计算』L0、L1与L2范数_理解

     『教程』L0.L1与L2范数 一.L0范数.L1范数.参数稀疏 L0范数是指向量中非0的元素的个数.如果我们用L0范数来规则化一个参数矩阵W的话,就是希望W的大部分元素都是0,换句话说,让参数W是稀 ...

  4. 『科学计算』图像检测微型demo

    这里是课上老师给出的一个示例程序,演示图像检测的过程,本来以为是传统的滑窗检测,但实际上引入了selectivesearch来选择候选窗,所以看思路应该是RCNN的范畴,蛮有意思的,由于老师的注释写的 ...

  5. 『科学计算』科学绘图库matplotlib学习之绘制动画

    基础 1.matplotlib绘图函数接收两个等长list,第一个作为集合x坐标,第二个作为集合y坐标 2.基本函数: animation.FuncAnimation(fig, update_poin ...

  6. 『科学计算』科学绘图库matplotlib练习

    思想:万物皆对象 作业 第一题: import numpy as np import matplotlib.pyplot as plt x = [1, 2, 3, 1] y = [1, 3, 0, 1 ...

  7. 『TensorFlow』通过代码理解gan网络_中

    『cs231n』通过代码理解gan网络&tensorflow共享变量机制_上 上篇是一个尝试生成minist手写体数据的简单GAN网络,之前有介绍过,图片维度是28*28*1,生成器的上采样使 ...

  8. 『cs231n』通过代码理解gan网络&tensorflow共享变量机制_上

    GAN网络架构分析 上图即为GAN的逻辑架构,其中的noise vector就是特征向量z,real images就是输入变量x,标签的标准比较简单(二分类么),real的就是tf.ones,fake ...

  9. 『cs231n』通过代码理解风格迁移

    『cs231n』卷积神经网络的可视化应用 文件目录 vgg16.py import os import numpy as np import tensorflow as tf from downloa ...

随机推荐

  1. 升级到php7相关问题,日请求过亿QQ会员活动平台PHP7升级实践

    升级到php7相关问题,日请求过亿QQ会员活动平台PHP7升级实践 日请求过亿:QQ会员活动平台PHP7升级实践http://mp.weixin.qq.com/s?__biz=MjM5MjAwODM4 ...

  2. netty4----日志框架的检查

    https://segmentfault.com/a/1190000005797595 2016年06月25日  ·  4.1k 次阅读 Netty4.x Internal Logger机制 nett ...

  3. sp3485推荐电路(转)

    源: sp3485推荐电路 注意:转自电子发烧友 转:485通信自动收发电路 转: RS485收发的3种典型电路-重点-自动收发电路

  4. 负载均衡之-haproxy

    老规矩,先介绍?复制一段? 1)HAProxy提供高可用性.负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机,它是免费.快速并且可靠的一种解决方案. 2)HAProxy特别适用于那些负载特大的 ...

  5. mysql5.6升级及mysql无密码登录

    mysql5.6升级 mysql5.6的升级可以分为以下几个步骤: 安全关闭正在运行的MySQL实例 把/usr/local/mysql 的连接由MySQL5.6更改为MySQL5.7 启动MySQL ...

  6. 03: zabbix API接口 对 主机、主机组、模板、应用集、监控项、触发器等增删改查

    目录:Django其他篇 01: 安装zabbix server 02:zabbix-agent安装配置 及 web界面管理 03: zabbix API接口 对 主机.主机组.模板.应用集.监控项. ...

  7. 03: KindEditor (HTML可视化编辑器)

    目录: 1.1 kindEditor常用配置参数 1.2 kindEditor下载与文件说明 1.3 kindEditor实现上传图片.文件.及文件空间管理 1.1 kindEditor常用配置参数返 ...

  8. 20145334赵文豪 WEB基础实践

    实验问题回答 1.什么是表单 表单在网页中主要负责数据采集功能 一个表单有三个基本组成部分: 表单标签 表单域:包含了文本框.密码框.隐藏域.多行文本框.复选框.单选框.下拉选择框和文件上传框等 表单 ...

  9. linux内核分析 第六周

    一.进程的描述 为了管理进程,内核必须对每个进程进行清晰的描述,进程描述符提供了内核所需了解的进程信息. 1.进程控制块PCB--task_struct 进程状态 进程打开的文件 进程优先级信息 2. ...

  10. 最常用的15大Eclipse开发快捷键技巧【转】

    引言 做java开发的,经常会用Eclipse或者MyEclise集成开发环境,一些实用的Eclipse快捷键和使用技巧,可以在平常开发中节约出很多时间提高工作效率,下面我就结合自己开发中的使用和大家 ...