深度学习(一)

深度学习

一.深度学习介绍

1.1 深度学习与机器学习的区别

在这里插入图片描述

方面机器学习深度学习
特征提取手动完成,需要大量领域专业知识。深度学习通常由多个层组成,它们通常将更简单的模型组合在一起,将数据从一层传递到另一层来构建更复杂的模型。通过训练大量数据自动得出模型,不需要人工特征提取环节。适用于在难提取特征的图像、语言、自然语言处理领域。
数据量和计算性能要求执行时间短执行时间长,因为深度学习参数往往很庞大,需要通过大量的数据的多次优化来训练参数。
算法代表朴素贝叶斯算法、决策树等神经网络

1.2 深度学习的应用场景

主要应用于图像识别、自然语言处理、语音技术这些方面。

1.3 深度学习框架介绍

1.3.1 常见深度学习框架对比
框架名主语言从语言灵活性上手难易开发者
TensorflowC++cuda/pythonGoogle
CaffeC++cuda/python/Matlab一般中等贾杨请
PyTorchpythonC/C++中等FaceBook
MXNetC++cuda/R/julia中等李沐和陈天奇等
TorchluaC/cuda中等FaceBook
TheanopythonC++/cuda蒙特利尔理工学院

总结:

  • 最常用的框架当数TensorFlow和Pytorch,而 Caffe 和 Caffe2 次之。
  • PyTorch 和 Torch 更适用于学术研究(research);TensorFlow,Caffe,Caffe2 更适用于工业界的生产环境部署(industrial production)。
  • Caffe 适用于处理静态图像(static graph);Torch 和 PyTorch 更适用于动态图像(dynamic graph);TensorFlow 在两种情况下都很实用。
  • Tensorflow 和 Caffe2 可在移动端使用。
1.3.2 TemsorFlow特点
  1. 易用性:有对应Python的API

  2. 可移植性:一套代码就可以适应单个或者多个CPU、GPU、移动设备等

  3. 灵活性:可以部署在树莓派、安卓、windows、ios、linux等上

  4. 可视化:有tensorboard提供开发的可视化界面,方便跟踪调参

  5. 检查点:可以通过检查点记录保存实验数据

  6. 自动微积分:自动求解梯度

1.3.3 TensorFlow安装
对比GPUCPU
核芯数量
处理速度处理速度慢每个核处理速度快
处理任务适用于并行任务适用于处理连续性任务

二.TensorFlow框架介绍

2.1 TF数据流图

2.1.1 案例:TensorFlow实现一个加法运算
  1. 代码
import tensorflow as tf
# ensorFlow 2.x默认启用了Eager Execution模式,这个函数调用意在恢复旧有的(类似1.x版本)行为,可以使用会话,在2.0里面已经取消
tf.compat.v1.disable_eager_execution()


def tensorflow_machine_learning():
    a_t = tf.constant(1.0)
    b_t = tf.constant(2.0)
    c_t = a_t + b_t
    print(c_t)
    with tf.compat.v1.Session() as sess:
        print(sess.run(c_t))
    return None


if __name__ == '__main__':
    tensorflow_machine_learning()

2.TensorFlow结构分析

TensorFlow 程序通常被组织成一个构建图阶段一个执行图阶段

在构建阶段,数据(张量Tensor)与操作(节点Op)的执行步骤被描述成一个图。

在执行阶段,使用会话执行构建好的图中的操作

  • 图和会话:
    • 图 : 这是 TensorFlow 将计算表示为指令之间的依赖关系的一种表示法
    • 会话 : TensorFlow 跨一个或多个本地或远程设备运行数据流图的机制
  • 张量 : TensorFlow 中的基本数据对象
  • 节点 : 提供图当中执行的操作
2.1.2 数据流图介绍

在这里插入图片描述

​ TensorFlow是一个采用数据流图(data flow graphs),用于数值计算的开源框架。

​ 节点(Operation)在图中表示数学操作,线(edges)则表示在节点间相互联系的多维数据数组,即张量(tensor)。

2.2 图与TensorBoard

2.2.1 图结构

​ 图包含一组tf.Operation代表的计算单元对象和tf.Tensor代表的计算单元之间流动的数据。

2.2.2 图相关操作
  1. 默认图

    通常TensorFlow会默认帮我们创建一张图。

    查看默认图的两种方法

    • 通过tf.compat.v1.get_default_graph()方法
    • 数据,操作这些里面都有graph属性,默认都在一张图中
    def graph_demo():
        a_t = tf.constant(1.0)
        b_t = tf.constant(2.0)
        c_t = a_t + b_t
        print(c_t)
        # 查看默认图
        default_g = tf.compat.v1.get_default_graph()
        print(default_g)
        print(a_t.graph)
        print(b_t.graph)
        print(default_g.get_operations())
        with tf.compat.v1.Session() as sess:
            print(sess.run(c_t))
        return None
    
    
    if __name__ == '__main__':
        graph_demo()
    
    
  2. 创建图

    • 可以通过tf.Graph()自定义创建图
    • 如果要在这张图中创建数据和操作,使用tf.Graph.as_default()
    def graph_demo():
        """
        创建一个计算图
        :return:
        """
        new_g = tf.Graph()
        # with关键字用于定义一个上下文管理器
        with new_g.as_default():
            a_t = tf.constant(1.0)
            b_t = tf.constant(2.0)
            c_t = a_t + b_t
            print(c_t)
            print(a_t.graph)
            print(b_t.graph)
    
        with tf.compat.v1.Session(graph=new_g) as sess:
            print(sess.run(c_t))
        return None
    
    
    if __name__ == '__main__':
        graph_demo()
    
    
    
2.2.3 TensorBoard:可视化学习
  1. 如何实现可视化?

    • 数据序列化-events文件

      • TensorBoard 通过读取 TensorFlow 的事件文件来运行,需要将数据生成一个序列化的 Summary protobuf 对象。

        tf.summary.FileWriter(path,graph=sess.graph)
        

        这样的话,在指定目录中生成一个event文件,其名称格式如下:

        events.out.tfevents.{timestamp}.{hostname}
        
    • 启动TensorBoard,在终端运行

      tensorboard --logdir=./tmp/summary
      

      在浏览器中打开 TensorBoard 的图页面 127.0.0.1:6006,会看到与以下图形类似的图,在GRAPHS模块我们可以看到以下图结构:

      在这里插入图片描述

2.2.4 OP
  1. 常见OP

    类型实例
    标量运算add, sub, mul, div, exp, log, greater, less, equal
    向量运算concat, slice, splot, constant, rank, shape, shuffle
    矩阵运算matmul, matrixinverse, matrixdateminant
    带状态的运算Variable, assgin, assginadd
    神经网络组件softmax, sigmoid, relu,convolution,max_pool
    存储、恢复Save, Restroe
    队列及同步运算Enqueue,Dequeue, MutexAcquire,MutexRelease
    控制流Merge, Switch, Enter, Leave, Nextlteration

    这块的话,我们区分两个概念操作函数和操作对象:

    • 操作函数:传进来的tensor对象,然后操作函数会根据与之对应的类去生成相应的对象。

    • 操作对象:是通过op的构造函数创建出来的。

      输出的结果:

      在这里插入图片描述

      tf.Tensor 对象以输出该张量的 tf.Operation 明确命名。张量名称的形式为<OP_NAME>:",其中:

      • ""是生成该张量的指令的名称
      • ""是一个整数,它表示该张量在指令的输出中的索引
  2. 指令名称

    tf.Graph对象为其包含的 tf.Operation对象定义的一个命名空间。TensorFlow 会自动为图中的每个指令选择一个唯一名称,用户也可以指定描述性名称,使程序阅读起来更轻松。我们可以通过以下方式改写指令名称

    • 每个创建新的 tf.Operation 或返回新的 tf.Tensor 的 API函数可以接受可选的name 参数。

      例如:

      a = tf.constant(1.0, name='a')
      b = tf.constant(2.0, name='b')
      

      在这里插入图片描述

2.3 会话

一个运行TensorFlow operation的类,会话包含以下两种开启方式:

  • tf.Session:用在一个完整的程序当中
  • tf.InteractiveSession:用于交互式上下文的TensorFlow,例如:命令窗口、shell等

注:

  1. TensorFlow 使用 tf.Session 类来表示客户端程序(通常为 Python 程序,但也提供了使用其他语言的类似接口)与 C++ 运行时之间的连接。2
  2. tf.Session 对象使用分布式 TensorFlow 运行时提供对本地计算机中的设备和远程设备的访问权限。
2.3.1 会话初始化_ int_(target = ‘’,graph = None,config = None)

​ 我们可以在会话创建的时候,给里面传入参数,然后会话会调用内部的init方法进行初始化操作。

​ 会话会拥有一定的资源,比如:tf.variable、tf.QueueBase、tf.ReaderBase。当这些资源不需要时,释放这些资源非常重要。因此,需要调用tf.Session.close会话中的方法,或将会话用作上下文管理器(with)。

  • target:如果将此参数留空(默认设置),会话将仅使用本地计算机中的设备可以指定 grpc:// 网址,以便指定 TensorFlow 服务器的地址,这使得会话可以访
    问该服务器控制的计算机上的所有设备。

  • graph:默认情况下,新的 tf.Session 将绑定到当前的默认图

  • config:此参数允许您指定一个 tf.ConfigProto 以便控制会话的行为。例如,ConfigProto协议用于打印设备使用信息

    def tensorflow_machine_learning():
        a_t = tf.constant(1.0)
        b_t = tf.constant(2.0)
        c_t = a_t + b_t
        print(a_t)
        print(b_t)
        print(c_t)
    
        config = tf.compat.v1.ConfigProto(allow_soft_placement=True, log_device_placement=True)
        with tf.compat.v1.Session(config=config) as sess:
            print(c_t.eval())
        return None
    

    在这里插入图片描述

2.3.2 会话的run()
  • run(fetches,feed_dict=None, options=None, run metadata=None)

    • 通过使用sess.run()来运行operation

    • fetches:单一的operation,或者列表、元组(其它不属于tensorflow的类型不行)

    • feed_dict:参数允许调用者覆盖图中张量的值,运行时赋值

      • ”与tf.placeholder搭配使用,则会检查值的形状是否与占位符兼容

注:使用tf.operation.eval()也可运行operation,但需要在会话中运行

2.3.3 feed操作
  • placeholder提供占位符,run的时候通过feed_dict指定参数

    def session_demo():
        a_t = tf.compat.v1.placeholder(tf.float32)
        b_t = tf.compat.v1.placeholder(tf.float32)
        sum_ab = tf.add(a_t, b_t)
        print(sum_ab)
    
        # 开启会话
        with tf.compat.v1.Session() as sess:
            print(sess.run(sum_ab, feed_dict={a_t: 1.0, b_t: 2.0}))
    

    在这里插入图片描述

2.4 张量

2.4.1 张量(Tensor)

TensorFlow的张量就是一个n维数组,类型为tf.Tensor。Tensor有以下两个重要的属性。

  • type : 数据类型
  • shape : 形状(阶)
  1. 张量的类型

    数据类型python类型描述
    DF_FLOATtf.float3232 位浮点数
    DF_DOUBLEtf.float6464 位浮点数
    DT_INT64tf.int6464 位有符号整型
    DT_INT32tf.int3232 位有符号整型
    DT_INT16tf.int1616 位有符号整型
    DT _INT8tf.int88 位有符号整型
    DT_UINT8tf.uint88 位无符号整型
    DT_STRINGtf.string可变长度的字节数组.每一个张量元素都是一个字节数组
    DT BOOLtf.bool布尔型
    DT_COMPLEX64tf.complex64由两个32位浮点数组成的复数:实数和虚数
    DT_QINT32tf.gint32用于量化Ops的32位有符号整型
    DT_QINT8tf.qint8用于量化Ops的8位有符号整型
    DT_QUINT8tf.quint8用于量化Ops的8位无符号整型
  2. 张量的阶

    数学实例python例子
    0纯量只有大小a_t = 1
    1向量既有大小,又有方向v = [1,5,2]
    2矩阵数据表n = [[1,2,3],[4,5,6]]
    33阶张量数据立体t = [[[1,2,3],[4,5,6]]]
    nn阶

示例:

def tensor_demo():
    """
    张量的创建
    :return:
    """
    tensor1 = tf.constant(1.0)
    tensor2 = tf.constant([1.0, 2.0, 3.0])
    tensor3 = tf.constant([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
    print(tensor1)
    print(tensor2)
    print(tensor3)

在这里插入图片描述

2.4.2 创建张量的指令
  1. 固定值张量

    # 创建所有元素设置为零的张量。此操作返回一个dtype具有形状shape和所有元素设置为零的类型的张量。
    tf.zeros(shape, dtype=tf.float32,name=None)
    
    # 给tensor定单张量(),此操作返回tensor与所有元素设置为零相同的类型和形状的张量
    tf.zeros like(tensor, dtype=None, name=None)
    
    # 创建一个所有元素设置为1的张量。此操作返回一个类型的张量,dtype形状shape和所有元素设置为1。
    tf.ones(shape, dtype=tf.float32, name=None)
    
    # 给tensor定单张量(),此操作返回tensor与所有元素设置为1相同的类型和形状的张量。
    tf.ones like(tensor, dtype=None,name=None)
    
    # 创建一个填充了标量值的张量。此操作创建一个张量的形状dims并填充它value。
    tf.fill(dims,value,name=None)
    
    # 创建一个常数张量。
    tf,constant(value, dtype=None, ape=None, name='Const’)
    
  2. 随机值张量

    # 从正态分布中输出随机值,由随机正态分布的数字组成的矩阵
    tf.random normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
    
  3. 其他特殊的创建张量的op

    • tf.Variable
    • tf.placeholder
2.4.3 张量的变换
  1. 类型改变

    改变张量中数值类型的函数:

    tf.string to_number(string_tensor, out_type=None, name=None)
    
    tf.to_double(x, name='ToDouble')
    
    tf.to_float(x, name='ToFloat')
    
    tf.to_bfloat16(x, name='ToBFloat16')
    
    tf.to_int32(x, name='ToInt32')
    
    tf.to_int64(x, name='Tolnt64’)
    
    # 转换为任何类型的可以使用这个函数
    tf.cast(x, dtype, name=None)
    

    示例:

    def tensor_demo():
        a_t = tf.constant(1.0)
        print("Before conversion:", a_t)
    
        # 使用 tf.cast 进行转换,直接生效于 Eager 模式
        a_t = tf.cast(a_t, dtype=tf.float64)
        print("After conversion:", a_t, "Data type:", a_t.dtype)
        return None
    

    在这里插入图片描述

  2. 形状改变

    TensorFlow的张量具有两种形状变换,动态形状和静态形状:

    • tf.reshape

      • 使用的时候需要保证张量元素个数是匹配的,例如:
      def tensor_demo():
          # 直接创建一个未初始化的变量,可以在运行时分配值
          a_t = tf.Variable(initial_value=tf.zeros([2, 3], dtype=tf.float32), shape=[None, None], trainable=False)
          print("Initial variable:", a_t)
      
          # 假设我们有具体的数据可以赋值给a_t,这里仅做示例使用随机数据
          sample_data = tf.random.normal(shape=[2, 3])
          a_t.assign(sample_data)
      
          # 重塑操作依然可用,但需确保重塑后的尺寸与原尺寸兼容
          a_t_reshape = tf.reshape(a_t, shape=[3, 2])  # 示例中调整了重塑的形状以匹配可能的使用场景
          print("After reshape:", a_t_reshape)
          return None
      
    • tf.set_shape

      • 形状没有固定下来的时候可以使用,例如:

        # None在那块相当于占位符,然后里面维度要等用的时候再确定 
        a_t = tf.compat.v1.placeholder(dtype=tf.float32,shape=[None,None])
        # 修改形状
        a_t.set_shape([2,3])
        
2.4.4 张量的数学运算
  • 算式运算符
  • 基本数学函数
  • 矩阵运算
  • reduce操作
  • 序列索引操作

详细的可以查看:Module: tf.math | TensorFlow v2.16.1 (google.cn)

2.5 变量OP

TensorFlow变量是表示程序处理的共享持久状态的最佳方法。变量通过 tf.Variable OP类进行操作。变量的特点:

  • 存储持久化

  • 可修改值

  • 可指定被训练

2.5.1 创建变量
tf.Variable(initial_value=None,trainable=True,collections=None,name=None)
# initial_value:初始化的值
# trainable:是否被训练
# collections:新变量将添加到列出的图的集合中collections,默认为[GraphKeyS.GLOBAL_VARIABLES],如果trainable是True变量也被添加到图形集合 GraphKeyS.TRAINABLE_VARIABLES

示例:

def variable_demo():
    """
    创建一个变量
    :return:
    """
    a_t = tf.Variable(initial_value=tf.ones([2, 3], dtype=tf.float32), shape=[None, None], trainable=False)
    print("Initial variable:", a_t)

在这里插入图片描述

如果是低版本的话,需要加入显式初始化以及会话:

import tensorflow as tf
tf.compat.v1.disable_eager_execution()

def variable_demo():
    """
    创建一个变量
    :return:
    """
    a_t = tf.Variable(initial_value=tf.ones([2, 3], dtype=tf.float32), shape=[None, None], trainable=False)
    # 进行显式初始化
    init = tf.compat.v1.global_variables_initializer()
    with tf.compat.v1.Session() as sess:
        sess.run(init)
        print(sess.run(a_t))

在这里插入图片描述

2.5.2 使用tf.veriable_scope()修改变量的命名空间

示例:

def variable_demo():
    """
    创建一个变量
    :return:
    """
    with tf.name_scope("qiaochuan"):
        # 在此范围内定义的变量和操作将会自动加上"qiaochuan/"前缀
        a_t = tf.Variable(initial_value=tf.ones([2, 3], dtype=tf.float32), shape=[None, None], trainable=False)
    print(a_t)

在这里插入图片描述

2.6 高级API

2.6.1 其他基础API
  1. tf.app
    这个模块相当于为 TensorFlow 进行的脚本提供一个 main 函数入口,可以定义脚本运行的 flags。
  2. tf.image
    TensorFlow 的图像处理操作。主要是一些颜色变换、变形和图像的编码和解码
  3. tf.gfile
    这个模块提供了一组文件操作函数
  4. tf.summary
    用来生成 TensorBoard 可用的统计日志,目前 Summary 主要提供了 4 种类型audio、image、histogram、scalar
  5. tf.python _io
    用来读写 TFRecords文件
  6. tf.train
    这个模块提供了一些训练器,与 tf.nn 组合起来,实现一些网络的优化计算。
  7. tf.nn
    这个模块提供了一些构建神经网络的底层函数。TensorFlow 构建网络的核心模块。其中包含了添加各种层的函数,比如添加卷积层池化层等。
2.6.2 高级API
  1. tf.keras
    Keras 本来是一个独立的深度学习库,tensorflow将其学习过来,增加这部分模块在于快速构建模型。
  2. tf.layers
    高级 API,以更高级的概念层来定义一个模型。类似tf.keras。
  3. tf.contrib
    tf.contrib.layers提供够将计算图中的 网络层、正则化、摘要操作、是构建计算图的高级操作,但是tf.contrib包含不稳定和实验代码,有可能以后API会改变。
  4. tf.estimator
    一个 Estimator 相当于 Model+Training+Evaluate 的合体。在模块中,已经实现了几种简单的分类器和回归器,包括:Baseline,Learning和DNN。这里的 DNN 的网络,只是全连接网络,没有提供卷积之类的。
2.6.3 TensorFlow的API图示

在这里插入图片描述

2.7 案例:实现线性回归

回顾:

  1. 构造模型 y = w1x1 + w2x2 + … + wnxn + b

  2. 构造损失函数 最小二乘法

  3. 优化损失 使用梯度下降

import tensorflow as tf


def liner_regression(num_epochs=1000):
    """
    实现线性回归
    :return:
    """
    # 1. 准备数据
    x = tf.random.normal(shape=[100, 1])
    y_true = tf.matmul(x, [[0.8]]) + 0.7  # 模拟线性关系的数据
    # print("Features (x):\n", x.numpy())
    # print("True Labels (y):\n", y_true.numpy())

    # 2. 构建模型
    weights = tf.Variable(initial_value=tf.random.normal(shape=[1, 1]), name='weights')
    biases = tf.Variable(initial_value=tf.random.normal(shape=[1, 1]), name='biases')
    y_predict = tf.matmul(x, weights) + biases

    # 3. 构造损失函数
    error = tf.reduce_mean(tf.square(y_predict - y_true))

    # 4. 使用梯度下降进行优化损失
    optimizer = tf.optimizers.SGD(learning_rate=0.01)

    # 训练循环
    for epoch in range(num_epochs):
        with tf.GradientTape() as tape:
            y_predict = tf.matmul(x, weights) + biases
            # 重新计算预测值,因为在训练过程中weights和biases会更新
            error = tf.reduce_mean(tf.square(y_predict - y_true))

        # 计算梯度
        gradients = tape.gradient(error, [weights, biases])
        # 更新权重和偏置
        optimizer.apply_gradients(zip(gradients, [weights, biases]))

        if (epoch + 1) % 100 == 0:
            print(f"Epoch {epoch + 1}, Loss: {error.numpy()}")

    # 打印最终的权重和偏置值
    print(f"\nFinal Weights: {weights.numpy()}, Biases: {biases.numpy()}")


if __name__ == '__main__':
    liner_regression()

在这里插入图片描述

增加其他功能

  • 变量Tensorboard显示
  • 模型保存与加载
  • 命令行参数设置

1.增加变量显示

目的:在TensorBoard当中观察模型的参数、损失值等变量值的变化

  • 1、收集变量
    • tf.summary.scalar(name=”,tensor)收集对于损失函数和准确率等单值变量,name为变量的名字,tensor为值
    • otf.summary.histogram(name=',tensor) 收集高维度的变量参数
    • otf.summary.image(name=”,tensor)收集输入的图片张量能显示图片
  • 2、合并变量写入事件文件
    • merged=tf.summary.merge_all()
    • 运行合并:summary=sess.run(merged),每次迭代都需运行
    • 添加:FileWriter.add_summary(summary,i),i表示第几次的值
import tensorflow as tf


def liner_regression(num_epochs=1000):
    """
    实现线性回归
    :return:
    """
    # 1. 准备数据
    x = tf.random.normal(shape=[100, 1])
    y_true = tf.matmul(x, [[0.8]]) + 0.7  # 模拟线性关系的数据
    # print("Features (x):\n", x.numpy())
    # print("True Labels (y):\n", y_true.numpy())

    # 2. 构建模型
    weights = tf.Variable(initial_value=tf.random.normal(shape=[1, 1]), name='weights')
    biases = tf.Variable(initial_value=tf.random.normal(shape=[1, 1]), name='biases')
    y_predict = tf.matmul(x, weights) + biases

    # 3. 构造损失函数
    error = tf.reduce_mean(tf.square(y_predict - y_true))

    # 4. 使用梯度下降进行优化损失
    optimizer = tf.optimizers.SGD(learning_rate=0.01)

    # 5_1. 创建事件文件
    writer = tf.summary.create_file_writer('./tmp/liner_regression')

    # 6. 训练循环
    for epoch in range(num_epochs):
        with tf.GradientTape() as tape:
            y_predict = tf.matmul(x, weights) + biases
            # 重新计算预测值,因为在训练过程中weights和biases会更新
            error = tf.reduce_mean(tf.square(y_predict - y_true))

        # 计算梯度
        gradients = tape.gradient(error, [weights, biases])
        # 更新权重和偏置
        optimizer.apply_gradients(zip(gradients, [weights, biases]))

        with writer.as_default():
            # 5_2. 收集事件
            tf.summary.scalar('error', error, step=epoch)
            tf.summary.histogram('weights', weights,step=epoch)
            tf.summary.histogram('biases', biases,step=epoch)

        if (epoch + 1) % 100 == 0:
            print(f"Epoch {epoch + 1}, Loss: {error.numpy()}")

    # 7. 打印最终的权重和偏置值
    print(f"\nFinal Weights: {weights.numpy()}, Biases: {biases.numpy()}")


if __name__ == '__main__':
    liner_regression()

在终端输入以下命令:

tensorboard --logdir=./tmp/liner_regression

打开网址: http://localhost:6006/ 就可以看到生成的图形。

在这里插入图片描述

2.模型的保存与加载

保存:

# 创建Checkpoint对象
checkpoint = tf.train.Checkpoint(weights=self.weights, biases=self.biases)
# 参数解释:
# - weights=self.weights: 指定要保存的权重变量。这里`self.weights`是之前定义的tf.Variable实例。
# - biases=self.biases: 指定要保存的偏置变量。同样,`self.biases`是之前定义的tf.Variable实例。
# 功能说明:
# `tf.train.Checkpoint`是一个用于保存和恢复TensorFlow模型和变量的类。通过传递变量作为参数,
# 可以指示系统在保存时包含这些变量的状态。这样,在后续恢复模型时,可以从保存的状态中恢复这些变量的值。

# 设置CheckpointManager,它会帮助管理检查点文件,保持最多5个最近的检查点
checkpoint_manager = tf.train.CheckpointManager(checkpoint, self.checkpoint_dir, max_to_keep=5)
# 参数解释:
# - checkpoint: 是之前创建的`tf.train.Checkpoint`对象,包含了要保存的所有变量。
# - self.checkpoint_dir='./tmp/model/my_linear.ckpt': 指定了检查点文件保存的目录路径。
#   系统会在该目录下生成检查点文件,如'./tmp/model/my_linear.ckpt/ckpt-1'。
# - max_to_keep=5: 指定了要保留的最近检查点的最大数量。当新的检查点被保存并且超过这个数量时,
#   最旧的检查点文件会被自动删除,以此来管理磁盘空间。设置为5意味着系统会始终保持最新的5个检查点文件。
# 功能说明:
# `tf.train.CheckpointManager`是一个高级API,用于简化检查点的保存和管理过程。它会根据`max_to_keep`参数自动
# 删除旧的检查点,确保不会因为频繁的训练和保存操作而导致存储空间耗尽。

加载:

# 使用tf.train.latest_checkpoint函数查找指定目录下最新的检查点文件路径
checkpoint_path = tf.train.latest_checkpoint(self.checkpoint_dir)
# 参数说明:
# - self.checkpoint_dir:之前定义的目录路径,用于存放模型的检查点文件。
# 功能说明:
# 此函数会自动在给定的目录中搜索,并返回最新的检查点文件的完整路径。如果没有找到任何检查点,则返回None。

# 创建一个Checkpoint对象,用于保存和恢复模型变量
checkpoint = tf.train.Checkpoint(weights=self.weights, biases=self.biases)
# 参数说明:
# - weights=self.weights:指定要管理的变量,这里是模型的权重变量。
# - biases=self.biases:指定要管理的另一个变量,这里是模型的偏置变量。
# 功能说明:
# 通过将变量作为参数传递给tf.train.Checkpoint构造器,可以创建一个Checkpoint对象,该对象负责在保存和恢复时跟踪这些变量的状态。

# 使用找到的最新检查点路径来恢复模型变量的值
checkpoint.restore(checkpoint_path)
# 参数说明:
# - checkpoint_path:由latest_checkpoint函数获取的检查点文件路径。
# 功能说明:
# 此调用会根据提供的检查点路径,恢复Checkpoint对象中关联的所有变量的值,即加载之前训练好的模型权重和偏置到当前的变量中。
# 注意,此操作是立即执行的,且通常不需要等待或返回值来确认操作成功,除非发生异常。

结合这些,帮代码重写做了调整,更加规范。

import tensorflow as tf


class LinerRegression:
    """
    线性回归
    """

    def __init__(self, num_epochs=1000):
        """
        初始化
        :param num_epochs: 迭代次数
        """
        self.num_epochs = num_epochs
        self.checkpoint_dir = './tmp/model/my_linear.ckpt'
        # 直接在初始化时定义变量,确保在恢复模型前它们已被正确定义
        self.weights = tf.Variable(initial_value=tf.random.normal(shape=[1, 1]), name='weights')
        self.biases = tf.Variable(initial_value=tf.random.normal(shape=[1, 1]), name='biases')
        self.variables_to_save = [self.weights, self.biases]
        self.checkpoint_prefix = 'ckpt-'
        self.max_to_keep = 5
        self.learning_rate = 0.01
        self.writer_dir = './tmp/liner_regression'

    def train(self):
        """
        实现线性回归(生成模型)
        :return:
        """
        # 1. 准备数据
        x = tf.random.normal(shape=[100, 1])
        y_true = tf.matmul(x, [[0.8]]) + 0.7  # 模拟线性关系的数据
        # print("Features (x):\n", x.numpy())
        # print("True Labels (y):\n", y_true.numpy())

        # 2. 构建模型
        self.variables_to_save = [self.weights, self.biases]
        y_predict = tf.matmul(x, self.weights) + self.biases

        # 3. 构造损失函数
        error = tf.reduce_mean(tf.square(y_predict - y_true))

        # 4. 使用梯度下降进行优化损失
        optimizer = tf.optimizers.SGD(learning_rate=self.learning_rate)

        # 5_1. 创建事件文件
        writer = tf.summary.create_file_writer(self.writer_dir)

        # 创建Checkpoint对象
        checkpoint = tf.train.Checkpoint(weights=self.weights, biases=self.biases)
        # 设置CheckpointManager,它会帮助管理检查点文件,保持最多5个最近的检查点
        checkpoint_manager = tf.train.CheckpointManager(checkpoint, self.checkpoint_dir, max_to_keep=self.max_to_keep)

        # 6. 训练循环
        for epoch in range(self.num_epochs):
            with tf.GradientTape() as tape:
                y_predict = tf.matmul(x, self.weights) + self.biases
                # 重新计算预测值,因为在训练过程中weights和biases会更新
                error = tf.reduce_mean(tf.square(y_predict - y_true))

            # 计算梯度
            gradients = tape.gradient(error, [self.weights, self.biases])
            # 更新权重和偏置
            optimizer.apply_gradients(zip(gradients, [self.weights, self.biases]))

            with writer.as_default():
                # 5_2. 收集事件
                tf.summary.scalar('error', error, step=epoch)
                tf.summary.histogram('weights', self.weights, step=epoch)
                tf.summary.histogram('biases', self.biases, step=epoch)

            if (epoch + 1) % 10 == 0:  # 例如,每10个epoch保存一次
                save_path = checkpoint_manager.save()

            if (epoch + 1) % 100 == 0:
                print(f"Epoch {epoch + 1}, Loss: {error.numpy()}")

        # 7. 打印最终的权重和偏置值
        print(f"\nFinal Weights: {self.weights.numpy()}, Biases: {self.biases.numpy()}")

    def restore_model(self):
        """
        恢复模型
        :return:
        """
        checkpoint_path = tf.train.latest_checkpoint(self.checkpoint_dir)
        if checkpoint_path is None:
            print("No checkpoint found in directory:", self.checkpoint_dir)
            return False

        print(f"Restoring from checkpoint: {checkpoint_path}")

        # 确保使用正确的变量名映射到Checkpoint对象
        checkpoint = tf.train.Checkpoint(weights=self.weights, biases=self.biases)

        try:
            checkpoint.restore(checkpoint_path)
            print("Model restored successfully.")
        except Exception as e:
            print(f"Error occurred during model restoration: {e}")
            return False

        # 打印恢复后的权重和偏置
        print(f"Weights after restore: {self.weights.numpy()}")
        print(f"Biases after restore: {self.biases.numpy()}")
        return True


if __name__ == '__main__':
    lr = LinerRegression()
    lr.train()
    lr.restore_model()

4.命令行参数使用

  • 导入库

    pip install absl-py
    
  • 定义参数

    from absl import app, flags
    
    # 定义字符串参数
    flags.DEFINE_string('data_dir', '/path/to/data', '数据目录的路径')
    
    # 定义整型参数
    flags.DEFINE_integer('batch_size', 32, '训练批次大小')
    
    # 定义布尔型参数
    flags.DEFINE_boolean('debug_mode', False, '是否开启调试模式')
    
    # 定义浮点型参数
    flags.DEFINE_float('learning_rate', 0.001, '学习率')
    
    FLAGS = flags.FLAGS
    
    
  • 主函数与程序入口

    def main(_):
        # 在这里使用FLAGS变量访问定义的参数
        print(f"数据目录: {FLAGS.data_dir}")
        print(f"批次大小: {FLAGS.batch_size}")
        print(f"是否调试模式: {FLAGS.debug_mode}")
        print(f"学习率: {FLAGS.learning_rate}")
        
        # 放置您的主要逻辑代码
        # ...
    
    if __name__ == '__main__':
        app.run(main)
    

示例:

import tensorflow as tf
from absl import app, flags

# 1. 定义命令行参数
flags.DEFINE_integer('max_step', 100, '训练的步数')
flags.DEFINE_string('model_dir', "UnKnown", '模型保存的路径+模型名字')

# 2. 简化变量名
FLAGS = flags.FLAGS


# 当你看到def main(_):这样的函数定义,特别是在处理一些框架或库(如absl.app)的入口点时,这里的_参数是因为某些机制(比如app.run(main))要求函数接受一个参数,但实际上这个参数在main函数内部并不需要使用。所以,我们用_来接收它,作为一种“我了解这里有东西传来,但我不会处理它”的标记。
def command_demo(_):
    """
    命令行演示
    :return:
    """
    print(f"训练步数设置为: {FLAGS.max_step}")
    print(f"模型将保存在: {FLAGS.model_dir}")
    return None

if __name__ == '__main__':
    app.run(command_demo)

在这里插入图片描述

  • 64
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CPanMirai

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值