Tensorflow实现逻辑回归(使用MNIST数据集)

今天我们讲一下如何使用Tensorflow实现逻辑回归,代码中采用了MNIST数据集。

首先,我们去获取MNIST数据集(下载链接:http://yann.lecun.com/exdb/mnist/),并将其读取到程序中。代码实现如下所示:

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data


mnist = input_data.read_data_sets('./data/mnist_data/', one_hot=True)
train_img = mnist.train.images
train_label = mnist.train.labels
test_img = mnist.test.images
test_label = mnist.test.labels

我将获取到的MNIST数据放在了当前目录下的data/mnist_data文件夹下,然后利用input_data函数解析该数据集。train_img和train_label构成训练集,包含60000个手写体数字图片和对应的标签;test_img和test_label表示测试集,包含10000个样本和10000个标签。

根据逻辑回归的基本公式y=Wx+b,在设计逻辑回归模型之前,我们先设定模型的输入和待求变量,代码如下所示:

x = tf.placeholder("float", [None, 784])
y = tf.placeholder("float", [None, 10])
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))

其中x是一个placeholder,它用来保存我们之后喂给模型的手写体数字图片,它的两个维度中None表示图片的数量,784表示每张图片的像素个数。第一个维度采用None在Tensorflow里表示无穷,一开始这样使用是因为我们还不确定每次给模型喂的数据数量是多少,也方便后面调整其他超参数。y同样是一个placeholder,它表示图像的真实分类,因为阿拉伯数字有10个,所以它的第二个维度是10,需要注意的是我们使用了one-hot编码,也就是说,数字3在这里会被表示为[0, 0, 0, 1, 0, 0, 0, 0, 0, 0]

Wb是待求参数,它们再模型的训练过程中是不断变化的,所以采用了Variable来实现。W的维度为[784, 10],这表示每张图片的784个像素都需要被预测到0-9这10个数字上,也就是每个像素都对应一个10为的one-hot向量。而b则表示在这10个数字预测结果上的偏置。Wb可以随机初始化,也可以采用零值初始化,这里使用零值进行初始化。

下面我们正式构建逻辑回归模型:

# 逻辑回归模型
actv = tf.nn.softmax(tf.matmul(x, W) + b)
# 成本函数
cost = tf.reduce_mean(-tf.reduce_sum(y*tf.log(actv), reduction_indices=1))
# 优化器
learning_rate = 0.01
optm = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost)
# 预测结果
pred = tf.equal(tf.argmax(actv, 1), tf.argmax(y, 1))
# 计算准确率
accr = tf.reduce_mean(tf.cast(pred, "float"))

让我们一行行看这部分代码,首先actv = tf.nn.softmax(tf.matmul(x, W) + b)tf.matmul(x, W) + b就实现了逻辑回归公式,表示图片属于某一个类别的分数,然后外层我们再使用softmax作为激活函数,将其转换为每张图片属于10个数字的概率。需要注意的是,多分类任务一般使用softmax作为激活函数,二分类任务采用sigmoid。sotfmax函数将数据进行归一化处理,使所有数据都在0和1之间,并且求和为1。

再下一行我们定义了成本函数。这里我们没有完全依照逻辑回归的成本函数计算公式,而是使用了较简易的版本,将每个样本的损失函数定义为y*log(\hat{y}),其中y表示样本所属的真实类别,\hat{y}表示我们模型的预测类别,然后利用reduce_sum函数将所有样本的损失函数值相加(注意reduction_indices=1表示将矩阵中的元素按行相加)再取负求平均,就得到了成本函数值。

然后optm使用了梯度下降法来对模型进行拟合,学习率我们设置为0.01,这里的学习目标是使成本函数值最小。

pred比较了预测结果和实际样本的类别,这里使用了argmax获取了每个向量最大值的索引,因为是one-hot编码,所以索引也就对应了实际的数字。

最后,accr将比较结果的bool类型变量转换为float型,再将得到的所有0和1求平均就是模型预测的准确率了。

下面是具体的训练过程代码:

init = tf.global_variables_initializer()
training_epochs = 50
batch_size = 100
display_step = 5

sess = tf.Session()
sess.run(init)

for epoch in range(training_epochs):
    avg_cost = 0.
    num_batch = int(mnist.train.num_examples / batch_size)
    for i in range(num_batch):
        batch_xs, batch_ys = mnist.train.next_batch(batch_size)
        feeds_train = {x: batch_xs, y: batch_ys}
        sess.run(optm, feed_dict=feeds_train)
        avg_cost += sess.run(cost, feed_dict=feeds_train) / num_batch
    # 训练过程输出
    if epoch % display_step == 0:
        feeds_test = {x: mnist.test.images, y: mnist.test.labels}
        train_acc = sess.run(accr, feed_dict=feeds_train)
        test_acc = sess.run(accr, feed_dict=feeds_test)
        print("Epoch: %03d/%03d cost: %.9f train_acc: %.3f test_acc: %.3f"
              % (epoch, training_epochs, avg_cost, train_acc, test_acc))
print("DONE")

首先,init初始化了所有的变量,training_epochs设置为50表示把所有的样本迭代50次,batch_size为100表示每个epoch中每次取100个样本进行训练,display_step用于输出训练过程,这里设置成每5个epoch输出一次。

在之后的for循环中,外层的for表示训练的epoch,在内层for循环之前初始化了avg_cost变量,num_batch计算了每个epoch的batch数量。内层for循环中的batch_xs和batch_ys获取每个batch的样本和标签,然后将其输入feed_dict来喂给模型,模型训练需要的一个参数是数据,另外一个就是optm优化器。最后再利用cost函数计算了平均成本函数值。在if条件结构中,我们利用了accr、训练数据和测试数据计算了模型在训练集和测试集上的准确率并打印输出使得我们能够方便的观察训练效果。

这篇文章到这里就结束了,最后想要说的是实际上有很多人的博客里贴出了这份代码,但是他们都基本没有对代码进行解释,这里为了帮助新手快速入门,尽可能详细的解释了代码的实现过程。整个解说过程如果有什么问题,欢迎大家和我交流!

你可能感兴趣的:(TensorFlow,机器学习)