日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

手撕神经网络(1)——神经网络的基本组件

發(fā)布時間:2023/12/20 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 手撕神经网络(1)——神经网络的基本组件 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1.你玩過樂高積木嗎?——寫這篇文章的目的

隨著深度學習的火熱,越來越多的領域,越來越多的人,開始使用深度學習。當然,你可以使用現(xiàn)有的深度學習框架如tf和torch。然而,這些框架都是高度封裝的,讀者雖然用著好用,但是這對于想深入理解神經(jīng)網(wǎng)絡的讀者不是最好的選擇。因此,有一些想要深入理解神經(jīng)網(wǎng)絡的讀者就想要使用源代碼對神經(jīng)網(wǎng)絡進行復現(xiàn)。
很多讀者在網(wǎng)上尋找手撕神經(jīng)網(wǎng)絡的源代碼,卻發(fā)現(xiàn)很多都是面向過程的:定義一堆函數(shù),函數(shù)與函數(shù)之間相互交叉調(diào)用,然后使用一個非常冗長的函數(shù)把他們組合,然后放一堆代碼進行訓練。。。這對新手十分不友好。
如果你對后文中反向傳播和計算圖理解起來有困難,可以看我的這篇文章:https://blog.csdn.net/weixin_57005504/article/details/126159919?spm=1001.2014.3001.5501
我們知道,python是一門面向?qū)ο缶幊痰恼Z言,因此,我們希望能夠利用這一點,將神經(jīng)網(wǎng)絡中的各個組件封裝成一個類,然后將這些類拼裝,就成了我們的神經(jīng)網(wǎng)絡,就像搭建積木一樣。

2.Affine層

初始化

什么是Affine層?所謂的Affine層就是,接受一個輸入X,輸出XW+BXW+BXW+B的神經(jīng)網(wǎng)絡層。因此,該層需要具有屬性w,b。
不要忘了,我們上面所討論的僅僅是該層的正向傳播的輸出,該層在反向傳播時,還需要能夠輸出對W和B的梯度,同時,我們在后面的梯度下降的過程中還希望能夠獲取這兩個梯度,以更新權重,所以還要有屬性dW,dB,因此,我們對該類的初始化代碼:

class Affine:def __init__(self, w, b):self.w = wself.b = bself.x = Noneself.dw = Noneself.db = None

前向傳播

前向傳播的代碼相當簡單,只需要完成XW+BXW+BXW+B的計算即可:

def forward(self, x):"""x是n行 一維行向量組成的批"""self.x = xout = np.dot(x, self.w) + self.breturn out

反向傳播

該方法接受一個后面一層反向傳播過來的梯度dout,通過以下公式完成對dW,dB的梯度的計算以及反向傳播:
?Loss?W=XT?dout\frac{\partial Loss}{\partial W}=X^T·dout?W?Loss?=XT?dout
?Loss?B=∑dout\frac{\partial Loss}{\partial B}=\sum dout?B?Loss?=dout
所以,代碼如下:

def backward(self, dout):dx = dout.dot(self.w.T)self.dw = np.dot(self.x.T, dout)self.db = np.sum(dout, axis=0)return dx

3.Sigmoid層

初始化

首先,需要明確sigmoid函數(shù):
sigmoid(x)=11+e?xsigmoid(x)=\frac{1}{1+e^{-x}}sigmoid(x)=1+e?x1?
該函數(shù)有一個很好的性質(zhì):
y=sigmoid(x)y=sigmoid(x)y=sigmoid(x),則有dydx=y(1?y)\frac{dy}{dx}=y(1-y)dxdy?=y(1?y)。
因此,我們發(fā)現(xiàn),該層的正向輸出yyy在計算梯度中也可以巧妙地用到,所以,對于輸出yyy,我們可將其添加到該類的屬性,以便前向傳播的結果在反向傳播中也能方便的用到,故其初始化的代碼:

class Sigmoid:def __init__(self):self.out = None

前向傳播

直接帶入sigmoidsigmoidsigmoid函數(shù)計算即可:

def forward(self, x):out = 1 / (1 + np.exp(-x))self.out = outreturn out

反向傳播

如前所述,dydx=y(1?y)\frac{dy}{dx}=y(1-y)dxdy?=y(1?y)。則有:

def backward(self, dout):dx = dout * (1.0 - self.out) * self.outreturn dx

4.ReLU層

該層和Sigjoid層類似,也是一個激活層,這里對于代碼的講解不再贅述:

class ReLU:def __init__(self, ):self.out = Nonedef forward(self, x):mask = (x < 0)self.mask = maskout = x.copy()out[mask] = 0return outdef backward(self, dout):dout[self.mask] = 0return dout

5.MSELoss層

初始化

對于回歸問題,一個經(jīng)典的LossLossLoss 函數(shù)是選用均方誤差計算:
Loss=1n∑i=1n(y^?ylabel)2Loss=\frac{1}{n}\sum_{i=1}^{n} (\hat y-y_{label})^2 Loss=n1?i=1n?(y^??ylabel?)2
其中,y^\hat yy^?是網(wǎng)絡的預測值,而ylabely_{label}ylabel?是標簽。
求導可得:
?Loss?y^=1n(y^?ylabel)\frac{\partial Loss}{\partial \hat y}=\frac{1}{n}(\hat y -y_{label})?y^??Loss?=n1?(y^??ylabel?)
你可能好奇,為什么是1n\frac{1}{n}n1?,而不是2n\frac{2}{n}n2?呢?這是因為在后面使用梯度下降法更新權重的時候,還需要乘以一個學習率α\alphaα,所以這里分子是1和2沒有區(qū)別,而我們再寫代碼時,我們習慣分子是1.
從上面的分析可知,我們的y^,ylabel\hat y ,y_{label}y^?,ylabel? 在正向傳播和反向傳播中都出現(xiàn)了,所以為了方便傳遞,我們將此二者添加到類的屬性中:

class MSELoss:"""均方根誤差層"""def __init__(self):self.pre = Noneself.y_true = Noneself.loss = None

前向傳播

def forward(self, pre, y_true):self.pre = prem, n = self.pre.shapeself.y_true = y_true.reshape(m, n)assert self.pre.shape == self.y_true.shapereturn np.mean(np.power((pre - y_true), 2)) # loss 標量

反向傳播

def backward(self, dout, ):return dout * (self.pre-self.y_true)

時間和經(jīng)理有限,對于文章中有的細節(jié),我后面會逐漸更新上去,所以歡迎收藏和關注我的文章!

——by 神采的二舅

總結

以上是生活随笔為你收集整理的手撕神经网络(1)——神经网络的基本组件的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。