tf2.0学习(一)——基础知识

类型

通过tf.constant()可以创建3中数据类型,分别是数值、布尔、字符串

# 标量
tf.constant(2., dtype=tf.float16)

# 向量
tf.constant([2,3], dtype=tf.int16)

# 张量 维度>2
tf.constant([[[1,2], [3,4]], [[5,6], [7,8]]])

数值精度

TensorFlow支持一下几种数据类型,一般在数据定义的时候指定dtype来确定数据类型。

  1. tf.float16
  2. tf.float32
  3. tf.float64 也是tf.double
  4. tf.int16
  5. tf.int32
  6. tf.int64
tf.constant([1,2,3], dtype=tf.float32)
<tf.Tensor: shape=(3,), dtype=float32, numpy=array([1., 2., 3.], dtype=float32)>

类型转换

进行类型转换时,需要保证转换的合法性,例如从高精度转换为低精度时,可能会出现数据溢出

a = tf.constant(123456789, dtype=tf.int32) tf.cast(a, tf.int16) # 转换为低精度整型

<tf.Tensor: id=38, shape=(), dtype=int16, numpy=-13035>

待优化的张量

有些数值型数据需要计算张量,而有些不需要。TensorFlow增加了一种专门的数据类型来记录支持梯度信息的数据:tf.Variable(),包含name,trainable等属性来支持计算图的构建。

a = tf.Variable(12, name='hahatest')
a.name
    'hahatest:0'
a.trainable
    True

其中trainble属性用来表示当前数据是否需要被优化,默认值是True,也可设置成False来确保该数据不被优化。

创建张量

在TensorFlow中有多种方式创建张量:

  1. python列表
  2. numpy数组
  3. 采样自某种已知分布

从numpy数组或python列表等容器中创建

tf.convert_to_tensor([1, 2.])
<tf.Tensor: shape=(2,), dtype=float32, numpy=array([1., 2.], dtype=float32)>


tf.convert_to_tensor(np.array([[1, 2.], [3,4]]))
<tf.Tensor: shape=(2, 2), dtype=float64, numpy=
array([[1., 2.],
       [3., 4.]])>

numpy的浮点数默认是64位

创建全0/全1张量

通过tf.ones()/tf.zeros()来快速创建全0/全1的张量。

tf.zeros([2,2])
<tf.Tensor: shape=(2, 2), dtype=float32, numpy=
array([[0., 0.],
       [0., 0.]], dtype=float32)>


tf.ones([2,3])
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[1., 1., 1.],
       [1., 1., 1.]], dtype=float32)>

还可一通过tf.zeros_like(),创建与某张量shape一致的全0张量。
tf.ones_like()同理。

自定义数值张量

实际上除了初始化全0,全1向量外,我们偶尔也会用到其他数值的向量,TensorFlow同样提供了函数快速创建, tf.fill()。

tf.fill([2, 3], -1)
<tf.Tensor: shape=(2, 3), dtype=int32, numpy=
array([[-1, -1, -1],
       [-1, -1, -1]], dtype=int32)>

创建已知分布的张量

在深度学习中创建采样自某种分布的张量非常有用。例如在卷积网络中卷积核W初始化为正太分布会有利于神经网络的训练。
通过tf.random.nomal(shape, mean=0.0, stddev=1.0)可以创建形状为shape,均值为mean,标准差为stddev的正态分布张量。
通过tf.random.uniform(shape, minval=0, maxval=None, dtype=tf.float32)可以创建采样自 [minval, maxval)区间的均匀分布的张量。

tf.random.uniform([2,3], minval=0, maxval=10)
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[7.98023  , 5.8388844, 3.1424844],
       [1.8403566, 5.9672403, 4.1040087]], dtype=float32)>

创建序列

在python中可以通过range(limit)创建一个[0,limit)的列表,在TensorFlow中可以通过tf.range()实现类似的功能。

tf.range(10)
<tf.Tensor: shape=(10,), dtype=int32, numpy=array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=int32)>

# 同下
tf.constant([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=tf.int32)
<tf.Tensor: shape=(10,), dtype=int32, numpy=array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=int32)>

张量的应用

前面介绍了张量的创建和部分属性,后面将介绍下不同张量的典型应用,希望能够直观的理解不同张量的无力意义和用途。

标量

标量是指没有维度的,简单的一个数字。可以用作各种测量指标的表示,例如loss值,准确率(Accuracy,acc),精度(Precision)和召回率(Recall)等。
经过 tf.keras.losses.mse(或 tf.keras.losses.MSE,两者相同功能)返回每个样本上的误差值:

out = tf.random.uniform([4, 10])
<tf.Tensor: shape=(4, 10), dtype=float32, numpy=
array([[0.84483695, 0.93099034, 0.5165094 , 0.36359835, 0.45167565,
        0.53549457, 0.35292995, 0.72738886, 0.86134624, 0.926762  ],
       [0.60033536, 0.4691106 , 0.15967238, 0.84809935, 0.01495636,
        0.9536545 , 0.9755062 , 0.08139396, 0.2499156 , 0.99979615],
       [0.42064786, 0.6357846 , 0.11822903, 0.13693142, 0.02659714,
        0.9410871 , 0.49241388, 0.2925855 , 0.08305645, 0.7115592 ],
       [0.33314943, 0.9935945 , 0.5966996 , 0.23640716, 0.6664102 ,
        0.09254563, 0.1807183 , 0.08634591, 0.10667193, 0.32951713]],
      dtype=float32)>

y = tf.constant([2,3,1,0])
y = tf.one_hot(y, depth=10)
<tf.Tensor: shape=(4, 10), dtype=float32, numpy=
array([[0., 0., 1., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],
       [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
       [1., 0., 0., 0., 0., 0., 0., 0., 0., 0.]], dtype=float32)>

loss = tf.keras.losses.mse(out, y)
<tf.Tensor: shape=(4,), dtype=float32, numpy=array([0.46916837, 0.35590047, 0.20699708, 0.24566011], dtype=float32)>

loss = tf.reduce_sum(loss)  # 此时loss即为标量
<tf.Tensor: shape=(), dtype=float32, numpy=1.2777259>

向量

向量也是一种非常常用的数据,如全连接层中的偏置bias就是使用向量来表示的。

fc = tf.keras.layers.Dense(3)
fc.build(input_shape=(2,4))

fc.bias
<tf.Variable 'bias:0' shape=(3,) dtype=float32, numpy=array([0., 0., 0.], dtype=float32)>

全连接层中的bias就是一种典型的向量,而且是Variable的数据,即默认可优化的数据。

矩阵

全连接层中的W就是一种典型的矩阵,而且是Variable的数据,即默认可优化的数据。

fc = tf.keras.layers.Dense(3)
fc.build(input_shape=(2,4))

fc.kernel
<tf.Variable 'kernel:0' shape=(4, 3) dtype=float32, numpy=
array([[ 0.09304154,  0.7754861 , -0.6330199 ],
       [-0.68237156,  0.8677367 , -0.6535898 ],
       [-0.33738226, -0.44297722,  0.3789575 ],
       [ 0.31737828,  0.08265066,  0.33587444]], dtype=float32)>

三维张量

三维张量的一个典型应用就是序列数据。例如信号数据、文本数据等。

X = [batch_size, sequence_len, feature_len]

其中sequence_len表示数据在时间维度上的采样点数,例如文本里的文字长度。
feature_len表示每个时间步的特征长度,例如每个单词的embedding长度。

(x_train, y_train), (x_test, y_test) = tf.keras.datasets.imdb.load_data(num_words=10000)
# 将文本填充/截取成等长的
x_train = tf.keras.preprocessing.sequence.pad_sequences(x_train, max_len=100)
x_train.shape
(25000, 100)

embedding=tf.keras.layers.Embedding(10000, 80)
out = embedding(x_train)
out.shape
TensorShape([25000, 100, 80])

其中out即为三维张量,维度分别表示文本的数量,每个文本的单词长度,每个单词的embedding维度。

四维张量

神经网络中,一般将n张彩色图片用张量表示成:[n, h, w, 3],其中3维通道数量。在卷积的过程中,通道数还会发生变化。

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

x.shape
TensorShape([4, 32, 32, 3])

out.shape
TensorShape([4, 30, 30, 16])

索引与切片

索引和切片可以很方便的提取张量的部分数据。

索引

在TensorFlow中支持两种索引方式:

  • 标准索引方式:[i][j]...
  • 通过都好分隔索引号的方式

如下所示,两种方式显示结果是一样的

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

切片

切片只有一种方式,即start: end: step

x = tf.random.normal([4,32,32,3])

# 取第一张图片的所有信息
x[0,::]  

# 取第一,二,三张图片
x[0:3]

维度变换

在神经网络中,维度变换是最核心的操作之一,通过维度变换可以将数据任意的切换形式,满足不同的计算需要。
TensorFlow中基本的维度变换函数包括:

  1. 改变视图reshape
  2. 插入新维度expand_dim
  3. 删除维度squeeze
  4. 交换维度transpose
  5. 复制数据tile等

改变视图

张量中存在两个很重要的概念,存储(Storage)和视图(View)。
张量的视图就是我们理解张量的方式,比如shape为[2,4,4,3]的张量,我们从逻辑上可以理解为有两张图片,每张图片有RGB三个通道,每个通道是4x4个像素。
张量的存储体现在张量在内存上保存为一段连续的内存区域。
同一个存储,从不同的角度观察数据,可以产生不同的视图。这就是存储和视图的关系。视图的产生是十分灵活的,但必须是合理的。

x = tf.range(10)
x = tf.reshape(x, shape=[2,5])
x
<tf.Tensor: shape=(2, 5), dtype=int32, numpy=
array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]], dtype=int32)>

x = tf.reshape(x, shape=[2,5,1])
x
array([[[0],
        [1],
        [2],
        [3],
        [4]],

       [[5],
        [6],
        [7],
        [8],
        [9]]], dtype=int32)>

增删维度

增加维度,是指增加一个长度为1的维度,也就是给原有的数据增加一个维度。通过tf.expand_dims(x, axis)实现。

x = tf.random.uniform([28, 28])
x.shape
TensorShape([28, 28])

x = tf.expand_dims(x, axis=2)
x.shape
TensorShape([28, 28, 1])

当axis为正时,是指在指定的位置之前加一个维度。
当axis为负时,是指在指定的位置之后加一个维度。

删除维度可以理解为增加维度的逆操作。只能删除长度为1的维度,不会改变张量的存储。通过tf.squeeze(x, axis)实现。

x.shape
TensorShape([28, 28, 1])

tf.squeeze(x, axis=2).shape
TensorShape([28, 28])

axis为要删除的维度。如果不指定axis,那么将默认删除所有长度为1的维度。

维度交换

改变视图,增删维度都是在保持维度顺序不变的条件下进行的,因此这些操作仅仅是改变了张量的理解方式,并没有改变张量的存储。但有时候我们需要改变张量的维度顺序,改变其存储。例如在TensorFlow中图片的默认默认存储格式是通道后行格式[b, h, w, c],但有些数据库中提供的图片是通道先行格式[b, c, h, w],需要[b, c, h, w]到[b, h, w, c]的转换。需要使用tf.transpose(x, perm),其中perm为新维度的顺序list。

x = tf.random.uniform(shape=[2,3,32,32])
x.shape
TensorShape([2, 3, 32, 32])

tf.transpose(x, perm=[0,2,3,1]).shape
TensorShape([2, 32, 32, 3])

复制数据

当我们对数据增加维度后,可能会希望在新的维度上复制若干份数据,来满足后续算法的格式要求。
tf.tile(x, multiples)可以实现以上操作,其中multiples 分别指 定了每个维度上面的复制倍数。

b = tf.constant([1, 2])
b = tf.expand_dims(b, axis=0)
b.shape
TensorShape([1, 2])

b = tf.tile(b, multiples=[2,1])
b
<tf.Tensor: shape=(2, 2), dtype=int32, numpy=
array([[1, 2],
       [1, 2]], dtype=int32)>

其中multiples=[2, 1]是说,对第0维数据复制1份,对第1维数据维持原样,即数量*1(不变)。

Broadcasting

Broadcasting称为广播机制(自动扩展机制),它是一种轻量级的张量复制手段,在逻辑上扩展张量数据的形式,但只有在需要时才会执行实际的存储复制操作。

x = tf.random.uniform([2, 4])
w = tf.random.uniform([4, 3])
b = tf.random.normal([3])

y = x @ w + b

tf.broadcast_to(b, [2,3])
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[-0.5195319 ,  2.6407762 ,  0.00587736],
       [-0.5195319 ,  2.6407762 ,  0.00587736]], dtype=float32)>

上例中b的shape与x@w的shape并不相同,但却能相加,没有发生逻辑错误。因为自动调用了tf.broadcast_to(x, new_shape),将两者的shape扩展成一样的。
注意:tf.broadcast_to()操作是自动进行的。

数学运算

  • TensorFlow 已经重载了+、 − 、 ∗ 、/运算符,一般推荐直接使用运算符来完成 加、减、乘、除运算。
  • 整除和余除也是常见的运算之一,分别通过//和%运算符实现。
  • tf.pow(x, a) 与x ** a都为乘方运算。
  • 对于常见的平方和平方根运算,可以使用 tf.square(x)和 tf.sqrt(x)实现。
  • 对于自然指数e𝑥,可以通过 tf.exp(x)实现。
  • 自然对数loge 可以通过 tf.math.log(x)实现。

矩阵相乘

特别要注意一下矩阵相乘
通过@运算符可以方便的实现矩阵相乘
还可以通过 tf.matmul(a, b)函数实现
根据矩阵相乘的定义,𝑨和𝑩能够矩阵相乘的条件是,𝑨的倒数第一个维度长度(列)和𝑩 的倒数第二个维度长度(行)必须相等

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容