『科学计算』通过代码理解SoftMax多分类

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深度学习算法都需要矩阵乘法,亦即梯度必须使用本公式,所以是很重要的废话)。

#计算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,以后可能有所应用。

时间: 2024-10-09 17:25:56

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

『科学计算』线性代数部分作业

最小二乘法求解垂足 from matplotlib import pyplot as plt import numpy as np from mpl_toolkits.mplot3d import Axes3D A=np.array([[1],[2],[3]]) B=np.array([[1],[1],[1]]) x=np.linspace(-0.5,1,10) x.shape=(1,10) xx=A.dot(x) C=A.T.dot(B) AA=np.linalg.inv(A.T.dot(A)

『科学计算』层次聚类实现

层次聚类理论自行百度,这里是一个按照我的理解的简单实现, 我们先看看数据, 啤酒名 热量 钠含量 酒精 价格Budweiser 144.00 19.00 4.70 .43Schlitz 181.00 19.00 4.90 .43Ionenbrau 157.00 15.00 4.90 .48Kronensourc 170.00 7.00 5.20 .73Heineken 152.00 11.00 5.00 .77Old-milnaukee 145.00 23.00 4.60 .26Aucsberg

『科学计算_理论』优化算法:梯度下降法&amp;牛顿法

梯度下降法 梯度下降法用来求解目标函数的极值.这个极值是给定模型给定数据之后在参数空间中搜索找到的.迭代过程为: 可以看出,梯度下降法更新参数的方式为目标函数在当前参数取值下的梯度值,前面再加上一个步长控制参数alpha.梯度下降法通常用一个三维图来展示,迭代过程就好像在不断地下坡,最终到达坡底.为了更形象地理解,也为了和牛顿法比较,这里我用一个二维图来表示: 懒得画图了直接用这个展示一下.在二维图中,梯度就相当于凸函数切线的斜率,横坐标就是每次迭代的参数,纵坐标是目标函数的取值.每次迭代的过程

『科学计算_理论』最大似然估计

概述 通俗来讲,最大似然估计,就是利用已知的样本结果,反推最有可能(最大概率)导致这样结果的参数值. 重要的假设是所有采样满足独立同分布. 求解模型参数过程 假如我们有一组连续变量的采样值(x1,x2,-,xn),我们知道这组数据服从正态分布,标准差已知.请问这个正态分布的期望值为多少时,产生这个已有数据的概率最大? P(Data | M) = ? 根据公式 可得: 对μ求导可得 ,则最大似然估计的结果为μ=(x1+x2+-+xn)/n 由上可知最大似然估计的一般求解过程: (1) 写出似然函数

『Python』Numpy学习指南第十章_高端科学计算库scipy入门(系列完结)

简介: scipy包包含致力于科学计算中常见问题的各个工具箱.它的不同子模块相应于不同的应用.像插值,积分,优化,图像处理,,特殊函数等等. scipy可以与其它标准科学计算程序库进行比较,比如GSL(GNU C或C++科学计算库),或者Matlab工具箱.scipy是Python中科学计算程序的核心包;它用于有效地计算numpy矩阵,来让numpy和scipy协同工作. 在实现一个程序之前,值得检查下所需的数据处理方式是否已经在scipy中存在了.作为非专业程序员,科学家总是喜欢重新发明造轮子

『重构--改善既有代码的设计』读书笔记----Change Value to Reference

有时候你会认为某个对象应该是去全局唯一的,这就是引用(Reference)的概念.它代表当你在某个地点对他进行修改之后,那么所有共享他的对象都应该在再次访问他的时候得到相应的修改.而不会像值对象(Value)一样,不可修改.举个例子,你认识小明,我也认识小明,小明忽然把头发都踢了,这个时候你认识的小明和我认识的小明都是同一个人,都是光头,这个小明就是世界的唯一实例,然而,你有100块钱,我有50块钱,我把50块钱花到只剩20,你手里的100块钱并不会因为我的50块钱改变而改变,不会相应的修改,这

20172311『Java程序设计』课程 结对编程练习_四则运算第一周阶段总结

20172311『Java程序设计』课程 结对编程练习_四则运算第一周阶段总结 结对伙伴 学号 :20172307 姓名 :黄宇瑭 伙伴第一周博客地址: 需求分析 功能要求 1.自动生成题目 可独立使用(能实现自己编写测试类单独生成题目的功能) 可生成不同等级题目,类似于: 1级题目:2 + 5 =: 10 - 5 = 之类的两个数,一个运算符的题目 2.题目运算(判题) 可独立使用 实现中缀表达式转为后缀表达式并计算 判断用户答题正误,并输出正确结果 3.支持真分数 可独立使用 实现分数算式的

『Python进阶』专题汇总

基础知识 『流畅的Python』第1~4章_数据结构.编码 『Python』基础数据结构常见使用方法 『Python CoolBook』数据结构和算法_多变量赋值&“*”的两种用法 『Python CoolBook:Collections』数据结构和算法_collections.deque队列&yield应用 『Python CoolBook:heapq』数据结构和算法_heapq堆队列算法&容器排序 『Python CoolBook:Collections』数据结构和算法_容器型

收集的Java科学计算库

将数学.物理.生物.航天.经济学等的计算集成到单一系统架构,提供了细致全面的计算系统. 科学计算框架 Catalano http://www.oschina.net/p/catalano Catalano Framework 是一个 Java 和 Android 的科学计算框架. 主要计算功能: 图像处理 模糊逻辑 数学计算 统计 机器学习 神经网络 科学计算可移植扩展工具包 PETSc http://www.oschina.net/p/petsc PETSc(Portable, Extensi