优点
既是一个实线机器学习算法的接口,同时也是执行机器学习算法的框架
可以在众多异构系统平台上移植
- 基础架构
- 接口(负责构造计算图)
- c++
- python
- java
- tensorflow核心执行系统(负责执行计算图)
- CPU、GPU(负责执行计算图)
- 接口(负责构造计算图)
- 并行计算
- 不需要给大规模模型训练和小规模应用部署开发两套系统
核心概念
计算图
又被称为有向图,数据流图
- 用节点和边的有向图描述数学计算
- 节点一般用来表示施加的数学操作,但也可以表示数据输入的起点或输出的终点
- 线表示节点之间的输入输出关系,这些数据线可以输运size可动态调整的多维数据数组,即张量
- 一旦输入端的所有张量准备好,节点将被分配到各种计算设备完成异步并行的执行计算
- 描述了张量数据的计算流程,负责维护和更新状态,对分支进行条件控制和循环操作
- 有一类特殊的边中没有数据流动,这种边被称为依赖空值,作用是控制节点的执行顺序,它可以让起始节点执行完毕再去执行目标节点,用户可以使用这样的边进行灵活控制,比如限制内存使用的最高峰值,比如可以去掉几个边
- 可以使用c++、python、java实现计算图
- 构成
- inference()
- 尽可能 的构架好图表,满足促使神经网络向前反馈并做出预测的要求
- 推断,输入输出关系
- loss()
- 往inference图表中添加生成损失loss所需要的操作ops
- inference好不好
- training()
- 不断更新变量
- 往损失图表中添加计算并应用梯度所需的操作
- inference()
- 运算操作的知识点
- 一个运算操作代表了一种类型的抽象运算,比如矩阵乘法或者向量加法
- 一个运算操作可以有自己的属性,但是所有属性都必须被预先设置,或者额能够在创建计算图时根据上下文推断出来
- 通过设置运算操作的属性可以用来支持不同的张量元素类型,比如让向量加法支持浮点数或者整数
- 运算核是一个运算操作在某个具体的硬件(比如在cpu或者gpu中)的实现
- 在tensorflow中可以通过注册机制加入新的运算操作或者为己有的原酸操作添加新的运算核
- 操作
- 变量
- 创建Variable
- 训练模型时,用变量来储存和更新参数,变量包含张量存放于内存的缓冲区。建模时他们需要被明确的初始化,模型训练后他们必须被储存到磁盘,这些变量的值可在之后模型训练和分析时被加载
- 当创建一个变量时,将初始值传入构造函数Variable()。tensorflow提供了一系列操作符来初始化张量,初始值是常量或者是随机值
- 添加操作到graph
- 初始化
- 一次性全部初始化
- 模型运行之前必须全部完成
- 创建Variable
tf.initialize_all_variables()
sess=tf.Session()
sess.run()
- 自定义初始化
- 由另一个变量初始化另一个变量
Variable(weight.initialized_value())
- 保存和加载
- tf.train.Saver
- 给所有graph的变量添加save和ops。saver对象提供了方法来运行这些ops,定义检查点文件的读写路径
- 检查点文件
- 变量储存在二进制文件里,主要包含从变量名到tensor值的映射关系
- 当创建一个saver对象时,可以选择性的为检查点文件中的变量挑选文件名。默认情况下将每个变量Variable.name属性的值
- 恢复变量
- 单独保存
- 使用字典表
tf.compat.v1.Saver({'my_v2': v2})
- 使用字典表
- tf.train.Saver
- 会话Session
- 完成全部的构建准备、生成全部所需的操作之后,我们就可以创建一个tf.Session,用于运行图表
- 创建
- sess = tf.Session()
- with tf.Session() as sess:只存在with中
- Session中没有传入参数,表明该代码将会依附于默认的本地会话
- 生成会话之后,所有的variable实例都会立即通过调用各自初始化操作中的sess.sun()函数进行初始化
- sess.run()方法将会运行图表中与作为参数传入的操作相对应的完整子集。在初次调用时,init操作只包含了初始化程序tf.group。图标的其他部分不会在这里,而是在下面的训练循环进行
- 完成会话中变量的初始化之后,就可以开始训练了
- 由另一个变量初始化另一个变量
- 实现原理
- client
- master
- worker
- 每一个worker可以管理多个设备,每一个设备的name包含硬件类别、编号、任务号(单机版本没有),实例如下
- 单机版本/job:localhost/device:cpu:0
- 分布式版本/job:worker/task:17/device:cpu:0
- device
- tensorflow有一个很重要组件client,也就是客户端,他通过session的接口与master以及多个worker相连。每个worker与可以与多个设备相连比如CPU、Gpu,并负责管理这些硬件。Master则负责知道所有的worker按照流程执行计算图
- tensorfow由单机模式和分布式模式。单机模式下client、master、worker全部都在同一台计算机上的同一个进程中。分布式模式允许client、master、worker在不同的机器的不同进程中,同时由集群调度系统统一管理各项任务
- tensor引用次数为0,就删掉
- 如果只有一个硬件设备,计算图会按照依赖关系被顺序执行
- 多个设备
- 每个节点什么设备执行
- 代价模型,估算每个节点输入输出张量大小,估算时间
- 模拟执行计算图,在执行每个节点时,会把每一个能执行这个节点的设备都测试一遍,测试内容包括计算时间的估计以及数据传递所需要的通信时间。最后选择一个总和时间最短的设备计算相应 的节点。这是一个贪婪的策略
- 除了运算时间,内存的最高使用峰也会被考虑进来
- 如何管理设备之间通信
- 单机
- 当给节点分配设备的方案被确定,整个计算图都会被划分为许多子图,使用同一个设备并且相邻的节点会被划分到同一子图,然后计算从途中xy的边,会被取代为一个发送端的发送节点(send node),一个接收端的接收节点(receive node)以及从发送节点到接收节点的边
- 把数据通信问题变成了发送节点和接收节点 的实现问题
- 两个子图之间可能会有多个接收节点,如果这些接受节点接受的是同一个张量,那么所有这些接受节点会被自动合并为一个,避免了数据的反复传递和设备内存占用
- 单机多个gpu
- 分布式
- 不同机器之间的使用tcp或rdma传输数据
- 同时容错性也是分布式系统的一个特点。通信故障会在两种情况下被检测出来:一种是信息从发送节点传输到接收节点失败时,另一种是周期性的worker心跳检测失败时
- 当检测到通信故障时,整个计算图会被终止并重启。其中,Variable node可以通过检查点的保存和恢复机制持久化。每个变量节点都会连接一个save节点,每隔几轮迭代就会保存一次数据到持久化存储系统。同样每个变量节点也会子啊连接一个restore系欸但,在每次重启时调用以便恢复变量节点的数据。这样,发生故障以后只要重启,接着上一个检查点继续运行就可以,无需从头再来
- 单机
- 每个节点什么设备执行
#!usr/bin/env python
# -*- coding:utf-8 _*-
"""
@author: Caramel
@file: 1-basic.py
@time: 2020/05/22
@desc:
"""
import tensorflow as tf
import numpy as np
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
#生成假数据
x_data = np.float32(np.random.rand(2, 100))
y_data = np.dot([0.100, 0.200], x_data) + 0.300
#构造一个线性模型
b = tf.Variable(tf.zeros([1]))
w = tf.Variable(tf.random.uniform([1, 2], -1.0, 1.0))
y = tf.matmul(w, x_data) + b
#最小化方差
loss = tf.reduce_mean(tf.square(y - y_data))
optimizer = tf.compat.v1.train.GradientDescentOptimizer(0.5)
train = optimizer.minimize(loss)
#添加一个初始化操作初始化前面定义的所有变量
init_op = tf.compat.v1.global_variables_initializer()
#添加Saver操作对变量进行保存和恢复
saver = tf.compat.v1.train.Saver()
#启动会话
with tf.compat.v1.Session() as sess:
#运行初始化节点
sess.run(init_op)
#将变量的值保存在硬盘里
save_path = saver.save(sess, "model.ckpt")
print('Model saved in file:', save_path)
with tf.compat.v1.Session() as sess:
#从磁盘里卖弄读取检查点文件并恢复到对应的变量中
saver.restore(sess, 'model.ckpt')
print('model restored')
for step in range(0, 201):
sess.run(train)
if step%20 == 0:
print(step, sess.run(w), sess.run(b))