一、reactsuper的作用
在進行神經網絡的設計時,我們通常會添加一些非線性函數對隱藏層進行激活,這些非線性函數被稱為激活函數,這些函數的作用在於增加模型的複雜度,以更好地擬合訓練數據。relu激活函數是非常常用的一種,因為其相比於其他函數來說計算速度比較快,同時也相對不容易出現梯度消失的情況。
relu 函數可以定義為 max(0,x),它對非負值返回輸入值(直接傳輸到輸出端),而對負值返回0。在整個網絡中,relu函數負責非線性轉換從而增強網絡的表達能力,甚至可以將低維的輸入空間映射到高維的特徵空間。
def relu(x): return np.maximum(0, x)
二、relu層的作用
在構建卷積神經網絡時,經常使用的一個層是 relu 層,這個層的作用就是應用 relu 函數到每一個輸入神經元,這樣輸出就不再是線性的而是非線性的,並能夠在跟小的計算負載下進行擬合。由於 relu 可以自動執行去除線性軸大多數部分的工作,因此可以被看作是一個類似降維的操作。
在網絡的實現上,relu層往往添加在卷積層或全連接層後面,起到增強層數的效果,並能提高模型表現。其主要的作用是在計算神經元的加權和時,能夠將負數直接變為0,這樣就能強制網絡學習到較為魯棒的特徵。當 relu 激活函數提取的特徵能夠很好地識別訓練數據的特徵時,就可以用來對未知數據進行預測。
class ReLU(Layer): def forward(self, x): self.x = x return np.maximum(0, x) def backward(self, grad): grad[self.x < 0] = 0 return grad
三、relu函數使用方法
在使用 relu 函數時,我們可以直接調用 np.maximum(0,x) 函數,其中 x 是輸入的一個向量、矩陣或張量等。同時,也可以使用類似 Keras 這樣的深度學習框架內置的 relu 層,來簡化我們對 relu 函數的使用。例如在 Keras 中,我們可以直接定義一個激活函數層使用 relu 激活函數。
from keras.layers import Activation from keras.layers import Dense model = Sequential([ Dense(units=64, input_shape=(784,)), Activation('relu'), Dense(units=10), Activation('softmax') ])
四、relu函數優缺點
我們知道,使用激活函數的主要原因是為了增強神經網絡的非線性能力,以更好地擬合訓練數據。而 relu 作為其中的一種激活函數,它的主要優點有兩個:
一方面是計算速度相對較快,這是由於 relu 函數計算簡單,僅需要一個比較運算和一個取最大值的操作即可;
另一方面是可以有效避免梯度消失的問題,當神經網絡的深度增加時,使用 sigmoid 或 tanh 等函數作為激活函數時,往往會出現梯度消失的情況,從而導致無法進行有效的反向傳播。而 relu 函數的導數在大於0時為1,在小於等於0時為0,這樣就保證了當值為0時,導數仍然為0,但並不會像 sigmoid、tanh 函數那樣導致梯度消失。
但是,relu 函數也存在缺點,主要原因在於其輸入小於0時對應的導數為0。這種情況稱之為“神經元死亡”,如果這種情況發生在大量的神經元中,就可能導致整個網絡的學習過程被破壞,無法進行訓練。一種改進的方法是使用 LeakyReLU 或 PRelu 等函數替代 relu 函數,這些函數在輸入小於0時的導數不再為0,從而避免了“神經元死亡”的情況。
五、對relu改進後的激活函數
經過不斷改進,出現了一些可以替代 relu 函數的激活函數,比如參數 ReLU (PReLU) 和 Exponential Linear Units (ELU) 等。PReLU 是基於參數的 ReLU 函數,不同於傳統的“輸入小於0時輸出0”的數值,PReLU 使用學習到的參數來將多數負輸入映射到非零輸出,以散布有用的梯度。比如這類函數可以解決 relu 導致的神經元死亡問題。
class PreLU(Layer): def __init__(self, dim): self.dim = dim self.alpha = np.random.normal(size=(dim,)) self.alpha[self.alpha=0 out = np.copy(x) out[out<0] *= self.alpha[np.newaxis,:] return out def backward(self, grad): grad[self.mask] = 1 grad[~self.mask] = self.alpha[~self.mask] return grad
六、卷積神經網絡中relu層的作用
在卷積神經網絡中,常常使用 relu 函數作為激活函數,同時將其添加在卷積層和池化層之後。這種方式的主要作用在於,在輸入層和輸出層之間添加非線性映射,以提高模型的表達能力,在卷積層後應用 relu 函數,可以將負數直接變為0,這樣就能強制網絡學習到較為魯棒的特徵。
在使用 relu 函數的同時,我們還需要對其超參數進行調整,以達到較好的效果。超參數的主要有兩個:滑動窗口大小和步幅。其中滑動窗口大小是指單次取出的可能與卷積層大小相同或更大的圖像塊;而步幅則是指窗口每次滑動的距離。通過調整這兩個超參數,我們可以有效地提高卷積神經網絡的效果。
class Conv: def __init__(self, in_channel, out_channel, kernel_size, stride=1, bias=True): self.w = np.random.randn(out_channel, in_channel, kernel_size, kernel_size) self.b = np.zeros((out_channel, 1)) if bias else None self.stride = stride self.kernel_size = kernel_size def forward(self, x): n, c, h, w = x.shape hh = int((h - self.kernel_size) / self.stride) + 1 ww = int((w - self.kernel_size) / self.stride) + 1 out = np.zeros((n, self.w.shape[0], hh, ww)) self.x_cache = x for example in range(n): for ch in range(self.w.shape[0]): for i in range(hh): for j in range(ww): out[example, ch, i, j] = np.sum(x[example, :, i*self.stride:i*self.stride+self.kernel_size, j*self.stride:j*self.stride+self.kernel_size] * self.w[ch, :, :, :]) if self.b is not None: out += self.b.reshape(1, self.b.shape[0], 1, 1) return out def backward(self, grad_out): n, c, h_out, w_out = grad_out.shape _, _, h_in, w_in = self.x_cache.shape grad_w = np.zeros_like(self.w) grad_x = np.zeros_like(self.x_cache) for example in range(n): for ch in range(c): for i in range(h_out): for j in range(w_out): grad_x[example, ch, i*self.stride:i*self.stride+self.kernel_size, j*self.stride:j*self.stride+self.kernel_size] += grad_out[example, :, i, j] * self.w[:, ch, :, :] grad_w[:, ch, :, :] += grad_out[example, :, i, j][:, np.newaxis, np.newaxis] * self.x_cache[example, :, i*self.stride:i*self.stride+self.kernel_size, j*self.stride:j*self.stride+self.kernel_size] self.w -= self.lr * grad_w / n if self.b is not None: self.b -= self.lr * np.mean(grad_out, axis=(0, 2, 3), keepdims=True) return grad_x
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/159789.html