Tensorflow:TensorFlow基礎(一)

2020-10-14 13:01:01

TensorFlow基礎

import numpy as np
import tensorflow as tf
import tensorflow.keras as keras
import tensorflow.keras.layers as layers
physical_devices = tf.config.experimental.list_physical_devices('GPU')
assert len(physical_devices) > 0, "Not enough GPU hardware devices available"
tf.config.experimental.set_memory_growth(physical_devices[0], True)

1.資料型別

Tensorflow主要有3種資料型別:數值型,字串型,布林型

1.1 數值型別

標量(Scalar) 單個的實數,如 1.2, 3.4 等

向量(Vector) n 個實數的有序集合,通過中括號包裹,如[1.2],[1.2,3.4]等

矩陣(Matrix) n 行 m 列實數的有序集合,如[[1,2],[3,4]]

標量在 TensorFlow 是如何建立的

# python 語言方式建立標量
a = 1.2 
# TF 方式建立標量
aa = tf.constant(1.2)
type(a), type(aa), tf.is_tensor(aa)
(float, tensorflow.python.framework.ops.EagerTensor, True)

如果要使用 TensorFlow 提供的功能函數, 須通過 TensorFlow 規定的方式去建立張量,而不能使用 Python 語言的標準變數建立方式。

x = tf.constant([1,2.,3.3])
# 列印 TF 張量的相關資訊                
x
<tf.Tensor: shape=(3,), dtype=float32, numpy=array([1. , 2. , 3.3], dtype=float32)>
# 將 TF 張量的資料匯出為 numpy 陣列格式
x.numpy() 
array([1. , 2. , 3.3], dtype=float32)

與標量不同,向量的定義須通過 List 容器傳給 tf.constant()函數。

建立一個元素的向量:

# 建立一個元素的向量
a = tf.constant([1.2]) 
a, a.shape
(<tf.Tensor: id=2, shape=(1,), dtype=float32, numpy=array([1.2], dtype=float32)>,
 TensorShape([1]))

建立 3 個元素的向量:

 # 建立 3 個元素的向量
a = tf.constant([1,2, 3.])
a, a.shape
(<tf.Tensor: id=3, shape=(3,), dtype=float32, numpy=array([1., 2., 3.], dtype=float32)>,
 TensorShape([3]))

定義矩陣

# 建立 2 行 2 列的矩陣
a = tf.constant([[1,2],[3,4]]) 
a, a.shape
(<tf.Tensor: id=4, shape=(2, 2), dtype=int32, numpy=
 array([[1, 2],
        [3, 4]])>, TensorShape([2, 2]))

三維張量可以定義為:

# 建立 3 維張量
tf.constant([[[1,2],[3,4]],[[5,6],[7,8]]]) 
<tf.Tensor: id=5, shape=(2, 2, 2), dtype=int32, numpy=
array([[[1, 2],
        [3, 4]],

       [[5, 6],
        [7, 8]]])>

通過傳入字串物件即可建立字串型別的張量

# 建立字串
a = tf.constant('Hello, Deep Learning.') 
a
<tf.Tensor: id=6, shape=(), dtype=string, numpy=b'Hello, Deep Learning.'>

1.2 字串型別

通過傳入字串物件即可建立字串型別的張量

# 建立字串
a = tf.constant('Hello, Deep Learning.') 
a
<tf.Tensor: id=7, shape=(), dtype=string, numpy=b'Hello, Deep Learning.'>

在 tf.strings 模組中,提供了常見的字串型別的工具函數,如小寫化 lower()、 拼接
join()、 長度 length()、 切分 split()等。

# 小寫化字串
tf.strings.lower(a) 
<tf.Tensor: id=8, shape=(), dtype=string, numpy=b'hello, deep learning.'>

1.3 布林型別

布林型別的張量只需要傳入 Python 語言的布林型別資料,轉換成 TensorFlow 內部布林型即可。

# 建立布林型別標量
tf.constant(True) 
<tf.Tensor: id=9, shape=(), dtype=bool, numpy=True>

建立布林型別的向量

 # 建立布林型別向量
tf.constant([True, False])
<tf.Tensor: id=10, shape=(2,), dtype=bool, numpy=array([ True, False])>

需要注意的是, TensorFlow 的布林型別和 Python 語言的布林型別並不等價,不能通用

# 建立 TF 布林張量
a = tf.constant(True) 
# TF 布林型別張量與 python 布林型別比較
print(a is True) 
# 僅數值比較
print(a == True) 
False
tf.Tensor(True, shape=(), dtype=bool)

2.數值精度

對於數值型別的張量,可以保持為不同位元組長度的精度,如浮點數 3.14 既可以儲存為
16-bit 長度,也可以儲存為 32-bit 甚至 64-bit 的精度。Bit 位越長,精度越高,同時佔用的記憶體空間也就越大。常用的精度型別有 tf.int16, tf.int32, tf.int64, tf.float16, tf.float32, tf.float64,其中 tf.float64 即為 tf.double

在建立張量時,可以指定張量的儲存精度

# 建立指定精度的張量
tf.constant(123456789, dtype=tf.int16)
<tf.Tensor: id=14, shape=(), dtype=int16, numpy=-13035>

對於浮點數, 高精度的張量可以表示更精準的資料,例如採用 tf.float32 精度儲存π時,實際儲存的資料為 3.1415927

import numpy as np
# 從 numpy 中匯入 pi 常數
np.pi 
# 32 位
tf.constant(np.pi, dtype=tf.float32) 
<tf.Tensor: id=16, shape=(), dtype=float32, numpy=3.1415927>

如果採用 tf.float64 精度儲存π,則能獲得更高的精度

tf.constant(np.pi, dtype=tf.float64) # 64 位
<tf.Tensor: id=17, shape=(), dtype=float64, numpy=3.141592653589793>

2.1 讀取精度

通過存取張量的 dtype 成員屬性可以判斷張量的儲存精度

a = tf.constant(np.pi, dtype=tf.float16)

# 讀取原有張量的數值精度
print('before:',a.dtype) 
# 如果精度不符合要求,則進行轉換
if a.dtype != tf.float32: 
    # tf.cast 函數可以完成精度轉換
    a = tf.cast(a,tf.float32) 
# 列印轉換後的精度
print('after :',a.dtype) 
before: <dtype: 'float16'>
after : <dtype: 'float32'>

2.2 型別轉換

系統的每個模組使用的資料型別、 數值精度可能各不相同, 對於不符合要求的張量的型別及精度, 需要通過 tf.cast 函數進行轉換

# 建立 tf.float16 低精度張量
a = tf.constant(np.pi, dtype=tf.float16) 
# 轉換為高精度張量
tf.cast(a, tf.double) 
<tf.Tensor: id=21, shape=(), dtype=float64, numpy=3.140625>

進行型別轉換時,需要保證轉換操作的合法性, 例如將高精度的張量轉換為低精度的張量時,可能發生資料溢位隱患:

a = tf.constant(123456789, dtype=tf.int32)
# 轉換為低精度整型
tf.cast(a, tf.int16) 
<tf.Tensor: id=23, shape=(), dtype=int16, numpy=-13035>

布林型別與整型之間相互轉換也是合法的, 是比較常見的操作

a = tf.constant([True, False])
# 布林型別轉整型
tf.cast(a, tf.int32) 
<tf.Tensor: id=25, shape=(2,), dtype=int32, numpy=array([1, 0])>

一般預設 0 表示 False, 1 表示 True,在 TensorFlow 中,將非 0 數位都視為 True,

a = tf.constant([-1, 0, 1, 2])
# 整型轉布林型別
tf.cast(a, tf.bool) 
<tf.Tensor: id=27, shape=(4,), dtype=bool, numpy=array([ True, False,  True,  True])>

3.待優化張量

為了區分需要計算梯度資訊的張量與不需要計算梯度資訊的張量,TensorFlow 增加了一種專門的資料型別來支援梯度資訊的記錄:tf.Variabletf.Variable 型別在普通的張量型別基礎上新增了 nametrainable 等屬性來支援計算圖的構建。由於梯度運算會消耗大量的計算資源,而且會自動更新相關引數,對於不需要的優化的張量,如神經網路的輸入 X,不需要通過 tf.Variable 封裝;相反,對於需要計算梯度並優化的張量,如神經網路層的W 和𝒃,需要通過 tf.Variable 包裹以便 TensorFlow 跟蹤相關梯度資訊。

通過 tf.Variable()函數可以將普通張量轉換為待優化張量:

# 建立 TF 張量
a = tf.constant([-1, 0, 1, 2]) 
# 轉換為 Variable 型別
aa = tf.Variable(a) 
# Variable 型別張量的屬性, 名字, 是否求導數
aa.name, aa.trainable 
('Variable:0', True)

name 屬性用於命名計算圖中的變數,這套命名體系是 TensorFlow 內部維護的, 一般不需要使用者關注 name 屬性;
trainable屬性表徵當前張量是否需要被優化,建立 Variable 物件時是預設啟用優化標誌,可以設定trainable=False 來設定張量不需要優化。

# 直接建立 Variable 張量
tf.Variable([[1,2],[3,4]]) 
<tf.Variable 'Variable:0' shape=(2, 2) dtype=int32, numpy=
array([[1, 2],
       [3, 4]])>

4.建立張量

4.1 從陣列、列表物件建立

通過 tf.convert_to_tensor 函數可以建立新 Tensor,並將儲存在 Python List 物件或者Numpy Array 物件中的資料匯入到新 Tensor 中。

# 從列表建立張量
tf.convert_to_tensor([1,2.]) 
<tf.Tensor: id=44, shape=(2,), dtype=float32, numpy=array([1., 2.], dtype=float32)>
# 從陣列中建立張量
tf.convert_to_tensor(np.array([[1,2.],[3,4]])) 
<tf.Tensor: id=45, shape=(2, 2), dtype=float64, numpy=
array([[1., 2.],
       [3., 4.]])>

4.2 建立全0或全1張量

建立全 0 的矩陣

# 建立全 0 矩陣,指定 shape 為 2 行 2 列
tf.zeros([2,2]) 
<tf.Tensor: id=56, shape=(2, 2), dtype=float32, numpy=
array([[0., 0.],
       [0., 0.]], dtype=float32)>

建立全 1 的矩陣

# 建立全 1 矩陣,指定 shape 為 3 行 2 列
tf.ones([3,2]) 
<tf.Tensor: id=59, shape=(3, 2), dtype=float32, numpy=
array([[1., 1.],
       [1., 1.],
       [1., 1.]], dtype=float32)>

通過 tf.zeros_like, tf.ones_like 可以方便地新建與某個張量 shape 一致, 且內容為全 0 或全 1 的張量。

# 建立一個矩陣
a = tf.ones([2,3]) 
# 建立一個與 a 形狀相同,但是全 0 的新矩陣
tf.zeros_like(a) 
<tf.Tensor: id=63, shape=(2, 3), dtype=float32, numpy=
array([[0., 0., 0.],
       [0., 0., 0.]], dtype=float32)>

建立與張量A形狀一樣的全 1 張量

# 建立一個矩陣
a = tf.zeros([3,2]) 
# 建立一個與 a 形狀相同,但是全 1 的新矩陣
tf.ones_like(a) 
<tf.Tensor: id=69, shape=(3, 2), dtype=float32, numpy=
array([[1., 1.],
       [1., 1.],
       [1., 1.]], dtype=float32)>

4.3 建立自定義數值張量

通過 tf.fill(shape, value) 可以建立全為自定義數值 value 的張量,形狀由 shape 引數指定。

# 建立 2 行 2 列,元素全為 99 的矩陣
tf.fill([2,2], 99) 
<tf.Tensor: id=78, shape=(2, 2), dtype=int32, numpy=
array([[99, 99],
       [99, 99]])>

4.4 建立已知分佈的張量

通過 tf.random.normal(shape, mean=0.0, stddev=1.0)可以建立形狀為 shape,均值為mean,標準差為 stddev 的正態分佈 N ( m e a n , s t d d e v 2 ) \mathcal{N}(mean, stddev^2) N(mean,stddev2)

# 建立標準正態分佈的張量
tf.random.normal([2,2]) 
<tf.Tensor: id=84, shape=(2, 2), dtype=float32, numpy=
array([[0.4479265 , 1.2336508 ],
       [0.96864706, 2.076528  ]], dtype=float32)>

通過 tf.random.uniform(shape, minval=0, maxval=None, dtype=tf.float32) 可以建立取樣自[minval, maxval)區間的均勻分佈的張量

# 建立取樣自[0,1)均勻分佈的矩陣
tf.random.uniform([3,2]) 
<tf.Tensor: id=97, shape=(3, 2), dtype=float32, numpy=
array([[0.5197921 , 0.80691314],
       [0.38051474, 0.05250001],
       [0.18329549, 0.8741617 ]], dtype=float32)>
# 建立取樣自[0,10)均勻分佈的矩陣
tf.random.uniform([2,2],maxval=10) 
<tf.Tensor: id=104, shape=(2, 2), dtype=float32, numpy=
array([[0.4374528 , 7.3671246 ],
       [2.1262336 , 0.12584329]], dtype=float32)>

如果需要均勻取樣整形型別的資料,必須指定取樣區間的最大值 maxval 引數,同時指定資料型別為 tf.int*型

# 建立取樣自[0,100)均勻分佈的整型矩陣
tf.random.uniform([2,2],maxval=100,dtype=tf.int32)
<tf.Tensor: id=108, shape=(2, 2), dtype=int32, numpy=
array([[15, 50],
       [38, 84]])>

4.4 建立序列

tf.range(limit, delta=1) 可以建立[0, limit)之間,步長為 delta 的整型序列,不包含 limit 本身。

# 0~10,不包含 10
tf.range(10) 
<tf.Tensor: shape=(10,), dtype=int32, numpy=array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])>
# 建立 0~10,步長為 2 的整形序列
tf.range(10,delta=2)
<tf.Tensor: id=116, shape=(5,), dtype=int32, numpy=array([0, 2, 4, 6, 8])>
tf.range(1,10,delta=2) # 1~10
<tf.Tensor: id=120, shape=(5,), dtype=int32, numpy=array([1, 3, 5, 7, 9])>