内容简介:本教程演示了使用TensorFlow和简单线性模型的基本工作流程。 在使用手写数字图像加载所谓的MNIST数据集之后,我们在TensorFlow中定义并优化了一个简单的数学模型。 然后绘制并讨论结果。您应该熟悉基本的线性代数,Python和Jupyter Notebook编辑器。 如果您对机器学习和分类有基本的了解,它也会有所帮助。
本教程演示了使用TensorFlow和简单线性模型的基本工作流程。 在使用手写数字图像加载所谓的MNIST数据集之后,我们在TensorFlow中定义并优化了一个简单的数学模型。 然后绘制并讨论结果。
您应该熟悉基本的线性代数,Python和Jupyter Notebook编辑器。 如果您对机器学习和分类有基本的了解,它也会有所帮助。
#Imports
%matplotlib inline import matplotlib.pyplot as plt import tensorflow as tf import numpy as np from sklearn.metrics import confusion_matrix 复制代码
#Load Data
MNIST数据集大约为12 MB,如果它不在给定路径中,将自动下载。
from mnist import MNIST data = MNIST(data_dir="data/MNIST/") 复制代码
MNIST数据集现已加载,由70,000个图像和图像的类号组成。 数据集被分成3个互斥的子集。 我们将仅使用本教程中的培训和测试集。
print("Size of:") print("- Training-set:\t\t{}".format(data.num_train)) print("- Validation-set:\t{}".format(data.num_val)) print("- Test-set:\t\t{}".format(data.num_test)) Size of: - Training-set: 55000 - Validation-set: 5000 - Test-set: 10000 复制代码
为方便起见,复制一些数据维度。
# The images are stored in one-dimensional arrays of this length. img_size_flat = data.img_size_flat # Tuple with height and width of images used to reshape arrays. img_shape = data.img_shape # Number of classes, one class for each of 10 digits. num_classes = data.num_classes 复制代码
#One-Hot Encoding
输出数据作为整数类数和所谓的One-Hot编码数组加载。 这意味着类号已从单个整数转换为长度等于可能类数的向量。 向量的所有元素都是零,除了 '元素是1并且意味着类是 。 例如,测试集中前5个图像的One-Hot编码标签是:
data.y_test[0:5, :] array([[0., 0., 0., 0., 0., 0., 0., 1., 0., 0.], [0., 0., 1., 0., 0., 0., 0., 0., 0., 0.], [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.], [1., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 1., 0., 0., 0., 0., 0.]]) 复制代码
我们还需要将类作为整数进行各种比较和性能测量。 通过使用np.argmax()函数获取最高元素的索引,可以从One-Hot编码数组中找到这些数据。 但是在加载数据集时我们已经完成了这项工作,因此我们可以看到测试集中前五个图像的类编号。 将它们与上面的One-Hot编码数组进行比较。
data.y_test_cls[0:5] array([7, 2, 1, 0, 4]) 复制代码
接下来做一个小例子: 在3x3网格中绘制9个图像,并在每个图像下面写入真实和预测类的函数。
def plot_images(images, cls_true, cls_pred=None): assert len(images) == len(cls_true) == 9 # Create figure with 3x3 sub-plots. fig, axes = plt.subplots(3, 3) fig.subplots_adjust(hspace=0.3, wspace=0.3) for i, ax in enumerate(axes.flat): # Plot image. ax.imshow(images[i].reshape(img_shape), cmap='binary') # Show true and predicted classes. if cls_pred is None: xlabel = "True: {0}".format(cls_true[i]) else: xlabel = "True: {0}, Pred: {1}".format(cls_true[i], cls_pred[i]) ax.set_xlabel(xlabel) # Remove ticks from the plot. ax.set_xticks([]) ax.set_yticks([]) # Ensure the plot is shown correctly with multiple plots # in a single Notebook cell. plt.show() 复制代码
输出图像看看
# Get the first images from the test-set. images = data.x_test[0:9] # Get the true classes for those images. cls_true = data.y_test_cls[0:9] # Plot the images and labels using our helper-function above. plot_images(images=images, cls_true=cls_true) 复制代码
#TensorFlow Graph
TensorFlow的全部目的是拥有一个所谓的计算图,与直接在 Python 中执行相同的计算相比,它可以更有效地执行。 TensorFlow可以比NumPy更有效,因为TensorFlow知道必须执行的整个计算图,而NumPy一次只知道一个数学运算的计算 TensorFlow还可以自动计算优化图形变量所需的梯度,以使模型更好地运行。 这是因为图是简单数学表达式的组合,因此可以使用衍生的链规则计算整个图的梯度。 TensorFlow还可以利用多核CPU和GPU - 而Google甚至为TensorFlow构建了专用芯片,称为TPU(Tensor Processing Units)甚至比GPU更快。
TensorFlow图由以下部分组成,将在下面详述:
占位符变量用于将输入提供给图表。 模型变量将进行优化,以使模型更好地运行。 该模型本质上只是一个数学函数,它根据占位符变量和模型变量中的输入计算一些输出。 可用于指导变量优化的成本度量。 一种更新模型变量的优化方法。 复制代码
此外,TensorFlow图还可以包含各种调试语句,例如: 用于记录使用TensorBoard显示的数据,本教程未介绍。
#Placeholder variables
占位符变量用作图形的输入,我们可以在每次执行图形时更改这些输入。 我们称之为占位符变量,并在下面进一步说明。
首先,我们为输入图像定义占位符变量。 这允许我们更改输入到TensorFlow图形的图像。 这是一个所谓的张量,这意味着它是一个多维向量或矩阵。 数据类型设置为float32,形状设置为[None,img_size_flat],其中None表示张量可以保持任意数量的图像,每个图像是长度为img_size_flat的向量。
x = tf.placeholder(tf.float32, [None, img_size_flat]) 复制代码
接下来,我们有占位符变量,用于与占位符变量x中输入的图像相关联的真实标签。 此占位符变量的形状为[None,num_classes],这意味着它可以包含任意数量的标签,每个标签是长度为num_classes的向量,在这种情况下为10。
y_true = tf.placeholder(tf.float32, [None, num_classes]) 复制代码
最后,我们在占位符变量x中为每个图像的真实类提供占位符变量。 这些是整数,此占位符变量的维度设置为[None],这意味着占位符变量是任意长度的一维向量。
y_true_cls = tf.placeholder(tf.int64, [None]) 复制代码
#Variables to be optimized
除了上面定义的占位符变量以及用作将输入数据输入到模型中之外,还有一些模型变量必须由TensorFlow更改,以使模型在训练数据上表现更好。
必须优化的第一个变量称为权重,在此定义为TensorFlow变量,必须用零初始化并且其形状为[img_size_flat,num_classes],因此它是具有img_size_flat行的二维张量(或矩阵)和 num_classes列。
weights = tf.Variable(tf.zeros([img_size_flat, num_classes])) 复制代码
必须优化的第二个变量称为偏差,并定义为长度为num_classes的1维张量(或向量)。
biases = tf.Variable(tf.zeros([num_classes])) 复制代码
#Model
这个简单的数学模型将占位符变量x中的图像与权重相乘,然后添加偏差。
结果是形状[num_images,num_classes]的矩阵,因为x具有形状[num_images,img_size_flat]并且权重具有形状[img_size_flat,num_classes],因此这两个矩阵的乘法是具有形状[num_images,num_classes]的矩阵然后 偏差向量被添加到该矩阵的每一行。
请注意,名称logits是典型的TensorFlow术语,但其他人可能会将变量称为其他内容。
logits = tf.matmul(x, weights) + biases 复制代码
现在logits是一个包含num_images行和num_classes列的矩阵,其中 '行和 '列的元素估计 '输入图像是多少可能是 '。
然而,这些估计有点粗糙且难以解释,因为数字可能非常小或很大,因此我们希望对它们进行归一化,使得logits矩阵的每一行总和为1,并且每个元素限制在0和1之间。 这是使用所谓的softmax函数计算的,结果存储在y_pred中。
y_pred = tf.nn.softmax(logits) 复制代码
可以通过获取每行中最大元素的索引从y_pred矩阵计算预测类。
y_pred_cls = tf.argmax(y_pred, axis=1) 复制代码
#Cost-function to be optimized
为了使模型更好地对输入图像进行分类,我们必须以某种方式更改权重和偏差的变量。 为此,我们首先需要通过将模型y_pred的预测输出与期望输出y_true进行比较来了解模型当前的执行情况。
交叉熵是用于分类的性能度量。 交叉熵是一个始终为正的连续函数,如果模型的预测输出与期望输出完全匹配,则交叉熵等于零。 因此,优化的目标是最小化交叉熵,使其通过改变模型的权重和偏差尽可能接近零。
TensorFlow具有用于计算交叉熵的内置函数。 请注意,它使用logits的值,因为它还在内部计算softmax。
cross_entropy = tf.nn.softmax_cross_entropy_with_logits_v2(logits=logits, labels=y_true) 复制代码
我们现在已经计算了每个图像分类的交叉熵,因此我们可以测量模型对每个图像的单独执行情况。 但是为了使用交叉熵来指导模型变量的优化,我们需要一个标量值,因此我们只需要对所有图像分类采用交叉熵的平均值。
cost = tf.reduce_mean(cross_entropy) 复制代码
#Optimization method
现在我们有一个必须最小化的成本度量,然后我们可以创建一个优化器。 在这种情况下,它是渐变下降的基本形式,其中步长设置为0.5。
请注意,此时不执行优化。 事实上,根本没有计算任何东西,我们只需将optimizer-object添加到TensorFlow图中以便以后执行。
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.5).minimize(cost) 复制代码
#Performance measures
我们还需要一些性能指标来向用户显示进度。 这是布尔的向量,无论预测的等级是否等于每个图像的真实等级。
correct_prediction = tf.equal(y_pred_cls, y_true_cls) 复制代码
这通过首先将布尔值的矢量类型转换为浮点数来计算分类精度,使得False变为0并且True变为1,然后计算这些数字的平均值。
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) 复制代码
#TensorFlow Run 一旦创建了TensorFlow图,我们就必须创建一个用于执行图的TensorFlow会话。
session = tf.Session() 复制代码
在我们开始优化之前,必须初始化权重和偏差的变量。
session.run(tf.global_variables_initializer()) 复制代码
训练集中有55,000个图像。 使用所有这些图像计算模型的梯度需要很长时间。 因此,我们使用Stochastic Gradient Descent,它只在优化器的每次迭代中使用一小批图像。
batch_size = 100 复制代码
用于执行多个优化迭代的功能,以便逐渐改善模型的权重和偏差。 在每次迭代中,从训练集中选择一批新数据,然后TensorFlow使用这些训练样本执行优化程序。
def optimize(num_iterations): for i in range(num_iterations): # Get a batch of training examples. # x_batch now holds a batch of images and # y_true_batch are the true labels for those images. x_batch, y_true_batch, _ = data.random_batch(batch_size=batch_size) # Put the batch into a dict with the proper names # for placeholder variables in the TensorFlow graph. # Note that the placeholder for y_true_cls is not set # because it is not used during training. feed_dict_train = {x: x_batch, y_true: y_true_batch} # Run the optimizer using this batch of training data. # TensorFlow assigns the variables in feed_dict_train # to the placeholder variables and then runs the optimizer. session.run(optimizer, feed_dict=feed_dict_train) 复制代码
#Helper-functions to show performance 使用测试集数据进行Dict,以用作TensorFlow图的输入。 请注意,我们必须在TensorFlow图中使用占位符变量的正确名称。
feed_dict_test = {x: data.x_test, y_true: data.y_test, y_true_cls: data.y_test_cls} 复制代码
用于在测试集上打印分类精度的功能。
def print_accuracy(): # Use TensorFlow to compute the accuracy. acc = session.run(accuracy, feed_dict=feed_dict_test) # Print the accuracy. print("Accuracy on test-set: {0:.1%}".format(acc)) 复制代码
使用scikit-learn打印和绘制混淆矩阵的功能。
def print_confusion_matrix(): # Get the true classifications for the test-set. cls_true = data.y_test_cls # Get the predicted classifications for the test-set. cls_pred = session.run(y_pred_cls, feed_dict=feed_dict_test) # Get the confusion matrix using sklearn. cm = confusion_matrix(y_true=cls_true, y_pred=cls_pred) # Print the confusion matrix as text. print(cm) # Plot the confusion matrix as an image. plt.imshow(cm, interpolation='nearest', cmap=plt.cm.Blues) # Make various adjustments to the plot. plt.tight_layout() plt.colorbar() tick_marks = np.arange(num_classes) plt.xticks(tick_marks, range(num_classes)) plt.yticks(tick_marks, range(num_classes)) plt.xlabel('Predicted') plt.ylabel('True') # Ensure the plot is shown correctly with multiple plots # in a single Notebook cell. plt.show() 复制代码
用于绘制来自测试集的图像的错误分类的示例的功能。
def plot_example_errors(): # Use TensorFlow to get a list of boolean values # whether each test-image has been correctly classified, # and a list for the predicted class of each image. correct, cls_pred = session.run([correct_prediction, y_pred_cls], feed_dict=feed_dict_test) # Negate the boolean array. incorrect = (correct == False) # Get the images from the test-set that have been # incorrectly classified. images = data.x_test[incorrect] # Get the predicted classes for those images. cls_pred = cls_pred[incorrect] # Get the true classes for those images. cls_true = data.y_test_cls[incorrect] # Plot the first 9 images. plot_images(images=images[0:9], cls_true=cls_true[0:9], cls_pred=cls_pred[0:9]) 复制代码
#Helper-function to plot the model weights 用于绘制模型权重的函数。 绘制10个图像,每个数字一个,模型被训练识别。
def plot_weights(): # Get the values for the weights from the TensorFlow variable. w = session.run(weights) # Get the lowest and highest values for the weights. # This is used to correct the colour intensity across # the images so they can be compared with each other. w_min = np.min(w) w_max = np.max(w) # Create figure with 3x4 sub-plots, # where the last 2 sub-plots are unused. fig, axes = plt.subplots(3, 4) fig.subplots_adjust(hspace=0.3, wspace=0.3) for i, ax in enumerate(axes.flat): # Only use the weights for the first 10 sub-plots. if i<10: # Get the weights for the i'th digit and reshape it. # Note that w.shape == (img_size_flat, 10) image = w[:, i].reshape(img_shape) # Set the label for the sub-plot. ax.set_xlabel("Weights: {0}".format(i)) # Plot the image. ax.imshow(image, vmin=w_min, vmax=w_max, cmap='seismic') # Remove ticks from each sub-plot. ax.set_xticks([]) ax.set_yticks([]) # Ensure the plot is shown correctly with multiple plots # in a single Notebook cell. plt.show() 复制代码
#Performance before any optimization 测试集的准确度为9.8%。 这是因为模型只是初始化而根本没有优化,因此它总是预测图像显示零位数,如下图所示,结果发现测试集中9.8%的图像发生了 为零位数。
print_accuracy() Accuracy on test-set: 9.8% plot_example_errors() 复制代码
Performance after 1 optimization iteration(1次优化迭代后的性能)
optimize(num_iterations=1) print_accuracy() Accuracy on test-set: 15.9% plot_example_errors() 复制代码
权重也可以如下所示绘制。 正权重为红色,负权重为蓝色。 这些权重可以直观地理解为图像过滤器。
例如,用于确定图像是否显示零位的权重对圆的图像具有正反应(红色),并且对具有在圆的中心的内容的图像具有负反应(蓝色)。
类似地,用于确定图像是否显示一位数的权重对图像中心的垂直线呈正(红色)反应,并且对具有围绕该线的内容的图像作出负反应(蓝色)。
请注意,权重大多看起来像是他们应该识别的数字。 这是因为仅执行了一次优化迭代,因此权重仅在100个图像上进行训练。 在对数千个图像进行训练之后,权重变得更难以解释,因为它们必须识别数字如何被写入的许多变化。
plot_weights() 复制代码
Performance after 10 optimization iterations(10次优化迭代后的性能)
optimize(num_iterations=9) print_accuracy() Accuracy on test-set: 66.2% plot_example_errors() 复制代码
plot_weights() 复制代码
Performance after 1000 optimization iterations(1000次优化迭代后的性能) 在1000次优化迭代之后,模型仅对大约十分之一的图像进行错误分类。 如下所示,一些误分类是合理的,因为即使对于人类来说,图像也很难确定,而其他图像非常明显,应该通过一个好的模型正确分类。 但是这种简单的模型无法达到更好的性能,因此需要更复杂的模型。
optimize(num_iterations=990) print_accuracy() Accuracy on test-set: 91.5% plot_example_errors() 复制代码
该模型现已经过1000次优化迭代的训练,每次迭代使用来自训练集的100个图像。 由于图像种类繁多,权重现在变得难以解释,我们可能会怀疑模型是否真正理解数字是如何由线条组成的,或者模型是否只记忆了许多不同的像素变化。
plot_weights() 复制代码
我们还可以打印和绘制所谓的混淆矩阵,让我们可以看到有关错误分类的更多细节。 例如,它显示实际描绘5的图像有时被错误分类为所有其他可能的数字,但大多数为6或8。
print_confusion_matrix() 复制代码
[[ 956 0 3 1 1 4 11 3 1 0] [ 0 1114 2 2 1 2 4 2 8 0] [ 6 8 925 23 11 3 13 12 26 5] [ 3 1 19 928 0 34 2 10 5 8] [ 1 3 4 2 918 2 11 2 6 33] [ 8 3 7 36 8 781 15 6 20 8] [ 9 3 5 1 14 12 912 1 1 0] [ 2 11 24 10 6 1 0 941 1 32] [ 8 13 11 44 11 52 13 14 797 11] [ 11 7 2 14 50 10 0 30 4 881]]
我们现在使用TensorFlow完成,因此我们关闭会话以释放其资源。
# This has been commented out in case you want to modify and experiment # with the Notebook without having to restart it. # session.close() 复制代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Ajax Design Patterns
Michael Mahemoff / O'Reilly Media / 2006-06-29 / USD 44.99
Ajax, or Asynchronous JavaScript and XML, exploded onto the scene in the spring of 2005 and remains the hottest story among web developers. With its rich combination of technologies, Ajax provides a s......一起来看看 《Ajax Design Patterns》 这本书的介绍吧!