tensorflow 有些常用的函數,需要仔細的背起來
tf.random.normal
標準常態分佈亂數會在大部份集中於0左右的小數亂數。其實np.random.normal()也可以產生此功能。
import os os.environ['TF_CPP_MIN_LOG_LEVEL']='2' import tensorflow as tf import pylab as plt import seaborn as sns batch=10000 x=tf.random.normal([batch]) y=tf.random.normal([batch]) #plt.scatter(x, y, s=0.1) sns.histplot(x) plt.savefig("tf_normal_histplot.jpg") plt.show()
plt點散圖如下
海生圖如下
tf.random.uniform
在 陣列 這篇的說明,有提到 tf.random.uniform是產生均勻分佈陣列的函數,參數只需傳入要產生亂數的數量即可。另外 tf.random.unifomr 還可以下達 minval 及 maxval 設定最小值及最大值,但不包含最大值。
底下代碼可以產生均勻分佈亂數
import os os.environ['TF_CPP_MIN_LOG_LEVEL']='2' import numpy as np import tensorflow as tf import pylab as plt import seaborn as sns batch=10000 x=tf.random.uniform([batch])
y=tf.random.uniform([batch]) plt.scatter(x, y, s=0.1) #sns.histplot(y) print(y.numpy()) plt.savefig("tf_uniform_scatter.jpg") plt.show()
plt點散圖如下
海生圖分佈狀態如下
產生均勻分佈亂數,其實也可以用 np. random.uniform(0, 1, batch)。這二個有什麼不同呢? 當產生的數量多達1億個的時候,這二個所花費的時間差不多是在 0.4 秒左右,但如果產生的數量大於 1 億,numpy 的效能就會遠遠落後 tf 很多。
import os import time os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' import tensorflow as tf import numpy as np batch=500_000_000 t1=time.time() a=tf.random.uniform([batch]) t2=time.time() print(f'tf花費 : {t2-t1}秒') t1=time.time() b=np.random.uniform(0, 1, batch) t2=time.time() print(f'np花費 : {t2-t1}秒')
結果 : tf花費 : 0.4383711814880371秒 np花費 : 2.5611190795898438秒
tf.sqrt
sqrt 為求取平方的函數,只能用於小數型態。如果是整數型態,會發生例外錯誤。
另外如果傳入的型態是陣列的話,就會將陣列中的每一個元素進行運算。
import os os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' import tensorflow as tf #tf.sqrt只能用在小數型態 a=tf.constant(10.) print(tf.sqrt(a)) #底下為整數型態,無法使用 sqrt #b=tf.constant(10) #print(tf.sqrt(b)) c=tf.constant([1., 2., 3.]) print(tf.sqrt(c)) 結果 : tf.Tensor(3.1622777, shape=(), dtype=float32) tf.Tensor([1. 1.4142135 1.7320508], shape=(3,), dtype=float32)
numpy 也有 np.sqrt 的方法,底下對 1 億個數字進行進算,可見 tf.sqrt 效能遠遠比 numpy 好很多
import os os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' import tensorflow as tf import numpy as np import time batch=100_000_000 t1=time.time() a=tf.random.uniform([batch]) t2=time.time() print(f'tf產生亂數花費 : {t2-t1}秒') t1=time.time() b=np.random.uniform(0, 1, batch) t2=time.time() print(f'np產生亂數花費 : {t2-t1}秒') t1=time.time() a=tf.sqrt(a) t2=time.time() print(f'tf計算平方花費 : {t2-t1}秒') t1=time.time() b=np.sqrt(b) t2=time.time() print(f'np計算平方花費 : {t2-t1}秒') 結果: tf產生亂數花費 : 0.44187140464782715秒 np產生亂數花費 : 0.5215818881988525秒 tf計算平方花費 : 0.0009970664978027344秒 np計算平方花費 : 0.14860248565673828秒
tf.square
tf.square為求取平方值,適用於整數及小數。同樣如果是陣列,也會足一將每個元素的平方計算一遍。
import os os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' import tensorflow as tf a=tf.constant(10.) print(tf.square(a)) b=tf.constant(10) print(tf.square(b))
結果 : tf.Tensor(100.0, shape=(), dtype=float32) tf.Tensor(100, shape=(), dtype=int32)
tf.where
where後面的參數為條件,此法可將陣列中符合條件的索引值集合成一個新的 n*1 的 Tensor 陣列。
如果要取出符合的值,需使用 value = tf.gather(x, idx)。
最後若要得知符合的數量,使用 value.shape[0]。
import os os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' import tensorflow as tf batch=10 x=tf.random.uniform([batch]) print(f'原始資料 : {x}') idx=tf.where(x<=0.5) print(f'符合的索引 :\n{idx}') value=tf.gather(x, idx) print(f'符合的值 : {value}') print(f'符合的數量 : {value.shape[0]}') 原始資料 : [0.5912652 0.97370183 0.21289659 0.52576315 0.13146174 0.76325166 0.10665309 0.54943335 0.59710836 0.76287985] 符合的索引 : [[2] [4] [6]] 符合的值 : [[0.21289659] [0.13146174] [0.10665309]] 符合的數量 : 3
蒙地卡羅 tf 版
底下是 GPU 的版本,利用 tf.sqrt 及 tf.square 計算大量張量的平方及開根號求取與原點的距離。此張量的大小每次 (batch) 為 1 億個點,然後計算 50 萬次。也就是說計算 50 萬 * 1 億個點。GPU產生 1 億個亂數點非常快速,計算 1 億個點與原點的距離也只需 0.1 秒,比CPU快了很多。
GPU 一啟動,顯卡的溫度立即上升到攝氏 77 度,非常耗電。
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
import tensorflow as tf
batch=10_000_000
epochs=200
incircle=0
@tf.function
def cal():
points=tf.random.uniform([2, batch], dtype=tf.float32)
dist=tf.sqrt(tf.square(points[0])+tf.square(points[1]))
count=tf.where(dist<=1).shape[0]
return count
for e in range(epochs):
count=cal()
incircle+=count
area=incircle /((e+1)*batch)
pi=area*4
print(f'epoch:{e+1}, pi={pi}')
計算函數 cal() 前加了 @tf.function,是要將函數內的值改成 graph 計算 (模擬tf1的 session)。如此可加速計算效能。如果沒有 @tf.function,每個迴圈約要 0.18秒,如果加入 @tf.function,每個迴圈變成 0.16秒。但並不是所有的東西都加入圖計算就會變快,通常只有大量資料的計算加入圖計算才會加速。
結果如下
Epoch : 500,000 pi=3.1415926758672
導數
導數就是微分,微分就是導數。比如$(f(x)=x^{2})$,經過一次微分後,結果為$(f'(x)=2x)$,所以當x=3時,$(y=f'(x)=6)$
with tf.GradientTape() as prototype 的區塊中,就是在宣告函數的原型。然後再使用y_grad=prototype.gradient(x, y)就可以求取y對x的導數。
import os
os.environ['TF_CPP_MIN_LOG_LEVEL']='2'
import tensorflow as tf
cpus=tf.config.experimental.list_physical_devices(device_type='CPU')
tf.config.set_visible_devices(devices=cpus)
x = tf.Variable(3.)
with tf.GradientTape() as prototype:#宣告原型函數
y = tf.pow(x, 2)
y_grad = prototype.gradient(y, x)# 計算y關於x的導數
print('y=x^2, x=3, y=',y)
print('一次微分後,y導數=', y_grad)
結果 :
y=x^2, x=3, y= tf.Tensor(9.0, shape=(), dtype=float32)
一次微分後,y導數= tf.Tensor(6.0, shape=(), dtype=float32)
損失函數偏導數
$(x=\begin{bmatrix}1 & 2\\ 3 & 4 \end{bmatrix})$ , $(y=\begin{bmatrix}1\\2\end{bmatrix})$ , $(w=\begin{bmatrix}1\\2\end{bmatrix})$ , $(b=1)$
假設 y=xw + b ,則底下為其損失函數
$(L(w, b)=\sum (xw+b-y )^{2})$
import tensorflow as tf
X = tf.constant([[1., 2.], [3., 4.]])
y = tf.constant([[1.], [2.]])
w = tf.Variable(initial_value=[[1.], [2.]])
b = tf.Variable(initial_value=1.)
with tf.GradientTape() as tape:
L = tf.reduce_sum(tf.square(tf.matmul(X, w) + b - y))
w_grad, b_grad = tape.gradient(L, [w, b]) # 計算L(w, b)關於w, b的偏導數
print(L)
print(w_grad)
print(b_grad)
結果:
tf.Tensor(125.0, shape=(), dtype=float32)
tf.Tensor(
[[ 70.]
[100.]], shape=(2, 1), dtype=float32)
tf.Tensor(30.0, shape=(), dtype=float32)
todo