- def preprocess(x,y) map() 第一個參數 function 以參數序列中的每一個元素調用 function 函數
- map( function,iterable)
- shuffe(10000)
- Sequential 序貫模型
- 優化器optimizers.Adam(lr=1e-3)
- GradientTape 梯度帶
- logits
- 方差、標准差、均方差、均方誤差
- 信息熵、條件熵、相對熵、交叉熵
(1)def preprocess()
預處理函數,將樣本中的每一個數據進行處理,即通過map函數進行處理,將x轉換為float32格式,將y轉換為int32格式
(2)map( function,iterable)
第一個參數 function 以參數序列中的每一個元素調用 function 函數
(3)shuffe(10000)
在一個epoch中最后一個batch大小可能小於等於batch size ,dataset.repeat就是俗稱epoch,但在tf中與dataset.shuffle的使用順序可能會導致個epoch的混合 ,dataset.shuffle就是說維持一個buffer size 大小的 shuffle buffer,圖中所需的每個樣本從shuffle buffer中獲取,取得一個樣本后,就從源數據集中加入一個樣本到shuffle buffer中。shuffle(1)時,即buffer size為1,相當於不進行打亂,buffer size=數據集樣本數量,隨機打亂整個數據集。
(4)Sequential 序貫模型
序貫模型是函數式模型的簡略版,為最簡單的線性、從頭到尾的結構順序,不分叉,是多個網絡層的線性堆疊。Keras實現了很多層,包括core核心層,Convolution卷積層、Pooling池化層等。通過將層的列表傳遞給Sequential的構造函數
model = Sequential([ layers.Dense(256, activation=tf.nn.relu), # 256是該層的輸入,[b, 784] => [b, 256] layers.Dense(128, activation=tf.nn.relu), #[b, 256] => [b, 128] layers.Dense(64, activation=tf.nn.relu), #[b, 128] => [b, 64] layers.Dense(32, activation=tf.nn.relu), # [b, 64] => [b, 32] layers.Dense(10) # [b, 32] => [b, 10], 330 = 32*10 + 10 最后一層不需要激活函數 ])
此外我們還需要一個輸入層,模型需要知道它所期待的輸入的尺寸(shape)。所以,序貫模型中的第一層(只有第一層,因為下面的層可以自動的推斷尺寸)需要接收關於其輸入尺寸的信息,后面的各個層則可以自動的推導出中間數據的shape,因此不需要為每個層都指定這個參數,通過傳遞一個input_shape參數給第一層。它是一個表示尺寸的元組(一個整數或None的元組,其中None表示可能為任何正整數)。在input_shape中不包含數據的batch大小。
# dense表示全連接層 model.build(input_shape=[None,28*28]) #對第一層進行輸入,建立模型,傳入數據 model.summary() #調試的功能,作用是打印網絡結構
(5)優化器optimizers.Adam(lr=1e-3)
Adam 算法和傳統的隨機梯度下降不同。隨機梯度下降保持單一的學習率(即 alpha)更新所有的權重,學習率在訓練過程中並不會改變。而 Adam 通過計算梯度的一階矩估計和二階矩估計而為不同的參數設計獨立的自適應性學習率。Adam 算法的提出者描述其為兩種隨機梯度下降擴展式的優點集合,即:
- 適應性梯度算法(AdaGrad)為每一個參數保留一個學習率以提升在稀疏梯度(即自然語言和計算機視覺問題)上的性能。
- 均方根傳播(RMSProp)基於權重梯度最近量級的均值為每一個參數適應性地保留學習率。這意味着算法在非穩態和在線問題上有很有優秀的性能。
- Adam 是一種可以替代傳統隨機梯度下降(SGD)過程的一階優化算法,它能基於訓練數據迭代地更新神經網絡權重。
(6)GradientTape 梯度帶
使用上下文環境,用來包裹將要求梯度的函數或者損失函數
(7)logits
logits表示輸出結果, 把沒有加激活函數的輸出值稱作logits
(8)方差、標准差、均方差、均方誤差
方差:概率論和統計學中衡量隨機變量或一組數據時離散程度的度量。概率論中方差用來度量隨機變量和其數學期望(即均值)之間的偏離程度。統計中的方差(樣本方差)是每個樣本值與全體樣本值的平均數之差的平方值的平均數
。方差可以用來描述變量的波動程度。方差在統計學和概率分布中各有不同的定義,並有不同的公式。在統計學中,方差用來計算每一個變量(觀察值)與總體均數之間的差異。為避免出現離均差總和為零,離均差平方和受樣本含量的影響,統計學采用平均離均差平方和來描述變量的變異程度。總體方差計算公式:
方差: 標准差:
標准差在中文壞境中也被稱為均方差
而均方誤差(mean squared error),即MSE,是樣本數據值偏離真實樣本數據值的平方和的平均數,也即誤差平方和的平均數
均方誤差: 均方誤差根:
(9)信息熵、條件熵、相對熵、交叉熵
信息熵 (information entropy):信息量的度量就等於不確定性的多少,
假設一個發送者想傳送一個隨機變量的值給接收者。那么在這個過程中,他們傳輸的平均信息量可以通過求
關於概率分布 p(x)p(x) 的期望得到,即:
條件熵 (Conditional entropy):條件熵 H(Y|X)H(Y|X) 表示在已知隨機變量 XX 的條件下隨機變量 YY 的不確定性。條件熵 H(Y|X)H(Y|X)
定義為 XX 給定條件下 YY 的條件概率分布的熵對 XX 的數學期望:條件熵 H(Y|X)H(Y|X) 相當於聯合熵 H(X,Y)H(X,Y) 減去單獨的熵 H(X)H(X),即H(Y|X)=H(X,Y)−H(X)
相對熵 (Relative entropy),也稱KL散度 (Kullback–Leibler divergence)
交叉熵 (Cross entropy):
(10)完整代碼
1 import tensorflow as tf 2 from tensorflow import keras 3 from tensorflow.keras import datasets, layers, optimizers, Sequential, metrics 4 import os 5 # 優化器optimizer 損失函數loss 評估標准metrics 序貫模型Sequential 6 os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' 7 8 def preProcess(x,y): 9 x = tf.cast(x, dtype = tf.float32)/255 #歸一化 10 y = tf.cast(y, dtype = tf.int32) #y要轉換為int類型 11 return x, y 12 13 14 (x, y),(x_test, y_test) = datasets.fashion_mnist.load_data() 15 print(x.shape,x_test.shape) 16 print(type(x)) # numpy數組 17 18 19 batchsize = 128 20 db = tf.data.Dataset.from_tensor_slices((x, y)) #numpy數組轉換為tensor 21 db = db.map(preProcess).shuffle(1000).batch(batchsize) 22 23 db_test = tf.data.Dataset.from_tensor_slices((x_test,y_test)) 24 db_test = db_test.map(preProcess).batch(batchsize) 25 26 27 db_iter = iter(db) 28 sample = next(db_iter) 29 print('batch:', sample[0].shape, sample[1].shape) #batch: (128, 28, 28) (128,) 要next后才能有形狀 30 31 # Sequential 32 # layers.Dense dense:全連接層, 相當於添加一個層,即初學的add_layer()函數 33 # tf.nn :提供神經網絡相關操作的支持,包括卷積操作(conv)、池化操作(pooling)、歸一化、 34 # loss、分類操作、embedding、RNN、Evaluation。 35 36 model = Sequential([ 37 layers.Dense(256, activation=tf.nn.relu), # 256是該層的輸入,[b, 784] => [b, 256] 38 layers.Dense(128, activation=tf.nn.relu), #[b, 256] => [b, 128] 39 layers.Dense(64, activation=tf.nn.relu), #[b, 128] => [b, 64] 40 layers.Dense(32, activation=tf.nn.relu), # [b, 64] => [b, 32] 41 layers.Dense(10) # [b, 32] => [b, 10], 330 = 32*10 + 10 最后一層需要激活函數 42 ]) 43 # dense表示全連接層 44 model.build(input_shape=[None,28*28]) #對第一層進行輸入 45 model.summary() 46 47 # w = w - lr*grad 權值更新 48 optimizer = optimizers.Adam(lr=1e-3) 49 #適應性矩估計(adaptive moment estimation) Adam 是一種可以替代傳統隨機梯度下降(SGD)過程的一階優化算法, 50 #它能基於訓練數據迭代地更新神經網絡權重 51 52 def main(): 53 print("kkkkkkkkkkkkkkk") 54 for epoch in range(20): #進行20個循環 55 for step, (x,y) in enumerate(db): 56 # x: [b, 28, 28] => [b, 784] 57 # y: [b] 58 x= tf.reshape(x,[-1,28*28]) 59 60 with tf.GradientTape() as tape: 61 logits = model(x) # ? logits表示輸出結果, 把沒有加激活函數的輸出值稱作logits 62 y_onehot = tf.one_hot(y, depth=10) 63 64 # 均方差損失函數 65 loss_mse = tf.reduce_mean(tf.losses.MSE(y_onehot,logits)) 66 #方差用來度量隨機變量和其數學期望(即均值)之間的偏離程度 ,均方誤差表示各數據偏離真實值的距離平方和的平均數 67 #均方差是數據序列與均值的關系,而均方誤差是數據序列與真實值之間的關系 68 69 #sigmoid函數會造成梯度消失,則考慮使用下面的交叉熵損失函數,交叉熵是用來評估當前訓練得到的概率分布與真實分布的差異情況。 70 # 它刻畫的是實際輸出(概率)與期望輸出(概率)的距離,也就是交叉熵的值越小,兩個概率分布就越接近 71 # 交叉熵損失函數,直接用logits進行運算,一定要設置from_logits = True 72 loss_ce = tf.losses.categorical_crossentropy(y_onehot, logits, from_logits=True) 73 loss_ce = tf.reduce_mean(loss_ce) # 由於上一步計算的loss_ce是tensor,這里要做一下求平均值 74 75 grads = tape.gradient(loss_ce,model.trainable_variables) #計算梯度 model.trainable_variables返回變量列表,不需要我們再額外管理變量 76 optimizer.apply_gradients(zip(grads, model.trainable_variables))#反向傳播計算。參數中 梯度(grads)和變量要一一對應,所以用了zip() 77 78 if step % 100 == 0: 79 print(epoch, step,"loss: ",float(loss_ce),float(loss_mse)) 80 81 82 #test 83 total_correct = 0 84 total_num = 0 85 for x, y in db_test: 86 # x: [b, 28, 28] => [b, 784] 87 # y: [b] 88 x = tf.reshape(x,[-1,28*28]) 89 90 # [b, 10] 每一個樣本有10個預測值 91 logits = model(x) #沒有經過激活函數處理得到結果 92 93 # logits => prob, [b, 10] 94 prob = tf.nn.softmax(logits, axis=1) #壓縮列,操作每一行,將每一行的每個數通過softmax處理 95 pred = tf.argmax(prob, axis=1)#預測 96 pred = tf.cast(pred, dtype=tf.int32) #將float32轉換為int32類型 97 # pred:[b] 取出了最大概率的索引即為預測值 98 # y: [b] 測試情況下,y不需要做one_hot 99 100 correct = tf.equal(pred,y) 101 correct = tf.reduce_sum(tf.cast(correct, tf.int32)) #ture轉換為int數字之后進行求和 102 total_correct += int(correct) #每一個循環的求和 103 104 total_num += x.shape[0] #計算樣本的總數 105 106 acc = total_correct/total_num #計算准確率 107 print(total_num) 108 print(epoch,"acc:",acc) 109 110 if __name__ == '__main__': 111 main()