TensorFlow学习(5)——TensorFlow的基本使用

本节学习目标:
  • 学习基本的 TensorFlow 概念
  • 在 TensorFlow 中使用 LinearRegressor 类并基于单个输入特征预测各城市街区的房屋价值中位数
  • 使用均方根误差 (RMSE) 评估模型预测的准确率
  • 通过调整模型的超参数提高模型准确率
TensorFlow框架概览

以下是TensorFlow的架构体系:
在这里插入图片描述

我们一般用到的是 TensorFlow Estimators层,该层相对比较容易,易于入手,本学习大部分内容也都是介绍Estimator层的使用。随着应用的熟练,我们可以逐步往下学习,自定义编程更加灵活轻便。下面进入本节的主要内容:

引入并检查数据

首先引入必要的依赖库:

from __future__ import print_function

import math

from IPython import display
from matplotlib import cm
from matplotlib import gridspec
from matplotlib import pyplot as plt
import numpy as np
import pandas as pd
from sklearn import metrics
import tensorflow as tf
from tensorflow.python.data import Dataset

tf.logging.set_verbosity(tf.logging.ERROR)
pd.options.display.max_rows = 10
pd.options.display.float_format = '{:.1f}'.format

这里有几个库要进行另外下载安装,首先找到Scripts目录(我这里是\Python\Python35\Scripts),然后分别安装IPython、sklearn、scipy

pip install IPython

pip install sklearn

pip install scipy

加载加利福尼亚房屋交易数据:

california_housing_dataframe = pd.read_csv("https://download.mlcc.google.cn/mledu-datasets/california_housing_train.csv", sep=",")

对数据进行随机化处理:

california_housing_dataframe = california_housing_dataframe.reindex(
    np.random.permutation(california_housing_dataframe.index))

将 median_house_value 调整为以千为单位:

california_housing_dataframe["median_house_value"] /= 1000.0

检查数据,输出快速摘要:样本数、均值、标准偏差、最大值、最小值和各种分位数等:

print(california_housing_dataframe.describe())

摘要输出结果如下:
在这里插入图片描述

构建第一个模型

由于我们使用的是加利福尼亚房屋交易数据,因此本节我们就尝试去预测该地方的 median_house_value,并且我们使用 total_rooms 作为输入特征。在本节中我们使用到的接口是 LinearRegressor ,该接口提供了大量低级别的模型搭建工作,并提供模型训练、评估和推理等方法。具体步骤如下:

第1步:定义特征并配置特征列

首先我们要找到特征列,这里我们用房间总数 total_rooms 作为特征列:

# 定义特征
my_feature = california_housing_dataframe[["total_rooms"]]

# 配置特征列
feature_columns = [tf.feature_column.numeric_column("total_rooms")]
第2步:定义目标

我们要进行机器学习,肯定是要有一个学习出一个结果的,这就是目标。在此,我们的目标就是要找到房价中位数 median_house_value :

# 定义学习目标
targets = california_housing_dataframe["median_house_value"]
第3步:配置 LinearRegressor

在本次学习中我们将用线性回归 LinearRegressor ,并且用小批量随机梯度下降 GradientDescentOptimizer 进行训练,其中步长为 learning_rate = 0.0000001 . 为了防止梯度在训练过程中会变得过大,我们需要用到 clip_gradients_by_norm 进行裁剪。具体如下:

# 设置梯度下降方法
my_optimizer=tf.train.GradientDescentOptimizer(learning_rate=0.0000001)
# 进行梯度裁剪
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
)
第4步:定义输入函数
# 定义输入函数
def my_input_fn(features, targets, batch_size=1, shuffle=True, num_epochs=None):
    # 将pandas数据转换为Numpy数组
    features = {key:np.array(value) for key,value in dict(features).items()}                                           
 
    # 构建一个 dataset 对象
    ds = Dataset.from_tensor_slices((features,targets)) # warning: 2GB limit
    # 把数据拆分成多批次,并按num_epochs进行循环,此处为无限循环
    ds = ds.batch(batch_size).repeat(num_epochs)
    
    # 循环对数据进行随机处理,每次娶10000份数据
    if shuffle:
      ds = ds.shuffle(buffer_size=10000)
    
    # 构建迭代器,并返回数据给 LinearRegressor 
    features, labels = ds.make_one_shot_iterator().get_next()
    return features, labels
第5步:训练模型

现在,我们可以在 linear_regressor 上调用 train() 来训练模型。我们会将 my_input_fn 封装在 lambda 中,以便可以将 my_feature 和 target 作为参数传入。首先,我们会训练 100 步。

_ = linear_regressor.train(
    input_fn = lambda:my_input_fn(my_feature, targets),
    steps=100
)
第 6 步:评估模型

要对模型做评估,就必须要进行一次预测,下面我们就用上面预测到的模型做一次预测吧:

# 基于以上的训练我们做一次预测,由于是预测,所以只需要运行一次,不需要再次循环了
prediction_input_fn =lambda: my_input_fn(my_feature, targets, num_epochs=1, shuffle=False)

# 执行预测
predictions = linear_regressor.predict(input_fn=prediction_input_fn)

为了更直观的看到预测结果,我们现在打印预测结果的相关参数:


# 为了能够对数据进行误差统计,我们需要用Numpy对数据进行格式化操作
predictions = np.array([item['predictions'][0] for item in predictions])

# 打印预测结果的相关数据
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)

min_house_value = california_housing_dataframe["median_house_value"].min()
max_house_value = california_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)

打印预测摘要:

#打印预测总体摘要,了解预测的基本情况
calibration_data = pd.DataFrame()
calibration_data["predictions"] = pd.Series(predictions)
calibration_data["targets"] = pd.Series(targets)
calibration_data.describe()

结果输出如下图:
在这里插入图片描述

如果你觉得还不够直观,你可以绘制图表进行观察:

#为了进一步了解预测得结果,我们现在要把预测结果进行可视化图形输出
sample = california_housing_dataframe.sample(n=300)

# Get the min and max total_rooms values.
x_0 = sample["total_rooms"].min()
x_1 = sample["total_rooms"].max()

# Retrieve the final weight and bias generated during training.
weight = linear_regressor.get_variable_value('linear/linear_model/total_rooms/weights')[0]
bias = linear_regressor.get_variable_value('linear/linear_model/bias_weights')

# Get the predicted median_house_values for the min and max total_rooms values.
y_0 = weight * x_0 + bias
y_1 = weight * x_1 + bias

# 从 (x_0, y_0) 到 (x_1, y_1)画一条直线
plt.plot([x_0, x_1], [y_0, y_1], c='r')

# 绘制坐标线名称
plt.ylabel("median_house_value")
plt.xlabel("total_rooms")

# 绘制分布图
plt.scatter(sample["total_rooms"], sample["median_house_value"])

# 显示图表
plt.show()

图表如下:
在这里插入图片描述

第7步:调整参数优化模型

从上面的图表显示结果我们发现,我们的预测模型非常糟糕,并没有正确的把中位数给预测出来,所以接下来我们要优化我们的模型。


"""
训练模型
  learning_rate: 学习速率
  steps: 循环次数
  batch_size: 数据批次
  input_feature: 输入的特征值
"""
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]

    # 创建特征列
    feature_columns = [tf.feature_column.numeric_column(my_feature)]

    # 创建输入函数
    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)

    # 创建和配置线性回归
    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
    )

    # 每次运行都绘制一条线
    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)]

    # 循环
    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)

现在我们修改步长和数据批次为如下:

train_model(
    learning_rate=0.00002,
    steps=500,
    batch_size=5
)

则运行结果如下:
在这里插入图片描述

很明显比之前的效果好了很多,现在我们可以用红色的线来判断房子价格的中位数了。

你可能会发现我们在给模型定义学习速率、步长还有数据批次大小的时候,是凭借主观意识乱猜的,那么有没有可以遵循的一般规律呢?以下TensorFlow官方为我们总结了一些:

  • 训练误差应该稳步减小,刚开始是急剧减小,最终应随着训练收敛达到平稳状态。
  • 如果训练尚未收敛,尝试运行更长的时间。
  • 如果训练误差减小速度过慢,则提高学习速率也许有助于加快其减小速度。
  • 但有时如果学习速率过高,训练误差的减小速度反而会变慢。
  • 如果训练误差变化很大,尝试降低学习速率。
  • 较低的学习速率和较大的步数/较大的批量大小通常是不错的组合。
  • 批量大小过小也会导致不稳定情况。不妨先尝试 100 或 1000 等较大的值,然后逐渐减小值的大小,直到出现性能降低的情况。
  • 重申一下,切勿严格遵循这些经验法则,因为效果取决于数据。请始终进行试验和验证。

本节到此结束/
欢迎大家加入Q群讨论:463255841
本节到此结束/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值