【读书笔记】【机器学习实战】第九章:TensorFlow

本文介绍TensorFlow的基本概念与使用方法,包括构建计算图、执行会话、实现线性回归及梯度下降等内容,并演示如何利用TensorFlow自动微分及优化器进行高效训练。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

阅读书籍为《Hands-On Machine Learning with Scikit-Learn & TensorFlow》王静源等翻译的中文译版《机器学习实战,基于 Scikit-Learn 和 TensorFlow》,本文中所有图片均来自于书籍相关部分截图。

TensorFlow是什么鬼

是什么: 是一个用于数值计算的开源软件库,或者框架。
为什么叫TensorFlow: TF中的操作可以接受任意数量的输入,也可以产生任意数量的输出。当输入和输出都是多维数组的时候被称为张量Tensor。
基本的原理: 首先再python中定义一个用来计算的图,然后TF使用,并且使用优化过的C++代码进行执行。
特点: 设计清晰,灵活性,扩展性还有完善的文档。
优势: TF可以将一个计算图划分为多个子图,然后进行分布式并行计算。这个优势使得TF非常适用于在庞大的(数十亿的数据量)数据集上训练巨大的(上百万的特征量)神经网络。
在这里插入图片描述
在这里插入图片描述

如何使用TensorFlow

  • 构造一个节点树:

    import tensorflow as tf
    
    x = tf.Variable(3, name="X")
    y = tf.Variable(4, name="Y")
    f = x*x*x + y + 2
    
    init = tf.global_variables_initializer()
    
  • 什么是会话:当前运行的一次过程,有两种启动方式

    #1 使用with
    with tf.Session() as sess:
        init.run()
        result = f.eval()
        print(result)
    
    #2 不使用with,这个要记得手动关闭会话
    sess = tf.InteractiveSession()
    init.run()
    re = f.eval()
    print(re)
    sess.close()
    
  • 节点会自己加入结点树吗:会!

    x1 = tf.Variable(1)
    a = x1.graph is tf.get_default_graph()
    print(a)
    #will print true
    
  • 设置默认结点:两种方法

    #1
    graph = tf.Graph()
    with graph.as_default():
        x2 = tf.Variable(2)
    print(x2.graph is graph)
    # will print ture
    
    #2
    tf.get_default_graph()
    #可以用来直接重置默认结点
    print(x2.graph is tf.get_default_graph())
    #will print flase
    
  • 一个节点的生命周期:
    节点值每次执行后都会被抛弃;
    变量值由会话维护,从初始化器的执行开始到关闭会话结束;

    w = tf.constant(3)
    x = w + 2
    y = x + 5
    z = x * 3
    
    with tf.Session() as sess:
        print(y.eval())
        print(z.eval())
    

    此段代码描述了一个简单的计算图,执行阶段
    1.启动一个会话(with那行);
    2.求值Y, 检测到y依赖x,x依赖w, 所以先计算w,再计算x,最后合成y。(第一个print那行);
    3.求值z, 检测到z依赖x,x依赖w,所以先计算w,再计算x,最后合成z。(第二个print那行);
    过程中可见,W和X被计算两次,此处体现了,节点值每次执行后都会被抛弃;

用加州的房价数据集实现一个线性回归

import numpy as np
from sklearn.datasets import fetch_california_housing
import tensorflow as tf

# import data
housing = fetch_california_housing()
m, n = housing.data.shape
housing_data_plus_bias = np.c_[np.ones((m, 1)), housing.data]

# prepare array
X = tf.constant(housing_data_plus_bias, dtype=tf.float32, name="X")
Y = tf.constant(housing.target.reshape(-1, 1), dtype=tf.float32, name="Y")
XT = tf.transpose(X)
# formula computing theta
theta = tf.matmul(tf.matmul(tf.matmul_inverse(tf.matmul(XT, X)), XT), Y)

# do
with tf.Session() as sess:
    theta_value = theta.eval()
    print(theta_value)

结果如下:
与直接使用numpy计算相比,TF会自动把计算任务发给不同的CPU或者GPU,快得很。
在这里插入图片描述
这里theta参数集使用正规方程计算:
在这里插入图片描述

实现一个梯度下降

TF有个强大的功能就是可以自动微分从而自动计算梯度。除此之外还有众多的优化器可以帮助更好的实现梯度下降。
我们将对比手工,自动微分,和优化器的三种不同梯度下降方法:

  • 手工实现
    import numpy as np
    from sklearn.datasets import fetch_california_housing
    import tensorflow as tf
    
    
    housing = fetch_california_housing()
    m, n = housing.data.shape
    #梯度下降前应该对数据进行特征向量归一化,这里没有进行归一化所以结果有误
    housing_data_plus_bias = np.c_[np.ones((m, 1)), housing.data]
    
    n_epochs = 1000
    L_rate = 0.01
    X = tf.constant(housing_data_plus_bias, dtype=tf.float32, name="X")
    Y = tf.constant(housing.target.reshape(-1, 1), dtype=tf.float32, name="Y")
    theta = tf.Variable(tf.random_uniform([n+1, 1], -1.0, 1.0),  name="theta")
    y_pred = tf.matmul(X, theta, name="pred")
    error = y_pred - Y
    mse = tf.reduce_mean(tf.square(error), name="mse")
    grad = 2/m * tf.matmul(tf.transpose(X), error)
    training_op = tf.assign(theta, theta-L_rate*grad)
    
    init = tf.global_variables_initializer()
    
    with tf.Session() as sess:
        sess.run(init)
        
        for epoch in range(n_epochs):
            if epoch % 100 == 0:
                print("epoch", epoch, "MSE=", mse.eval())
            sess.run(training_op)
        best_theta = theta.eval()
        print(best_theta)
    
  • 自动微分实现
    # grad = 2/m * tf.matmul(tf.transpose(X), error) 替换为下列语句即可。
    grad = tf.gradients(mse, [theta])[0]
    

    自动计算梯度主要有四种方法:
    在这里插入图片描述

  • 优化器实现
    # training_op = tf.assign(theta, theta - L_rate * grad)替换为下列两个语句。
    op = tf.train.GradientDescentOptimizer(learning_rate=L_rate)
    training_op = op.minimize(mse)
    

怎样保存和恢复模型

TF提供了非常便捷的模型保存和恢复语句:

  • 保存模型参数, 调用 save()方法:
    [....]
    theta = .....
    [...]
    init = tf.global_variables_initializer()
    saver = tf.train.Saver()
    
    with tf.Session() as sess:
        sess.run(init)
    
        for epoch in range(n_epochs):
            if epoch % 100 == 0:
                print("epoch", epoch, "MSE=", mse.eval())
            sess.run(training_op)
        best_theta = theta.eval()
        save_path  = saver.save(sess, "相对路径字符串")
    
  • 恢复模型参数,调用restore()方法:
    #前面一样
    [.......]
    
    with tf.Session() as sess:
         saver.restore(sess, "相对路径字符串")
         [.....]
    

TensorBoard又是什么鬼

是一个更好地可视化训练过程的库,我们可以用它来查看所定义的计算图, 可以查看训练曲线,可以查看MSE等重要的训练信息。相比我们之前依赖print来监控训练过程好的太多了。
在这里插入图片描述
在这里插入图片描述

其他:

命名作用域

随着我们计算的问题越来越复杂,图就很容易变得杂乱而庞大,一些相关的结点就有可能绕在一起混淆我们的思维。为了避免这个问题,我们可以建议命名作用域来在不使用时将相关结点收起来。具体操作如下:

#通过在变量命名前为其规定命名空间将其“收纳”
with tf.name_scope("loss") as scope:
    error = y_pred - Y
    mse = tf.reduce_mean(tf.square(error), name="mse")

图就会变成如下模样(loss在一般情况下自行收起,使图面看起来整洁清爽):
在这里插入图片描述

模块化

在很多项目的代码编写中我们经常会用到相同的语句比如下图所示:
在这里插入图片描述
这种操作产生的问题有:难以维护,复制过程中出错不易发现。TF为我们提供了避免这种情况产生的语句:
在这里插入图片描述
具体操作原理如下:
当TF创建一个结点的时候, 会先检查这个名字是否已经存在,如果存在,则会为其添加一个下划线和一个索引以保证结点的唯一性。然后TF会发现这种命名规律,然后将其归类到一个命名空间以避免界面的混乱,如下图:
在这里插入图片描述
如何实现归类到命名空间,具体实现如下:
在这里插入图片描述
在这里插入图片描述

共享变量

当我们想在图的不同组建中共享变量的时候,最简单的方法是先创建,然后将其作为参数传给需要他的函数。
不过当共享的参数特别多的时候,这样的办法就不再使用,这种情况下,有人创建一个包含模型所需要的所有变量的字典,然后传递给每一个函数。有人为每一个模块都创建一个类。还有一种方法是在第一次调用的时候将共享变量设置为relu()函数中的一个属性,像下面做的那样:
在这里插入图片描述除过这三种方法之外,TF还提供另一个可以让代码看起来更清晰,更加模块化的选择,这种方法将在很多项目中都会频繁使用。
方法的实现如下(这段我并没有读懂, 希望以后使用的过程中慢慢理解吧,好累):
如果共享变量不存在,先用get_variable()函数创建共享变量;如果已经存在,复制它;复制与否的行为通过variable_scope()函数中的一个属性控制到底是复制还是创建。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值