运用tensorflow改写《机器学习与实战》一书中的手写识别系统

最近想入坑机器学习,同时在看《机器学习与实战》一书以及Tensorflow的官方中文文档,发现可以用Tensorflow改写一些书中的示例代码,有的甚至只需要改变一些参数即可,因此决定动手实践一下。由于Tensorflow的文档里面提到了一个叫做MNIST的手写识别数据集,而《机器学习与实战》一书中正好也有一个用KNN算法实现的手写识别系统,因此我首先选择了用Tensorflow改写一下这个系统。

这个系统的数据集是一张张 32*32 像素的图片,图片经过了二值化,因此像素点的取值只有0和1。首先需要把图片变换成一个 1*1024 的

numpy数组,这个函数在《机器学习与实战》附送的源代码的相关章节中已经实现了,我只是把它搬运到了我的模块里面:

def img2vector(filename):
    returnVect = zeros((1,1024))
    fr = open(filename)
    for i in range(32):
        lineStr = fr.readline()
        for j in range(32):
            returnVect[0,32*i+j] = int(lineStr[j])
    return returnVect

然后需要批量把训练和测试的图片转成numpy数组,同时把它们对应的标签(即0~9)也转为numpy数组,最后进行序列化方便随后使用。训练

和测试的图片在《机器学习与实战》附送的源代码里面可以获取到,我在文末也会提供,每张图片对应的标签由它的文件名提供,=。相关函数

如下:

#持久化训练集和测试集
def storeVector():
    trainingFileList = listdir('trainingDigits')
    m = len(trainingFileList)
    trainingMat = zeros((m, 1024))
    hwLabels = zeros((m, 10))
    for i in range(m):
        fileNameStr = trainingFileList[i]
        fileStr = fileNameStr.split('.')[0]     #take off .txt
        classNumStr = int(fileStr.split('_')[0])
        trainingMat[i,:] = img2vector('trainingDigits/%s' % fileNameStr)
        hwLabels[i, classNumStr] = 1

    #序列化训练集
    f = open('trainX', 'wb')
    pickle.dump(trainingMat, f)
    f.close()

    #序列化训练集标签
    f = open('trainY', 'wb')
    pickle.dump(hwLabels, f)
    f.close()

    testFileList = listdir('testDigits')
    mTest = len(testFileList)
    testMat = zeros((mTest, 1024))
    testLabels = zeros((mTest, 10))
    for i in range(mTest):
        fileNameStr = testFileList[i]
        fileStr = fileNameStr.split('.')[0]  # take off .txt
        classNumStr = int(fileStr.split('_')[0])
        testMat[i, :] = img2vector('testDigits/%s' % fileNameStr)
        testLabels[i, classNumStr] = 1

    #序列化测试集
    f = open('testX', 'wb')
    pickle.dump(testMat, f)
    f.close()

    #序列化测试集标签
    f = open('testY', 'wb')
    pickle.dump(testLabels, f)
    f.close()

#读取训练数据和测试数据
def getData():
    f = open('testX')
    testX = pickle.load(f)
    f.close()

    f = open('testY')
    testY = pickle.load(f)
    f.close()

    f = open('trainX')
    trainX = pickle.load(f)
    f.close()

    f = open('trainY')
    trainY = pickle.load(f)
    f.close()

    return trainX, trainY, testX, testY

trainX, trainY, testX, testY = getData()

需要指出的是,每个样本对应的标签是以"one-hot vector"的形式存储的,即如果一个样本对应的数字为2,则它的标签是(0,0,1,0,0,0,0,0,0,0),即只有

对应位为1,其余位均为0.

接下来需要定义一个随机获取训练子集的函数,以供随后的模型训练:

def next_batch(count):
    trainLen = shape(trainX)[0]
    if count > trainLen:
        print '没有足够的训练数据供随机抽取'
        return
    returnListIndex = rand.sample(range(trainLen), count)
    returnListX = zeros((count, 1024))
    returnListY = zeros((count, 10))
    for i in range(count):
        returnListX[i,:] = trainX[returnListIndex[i], :]
        returnListY[i,:] = trainY[returnListIndex[i], :]
    return returnListX, returnListY


接下来便是使用tensorflow进行模型的构建、训练和测试的过程了,这个我仅仅是把从tensorflow官方文档上的相关代码copy下来,把训练和测试数据

换为了我自己的,然后调整了一下几个参数而已,代码如下:

if __name__ == '__main__':
    x = tf.placeholder(tf.float32, [None, 1024])
    # 权重值
    W = tf.Variable(tf.zeros([1024, 10]))
    # 偏置量
    b = tf.Variable(tf.zeros([10]))
    # 计算输出
    y = tf.nn.softmax(tf.matmul(x, W) + b)
    # 占位符用于输入正确值
    y_ = tf.placeholder("float", [None, 10])
    # 计算交叉熵
    cross_entropy = -tf.reduce_sum(y_ * tf.log(y))
    # 使用梯度下降算法以0.01的学习速率最小化交叉熵
    train_step = tf.train.GradientDescentOptimizer(0.001).minimize(cross_entropy)
    # 初始化变量
    init = tf.global_variables_initializer()
    # 创建会话并且初始化变量
    sess = tf.Session()
    sess.run(init)
    # 开始训练模型
    for i in range(1000):
        batch_xs, batch_ys = next_batch(100)
        sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
    # 评估模型
    correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
    # 将布尔数组转换为浮点数并取平均值来确定正确预测项的比例
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
    # 打印所学习到的模型在测试数据集上面的正确率
    print sess.run(accuracy, feed_dict={x: testX, y_: testY})

代码上都有比较详尽的注释,以上代码调用了tensorflow的梯度下降算法,我仅仅修改了算法的步长参数,对tensorflow框架感兴趣的朋友

可以去极客学院学习一下该框架的官方中文文档,地址:http://wiki.jikexueyuan.com/project/tensorflow-zh/tutorials/mnist_beginners.html

算法的正确率为97%左右,而原书中使用KNN算法的正确率也是这么多。

下面附上文中用到的文件资源链接:

http://download.csdn.net/download/qq_33534383/10155187

解压缩该文件夹,里面的 kNN.py 模块是《机器学习与实战》中使用KNN算法实现手写识别系统的源码,运行该模块的handwritingClassTest函数便能看到测试结果。

tensorForDigits.py 模块是使用Tensorflow实现的手写识别系统,使用命令 python tensorForDigits.py 即可得到测试正确率。


猜你喜欢

转载自blog.csdn.net/qq_33534383/article/details/78778156