人工智能学习笔记大数据,机器学习,人工智能机器学习与数据挖掘

Tensorflow入门——单层神经网络识别MNIST手写数字

2019-03-30  本文已影响14人  Hongtao洪滔

手写数字识别是一个非常经典的机器学习项目,这篇文章,我们就通过Kaggle上这个经典项目,学习如何用Tensorflow和Keras用最简单的单层神经网络,来识别手写数字。

同样的,为了方便与读者交流,所有的代码都放在了这里:

Repository:

https://github.com/zht007/tensorflow-practice

1. 数据下载和预处理

Kaggle的项目页面可以下载两个csv文件,"train.csv"包含数据和标签,"test.csv"仅包含带验证数据。你可以用train.csv训练自己的模型,然后再用这个模型识别test.csv中的手写数字,并将其分类,最后将结果上传至Kaggle的项目,查看正确率和全球排名。

通过pands的read_csv方法读取csv文件,分离数据和标签,并分用scikit-learn 中的train_test_split,分出训练集和验证集。

labeled_images = pd.read_csv('train.csv')
images = labeled_images.iloc[:,1:]
labels = labeled_images.iloc[:,:1]
train_images, test_images,train_labels, test_labels = train_test_split(images, labels, test_size=0.01)

2. Batch training 的帮助函数

这个部分虽然比较难,但是不是这篇文章的重点,就此略过,主要作用是从训练数据集中顺序取出指定数量的batch,在Session中给模型训练。帮助函数处理之后数据的shape为[batch_size, 28,28,1]

帮助函数还有一个作用,就是将标签onehot encode。onehot-encoded 的标签shape为[batch_size, 10]。

3. 创建模型

单层神经网络,神经元个数就等于输出的类别的个数,手写数字分成0到9,一共10个类别,神经元个数就是10。

神经网络是全链接的,我们需要把输入的28*28个像素的二维图片,拆解拼凑成一个784个像素点的一维向量。此时输入的feature数就是784。

输入的feature数和输出的类别数共同决定了权重W和偏移b的shape

初始化权重W1和偏移B1:

W1 = tf.Variable(tf.truncated_normal([784, 10], stddev=0.1))  # 784 = 28 * 28
B1 = tf.Variable(tf.ones([10])/10)

单层神经网络通过softmax的激活,就能得到最终的结果

XX = tf.reshape(X,[-1,784])
Ylogits = tf.matmul(XX, W1) + B1
Y = tf.nn.softmax(Ylogits)

Cross_entropy 可以直接通过公式计算

cross_entropy = -tf.reduce_mean(Y_true * tf.log(Y)) * 1000.0 

也可以用tensorflow中自带的,如何选择我在前面的文章中已经介绍过了。

cross_entropy = tf.losses.softmax_cross_entropy(onehot_labels = Y_true, logits = Ylogits)

Optimizer 可以选择基本的GradientDescent也可以选择Adam

optimizer = tf.train.AdamOptimizer(learning_rate=0.001)
train = optimizer.minimize(cross_entropy)

4. 模型训练

将batch中的数据通过Feed_dict载入数据,剩下的就交给Tensorflow吧,注意,为了记录loss 和 Accuracy的变化,我创建了history这个字典,记录每100个Iteration它们的数字变化。

history = {'acc_train':list(),'acc_val':list(),
           'loss_train':list(),'loss_val':list()}
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    
    for i in range(30000):
        batch = ch.next_batch(100)
        sess.run(train, feed_dict={X: batch[0], Y_true: batch[1]})
        
        # PRINT OUT A MESSAGE EVERY 100 STEPS
        if i%100 == 0:
            
            # Test the Train Model
            feed_dict_train = {X: batch[0], Y_true: batch[1]}
            feed_dict_val = {X:ch.test_images, Y_true:ch.test_labels}

            matches = tf.equal(tf.argmax(Y,1),tf.argmax(Y_true,1))
            acc = tf.reduce_mean(tf.cast(matches,tf.float32))
            history['acc_train'].append(sess.run(acc, feed_dict = feed_dict_train))
            history['acc_val'].append(sess.run(acc, feed_dict = feed_dict_val))

            history['loss_train'].append(sess.run(cross_entropy, feed_dict = feed_dict_train))
            history['loss_val'].append(sess.run(cross_entropy, feed_dict = feed_dict_val))
            
            print("Iteration {}:\tloss_train={:.6f}:\tloss_val={:.6f}:\tacc_train={:.6f}:\tacc_val={:.6f}"
                  .format(i,history['loss_train'][-1],history['loss_val'][-1],history['acc_train'][-1],history['acc_val'][-1]))
            
            print('\n')

4.查看训练结果

可以看到,即便只有一层神经网络,我们也达到了将近90%的Accuracy.

image-20190329150857000

5. 用Keras试试看

Keras就更加简单了,Model两行代码搞定了。

model = models.Sequential()
model.add(layers.Dense(units=10, activation='softmax',input_shape=(784,)))

6.预测测试集数据并上传Kaggle

我们在训练的最后已经将tensorflow的模型保存起来了

 saver.save(sess,'models_saving/my_model.ckpt')

预测的时候取出来就行了

unlabeled_images_test = pd.read_csv('test.csv')

with tf.Session() as sess:
    
    # Restore the model
    saver.restore(sess, 'models_saving/my_model.ckpt')
    # Fetch Back Results
    label = sess.run(Y, feed_dict={X:X_unlabeled})

最后,按照Kanggle提供模板格式,将结果转换成csv文件,上传服务器,就可以看到训练成果啦。

详细过程请参见jupyter notbook中的代码和注释。


参考资料

https://www.kaggle.com/c/digit-recognizer/data

https://codelabs.developers.google.com/codelabs/cloud-tensorflow-mnist/#0

https://www.tensorflow.org/api_docs/


同步到我的Steemit

https://steemit.com/@hongtao

上一篇下一篇

猜你喜欢

热点阅读