当前位置: 首页 > news >正文

tensorflow基础

  • TensorFlow是一个面向深度学习的计算库,内部数据保存在张量对象上,所有的运算操作也都是基于张量进行的。
  • 复杂的神经网络本质上就是各种张量相乘、相加等基本操作的组合。

数据类型

数值型、字符串型、布尔型

1.数值型

标量(shape=())、向量(shape=(n))、矩阵(shape=(n,m))、张量

注意,下面这两不一样:

print(tf.constant([2])) # 向量
print(tf.constant(2)) # 标量
  1. 创建张量
    tf.constant([[1, 2], [3, 4]])
  2. 打印张量时,不仅会有数据信息,还有dtype,shape的信息
  3. 转换成numpy,使用numpy()方法
  4. tf.is_tensor(a)
    判断是否是张量。
# 标量
a = tf.constant(1.2)
print(a)
print(type(a))
print(tf.is_tensor(a))  # 判断是否是tensor

x = tf.constant([1.2, 3.3])
print(x)

# 转换成numpy,使用numpy()方法
num_x = x.numpy()
print(num_x, type(num_x))
<class 'tensorflow.python.framework.ops.EagerTensor'>
True
tf.Tensor([1.2 3.3], shape=(2,), dtype=float32)
[1.2 3.3] <class 'numpy.ndarray'>

注意:如果要使用tensorflow提供的功能函数。就必须通过tf规定的方式去创建张量,不能用Python语言的标准变量创建方式。

2.字符串类型

在 tf.strings 模块中,提供了常见的字符串类型的工具函数,如小写化 lower()、拼接join()、长度 length()、切分 split()等。

s = tf.constant('Hello, Deep Learning!')
print(s)
# tf.strings模块提供了很多处理字符串的函数
print(tf.strings.lower(s))
tf.Tensor(b'Hello, Deep Learning!', shape=(), dtype=string)
tf.Tensor(b'hello, deep learning!', shape=(), dtype=string)

3.bool类型

注意:tf的bool类型和python的bool类型并不等价!!!数值比较可以,但是对象比较不行。

b = tf.constant(True)
print(b)
print(b == True)  # 数值比较,还是能判断的,结果是True
print(b is True)  # 结果是False
tf.Tensor(True, shape=(), dtype=bool)
tf.Tensor(True, shape=(), dtype=bool)
False

4.数值精度

常用的精度类型有 tf.int16、tf.int32、tf.int64、tf.float16、tf.float32、tf.float64 等。

对于大部分深度学习算法,一般使用 tf.int32 和 tf.float32 可满足大部分场合的运算精度要求,部分对精度要求较高的算法,如强化学习某些算法,可以选择使用 tf.int64 和tf.float64 精度保存张量。

可以使用dtype属性读取精度。

5.类型转换

对于不符合要求的张量的类型及精度,需要类型转换,使用 :
tf.cast 函数

# 转化为高精度张量
xx = tf.constant(np.pi, dtype=tf.float16)
print(xx)
yy = tf.cast(xx, tf.float64)
print(yy)
tf.Tensor(3.14, shape=(), dtype=float16)
tf.Tensor(3.140625, shape=(), dtype=float64)

注意:需要保证转换操作的合法性,例如将高精度的张量转换为低精度的张量时,可能发生数据溢出隐患:

aa = tf.constant([123456789], dtype=tf.int32)
bb = tf.cast(aa, tf.int8)
print(bb)
tf.Tensor([21], shape=(1,), dtype=int8)

待优化张量

为了区分需要优化和不需要优化的变量。
需要优化的变量要是 tf.Variable 数据类型,支持记录梯度信息。
在普通张量上加了name, trainable 等属性来支持计算图构建

  • name和trainable是Variable的特有属性,name 属性用于命名计算图中的变量,这套命名体系是 TensorFlow 内部维护的,一般不需要用户关注 name 属性;;trainable属性表征当前张量是否需要被优化,创建 Variable 对象时是默认启用优化标志,可以设置trainable=False 来设置张量不需要优化。
  1. tf.Variable() 函数将普通张量转换为待优化张量
z = tf.constant([1, 2, 3.3])
vz = tf.Variable(z, trainable=False)  # 设置不需要被优化,默认是True
print(vz)
print(vz.name, vz.trainable)
<tf.Variable 'Variable:0' shape=(3,) dtype=float32, numpy=array([1. , 2. , 3.3], dtype=float32)>
Variable:0 False
  1. tf.Variable()也可以直接创建
vv = tf.Variable([1, 2])
  1. 普通张量其实也可以通过 GradientTape.watch()方法临时加入跟踪梯度信息的列表,从而支持自动求导功能

5.创建张量

tf.convert_to_tensor()
tf.constant()
都能够自动的把 Numpy 数组或者 Python 列表数据类型转化为 Tensor 类型.

tf.zeros()
tf.ones()

tf.zeros_like()
tf.ones_like()

tf.fill(shape, value): tf.fill([], -1) # 创建-1 的标量 / tf.fill([2,2], 99) # 创建 2 行 2 列,元素全为 99 的矩阵

创建已知分布的张量 :
tf.random.normal(shape, mean=0.0, stddev=1.0)

tf.random.uniform(shape, minval=0, maxval=None, dtype=tf.float32)可以创建采样自[minval, maxval)区间的均匀分布的张量。
如果需要均匀采样整形类型的数据,必须指定采样区间的最大值 maxval 参数,同时指 定数据类型为 tf.int*型:
tf.random.uniform([2,2],maxval=100,dtype=tf.int32)

创建序列:
tf.range(limit, delta=1)可以创建[0, limit)之间,步长为 delta 的整型序列,不包含 limit 本身。

6.张量典型应用

标量:误差值、准确度、精度、召回率
tf.keras.losses.mse(或 tf.keras.losses.MSE)返回每个样本上的误差值

向量:偏置b
通过高层接口类Dense()的方式创建网络层,张量W和b存储在类的内部,由类自动创建并管理。

# 创建一个全连接层对象
fc = layers.Dense(3)
# 通过build函数创建w,b张量,输入节点为4
fc.build(input_shape=(2, 4))
print(fc.bias)  # 查看偏置
<tf.Variable 'bias:0' shape=(3,) dtype=float32, numpy=array([0., 0., 0.], dtype=float32)>

可以发现 ,bias初始化为全0,这也是默认的初始化方式。
bias是Variable数据类型,因为它是待优化变量。

矩阵
权值矩阵W

x = tf.random.normal([2, 4])
w = tf.ones([4, 3])
b = tf.zeros([3])
o = x @ w + b
print(o)
# 上面其实就是一个不带激活函数的全连接层,下面用Dense接口直接创建
fc = layers.Dense(3)
fc.build(input_shape=(2, 4))
print(fc.kernel)  # 查看权值矩阵w
tf.Tensor(
[[3.6994305 3.6994305 3.6994305]
 [0.3701757 0.3701757 0.3701757]], shape=(2, 3), dtype=float32)
<tf.Variable 'kernel:0' shape=(4, 3) dtype=float32, numpy=
array([[-0.01163948,  0.28521907, -0.06265694],
       [-0.42561263,  0.9115014 ,  0.67937183],
       [-0.48957258, -0.55697334, -0.39781886],
       [ 0.39810383,  0.85386693, -0.6553062 ]], dtype=float32)>

三维张量
三维的张量一个典型应用是表示序列信号
在这里插入图片描述
四维张量
卷积神经网络用的多。
[b,h,w,c]: b表示batch、h表示图片高、w表示图片宽、c表示图片通道数,一般是1 or 3;1就是灰度图片,3就是RGB三通道图片。

创建卷积层的简单例子:

x = tf.random.normal([4, 32, 32, 3])  # 4张32x32的3通道图片
layer = layers.Conv2D(16, kernel_size=3)  # 第一个参数表示特征映射的数量
# 前向传播
out = layer(x)
print(out)
print(out.shape)

索引与切片

print("---------------------------------")
x = tf.random.normal([4, 32, 32, 3])
print(x[0])  # 32, 32, 3
print(x[0][5])  # 32, 3
print(x[0, 1:6:2, :, 0])  # 3, 32

在这里插入图片描述

  • 特别地,step 可以为负数,考虑最特殊的一种例子,当step = −1时,start: end: −1表示从 start 开始,逆序读取至 end 结束(不包含 end),索引号𝑒𝑛𝑑 ≤ 𝑠𝑡𝑎𝑟𝑡。
    在这里插入图片描述

维度变换

reshape、插入新维度 expand_dims,删除维度 squeeze、交换维度 transpose、复制数据 tile 等函数。

改变视图:
张量的存储体现在张量在内存上保存为一段连续的内存区域,对于同样的存储,我们可以有不同的理解方式
比如 shape 为[2,4,4,3]的张量𝑨,可以理解为 2 张图片,每张图片 4 行 4 列,每个位置有 RGB 3 个通道的数据;还理解为 2个样本,每个样本的特征为长度 48 的向量。
如果新的逻辑结构不需要改变数据的存储方式,就可以节省大量计算资源,这也是改变视图操作的优势。

所以tf.reshape只是从观察角度改变张量的形状,不改变内存。
在这里插入图片描述
在这里插入图片描述

x = tf.range(100)
y = tf.reshape(x, [2, 25, 2])

注意:由于只是从观察视角改变形状,x和y共享内存,y改变,x也会改变。 ??不太确定

增、删维度

通过 tf.expand_dims(x, axis)可在指定的 axis 轴前可以插入一个新的维度:

x = tf.random.normal([28, 28])
y = tf.expand_dims(x, axis=2)
print(y.shape)
(28, 28, 1)

是增加维度的逆操作,与增加维度一样,删除维度只能删除长度为 1 的维度,也不会改变张量的存储。

# 删除维度
z = tf.squeeze(y, axis=2)
print(z.shape)
(28, 28)

如果不指定维度参数 axis,即 tf.squeeze(x),那么它会默认删除所有长度为 1 的维度。
建议使用 tf.squeeze()时逐一指定需要删除的维度参数,防止 TensorFlow 意外删除某些长度为 1 的维度,导致计算结果不合法。

交换维度

tf.transpose(x, perm)函数完成维度交换操作。,其中参数 perm表示新维度的顺序 List。
比如在 TensorFlow 中,图片张量的默认存储格式是通道后行格式:[𝑏, ℎ,w , 𝑐],但是部分库的图片格式是通道先行格式:[𝑏, 𝑐, ℎ,w ],因此需要完成[𝑏, ℎ, , 𝑐]到[𝑏, 𝑐, ℎ, w]维度交换运算,考虑图片张量 shape 为[2,32,32,3],“图片数量、行、列、通道数”的维度索引分别为 0、1、2、3,如果需要交换为[𝑏, 𝑐, ℎ, w]格式,则新维度的排序为“图片数量、通道数、行、列”,对应的索引号为[0,3,1,2],因此参数 perm 需设置为[0,3,1,2]。

需要注意的是,通过 tf.transpose 完成维度交换后,张量的存储顺序已经改变,视图也随之改变,后续的所有操作必须基于新的存续顺序和视图进行。相对于改变视图操作,维度交换操作的计算代价更高。

x = tf.random.normal([2, 24, 24, 3])  # [b,h,w,c]
y = tf.transpose(x, [0, 3, 1, 2])  # [b,c,h,w]

复制数据

tf.tile(x, multiples)函数完成数据在指定维度上的复制操作,multiples 分别指定了每个维度上面的复制倍数。
例子:
线性回归 Y = X @ W + b Y=X@W+b Y=X@W+b中,b的维度和 X @ W X@W X@W不匹配,需要对b进行复制:1.先将向量b转换成矩阵2.再使用tile复制几行b(行数和样本数匹配):

b = tf.constant([1, 2, 3])
b = tf.expand_dims(b, axis=0)  # 扩展成矩阵,(1,3)
b = tf.tile(b, multiples=[3, 1])  # 复制三行b
print(b)
tf.Tensor(
[[1 2 3]
 [1 2 3]
 [1 2 3]], shape=(3, 3), dtype=int32)

但是,实际上,我们不需要做增加维度和复制的工作,tensor的广播机制会帮我们完成。
需要注意的是,tf.tile 会创建一个新的张量来保存复制后的张量,由于复制操作涉及大量数据的读写 IO 运算计算代价相对较高。

Broadcasting★

是一种轻量级的张量复制手段,逻辑上扩展张量数据的形状,但只有在需要的时候才会执行实际的复制手段。
broadcasting 和 tile 的区别:
tile: 会创建一个新的张量,执行复制IO操作,并保存复制后的张量数据。
broadcasting:避免实际复制数据,最终效果同tile,大大节省了计算资源,计算过程尽可能使用。

broadcasting会在运算时自动实现,也可以手动使用函数 tf.broadcast_to(x, new_shape)实现:

y = x@w + tf.broadcast_to(b,[2,3]) # 手动扩展,并相加

在这里插入图片描述
Broadcasting的核心思想是:普适性
有关Broadcasting的具体规则,见书。
在这里插入图片描述

数学运算

加、减、乘、除是最基本的数学运算,分别通过 tf.add, tf.subtract, tf.multiply, tf.divide函数实现,TensorFlow 已经重载了**+、 − 、 ∗ 、/运算符,一般推荐直接使用运算符来完成加、减、乘、除运算。
整除和余除也是常见的运算之一,分别通过
//和%运算符实现。
通过 tf.pow(x, a)可以方便地完成𝑦 =x^𝑎的乘方运算,也可以通过运算符
实现 x∗∗ 𝑎运 算

数e^𝑥,可以通过 **tf.exp(x)**实现

数log_e x可以通过 tf.math.log(x)

矩阵相乘运算:

  1. 使用@运算符
  2. 通过 tf.matmul(a, b)函数。
    注:
    TensorFlow 中的矩阵相乘可以使用批量方式,也就是张量𝑨和𝑩的维度数可以大于 2。当张量𝑨和𝑩维度数大于 2 时,TensorFlow 会选择𝑨和𝑩的最后两个维度进行矩阵相乘前面所有的维度都视作Batch 维度。

矩阵相乘同样适用于广播机制:
在这里插入图片描述
会自动将b扩展成[4,32,16]

前向传播实战

print("前向传播---------------")
## 前向传播实战
(x, y), (x_test, y_test) = mnist.load_data()
# 转换从成tensor
x = tf.convert_to_tensor(x, dtype=tf.float32)
y = tf.convert_to_tensor(y, dtype=tf.int32)
with tf.GradientTape() as tape:
    # 初始化参数
    w1 = tf.Variable(tf.random.truncated_normal([784, 256], stddev=0.1))
    b1 = tf.Variable(tf.zeros([256]))
    w2 = tf.Variable(tf.random.normal([256, 128], stddev=0.1))
    b2 = tf.Variable(tf.zeros([128]))
    w3 = tf.Variable(tf.random.normal([128, 10], stddev=0.1))
    b3 = tf.Variable(tf.zeros(10))
    # 将x展平,适应于全连接网络
    x = tf.reshape(x, [-1, 28 * 28])

    # 前向传播,计算损失函数
    h1 = x @ w1 + b1
    h1 = tf.nn.relu(h1)
    h2 = h1 @ w2 + b2
    h2 = tf.nn.relu(h2)
    out = h2 @ w3 + b3

    # 将y独热编码
    y = tf.one_hot(y, depth=10)
    # 损失
    loss = tf.square(y, out)
    loss = tf.reduce_mean(loss)
# 获取梯度
grads = tape.gradient(loss, [w1, b1, w2, b2, w3, b3])
lr = 0.01
w1.assign_sub(lr*grads[0])
b3.assign_sub(lr*grads[-1])

相关文章:

  • android自定义Apk名称和指定生成的路径
  • java框架----SSM快速整合教程
  • mongodb基本操作及使用
  • jQuery中的函数
  • leetcode:188. 买卖股票的最佳时机IV
  • 电脑技巧:Win7、Win10、Win11如何选择,看完你就懂了
  • 【初阶数据结构】堆排序和TopK问题
  • 筑梦远航 势不可挡|和数研究院四周岁啦
  • 广东2022年上半年系统集成项目管理工程师下午真题及答案解析
  • 【论文解读系列】NER方向:LatticeLSTM (ACL2018)
  • java毕业设计成品源码网站基于JSP的网上订餐管理系统|餐饮就餐订餐餐厅
  • Jenkins更新版本和插件导致maven工程job丢失(不显示)或部分功能丧失(svn,ssh)
  • 计算机网络——传输层の选择题整理
  • 多级缓存的原理和实现
  • hadoop学习使用
  • Android交互
  • Android优雅地处理按钮重复点击
  • crontab执行失败的多种原因
  • C语言笔记(第一章:C语言编程)
  • el-input获取焦点 input输入框为空时高亮 el-input值非法时
  • git 常用命令
  • jdbc就是这么简单
  • nginx(二):进阶配置介绍--rewrite用法,压缩,https虚拟主机等
  • Otto开发初探——微服务依赖管理新利器
  • react 代码优化(一) ——事件处理
  • Spring框架之我见(三)——IOC、AOP
  • Swoft 源码剖析 - 代码自动更新机制
  • use Google search engine
  • 编写高质量JavaScript代码之并发
  • 对话 CTO〡听神策数据 CTO 曹犟描绘数据分析行业的无限可能
  • 记一次用 NodeJs 实现模拟登录的思路
  • 前端技术周刊 2018-12-10:前端自动化测试
  • 如何实现 font-size 的响应式
  • 如何在GitHub上创建个人博客
  • 通过几道题目学习二叉搜索树
  • 新手搭建网站的主要流程
  • 一个6年java程序员的工作感悟,写给还在迷茫的你
  • Java总结 - String - 这篇请使劲喷我
  • mysql面试题分组并合并列
  • # Pytorch 中可以直接调用的Loss Functions总结:
  • # Swust 12th acm 邀请赛# [ K ] 三角形判定 [题解]
  • #NOIP 2014# day.1 生活大爆炸版 石头剪刀布
  • #我与Java虚拟机的故事#连载12:一本书带我深入Java领域
  • (2020)Java后端开发----(面试题和笔试题)
  • (C++)栈的链式存储结构(出栈、入栈、判空、遍历、销毁)(数据结构与算法)
  • (cljs/run-at (JSVM. :browser) 搭建刚好可用的开发环境!)
  • (十一)JAVA springboot ssm b2b2c多用户商城系统源码:服务网关Zuul高级篇
  • (转)shell中括号的特殊用法 linux if多条件判断
  • .equal()和==的区别 怎样判断字符串为空问题: Illegal invoke-super to void nio.file.AccessDeniedException
  • .gitattributes 文件
  • .NET Remoting Basic(10)-创建不同宿主的客户端与服务器端
  • .net 写了一个支持重试、熔断和超时策略的 HttpClient 实例池
  • .NET 中使用 TaskCompletionSource 作为线程同步互斥或异步操作的事件
  • .net/c# memcached 获取所有缓存键(keys)
  • .NET开发不可不知、不可不用的辅助类(一)