【TF2.0】【笔记】Tensorflow2.0数据类型基础

tensorflow 基础

数据类型

数值

在 TensorFlow 中间,为了表达方便,一般把标量、向量、矩阵也统称为张量,不作区分,需要根据张量的维度数(Dimension)和形状自行判断.

与标量不同,向量的定义须通过 List 类型传给 tf.constant()。创建一个元素的向量

标量
t2 = tf.constant(1, dtype=tf.int32)
向量
t3 = tf.constant([1,2,3,4], dtype=tf.float32)
矩阵
t4 = tf.constant([[1, 2],[3, 4]], dtype=tf.float64)
张量
t5 = tf.constant([[[1, 2], [3, 4]],[[5, 6], [7, 8]]])
t6 = tf.constant([[[[1, 2], [3, 4]],[[5, 6], [7, 8]]],[[[1, 2], [3, 4]],[[5, 6], [7, 8]]]])

字符串

ts1 = tf.constant('Hello World', dtype=tf.string)
ts2 = tf.strings.lower(ts1)

布尔

tb1 = tf.constant(True)
tb2 = tf.constant([True, False])
tb3 = tf.constant(True, dtype=tf.int32)

数值精度

常用的精度类型有tf.int16, tf.int32, tf.int64, tf.float16, tf.float32, tf.float64,其中 tf.float64 即为 tf.double。

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

pi1 = tf.constant(np.pi, dtype=tf.float32)
pi2 = tf.constant(np.pi, dtype=tf.float64)
if pi1.dtype != tf.float64 :
	pi3 = tf.cast(pi1, tf.tf.float64)

results:

tf.Tensor(3.1415927, shape=(), dtype=float32)
tf.Tensor(3.141592653589793, shape=(), dtype=float64)
tf.Tensor(3.1415927410125732, shape=(), dtype=float64)

可以看到转换后数值不一致的,也不是零

待优化张量

通过tf.Variable()函数可以将普通张量转换为待优化张量

张量的 name 和 trainable 属性是 Variable 特有的属性,name 属性用于命名计算图中的

变量,这套命名体系是 TensorFlow 内部维护的,一般不需要用户关注 name 属性;trainable

表征当前张量是否需要被优化,创建 Variable 对象是默认启用优化标志,可以设置

trainable=False 来设置张量不需要优化

var1 = tf.Variable([1, 2, 3, 4],dtype=tf.float32, name='Test_var1')
var2 = tf.Variable([1, 2, 3, 4],dtype=tf.float32, name='Test_var2', trainable=False)
print(var1)
print(var2.trainable)
print(var1.numpy())

创建张量

从Numpy List中创建Tensor

Numpy Array 和 python list 是非常重要的数据载体,很多时候都是将原始数据读取出后通过Array 和list,即为数据预处理部分, 然后转化为tensor类型

通过 tf.convert_to_tensor 可以创建新 Tensor,并将保存在 Python List 对象或者 Numpy

Array 对象中的数据导入到新 Tensor 中:

a = [1., 1.]
ctt1 = tf.convert_to_tensor(a)
b = np.array([1.,1.])
ctt2 = tf.convert_to_tensor(b)
print(a)
print(ctt1)
print(b.max())
print(ctt2)

Numpy 中浮点数数组默认使用 64-Bit 精度保存数据,转换到 Tensor 类型时精度为 tf.float64,可以在需要的时候转换为 tf.float32 类型

tf.constant()tf.convert_to_tensor()都能够自动的把 Numpy 数组或者 Python List 数据类型转化为 Tensor 类型,这两个 API 命名来自 TensorFlow 1.x 的命名习惯,在 TensorFlow 2 中函数的名字并不是很贴切,使用其一即

全0,1 Tensor

print(tf.zeros([]))
print(tf.ones([]))
print(tf.zeros([2,2,3]))
zl1 = tf.constant([[2.,3.],[4, 5.]])
print(tf.zeros_like(zl1,name='zero_like1'))
print(tf.ones_like(zl1,name='one_like1', dtype=tf.int32))

tf.*_like 是一个便捷函数,可以通过 tf.zeros(a.shape)等方式实现

创建自定义张量

通过 tf.fill(shape, value)可以创建全为自定义数值 value 的张量

print(tf.fill([2,4], 3))

创建已知分布的张量

正态分布 Normal Distribution

高斯分布 Gaussian Distribution

创建采样自这 2 种分布的张量非常有用,比如在卷积神经网络中,卷积核张量W 初始化为正态分布有利于网络的训练;在对抗生成网络中,隐藏变量 z 一般采样自均匀分布

通过 tf.random.normal(shape, mean=0.0, stddev=1.0)可以创建形状为 shape,均值为mean,标准差为 stddev 的正态分布𝒩(𝑚𝑒𝑎𝑛, 𝑠𝑡𝑑𝑑𝑒𝑣2)

通过 tf.random.uniform(shape, minval=0, maxval=None, dtype=tf.float32)可以创建采样自[𝑚𝑖𝑛𝑣𝑎𝑙, 𝑚𝑎𝑥𝑣𝑎𝑙]区间的均匀分布的张量

print(tf.random.normal([3, 3], mean=0, stddev=1.0))
print(tf.random.normal([3, 3], mean=1, stddev=1.0))
print(tf.random.uniform([3,3],0, 1, tf.float64, seed=1, name='uniform_test'))
print(tf.random.uniform([3,3],0, 1, tf.float64, seed=1, name='uniform_test'))

如果需要均匀采样整形类型的数据,必须指定采样区间的最大值 maxval 参数,同时制定据类型为 tf.int*型

创建序列

print(tf.range(10))
print(tf.range(10, delta=2))
print(tf.range(5, 10))

results:

tf.Tensor([0 1 2 3 4 5 6 7 8 9], shape=(10,), dtype=int32)
tf.Tensor([0 2 4 6 8], shape=(5,), dtype=int32)
tf.Tensor([5 6 7 8 9], shape=(5,), dtype=int32)

张量的典型应用

标量

简单的数字,一般用于各种测试值指标

准确度 Acc Accuracy

精度 Precision

训练曲线 批次 batch

训练曲线 步数 step

代价 损失 loss

向量 矩阵

向量表示偏置b, 矩阵表示W

layer1 = tf.keras.layers.Dense(3, kernel_initializer=tf.random_uniform_initializer, bias_initializer=tf.random_normal_initializer)
layer2 = tf.keras.layers.Dense(3, kernel_initializer=tf.random_uniform_initializer(0,1), bias_initializer=tf.random_normal_initializer(1,1))
layer1.build([3,3])
layer2.build([3,3])
print(layer1.kernel)
print(layer1.bias)
print(layer2.kernel)
print(layer2.bias)

3维张量

可用于NLP预料数据中

(x_train, y_train), (x_test, y_test) = tf.keras.datasets.imdb.load_data(num_words=10000)
print(x_train[0])
x_train = tf.keras.preprocessing.sequence.pad_sequences(x_train, maxlen=80)
print(x_train.shape)
print(x_train[0])
embedding = tf.keras.layers.Embedding(10000, 100)
out = embedding(x_train)
print(out.shape)

4维张量

最常用就是图像卷积

x = tf.random.normal([4, 32, 32, 3])
layer = tf.keras.layers.Conv2D(16, kernel_size=3, padding='same')
out = layer(x)
print(out.shape)

切片与索引

索引

x = tf.random.normal([4,32,32,3])
print(x[0])
print(x[0][1])
print(x[0][1][2])
print(x[0,1,2])

当张量的维度数较高时,使用[𝑖][𝑗]. . .[𝑘]的方式书写不方便,可以采用[𝑖,𝑗, … , 𝑘]的方 式索引,它们是等价的

切片

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nkPjkfkR-1583029951598)(user-image/1581307001784.png)]

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-utbYucUr-1583029951599)(user-image/1581307300530.png)]

x = tf.random.normal([4,32,32,3])
print(x[0])
print(x[0][1])
print(x[0][1][2])
print(x[0, 1, 2])
print(x[0, 1, 2, 1:2])
print(x[0][1][2][1:2])
print(x[0][0:2][::])
print(x[2:,...])
print(x[...,1])

维度变换

我们先来认识一下张量的存储和视图(View)的概念。张量 的视图就是我们理解张量的方式,比如 shape 为[2,4,4,3]的张量 A,我们从逻辑上可以理解 为 2 张图片,每张图片 4 行 4 列,每个位置有 RGB 3 个通道的数据;张量的存储体现在张量在内存上保存为一段连续的内存区域,对于同样的存储,我们可以有不同的理解方式,比如上述 A,我们可以在不改变张量的存储下,将张量 A 理解为 2 个样本,每个样本的特征为长度 48 的向量,这就是存储与视图的关系

语法上来说,视图的变换只需要满足下面公式:
b ∗ h ∗ w ∗ c b*h*w*c bhwc
正是由于视图的设计约束很少,完全由用户定义,使得在改变视图时容易出现逻辑隐患

x1 = tf.range(50)
x2 = tf.reshape(x1, [2,-1])
x3 = tf.reshape(x1, [2, 5, 5, 1])
x4 = tf.reshape(x3, [1, 5, 5, 2])
print(x1.shape)
print(x2.shape)
print(x3.shape)
print(x3)
print(x4)
x5 = tf.random.uniform([28, 28], 0, 10, dtype=tf.int32)
x6 = tf.expand_dims(x5, axis=0)
x6 = tf.expand_dims(x6, axis=3)
x7 = tf.expand_dims(x5, axis=2)
x8 = tf.squeeze(x7, axis=2)
x9 = tf.squeeze(x6)
print(f'x5:{x5.shape} x6{x6.shape} x7{x7.shape} x8{x8.shape} x9{x9.shape}')
x10 = tf.transpose(x6, perm=[0, 2, 1, 3])
print(x6[:,0,...])
print(x10[:,:,0,:])

维度复制

tf.tile会创建一个新的张量来保存复制后的张量,复制操作涉及到大量数据的读写 IO 运算,计算代价相对较高

x1 = tf.range(4)
x2 = tf.reshape(x1, [2,2])
x3 = tf.tile(x2, multiples=[1, 2])
print(f'x1{x1}, x2{x2}, x3{x3}')

Broadcasting

Broadcasting 机制的核心思想是普适性,即同一份数据能普遍适合于其他位置。在验证普适性之前,需要将张量 shape 靠右对齐,然后进行普适性判断:对于长度为 1 的维度, 默认这个数据普遍适合于当前维度的其他位置;对于不存在的维度,则在增加新维度后默 认当前数据也是普适性于新维度的,从而可以扩展为更多维度数、其他长度的张量形状。

如+,-,*,/等运算等自动调用了broadcasting机制

数学运算

加减乘除

乘方

指数、对数

使用tf.sqrt时,需要指定传入数据类型

a = tf.range(5, dtype=tf.float32)
a1 = tf.reshape(a, [5,1])
b = tf.constant(2.)
print(tf.add(a, b))
print(tf.subtract(a, b))
print(tf.multiply(a, b))
print(tf.divide(a, b))
print(tf.multiply(a1, a))
print(tf.multiply(a1, a1))
print(a // b)
print(a % b)
print(tf.pow(a, 2))
print(a**3)
print(tf.square(a))
print(tf.sqrt([a]))
print(tf.exp(1.))
print(tf.math.log(tf.exp(1.)))

矩阵相乘

相乘也支持Broadcasting机制

构建模型时,需要将数据类型保持一致,全float32够用了,部分情况float64

一个例子:

下面这个例子有问题,y使用onehot编码,但是out的数字和onehot编码不一致,分类问题别用MSE衡量

上述有误,不是没有效果,是使用的数据太大了,变化太小,不稳定,理论是对的,实际数据太大导致>

# coding : utf-8
from __future__ import absolute_import, division, print_function, unicode_literals
import tensorflow as tf

(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()

w1 = tf.Variable(tf.random.truncated_normal([784, 256], stddev=0.1))
b1 = tf.Variable(tf.zeros([256]))
w2 = tf.Variable(tf.random.truncated_normal([256, 128], stddev=0.1))
b2 = tf.Variable(tf.zeros([128]))
w3 = tf.Variable(tf.random.truncated_normal([128, 10], stddev=0.1))
b3 = tf.Variable(tf.zeros([10]))

x_train = tf.reshape(x_train, [-1, 28*28])
x_train = tf.cast(x_train, tf.float32)
y_onehot = tf.one_hot(y_train, depth=10, dtype=tf.float32)

for epoch in tf.range(10):
    with tf.GradientTape() as tape:
        h1 = x_train @ w1 + tf.broadcast_to(b1, [x_train.shape[0], 256])
        h1 = tf.nn.relu(h1)
        h2 = h1 @ w2 + b2
        h2 = tf.nn.relu(h2)
        out = h2 @ w3 + b3
        loss = tf.square(y_onehot - 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])
    b1.assign_sub(lr * grads[1])
    w2.assign_sub(lr * grads[2])
    b2.assign_sub(lr * grads[3])
    w3.assign_sub(lr * grads[4])
    b3.assign_sub(lr * grads[5])

print('end')

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值