我们首先来学习softmax regression和one-hot encoding。这次本次实验需要学习和机器学习相关的两个重要概念。
我们之前学过逻辑回归。由于Logistic Regression算法复杂度低、容易实现等特点,在工业界中得到广泛使用,如计算广告中的点击率预估等。但是,Logistic Regression算法主要是用于处理二分类问题,若需要处理的是多分类问题,如手写字识别,即识别是{0,1,…,9}中的数字,此时,需要使用能够处理多分类问题的算法。Softmax Regression算法是Logistic Regression算法在多分类问题上的推广,主要用于处理多分类问题,其中,任意两个类之间是线性可分的。
我们知道,在Logistic回归中比较重要的有两个公式,一个是阶跃函数:
另一个是对应的损失函数:
最终,Logistic回归需要求出的是两个概率:
在Logistic回归需要求解的是两个概率,而在Softmax Regression中将不是两个概率,而是k个概率,k表示的是分类的个数。我们需要求出以下的概率值:
此时的损失函数为:
其中I{}是一个指示性函数,意思是大括号里的值为真时,该函数的结果为1,否则为0。下面就这几个公式做个解释:
先来看看损失函数的由来
概率函数可以表示为:
其似然函数为:
log似然为:
我们要最大化似然函数,即求max
转化成损失函数。
接着对log似然(或者是损失函数)求偏导
为了简单,我们仅取一个样本,则可简单表示为:
对上式求偏导
如Logistic回归中一样,可以使用基于梯度的方法来求解这样的最大化问题。
接下来学习独热编码。
在此之前我们先来了解什么是离散特征。
在机器学习算法中,我们经常会遇到分类特征,例如:人的性别有男女,祖国有中国,美国,法国等。
这些特征值并不是连续的,而是离散的,无序的。通常我们需要对其进行特征数字化。
那什么是特征数字化呢?例子如下:
性别特征:[“男”,“女”]
祖国特征:[“中国”,"美国,“法国”]
运动特征:[“足球”,“篮球”,“羽毛球”,“乒乓球”]
假如某个样本(某个人),他的特征是这样的[“男”,“中国”,“乒乓球”],我们可以用 [0,0,4] 来表示,但是这样的特征处理并不能直接放入机器学习算法中。因为类别之间是无序的
接着在回过头来学习独热编码。
One-Hot编码,又称为一位有效编码,主要是采用N位状态寄存器来对N个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候只有一位有效。
One-Hot编码是分类变量作为二进制向量的表示。这首先要求将分类值映射到整数值。然后,每个整数值被表示为二进制向量,除了整数的索引之外,它都是零值,它被标记为1。
举个例子
性别特征:[“男”,“女”],按照N位状态寄存器来对N个状态进行编码的原理,咱们处理后应该是这样的(这里只有两个特征,所以N=2):
男 => 10
女 => 01
祖国特征:[“中国”,"美国,“法国”](这里N=3):
中国 => 100
美国 => 010
法国 => 001
运动特征:[“足球”,“篮球”,“羽毛球”,“乒乓球”](这里N=4):
足球 => 1000
篮球 => 0100
羽毛球 => 0010
乒乓球 => 0001
所以,当一个样本为[“男”,“中国”,“乒乓球”]的时候,完整的特征数字化的结果为:
[1,0,1,0,0,0,0,0,1]
为什么使用one-hot编码来处理离散型特征呢?
在回归,分类,聚类等机器学习算法中,特征之间距离的计算或相似度的计算是非常重要的,而我们常用的距离或相似度的计算都是在欧式空间的相似度计算,计算余弦相似性,基于的就是欧式空间。
而我们使用one-hot编码,将离散特征的取值扩展到了欧式空间,离散特征的某个取值就对应欧式空间的某个点。
将离散型特征使用one-hot编码,确实会让特征之间的距离计算更加合理。
比如,有一个离散型特征,代表工作类型,该离散型特征,共有三个取值,不使用one-hot编码,其表示分别是x_1 = (1), x_2 = (2), x_3 = (3)。两个工作之间的距离是,(x_1, x_2) = 1, d(x_2, x_3) = 1, d(x_1, x_3) = 2。那么x_1和x_3工作之间就越不相似吗?显然这样的表示,计算出来的特征的距离是不合理。那如果使用one-hot编码,则得到x_1 = (1, 0, 0), x_2 = (0, 1, 0), x_3 = (0, 0, 1),那么两个工作之间的距离就都是sqrt(2).即每两个工作之间的距离是一样的,显得更合理
本次实验用到的数据集叫做MNIST.这个数据集非常出名。MNIST是手写数字图片数据集,包含60000张训练样本和10000张测试样本。
MNIST数据集来自美国国家标准与技术研究所,National Institute of Standards and Technology(NIST)。现在你是不是知道这个数据集名字的由来了。M是Modified的缩写。训练集是由来自250个不同人手写的数字构成,其中50%是高中学生,50%来自人口普查局的工作人员。测试集也是同样比例的手写数字数据。每张图片有28x28个像素点构成,每个像素点用一个灰度值表示,这里是将28x28的像素展开为一个一维的行向量(每行784个值)
完整的数据可以从这里下载:
http://yann.lecun.com/exdb/mnist/
进一步关于数据的介绍会在下面的代码部分再展开。
导入相关库以及serborn,metaplotlib来可视化
读入训练数据集和测试数据集
我们以训练数据集为例打印出它的前几行看看
完整代码在1.py
测试如下
可以每条数据是一个长度为784的一维矩阵,这是因为数据经过标准化处理了,每条数据为手写图片的784个像素点(上图打印的785加上了前面的序号0,1,2,这一列本身不算在内)
我们从上图看到了很多0,但是这并不能说明对应的是什么数字,我们可以还是以这5条为例,打印出对应的数字
完整代码在2.py,测试可以得到下图5张手写数字图片,对应的标签在图片上方
每个像素的对比度不同,组合起来后得到上面的手写图片,那么我们看看像素值的最大值
完整代码在3.py
可以看到像素值在0到255之间。所以在后面的预处理过程中需要对数据进行归一化,以便获得更好的结果。
首先,我们需要定义标签和特征。 我们将它们转换为浮点值,以便我们可以通过除以最大值255来缩放它们。我们在训练和测试集中进行此操作
处理后了之后再来看看我们的数据
完整代码在4.py
可以看到已经被缩放到0到1之间的数值了
我们上面已经对特征处理后了,接下来我们需要处理标签。
我们知道标签在0到9之间,不过我们从形状也可以看出,8和9之间比8和2之间更加相似,但是作为标签,存在这种偏差是不对的,我们本次实验通过One-Hot-Encoding消除这种偏差,我们可以创建一个只有1个1的用于描述每个数字的numpy数组
我们在下面的代码中是使用pandas的get_dummies进行独热编码
我们可以将经过独热编码处理后的数据打印出来
完整代码在5.py
测试如下
第一行是原来的标签,即0到9
之后是独特编码后的数据
可以看到,独热编码后的0到9分别由一组一维向量表示,每一组中只有1个是1,其他都是0。这么处理之后,我们再也不会认为8和9比8和2更加相似了
接下来就是搭建我们的模型,首先使用sklearn的train_test_split进行数据集的划分
导入tensorflow,设置learning_rate和epoch
我们还需要定义我们的预测函数。 这将采用y = W * x + b(bias,偏差)的形式。 我们需要先定义W,x和bias。由于我们拥有将要提供给模型的数据,因此我们将x定义为占位符(用于暂存变量),稍后将为其赋值。 但是,W和bias是在模型迭代时将更改的变量。 我们还有y_true的值,它们是实际的标签,因此我们也将其定义为占位符
因为我们要进行Softmax regression,所以要使用的通用指标是交叉熵,如下代码所示。 我们想使我们的交叉熵最小化。
我们还需要一种评估模型性能的方法,来对为数字进行分类的模型进行评估
接下来是我们的优化器。 我们将使用梯度下降,因为它是一种最小化交叉熵的非常常用且功能强大的方法。 其中一个参数是之前定义的学习率,以定义学习的速度。 我们需要找到一个恰当的学习率,因为太低和太高都会产生不好的结果。
接着启动我们的session. 在TensorFlow中,始终会启动一个session来运行计算并分配占位符值。 我们还将在session期间训练我们的模型。 我们来初始化所有定义的变量
然后使用梯度下降来训练模型
在模型训练完成后,打印出将我们的模型用于验证集时的准确率
在计算完成后关闭session
完整代码在6.py
测试如下
可以看到准确率在78.8%左右,说明模型的性能还可以。
参考:
1.https://www.kaggle.com/samsonqian/softmax-regression-with-tensorflow-mnist?select=test.csv
2.https://fengxc.me/MNIST%E6%95%B0%E6%8D%AE%E9%9B%86%E4%BB%8B%E7%BB%8D.html
3.https://www.biaodianfu.com/softmax-regression.html
4.https://www.imooc.com/article/35900