Tensorflow之:安装与验证
Tensorflow的安装非常简单,只要读者装有python和和相应版本的pip,输入:
pip install --upgrade tensorflow
即可。如果需要为python3的环境添加tensorflow(强烈推荐,毕竟到2020年python 2就退休了),则pip可能在有的环境下为pip3。如果读者计算设备安装有显卡加速(GPU),则输入如下指令能更快捷地安装tensorflow:
pip install --upgrade tensorflow-gpu
安装完毕之后,则可以用如下程序验证安装:
import tensorflow as tf
hello = tf.constant('Hello Tensorflow!')
sess = tf.Session()
print(sess.run(hello))
如果输出为类似下图效果,则证明tensorflow已经安装完毕。
机器学习是什么?它与AI的关系如何?机器学习DNN方法的大致步骤是哪些?
根据汤姆 米歇尔(Tom Mitchell)教授在1999年给出的定义,机器学习指的是“能够参考经验(E)得知完成任务(T)的方法并在任务中表现(P)不断提高的一种计算机程序”。然而我们事实上无法鉴定计算设备是否真正拥有人类所定义的“学习”的经历。现今来看,墨尔本大学知识技能科学(COMP90049 Knowledge Technology,slide machine learning)著名美女教授Dr.Sarah Erfani认为,机器学习是一种基于统计学、线性代数等数学学科以及计算机科学中的计算科学、算法等学科对于事物模式(pattern)的认知并指导实践中事件预测(prediction)的一门学科。机器学习又分为“监督式学习”(Supervised ML,即在训练过程中给出反馈结果,DNN是此类中一种比较高级的手段)和“非监督式学习”(Unsupervised ML,即只训练模型,不给出反馈)。它是人工智能的一种具体体现和实现手段。所以说实现了一个好的机器学习模型(“好”指按照用户预期的方式给出高精确度的执行,以满足用户对于潜在未知模式、规律或知识的认知),就迈出了人工智能的第一步。
而建成一个能实际使用的DNN机器学习模型,大致步骤如下:
- 获取数据集合:并将数据集合大致按照4:1的比例分为训练数据集合(Training data,简称“训练集”)和测试数据集合(Testing data,简称“测试集”)。这里4:1为理论上训练与结果评估的平衡值。低于这个值由于训练集合数据数量太少,训练效果不佳。高于这个值则评估的精确度就可能有问题。
- 训练预测模型:根据训练数据,对计算设备进行“训练”,其本质上是执行一段发现模式(pattern)的程序,并从模式中发现一个数据集可能拥有的规律,从而为进一步预测做好准备。在这一步的过程中,DNN会以训练集中的特征数据列(下简称“特征”,英文为feature)作为输入,以标签数据列(下简称“标签”,英文为label)作为输出,经历若干隐形中间层。通过这些中间层的运算发现从输入刀输出的精确度较好的映射(mapping,精确度较好指的是两个叫做loss和gradient较低,而精确度较高),从而得到一个预测模型(model)完成训练。
- 评估训练效果:根据得到的模型以及测试集中的特征对于测试集中的标签作出预测,并与测试集中真实的标签进行对比从而得出精确度。若精确度符合要求则结束训练,否则修改训练模型后重复步骤2。
- 预测未知输入:使用结束训练后的模型对于真实事件作出预测,给出在保证一定预测精确度条件下的结果。
本文所用数据集合
本文以对于鸢尾草种类的识别并实现自动分类为例,展示tensorflow DNN的工作原理。
鸢尾草大致分为三种,即setosa,versicolor和virginica。本数据集用csv文件存储,第一列为数据集总数以及这三个分类,作为数据集的标题栏(title)。第二列开始,每列前四个数据为对于每株鸢尾草测量的四个指标,最后第五个数据为它是哪一类的草。(0-setosa, 1-versicolor以及2-virginica)。本模型的任务就是训练相应的模型,对于给定未知鸢尾草的四个指标,使用上述四个步骤,预测种类并达到大于95%的精确度。
---------------------------------------------------------------正文开始---------------------------------------------------------------
搭建环境准备:
为了搭建此模型,首先需要一个运行模型的环境。这里需要导入一些python的模块,具体代码如下:
from __future__ import absolute_import, division, print_function
import os
import matplotlib.pyplot as plt
import tensorflow as tf
import tensorflow.contrib.eager as tfe
try:
tf.enable_eager_execution()
except ValueError:
pass
print("TensorFlow version: {}".format(tf.VERSION))
print("Eager execution: {}".format(tf.executing_eagerly()))
print()
其中,eager_execution()是一个减少图运算的内置模块,它能加速机器学习的过程并且很多模块依赖其才得以执行。然而,在一个环境中enable_eager_execution()这一语句只能运行一次,否则会报ValueError,因此环境准备程序应写成如上所示。
获取数据集:
下载数据集
此处鸢尾草数据集(包括训练集和测试集)都会从不同链接下载。因此本模块输入为一个URL,输出为数据集所在文件对象(包括路径和文件)以便获得数据集时调用。代码如下:
def get_iris_dataset_fp(datasetURL):
#Get the dataset:
dataset_fp = tf.keras.utils.get_file(fname=os.path.basename(datasetURL),
origin=datasetURL, cache_dir="F:\\Py_TF_wp", cache_subdir='mydataset')
#print("Local copy of the dataset file: {}".format(dataset_fp))
return dataset_fp
处理数据集中的每行数据
获得.csv数据集之后,需要将这些数据集处理为tensorflow能够使用的tensor对象(本质是一种numpy数组),并将数据集中的数据分为特征和标签。其处理方式如下:
"""
Input: Eachline of the Iris data file.
Output: Feature vector and label of eachline as tensors.
"""
def parse_csv(line):
example_defaults = [[0.], [0.], [0.], [0.], [0]] # sets field types
parsed_line = tf.decode_csv(line, example_defaults)
#print("Parsed line:", parsed_line)
# First 4 fields are features, combine into single tensor
features = tf.reshape(parsed_line[:-1], shape=(4,))
# Last field is the label
label = tf.reshape(parsed_line[-1], shape=())
return features, label
通过如下代码,读者可以自行查看对于这些数据处理的结果:
def parse_dataset(filefp):
dataFile = open(filefp)
# 注意第一行是方法头,这在后面的训练和评估过程中
# 也要记得略去
file_header = dataFile.readline()
for eachLine in dataFile:
features, label = parse_csv(eachLine.rstrip())
print("Parsing result for the line:")
print("Features:", features)
print("Label", label)
print()
parse_dataset("mydataset/iris_training.csv")
获得处理完成的数据集
"""
Model: get training / testing dataset.
"""
def get_dataset(sample_size, datasetURL):
# 根据URL获得文件对象的信息
dataset_fp = get_iris_dataset_fp(datasetURL)
dataset = tf.data.TextLineDataset(dataset_fp)
dataset = dataset.skip(1) # skip the first header row
#parse_csv is the method used to parse each_line of the csv file.
dataset = dataset.map(parse_csv) # parse each row
dataset = dataset.shuffle(buffer_size=1000) # randomize
dataset = dataset.batch(sample_size)
# View a single example entry from a batch
# features, label = tfe.Iterator(train_dataset).next()
#print("example features:", features[0])
#print("example label:", label[0])
return dataset
获取训练集和测试集的调用代码分别如下:
train_dataset = get_dataset(96, "http://download.tensorflow.org/data/iris_training.csv")
test_dataset = get_dataset(24, "http://download.tensorflow.org/data/iris_test.csv")
训练模型
搭建DNN架构:
在训练开始之前,首先需要搭建一个DNN架构。DNN架构是由许多层次训练步骤组成的(本文从输入到输出搭建了4层),一般来说,层次越多结果越准确,但速度也越慢。其中,搭建输入层模型时需要输入特征数据的维度。最后一层需要交代可能的标签种类的数量。
"""
# Build the DNN:
# First row of line input layer, in which shape is required.
# Middle row(s) hidden layer
# Last row output layer.
"""
def build_model():
model = tf.keras.Sequential([
tf.keras.layers.Dense(10, activation="relu", input_shape=(4,)), # input shape required
tf.keras.layers.Dense(10, activation="relu"),
tf.keras.layers.Dense(10, activation="relu"),
tf.keras.layers.Dense(3)
])
#print("Built model:", model)
return model
model = build_model()
定制“止损”策略
DNN会通过loss和gradient两个指标的计算,并结合精确度来训练模型。如前文所说,训练过程中loss和gradient应当尽量小,而精确度应当尽量大。
"""
Calculate loss of a model.
Input: model, independent variables, predictions.
Output: Loss value as calculated.
"""
def loss(model, x, y):
#y_ is the desired label.
y_ = model(x)
return tf.losses.sparse_softmax_cross_entropy(labels=y, logits=y_)
def gradient(model, inputs, targets):
with tfe.GradientTape() as tape:
loss_value = loss(model, inputs, targets)
return tape.gradient(loss_value, model.variables)
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)
开始训练模型:
这是本例最关键的一个环节。这个环节中根据用户设置的迭代次数(num_epochs),DNN会不断迭代寻找模型的最佳匹配规律。一般来说,迭代次数设置越大则预测越准确,但是耗时也长。经过多次尝试,发现迭代次数设置在200 - 250之间较为合适。
def train_model():
# keep results for plotting
train_loss_results = []
train_accuracy_results = []
#model = build_model()
num_epochs = 201
#num_epochs = 251
for epoch in range(num_epochs):
epoch_loss_avg = tfe.metrics.Mean()
epoch_accuracy = tfe.metrics.Accuracy()
# Training loop - using batches of 32
for x, y in tfe.Iterator(train_dataset):
# Optimize the model
grads = gradient(model, x, y)
optimizer.apply_gradients(zip(grads, model.variables),
global_step=tf.train.get_or_create_global_step())
# Track progress
epoch_loss_avg(loss(model, x, y)) # add current batch loss
# compare predicted label to actual label
epoch_accuracy(tf.argmax(model(x), axis=1, output_type=tf.int32), y)
# end epoch
train_loss_results.append(epoch_loss_avg.result())
train_accuracy_results.append(epoch_accuracy.result())
"""# Check training accuracies:
if epoch % 50 == 0:
print("Epoch {:03d}: Loss: {:.3f}, Accuracy: {:.3%}".format(epoch,
epoch_loss_avg.result(), epoch_accuracy.result()))
"""
return (train_loss_results, train_accuracy_results)
train_model()
描绘训练过程:
本过程虽然不是DNN的一个必须步骤,但是对于初学者来说,可以通过观察训练过程中“损失”的降低和精确度的提高,直观感受DNN神经网络的神奇之处。
def plot_training():
train_loss_results, train_accuracy_results = train_model()
fig, axes = plt.subplots(2, sharex=True, figsize=(12, 8))
fig.suptitle('Training Metrics')
axes[0].set_ylabel("Loss", fontsize=14)
axes[0].plot(train_loss_results)
axes[1].set_ylabel("Accuracy", fontsize=14)
axes[1].set_xlabel("Epoch", fontsize=14)
axes[1].plot(train_accuracy_results)
plt.show()
plot_training()
某次测试所得图形如下:
基本可以观察到,一开始随着迭代次数增加“损失”波动减少,精确度波动上升;而后面二者波动渐渐趋于稳定。因此为了节省训练时间,迭代次数也不必过多,达到预期精确度之后即可。
评估模型
评估模型时根据训练过的模型对结果进行预测,以test_accuracy.result()的方式呈现。
def evaluate():
test_dataset = get_dataset(96, "http://download.tensorflow.org/data/iris_test.csv")
test_accuracy = tfe.metrics.Accuracy()
for (x, y) in tfe.Iterator(test_dataset):
prediction = tf.argmax(model(x), axis=1, output_type=tf.int32)
test_accuracy(prediction, y)
print("Test set accuracy: {:.3%}".format(test_accuracy.result()))
evaluate()
对于本模型来说,预测准确度大约在数次尝试后稳定在96.67%左右。
预测未知数据
最后,经过训练后的模型满足要求后便可以投入实际使用。使用时,将特征指标转化为tensor对象,然后即可由标签中的“name”变量获取预测结果。
def classify_unkowns():
class_ids = ["Iris setosa", "Iris versicolor", "Iris virginica"]
predict_dataset = tf.convert_to_tensor([
[5.1, 3.3, 1.7, 0.5,],
[5.9, 3.0, 4.2, 1.5,],
[6.9, 3.1, 5.4, 2.1]
])
predictions = model(predict_dataset)
for i, logits in enumerate(predictions):
class_idx = tf.argmax(logits).numpy()
name = class_ids[class_idx]
print("Example {} prediction: {}".format(i, name))
classify_unkowns()
参考资料:
- Get Started, Tensorflow doc, URL: https://www.tensorflow.org/get_started/eager?hl=zh-cn
- 谷歌Tensorflow学习顺序参考页面:https://www.tensorflow.org/get_started/
- Installing Tensorflow, URL: https://www.tensorflow.org/install/?hl=zh-cn
- Slides machine learning, deep neuron network, COMP90049 Knowledge Technology, 2017 semester 2, University of Melbourne