想学深度学习很久了,tensorflow实战框架也买回来了一段时间了,但是由于一直在学其他的东西,就没能学成。恰巧,最近逛各种社区,想着开拓一下思路。于是发现了Kaggle,好似终于找到了把我所正在学的东西和深度学习结合起来的机会。
这篇文章其实是一片随手笔记,是阅读@量化大司马的3零基础用TensorFlow玩转Kaggle的“手写识别”的内容随手写下的东西。当然也顺手把代码补全了(敲了好久)。作为这个领域的菜鸟中的菜鸟,希望以后能继续向大佬们学习kaggle和深度学习。
文章还没写完,今天刚把小半部分代码理解完了,但是还有后半部分重要代码还没理解。又是深夜,睡觉去了。明日补。
以下是正文。
概述
MNIST是tensorflow的hello world(简单的Demo)。
Kaggle中的hello world是Digit Recognizer(手写图片识别)。
使用上述两者,上手时间tensorflow和Kaggle是一个不错的选择。
手写图片识别分别的实现分为三步:
-
数据准备
-
模型设计
-
代码实现
数据有Kaggle官方数据,模型使用MNIST Demo中设计的思路。
数据
Test——测试数据
28000条数据。每条数据是一个784大小的一维数组。是把一个28*28的图片给扁平化了。
Train——训练数据 + 验证数据
42000条数据。同样每一条数据都是一个一维数组,不过大小是784+1。加的那个1是label。(有监督学习)
一个好的算法都会利用其二维信息,但是鉴于这是一个上手,就先用一维结构进行分析。
显然这个数据集和相似度识别一样都存在同样的问题:采样率不一或者“速度”不一造成的尺度缩放问题。
但是没有噪声和local time shfting(比如缺失点和相等的时间平移)。
模型的设计
模型的组成是这样的:
-
使用一个最简单的单层神经网络进行学习
-
使用SoftMax来作为激活函数
-
使用交叉熵来作为损失函数
-
使用梯度下降来做优化方式
学习模型、激活函数、损失函数、学习方式这几个要素都是必要的,而这几个要素的实现都选择的最简单的形式。
神经网络
由多个神经元组成。每一个神经元都接收很多的输入:[x1, x2, x3, ..., xn],加权(a),加偏移(b)之后看看是不是超过了某个阈值,超过了发出1,没超过发出0。
单个神经元由很多个神经元互相连接,形成了神经网络。
单个神经元
激活函数
每个神经元都会输出一个数值,一个神经网络有这么多神经元,最终决定输出那个呢?需要的就是激活函数。其实每一个源的输入都是一个函数,而最终的激活函数就是在做一个规划以达到最好函数:
线性的模型是这样的:
线性模型
非线性的是这样的:
非线性模型显然,规划就是一个非常重要的课题。在经典教材《算法》中,没有提及规划算法,令很多人感到惋惜,现在终于可以理解原因了。
目前主流的几个激活函数是:sigmoid,tanh,ReLU。
sigmoid:采用S形函数,取值范围[0,1]
tanh:双切正切函数,取值范围[-1,1]
ReLU:简单而粗暴,大于0的留下,否则一律为0。
SoftMax:
我们知道max(A,B),�是指A和B里哪个大就取哪个值,但我们有时候希望比较小的那个也有一定概率取到,怎么办呢?我们就按照两个值的大小,计算出概率,按照这个概率来取A或者B。比如A=9,B=1,那取A的概率是90%,取B的概率是10%。
这个看起来比max(A,B)这样粗暴的方式柔和一些,所以叫SoftMax(名字解释纯属个人瞎掰😑大家能理解概念就好)
损失函数
在各种学习算法中,必然要着重讲的就是损失函数和优化方式。
损失函数也相当于相似度预测时候的相似度:表征对数据拟合程度的反映,拟合的越好、损失应该越少。然后我们根据损失函数进行调整。
交叉熵:交叉熵通俗讲就是训练程度和圆满之间的差距,我们希望距离越小越好(= =没看很懂)
优化方式
训练过程是一个逐渐达到收敛的过程,必然需要一个优化方式(要不要损失函数干什么)。
这个概念可以这样理解,我们要解决的问题是一座山,答案在山底,我们从山顶到山底的过程就是解决问题的过程。
梯度下降在山顶,想找到最快的下山的路。这个时候,我们的做法是什么呢?在每次选择道路的时候,选最陡的那条路。梯度是改变率或者斜度的另一个称呼,用数学的语言解释是导数。对于求损失函数最小值这样的问题,朝着梯度下降的方向走,就能找到最优值了。
代码实现
##############################################
# 载入数据,并对数据进行处理 #
##############################################
import tensorflow as tf
import pandas as pd
import numpy as np
# 1 加载数据集,把对输入和结果进行分开
filePath = "~/Downloads/"
train = pd.read_csv(filePath + "train.csv") # train中是仍然包含表头的
images = train.iloc[:, 1:].values # 删除表头,images是numpy.ndarray
labels_flat = train[["label"]].values.ravel() # 获取label
# 2 对输出进行处理
images = images.astype(np.float)
images = np.multiply(images, 1.0 / 255.0) # 转化到256阶的灰度
print('输入数据的数量:(%g, %g)' % images.shape) # ndarray.shape返回其维度
image_size = images.shape[1]
print('输入数据的纬度 => {0}'.format(image_size))
image_width = image_height = np.ceil(np.sqrt(image_size).astype(np.uint8))
print('图片的长 => {0}\n图片的高 => {1}'.format(image_width, image_height))
x = tf.placeholder('float', shape=[None, image_size])
# 3 对结果进行处理
labels_count = np.unique(labels_flat).shape[0] # 获取label中不重复的个数,显然是10个:0-9
print('结果的种类 => {0}'.format(labels_count))
# 进行One-hot编码
def dense_to_one_hot(labels_dense, num_classes):
num_labels = labels_dense.shape[0]
index_offset = np.arange(num_labels) * num_classes
labels_one_hot = np.zeros((num_labels, num_classes))
labels_one_hot.flat[index_offset + labels_dense.ravel()] = 1
return labels_one_hot
labels = dense_to_one_hot(labels_flat, labels_count)
labels = labels.astype(np.uint8)
print(type(labels.shape))
print('结果的数量:({0[0]}, {0[1]})'.format(labels.shape))
y = tf.placeholder('float', shape=[None, labels_count])
# 4 把输入数据划分训练集和验证集
# 把40000个数据作为训练集,2000个数据作为验证集
VALIDATION_SIZE = 2000
validation_images = images[:VALIDATION_SIZE]
validation_labels = labels[:VALIDATION_SIZE]
train_images = images[VALIDATION_SIZE:]
train_labels = labels[VALIDATION_SIZE:]
# 5 对训练集进行分批
batch_size = 100
n_batch = len(train_images)/batch_size
print(n_batch)
##############################################
# 建立神经网路、设置损失函数、设置梯度下降的优化参数 #
##############################################
# 6 设置一个简单的神经网络来对图片进行识别
weight = tf.Variable(tf.zeros([784, 10]))
biases = tf.Variable(tf.zeros([10]))
result = tf.matmul(x, weight) + biases
prediction = tf.nn.softmax(result)
# 7 创建损失函数、以交叉熵的平均值为衡量
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(labels=y, logits=prediction))
# 8 用梯度下降发优化参数
train_step = tf.train.GradientDescentOptimizer(0.1).minimize(loss)
#################################################
# 初始化变量,设置好准确度的计算方法,在Session中运行 #
#################################################
# 9 初始化变量
init = tf.global_variables_initializer()
# 10 计算准确度
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(prediction, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
with tf.Session() as sess:
# 初始化
sess.run(init)
# 循环50轮
for epoch in range(50):
for batch in range(int(n_batch)):
# 按照分片取出数据
batch_x = train_images[batch * batch_size:(batch + 1)*batch_size]
batch_y = train_labels[batch * batch_size:(batch + 1) * batch_size]
# 进行训练
sess.run(train_step, feed_dict={x:batch_x, y:batch_y})
# 每一轮计算一次准确度
accuracy_n = sess.run(accuracy, feed_dict={x:validation_images, y:validation_labels})
print('第' + str(epoch + 1) + "轮,准确度为:" + str(accuracy_n))
输出:
第1轮,准确度为:0.7925
第2轮,准确度为:0.808
第3轮,准确度为:0.8155
第4轮,准确度为:0.8535
第5轮,准确度为:0.876
第6轮,准确度为:0.8875
第7轮,准确度为:0.8915
第8轮,准确度为:0.895
第9轮,准确度为:0.897
第10轮,准确度为:0.897
第11轮,准确度为:0.899
第12轮,准确度为:0.9005
第13轮,准确度为:0.901
第14轮,准确度为:0.9035
第15轮,准确度为:0.9065
第16轮,准确度为:0.9075
第17轮,准确度为:0.908
第18轮,准确度为:0.909
第19轮,准确度为:0.9105
第20轮,准确度为:0.9105
第21轮,准确度为:0.911
第22轮,准确度为:0.911
第23轮,准确度为:0.9115
第24轮,准确度为:0.912
第25轮,准确度为:0.9125
第26轮,准确度为:0.9135
第27轮,准确度为:0.9135
第28轮,准确度为:0.9135
第29轮,准确度为:0.9135
第30轮,准确度为:0.914
第31轮,准确度为:0.9145
第32轮,准确度为:0.915
第33轮,准确度为:0.915
第34轮,准确度为:0.915
第35轮,准确度为:0.916
第36轮,准确度为:0.917
第37轮,准确度为:0.918
第38轮,准确度为:0.919
第39轮,准确度为:0.919
第40轮,准确度为:0.9195
第41轮,准确度为:0.9195
第42轮,准确度为:0.9195
第43轮,准确度为:0.919
第44轮,准确度为:0.9195
第45轮,准确度为:0.9185
第46轮,准确度为:0.919
第47轮,准确度为:0.919
第48轮,准确度为:0.919
第49轮,准确度为:0.919
第50轮,准确度为:0.9195
Process finished with exit code 0
我们这个网络识别的准确度是92%左右,这个成绩比较差,然而这只是我们最简单的模型而已
网友评论