[date: 2018-03-27 11:38] [visits: 79]

深度学习-图片识别(上)

本文主要针对优达学城深度学习课程中的练习题任务1至3,整理练习内容,有兴趣者可结合本文内容然后按练习题实践,帮助理解。

任务一:下载并整理数据

任务主要完成图片下载、图片内容数字化、选取三个数据集、打乱顺序、持久化数据等,步骤如下:

large与small不止数量大小区别,还在于large中的图片有没经过人工筛选,有噪点以及损坏图片,从中选取数据作为训练集与验证集,small中的图片经过人工筛选,数据相对干净,从中选取数据作为测试集

每张图片可以用一个28 x 28的二维数组表示,一个目录下的n张图片放到一个n x 28 x 28的三维数组中,然后通过pickle序列化到文件中

从处理好的数据中选取训练集、验证集、测试集,选取过程中每个类别打乱顺序并合并不同类别,同时使用数组记录每个数据项对应的类别(label)

针对每个数据集与label,再次打乱顺序,然后把所有数据集以及相应label包装成dict序列化到磁盘

任务作业

使用sklearn.linear_model中的LogisticRegression模型训练一个模型,主要代码:

import numpy as np
import pickle
from sklearn.linear_model import LogisticRegression

image_size = 28
train_size = 1000

data = pickle.load(open('notMNIST.pickle','rb'))

train_features = data['train_dataset'][:train_size]
train_labels = data['train_labels'][:train_size]

test_features = data['test_dataset']
test_labels = data['test_labels']

train_features = train_features.reshape(len(train_features), image_size * image_size)

test_features = test_features.reshape(len(test_features), image_size * image_size)

print 'start train!'
classifier = LogisticRegression()
classifier.fit(train_features, train_labels)

print 'start predict!'
score = classifier.score(test_features,test_labels)

print 'The accuray score is %.3f' % score

结果:

start train!
start predict!
The accuray score is 0.828

任务二:TF逻辑回归训练模型

任务主要构造TF计算图、训练模型,最后验证随机梯度下降算法带来的速度优化,这部分内容比上一个任务难度增加,开始涉及TF编程,分为以下几步:

将特征数组由n x 28 x 28的变形为n x 784,label的值使用One-Hot编码

选取了部分训练数据作为输入,使用tf.truncated_normal生成权重矩阵,计算输入矩阵与权重矩阵的乘积再加上偏差,然后计算softmax和交叉熵,并使用所有样本的交叉熵平均值作为模型针对样本的损失值,最后使用梯度下降算法优化器优化模型

训练801步,每训练100步,输出模型针对训练集与验证集的损失值、准确度

重新构造计算图,然后使用随机梯度下降算法训练3001步,训练速度比普通梯度下降算法更快

任务作业

任务二下面有留下一个需要解答的问题:“添加一层通过ReLU函数激活的隐藏层”,主要代码如下:

batch_size = 128
hidden_layer_node_num = 1024

graph = tf.Graph()
with graph.as_default():
    tf_train_dataset = tf.placeholder(tf.float32, shape=(batch_size, image_size * image_size))
    tf_train_labels = tf.placeholder(tf.float32, shape=(batch_size, num_labels))
    tf_valid_dataset = tf.constant(valid_dataset)
    tf_test_dataset = tf.constant(test_dataset)

    hidden_weights = tf.Variable(tf.truncated_normal([image_size * image_size, hidden_layer_node_num]))
    hidden_biases = tf.Variable(tf.zeros([hidden_layer_node_num]))

    weights = tf.Variable(tf.truncated_normal([hidden_layer_node_num, num_labels]))
    biases = tf.Variable(tf.zeros([num_labels]))

    logits = tf.matmul(tf.nn.relu(tf.matmul(tf_train_dataset, hidden_weights) + hidden_biases), weights) + biases
    loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=tf_train_labels, logits=logits))

    optimizer = tf.train.GradientDescentOptimizer(0.5).minimize(loss)

    train_prediction = tf.nn.softmax(logits)
    valid_prediction = tf.nn.softmax(tf.matmul(tf.nn.relu(tf.matmul(tf_valid_dataset, hidden_weights) + hidden_biases), weights) + biases)
    test_prediction = tf.nn.softmax(tf.matmul(tf.nn.relu(tf.matmul(tf_test_dataset, hidden_weights) + hidden_biases), weights) + biases)

任务三:优化模型

任务三本身没有多少现成代码,主要靠自己动手。

L2正则化

接任务二ReLU的代码,只要为损失函数loss添加L2正则化的结果即可,选0.001438作为超参λ的值,课程没有讲如何选择超参的值,这个值是从他人文章中借用的。

在之前的损失函数赋值后面添加:

loss = loss + 0.001438 * (tf.nn.l2_loss(hidden_weights) + tf.nn.l2_loss(hidden_biases) + tf.nn.l2_loss(weights) + tf.nn.l2_loss(biases))

过度拟合

将训练数据减少为几个批次的量,演示过度拟合。

从训练数据中取出一个较小的子集作为训练集:

batch_size = 128
train_dataset = train_dataset[:batch_size * 5, :]
train_labels = train_labels[:batch_size * 5, :]

过度拟合,会导致模型在训练集上的表现很好,但针对验证集或测试集,表现大打折扣。

丢弃法

dropout会随机将输入值丢弃或缩放,可达到训练模型冗余性,防止过度拟合。

核心代码:

tmp = tf.nn.relu(tf.matmul(tf_train_dataset, hidden_weights) + hidden_biases)
tmp = tf.nn.dropout(tmp, 0.5)
logits = tf.matmul(tmp, weights) + biases

dropout第二个参数0.5,说明dropout的行为是随机将部分值置为0,另外一部分x2,这样,整体样本的平均值不会变化。

多层神经网络

该习题的目的是使用多层神经网络,使最终测试集的准确率达到97.1%。

核心代码:

hlnn1 = 4096
hlnn2 = 2048
hlnn3 = 128

hw1 = tf.Variable(tf.truncated_normal([image_size * image_size, hlnn1], stddev=np.sqrt(2.0 / (image_size * image_size))))
    hb1 = tf.Variable(tf.zeros([hlnn1]))

    hw2 = tf.Variable(tf.truncated_normal([hlnn1, hlnn2], stddev=np.sqrt(2.0 / hlnn1)))
    hb2 = tf.Variable(tf.zeros([hlnn2]))

    hw3 = tf.Variable(tf.truncated_normal([hlnn2, hlnn3], stddev=np.sqrt(2.0 / hlnn2)))
    hb3 = tf.Variable(tf.zeros([hlnn3]))
    
    weights = tf.Variable(tf.truncated_normal([hlnn3, num_labels], stddev=np.sqrt(2.0 / hlnn3)))
    biases = tf.Variable(tf.zeros([num_labels]))

    tmp = tf.nn.relu(tf.matmul(tf_train_dataset, hw1) + hb1)
    tmp = tf.nn.relu(tf.matmul(tmp, hw2) + hb2)
    tmp = tf.nn.relu(tf.matmul(tmp, hw3) + hb3)
   
    logits = tf.matmul(tmp, weights) + biases

    loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=tf_train_labels, logits=logits))
    loss = loss + tf_beta * (tf.nn.l2_loss(hw1) + tf.nn.l2_loss(hb1) + tf.nn.l2_loss(hw2) + tf.nn.l2_loss(hb2) +
                             tf.nn.l2_loss(hw3) + tf.nn.l2_loss(hb3) + tf.nn.l2_loss(weights) + tf.nn.l2_loss(biases))

    learning_rate = tf.train.exponential_decay(0.5, global_step, 1000, 0.7, staircase=True)
    optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss, global_step=global_step)

添加多个隐藏层,然后使用学习速率衰减方式,让损失降低,准确率进一步提升,到这一步我的Mac电脑已经开始吃不消,训练5000步,模型在测试集上的准确率95.1%,继续训练,模型的表现应该会更好。