之前我们介绍过逻辑回归的二分类问题,但是在我们实际应用中往往都是多分类问题,这里我们以Mnist数据集为例来分析多分类问题,首先Mnist输入为图片,是高维度数据,不同于我们之前的一行或者一列,这里我们先从简单的开始,将28x28矩阵,转化为1x784的矩阵,这样我们的输入数据就和前面的一样,既然要对数据进行处理,那我们先分析一下我们要解析的数据是什么样的。
以下为二进制文件信息,前面4个32 bit integer表示文件信息,后面即使图片的二进制形式
magic number 用来标记文件或者协议的格式
number of images 图片数量
number of rows
number of columns 图片大小
下面是读取图片的过程
#--coding:UTF-8 --
import numpy as np
import struct
import matplotlib.pyplot as plt
#读取二进制数据
filename = './MNIST_data/t10k-images-idx3-ubyte'
binfile = open(filename , 'rb') # python3 'r' but python2 'rd'
buf = binfile.read()
#index为读取的索引
#读取文件标志、图片数量和大小
index = 0
magic, numImages, numRows, numColumns = struct.unpack_from('>IIII' , buf , index)
index += struct.calcsize('>IIII')
#读取一张图片即784Byte
im = struct.unpack_from('>784B' , buf , index)
index += struct.calcsize('>784B')
#将读取数据转化为矩阵并改成图片格式
im = np.array(im)
im = im.reshape(28,28)
#显示第一张图片
fig = plt.figure()
plotwindow = fig.add_subplot(111)
plt.imshow(im , cmap = 'gray')
plt.show()
以上是mnist数据集的了解过程,下面是我写的解析函数:
#--coding:UTF-8--
#mnist_read.py
import numpy as np
import struct
#对MNIST数据集进行解析,解析为对应矩阵形式,可以根据自己处理需求进行修改
def read_images(filename):
binfile=open(filename,'rb')
buf=binfile.read()
index=0
magic, numImages, numRows, numColumns = struct.unpack_from('>IIII' , buf , index)
index += struct.calcsize('>IIII')
image=[]
for i in range(numImages):
im=struct.unpack_from('>784B',buf,index)
im=list(im)
image.append(im)
index+=struct.calcsize('>784B')
return np.array(image)
#a=read_images('./data/MNIST_data/train-images-idx3-ubyte')
#print a
#将标签表示为10列矩阵
def read_labels(filename):
binfile=open(filename,'rb')
buf=binfile.read()
index=0
magic,numItems=struct.unpack_from('>II',buf,index)
index+=struct.calcsize('>II')
label=[]
for i in range(numItems):
l=struct.unpack_from('>1B',buf,index)
m=[0,0,0,0,0,0,0,0,0,0]
m[l[0]]=1
label.append(m)
index+=1
return np.array(label)
#b=read_labels('./data/MNIST_data/t10k-labels-idx1-ubyte')
#print b.astype(np.float32)
得到数据即可通过前面的知识进行简单的模型构建,首先是一层神经网络:
#--coding:UTF-8--
import tensorflow as tf
import numpy as np
import mnist_read
#通过自己写的解析函数将数据解析出来,并进行简单的预处理
train_images=mnist_read.read_images('./data/MNIST_data/train-images-idx3-ubyte').astype(np.float32)/255
train_labels=mnist_read.read_labels('./data/MNIST_data/train-labels-idx1-ubyte').astype(np.float32)
test_images=mnist_read.read_images('./data/MNIST_data/t10k-images-idx3-ubyte').astype(np.float32)/255
test_labels=mnist_read.read_labels('./data/MNIST_data/t10k-labels-idx1-ubyte').astype(np.float32)
x=tf.placeholder(tf.float32,shape=[None,784])
y=tf.placeholder(tf.float32,shape=[None,10])
W=tf.Variable(tf.zeros([784,10]))
b=tf.Variable(tf.zeros([10]))
y_=tf.matmul(x,W)+b
#使用欧氏距离表示损失函数
loss=tf.reduce_mean(tf.square(y-y_))
optimizer=tf.train.GradientDescentOptimizer(0.01)
train=optimizer.minimize(loss)
sess=tf.Session()
init=tf.global_variables_initializer()
sess.run(init)
#最大值索引号比较是否相同
correct_prediction=tf.equal(tf.argmax(y_,1),tf.argmax(y,1))
accuracy=tf.reduce_mean(tf.cast(correct_prediction,'float'))
for i in range(1000):
sess.run(train,feed_dict={x:train_images,y:train_labels})
print sess.run(accuracy,feed_dict={x:test_images,y:test_labels})
最后以0.01的学习率训练1000步得到在测试集上正确率为83.91%
通过softmax处理,并使用cross_entropy损失函数,以0.5学习率训练1000步正确率可以达到90.11%
在softmax基础上使用BatchGradientDescent正确率可以达到91.17%
一些小小总结:
二分类问题,可以用sigmiod函数将输出映射到(0,1)
对于多分类问题,可以用softmax将输出表示成(0,1)间的概率值
对于这种概率问题,一般使用交叉熵作为损失函数,即sum{-y_true*log(y_model)}
一般回归问题用mean squared error 分类问题用cross entropy
loss使用cross entropy解释
引用通俗说法即是:熵是什么?设p是一个分布,-plnp表示该种概率分布的熵,而-lnp表示编码长度。所以熵就是最小的平均编码长度。交叉熵,就是用几种分布p去近似未知的分布p,那么如何评价你选的分布q的好坏呢?就是你选定的q去编码分布q,然后得到的编码长度最小就表明你选择的分布q是最好的。