今天通过一个实例,来学习下 Tensorflow 的基本操作加实战
Tensorflow 是干嘛的,就不过多赘述了,小伙伴们可以访问官网来详细了解 https://www.tensorflow.org/
• 张量 • 指令 • 图 • 会话
标量,是零维数组(零阶张量)。例如,\'Howdy\' 或 5 矢量,是一维数组(一阶张量)。例如,[2, 3, 5, 7, 11] 或 [5] 矩阵,是二维数组(二阶张量)。例如,[[3.1, 8.2, 5.9][4.3, -2.7, 6.5]]
大多数 Tensorflow 代码都是指令。
图的节点是指令,图的边是张量。张量流经图,在每个节点由一个指令操控。一个指令的输出张量通常会变成后续指令的输入张量。 张量可以作为常量或者变量存储在图中。常量是始终会返回同一张量值的指令。变量是会返回分配给它的任何张量的指令。
定义常量:
x = tf.constant([5.2])
定义变量:
y = tf.Variable([5])
给变量赋值:
y = tf.Variable([0])
y = y.assign([5])
会话存储了它所运行图的状态。
with tf.Session() as sess:
initialization = tf.global_variables_initializer()
print(y.eval())
Tensorflow 编程总结:
因为搭建 Tensorflow 环境还是蛮复杂的,这里还是使用 Google Colab 环境。
import math
# display模块可以决定显示的内容以何种格式显示
from IPython import display
# matplotlib为python的2D绘图库
# cm为颜色映射表
from matplotlib import cm
# 使用 GridSpec 自定义子图位置
from matplotlib import gridspec
# pyplot提供了和matlab类似的绘图API,方便用户快速绘制2D图表
from matplotlib import pyplot as plt
# numpy为python的科学计算包,提供了许多高级的数值编程工具
import numpy as np
# pandas是基于numpy的数据分析包,是为了解决数据分析任务而创建的
import pandas as pd
# sklearn(scikit-_learn_)是一个机器学习算法库,包含了许多种机器学习得方式
# * Classification 分类
# * Regression 回归
# * Clustering 非监督分类
# * Dimensionality reduction 数据降维
# * Model Selection 模型选择
# * Preprocessing 数据预处理
# metrics:度量(字面意思),它提供了很多模块可以为第三方库或者应用提供辅助统计信息
from sklearn import metrics
# tensorflow是谷歌的机器学习框架
import tensorflow as tf
# Dataset无比强大得数据集
from tensorflow.python.data import Dataset
tf.logging.set_verbosity(tf.logging.ERROR)
# 为了观察数据方便,最多只显示10行数据
pd.options.display.max_rows = 10
pd.options.display.float_format = '{:.1f}'.format
数据基于加利福尼亚州 1990 年的人口普查数据。
housing_dataframe = pd.read_csv("https://download.mlcc.google.cn/mledu-datasets/california_housing_train.csv", sep=",")
housing_dataframe.describe()
随机排序数据,因为这样更接近生活中的真实数据,并将 median_house_value 的数值以千为单位处理,同时查看数据概要信息。
housing_dataframe = housing_dataframe.reindex(
np.random.permutation(housing_dataframe.index))
housing_dataframe["median_house_value"] /= 1000.0
housing_dataframe.describe()
构建模型
因为是准备预测 median_house_value 的值,所以它就是我们的标签(也成为目标)。因为 total_rooms 代表的是某个街区的总房数,所以用 total_rooms 作为输入特征。 这里选取 TensorFlow Estimator API(是基于 Tensorflow 的高级 API) 提供的 LinearRegressor 接口,来构建模型。
我们要指定每个特征所包含的数据类型,根据经验,主要有两种数据类型: 分类数据:一种文字数据。 数值数据:一种数字(整数或者浮点数)数据以及可以视为数字的数据。
在 TensorFlow 中,使用一种称为“特征列”的结构来表示特征的数据类型。特征列仅仅存储对特征数据的描述,不包含特征数据本身。
提取特征total_rooms数据,并使用 numeric_column定义特征列,将其数据指定为数值数据。
# Define the input feature: total_rooms.
my_feature = housing_dataframe[["total_rooms"]]
# Configure a numeric feature column for total_rooms.
feature_columns = [tf.feature_column.numeric_column("total_rooms")]
从 housing_dataframe 中提取标签
# Define the label.
targets = housing_dataframe["median_house_value"]
使用 LinearRegressor 配置线性回归模型,并通过 GradientDescentOptimizer(它会实现小批量随机梯度下降法 (SGD))训练该模型。learning_rate 参数可控制梯度步长的大小。 为了安全起见,我们还会通过 clip_gradients_by_norm 将梯度裁剪应用到优化器。梯度裁剪可确保梯度大小在训练期间不会变得过大,梯度过大会导致梯度下降法失败。
# Use gradient descent as the optimizer for training the model.
my_optimizer=tf.train.GradientDescentOptimizer(learning_rate=0.0000001)
my_optimizer = tf.contrib.estimator.clip_gradients_by_norm(my_optimizer, 5.0)
# Configure the linear regression model with our feature columns and optimizer.
# Set a learning rate of 0.0000001 for Gradient Descent.
linear_regressor = tf.estimator.LinearRegressor(
feature_columns=feature_columns,
optimizer=my_optimizer
)
梯度 (gradient):偏导数相对于所有自变量的向量。在机器学习中,梯度是模型函数偏导数的向量。梯度指向最速上升的方向。 梯度下降法 (gradient descent):一种通过计算并且减小梯度将损失降至最低的技术,它以训练数据为条件,来计算损失相对于模型参数的梯度。通俗来说,梯度下降法以迭代方式调整参数,逐渐找到权重和偏差的最佳组合,从而将损失降至最低。
这里还涉及了一些其他的机器学习的概念,比如学习速率,梯度裁剪等,感兴趣的同学可以自行查找概念。
主要定义TensorFlow 如何对数据进行预处理,以及在模型训练期间如何批处理、随机处理和重复数据。
def my_input_fn(features, targets, batch_size=1, shuffle=True, num_epochs=None):
# Convert pandas data into a dict of np arrays.
features = {key:np.array(value) for key,value in dict(features).items()}
# Construct a dataset, and configure batching/repeating.
ds = Dataset.from_tensor_slices((features,targets)) # warning: 2GB limit
ds = ds.batch(batch_size).repeat(num_epochs)
# Shuffle the data, if specified.
if shuffle:
ds = ds.shuffle(buffer_size=10000)
# Return the next batch of data.
features, labels = ds.make_one_shot_iterator().get_next()
return features, labels
有关 Dataset API 更详细的文档,请参阅 TensorFlow 编程人员指南.
现在再在 linear_regressor 上调用 train() 来训练模型。
_ = linear_regressor.train(
input_fn = lambda:my_input_fn(my_feature, targets),
steps=100
)
这里使用 _ 来接收函数,目的是表明函数是有返回值的,但是我们并不需要返回值。
我们基于该训练数据做一次预测,看看我们的模型在训练期间与这些数据的拟合情况。 训练误差可以衡量我们的模型与训练数据的拟合情况,但并不能衡量模型泛化到新数据的效果。
泛化能力(generalization ability)是指机器学习算法对新鲜样本的适应能力。学习的目的是学到隐含在数据对背后的规律,对具有同一规律的学习集以外的数据,经过训练的网络也能给出合适的输出,该能力称为泛化能力。
# Create an input function for predictions.
# Note: Since we're making just one prediction for each example, we don't
# need to repeat or shuffle the data here.
prediction_input_fn =lambda: my_input_fn(my_feature, targets, num_epochs=1, shuffle=False)
# Call predict() on the linear_regressor to make predictions.
predictions = linear_regressor.predict(input_fn=prediction_input_fn)
# Format predictions as a NumPy array, so we can calculate error metrics.
predictions = np.array([item['predictions'][0] for item in predictions])
# Print Mean Squared Error and Root Mean Squared Error.
mean_squared_error = metrics.mean_squared_error(predictions, targets)
root_mean_squared_error = math.sqrt(mean_squared_error)
print("Mean Squared Error (on training data): %0.3f" % mean_squared_error)
print("Root Mean Squared Error (on training data): %0.3f" % root_mean_squared_error)
得到的结果如下: (均方误差)Mean Squared Error (on training data): 56425052440.760 (均方根误差)Root Mean Squared Error (on training data): 237539.581 我们通常使用均方根误差来判断误差的大小,因为它通常会与 target 在同一个数量级上。 比较一下 RMSE 与目标最大值和最小值的差值
min_house_value = housing_dataframe["median_house_value"].min()
max_house_value = housing_dataframe["median_house_value"].max()
min_max_difference = max_house_value - min_house_value
print("Min. Median House Value: %0.3f" % min_house_value)
print("Max. Median House Value: %0.3f" % max_house_value)
print("Difference between Min. and Max.: %0.3f" % min_max_difference)
print("Root Mean Squared Error: %0.3f" % root_mean_squared_error)
结果:
Min. Median House Value: 14999.000 Max. Median House Value: 500001.000 Difference between Min. and Max.: 485002.000 Root Mean Squared Error: 237539.581
再根据总体摘要统计信息,了解预测和目标的符合情况
calibration_data = pd.DataFrame()
calibration_data["predictions"] = pd.Series(predictions)
calibration_data["targets"] = pd.Series(targets)
calibration_data.describe()
很明显,预测的结果并不好,我们要继续调整参数,增加训练时长,来获得更好的模型。
定义一个可以自由调整参数的函数,来方便的调节超参,并绘制出训练数据
def train_model(learning_rate, steps, batch_size, input_feature="total_rooms"):
periods = 10
steps_per_period = steps / periods
my_feature = input_feature
my_feature_data = california_housing_dataframe[[my_feature]]
my_label = "median_house_value"
targets = california_housing_dataframe[my_label]
# Create feature columns.
feature_columns = [tf.feature_column.numeric_column(my_feature)]
# Create input functions.
training_input_fn = lambda:my_input_fn(my_feature_data, targets, batch_size=batch_size)
prediction_input_fn = lambda: my_input_fn(my_feature_data, targets, num_epochs=1, shuffle=False)
# Create a linear regressor object.
my_optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
my_optimizer = tf.contrib.estimator.clip_gradients_by_norm(my_optimizer, 5.0)
linear_regressor = tf.estimator.LinearRegressor(
feature_columns=feature_columns,
optimizer=my_optimizer,
config=tf.estimator.RunConfig(model_dir='out')
)
# Set up to plot the state of our model's line each period.
plt.figure(figsize=(15, 6))
plt.subplot(1, 2, 1)
plt.title("Learned Line by Period")
plt.ylabel(my_label)
plt.xlabel(my_feature)
sample = california_housing_dataframe.sample(n=300)
plt.scatter(sample[my_feature], sample[my_label])
colors = [cm.coolwarm(x) for x in np.linspace(-1, 1, periods)]
# Train the model, but do so inside a loop so that we can periodically assess
# loss metrics.
print("Training model...")
print("RMSE (on training data):")
root_mean_squared_errors = []
for period in range (0, periods):
# Train the model, starting from the prior state.
linear_regressor.train(
input_fn=training_input_fn,
steps=steps_per_period
)
# Take a break and compute predictions.
predictions = linear_regressor.predict(input_fn=prediction_input_fn)
predictions = np.array([item['predictions'][0] for item in predictions])
# Compute loss.
root_mean_squared_error = math.sqrt(
metrics.mean_squared_error(predictions, targets))
# Occasionally print the current loss.
print(" period %02d : %0.2f" % (period, root_mean_squared_error))
# Add the loss metrics from this period to our list.
root_mean_squared_errors.append(root_mean_squared_error)
# Finally, track the weights and biases over time.
# Apply some math to ensure that the data and line are plotted neatly.
y_extents = np.array([0, sample[my_label].max()])
weight = linear_regressor.get_variable_value('linear/linear_model/%s/weights' % input_feature)[0]
bias = linear_regressor.get_variable_value('linear/linear_model/bias_weights')
x_extents = (y_extents - bias) / weight
x_extents = np.maximum(np.minimum(x_extents,
sample[my_feature].max()),
sample[my_feature].min())
y_extents = weight * x_extents + bias
plt.plot(x_extents, y_extents, color=colors[period])
print("Model training finished.")
# Output a graph of loss metrics over periods.
plt.subplot(1, 2, 2)
plt.ylabel('RMSE')
plt.xlabel('Periods')
plt.title("Root Mean Squared Error vs. Periods")
plt.tight_layout()
plt.plot(root_mean_squared_errors)
# Output a table with calibration data.
calibration_data = pd.DataFrame()
calibration_data["predictions"] = pd.Series(predictions)
calibration_data["targets"] = pd.Series(targets)
display.display(calibration_data.describe())
print("Final RMSE (on training data): %0.2f" % root_mean_squared_error)
调用函数训练 01
train_model(
learning_rate=0.00001,
steps=500,
batch_size=5
)
调用函数训练 02
train_model(
learning_rate=0.5,
steps=500,
batch_size=5
)
可以看到,通过修改学习速率和训练步数以及每批数据数量,可以慢慢的使模型接近于真实值。
我们把特征 total_rooms 切换为 population,来进行预测,可以得到如下的预测结果
train_model(
learning_rate=0.00002,
steps=1000,
batch_size=5,
input_feature="population"
)
好了,这就是今天的分享了,下次见!