Loss
1. L2損失
tf.nn.l2_loss(t, name=None)
output = sum(t ** 2) / 2
2. 交叉熵損失
a是經過sigmoid激活的,在0到1之間
交叉熵爲什麼能作爲代價函數?
首先,它是非負的,加號裏的每一項都是負的,整個式子前面是負的,負負得正
其次,實際輸出值很接近期望輸出值時,交叉熵會非常接近0
它有均方代價函數不具備的特徵,能夠避免學習速率降低的問題
TensorFlow四個交叉熵函數
tf.nn.sigmoid_cross_entrogy_with_logits
tf.nn.softmax_cross_entrogy_with_logits
tf.nn.sparse_softmax_cross_entrogy_with_logits
tf.nn.weighted_cross_entrogy_with_logits
(1)
tf.nn.sigmoid_cross_entrogy_with_logits(logits, targets, name=None)
# logits: 網絡模型中的W*X矩陣,不需要經過sigmoid
# targets: 標籤值,可包含多個1或0,和logits的shape相同
不能用於多分類問題,例如一個實際取值範圍爲0-4,目標標籤y也是0-4,實際取值經過sigmoid後取值範圍變爲0-1,ln(.)是負的,公式中(1-y)會出現負數,而且-yln(a)有可能會非常大
(2)
對於單目標多分類問題,分類之間是獨立且互斥的,這時候就要用 softmax的交叉熵函數
- 先看softmax激活:
tf.nn.softmax(logits, dim=-1, name=None)
# logits:Tensor
# dim: 默認爲-1,最後一個維度
softmax = exp(logits) / reduce_sum(exp(logits), dim)
softmax輸出0-1之間的概率分佈
- logsoftmax激活:
tf.nn.log_softmax(logits, dim=-1, name=None)
logsoftmax = logits - log(reduce_sum(exp(logits), dim))
- softmax交叉熵損失:
tf.nn.softmax_cross_entrogy_with_logits(logits, labels, dim=-1, name=None)
注意:只適合單目標二分類或者多分類問題
對於多分類問題,我們需要對輸入進行編碼,例如我們的年齡分爲5類,人工編碼爲0,1,2,3,4,因爲輸出值是5維特徵,因此我們需要人工做onehot encoding,分別編碼爲00001,00010,00100,01000,10000,作爲函數的輸入
(3)
tf.nn.sparse_softmax_cross_entrogy_with_logits(logits, labels, name=None)
# logits: shape=[batch_size, num_classes]
# labels: shape=[batch_size, num_classes] num_classes從0開始編碼
是softmax_cross_entrogy_with_logits
的易用版本,對於CIFAR-10、ImageNet都是多類單標籤問題,label都是0,1,2,3,…每次轉成onehot encoding比較麻煩,使用sparse_softmax_cross_entrogy_with_logits
,TensorFlow內部進行編碼
(4)
tf.nn.weights_cross_entrogy_with_logits(targets, logits, pos_weight, name=None)
let x = logits, z = targets q = pos_weights
是softmax_cross_entrogy_with_logits
的拓展版,pos_weight
的目的是增加或者減少正樣本在算Cross Entropy的損失,原理:在正樣本算出的值前面乘以一個係數
loss = qz * -log(sigmoid(x)) + (1 - z) * -log(1 - sigmoid(x))
=(1 - z) * x + (1 + (q - 1) * z) * log(1 + exp( - x))
Optimizer
兩個作用:計算損失的梯度,將梯度應用到變量的更新中去
Optimizer是一個基類:class tf.train.Optimizer
使用的時候,需要實例化它的一個子類,如下面的例子:
# 傳入學習率參數創建一個優化器類的對象實例
opt = GradientDescentOptimizer(learning_rate=0.1)
# 添加一系列操作節點到計算圖最小化cost來更新變量
opt_op = opt.minimize(cost, var_list=<list of variables>) # 傳入損失函數和變量列表,var_list不傳的話更新的是所有的變量
用處理的梯度更新模型參數
調用minimize()
有兩個連續步驟:計算梯度,應用到變量上,如下:
- 使用
comepute_gradients()
計算梯度 - 使用
apply_gradients()
把處理過的梯度用來更新varibles
如果想在應用在變量之前對梯度做一些特別處理時,需要在這兩步之間再加上一些處理:
- 使用
comepute_gradients()
計算梯度 - 根據需求對計算出的梯度做一些處理
- 使用
apply_gradients()
把處理過的梯度用來更新varibles
例子:
# 傳入學習率參數創建一個優化器類的對象實例
opt = GradientDescentOptimizer(learning_rate=0.1)
# 計算梯度
# grads_and_vars是一個元組列表(變量所對應的梯度, 變量)
grads_and_vars = opt.compute_gradients(loss, <list of variables>)
# 對梯度元組中的每一個值進行操作
capped_grads_and_vars = [(MyCapper(gc[0]), gv[1]) for gv in grads_and_vars]
# 用新的梯度更新參數
opt.apply_gradients(capped_grads_and_vars)
優化器子類:
10個
tf.train.GradientDescentOptimizer()
tf.train.ProximalGradientDescentOptimizer()
tf.train.AdagradOptimizer()
tf.train.ProximalAdagradOptimizer()
tf.train.AdagradDAOptimizer()
tf.train.AdadeltaOptimizer()
tf.train.AdamOptimizer()
tf.train.RMSPropOptimizer()
tf.train.FtrlOptimizer()
tf.train.MomentumOptimizer()
這篇也有講:https://blog.csdn.net/fzp95/article/details/83018744
比較
conv+relu+maxpool+linear_fc
tf.train.GradientDescentOptimizer()
tf.train.ProximalGradientDescentOptimizer()
tf.train.AdagradOptimizer()
tf.train.ProximalAdagradOptimizer()
tf.train.AdagradDAOptimizer()
tf.train.AdadeltaOptimizer() 在小網絡上表現很差
tf.train.AdamOptimizer() 學習率選取很重要,不能太小,也不能太大,合適的學習率優化效果好。
tf.train.FtrlOptimizer() 最優學習率爲0.1 不能太小
tf.train.MomentumOptimizer() 對於小學習率能夠快速下降
tf.train.RMSPropOptimizer() 對學習率變化不太敏感 而且優化效果好