1. 程式人生 > >深度學習(二)損失函式與梯度

深度學習(二)損失函式與梯度

文章目錄


25天看完了吳恩達的機器學習以及《深度學習入門》和《tensorflow實戰》兩本書,吳恩達的學習課程只學了理論知識,另外兩本書的程式碼自己敲了一遍,感覺過的太快,趁著跑cGAN的時間把兩本書的知識點總結下,然後繼續深度學習的課程。歡迎小夥伴一起學習~
另外,本文先把框架搭好,後續會一直補充細節和知識點。
最後,本文參考的書是《深度學習入門》齋藤康毅著,十分推薦初學者使用。

本文的程式碼地址

損失函式

之所以需要損失函式,是因為我們在優化模型時,需要通過損失函式來更新模型,不選擇識別精度的原因是因為識別精度對模型調整的敏感度不如損失函式。
損失函式有均方誤差、交叉熵誤差,上文提到交叉熵誤差通常和softmax一起計算即softmax_with_loss,這個通常用於單分類,而對於多分類,需要使用sigmoid函式,具體請看

一文搞懂交叉熵

#均方誤差
def mean_squared_error(y, t):
	return 0.5 * np.sum((y-t)**2)
#交叉熵誤差,具體公式推導可以看下吳恩達的機器學習教學
def cross_entropy_error(y, t):
	delta = 1e-7
	return -np.sum(t * np.log(y + delta))

這裡我們補充一個關於一個batch的交叉熵誤差的實現


def cross_entropy_error(y, t): # y是預測值,t是實際值
    if y.ndim == 1:
        t = t.
reshape(1, t.size) y = y.reshape(1, y.size) if t.size == y.size: t = t.argmax(axis=1) # 在列的維度上取獲得最大值的索引 batch_size = y.shape[0] # 這裡t為標籤形式,y為[batch_size,dim] return - np.sum(np.log(y[np.arange(batch_size), t])) / batch_size

當t為one-hot形式時,可以用以下程式碼實現

def cross_entrory_error
(y, t): if y.ndim ==1: t = t.reshape(1, t.size) y = y.reshape(1, y.size) batch_size = y.shape[0] return -np.sum(t * np.log(y + 1e-7)) / batch_size

梯度

利用微分求梯度的方法計算量太大,而誤差反向傳播演算法的出現提高了計算效率,誤差反向傳播演算法主要基於鏈式法則,主要有以下幾條規則。

1.如果是由a + b = y,則反向傳播時a b 的梯度相等,且等於y的梯度
2.如果是a * b = y,則反向傳播時a b 的梯度分別為b a,如果是矩陣運算會涉及到矩陣轉換
3.複雜的計算可以拆解成簡單的元運算來計算梯度

我們以全連線為例:y = xw + b
首先拆解為x
w 和 b,按照上述原則,假設y的梯度為1,x*w 和 b的梯度等於y處的梯度也為1,x 和 w的梯度按照第二條原則,則梯度分別為w 和 x,當前計算沒有考慮矩陣,如果是矩陣運算w和x都需要做轉置,具體見以下程式碼。此處介紹的很粗糙,僅限於初步理解。後續補幾張圖哈
下面給出幾個重點層包含反向傳播演算法的類。
全連線層的類

class Affine:
    def __init__(self, W, b):
        self.W = W
        self.b = b
        self.x = None
        self.original_x_shape = None
        self.dW = None
        self.db = None
    def forward(self, x):
        self.original_x_shape = x.shape
        x = x.reshape(x.shape[0], -1)
        self.x = x
        out = np.dot(self.x, self.W) + self.b
        return out
    def backward(self, dout):
        dx = np.dot(dout, self.W.T)
        self.dW = np.dot(self.x.T, dout)
        self.db = np.sum(dout, axis=0)
        # for tensor
        dx = dx.reshape(*self.original_x_shape)
        return dx