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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

(Python)零起步数学+神经网络入门

發(fā)布時間:2024/8/23 python 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 (Python)零起步数学+神经网络入门 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

在這篇文章中,我們將在Python中從頭開始了解用于構(gòu)建具有各種層神經(jīng)網(wǎng)絡(luò)(完全連接,卷積等)的小型庫中的機(jī)器學(xué)習(xí)和代碼。最終,我們將能夠?qū)懗鋈缦聝?nèi)容:

假設(shè)你對神經(jīng)網(wǎng)絡(luò)已經(jīng)有一定的了解,這篇文章的目的不是解釋為什么構(gòu)建這些模型,而是要說明如何正確實(shí)現(xiàn)

逐層

我們這里需要牢記整個框架:

1.?????將數(shù)據(jù)輸入神經(jīng)網(wǎng)絡(luò)

2.?????在得出輸出之前,數(shù)據(jù)從一層流向下一層

3.?????一旦得到輸出,就可以計(jì)算出一個標(biāo)量誤差

4.?????最后,可以通過相對于參數(shù)本身減去誤差的導(dǎo)數(shù)來調(diào)整給定參數(shù)(權(quán)重或偏差)。

5.?????遍歷整個過程。

最重要的一步是第四步。?我們希望能夠擁有任意數(shù)量的層,以及任何類型的層。?但是如果修改/添加/刪除網(wǎng)絡(luò)中的一個層,網(wǎng)絡(luò)的輸出將會改變,誤差也將改變,誤差相對于參數(shù)的導(dǎo)數(shù)也將改變。無論網(wǎng)絡(luò)架構(gòu)如何、激活函數(shù)如何、損失如何,都必須要能夠計(jì)算導(dǎo)數(shù)。

為了實(shí)現(xiàn)這一點(diǎn),我們必須分別實(shí)現(xiàn)每一層

每個層應(yīng)該實(shí)現(xiàn)什么

?

我們可能構(gòu)建的每一層(完全連接,卷積,最大化,丟失等)至少有兩個共同點(diǎn):輸入輸出數(shù)據(jù)。

現(xiàn)在重要的一部分

?

假設(shè)給出一個層相對于其輸出(?E/?Y)誤差的導(dǎo)數(shù),那么它必須能夠提供相對于其輸入(?E/?X)誤差的導(dǎo)數(shù)

è?°????E?ˉ??é??????a?°?-????X?Y?ˉ??éμ???

??

我們可以使用鏈規(guī)則輕松計(jì)算?E/?X的元素:

為什么是?E/?X

對于每一層,我們需要相對于其輸入的誤差導(dǎo)數(shù),因?yàn)樗鼘⑹窍鄬τ?strong>前一層輸出的誤差導(dǎo)數(shù)。這非常重要,這是理解反向傳播的關(guān)鍵!在這之后,我們將能夠立即從頭開始編寫深度卷積神經(jīng)網(wǎng)絡(luò)!

花樣圖解

?

基本上,對于前向傳播,我們將輸入數(shù)據(jù)提供給第一層,然后每層的輸出成為下一層的輸入,直到到達(dá)網(wǎng)絡(luò)的末端。

對于反向傳播,我們只是簡單使用鏈規(guī)則來獲得需要的導(dǎo)數(shù)。這就是為什么每一層必須提供其輸出相對于其輸入的導(dǎo)數(shù)。

這可能看起來很抽象,但是當(dāng)我們將其應(yīng)用于特定類型的層時,它將變得非常清楚。現(xiàn)在是編寫第一個python類的好時機(jī)。

抽象基類:Layer

所有其它層將繼承的抽象類Layer會處理簡單屬性,這些屬性是輸入輸出以及前向反向方法。

from abc import abstractmethod # Base class class Layer:def __init__(self):self.input = None;self.output = None;self.input_shape = None;self.output_shape = None;# computes the output Y of a layer for a given input X@abstractmethoddef forward_propagation(self, input):raise NotImplementedError# computes dE/dX for a given dE/dY (and update parameters if any)@abstractmethoddef backward_propagation(self, output_error, learning_rate):raise NotImplementedError

正如你所看到的,在back_propagation函數(shù)中,有一個我沒有提到的參數(shù),它是learning_rate。?此參數(shù)應(yīng)該類似于更新策略或者在Keras中調(diào)用它的優(yōu)化器,為了簡單起見,我們只是通過學(xué)習(xí)率并使用梯度下降更新我們的參數(shù)。

全連接層

現(xiàn)在先定義并實(shí)現(xiàn)第一種類型的網(wǎng)絡(luò)層:全連接層或FC層。FC層是最基本的網(wǎng)絡(luò)層,因?yàn)槊總€輸入神經(jīng)元都連接到每個輸出神經(jīng)元。

前向傳播

每個輸出神經(jīng)元的值由下式計(jì)算:

使用矩陣,可以使用點(diǎn)積來計(jì)算每一個輸出神經(jīng)元的值:

當(dāng)完成前向傳播之后,現(xiàn)在開始做反向傳播。

反向傳播

正如我們所說,假設(shè)我們有一個矩陣,其中包含與該層輸出相關(guān)的誤差導(dǎo)數(shù)(?E/?Y)。?我們需要?:

1.關(guān)于參數(shù)的誤差導(dǎo)數(shù)(?E/?W,?E/?B)

2.關(guān)于輸入的誤差導(dǎo)數(shù)(?E/?X)

首先計(jì)算?E/?W,該矩陣應(yīng)與W本身的大小相同:對于ixj,其中i是輸入神經(jīng)元的數(shù)量,j是輸出神經(jīng)元的數(shù)量。每個權(quán)重都需要一個梯度

使用前面提到的鏈規(guī)則,可以寫出:

那么:

這就是更新權(quán)重的第一個公式!現(xiàn)在開始計(jì)算?E/?B:

同樣,?E/?B需要與B本身具有相同的大小,每個偏差一個梯度。?我們可以再次使用鏈規(guī)則:

得出結(jié)論:

現(xiàn)在已經(jīng)得到?E/?W?E/?B,我們留下?E/?X這是非常重要的,因?yàn)樗鼘ⅰ白饔谩睘橹皩拥?E/?Y。

再次使用鏈規(guī)則:

最后,我們可以寫出整個矩陣:

?????·2?????°FC?±?é?????a???????

? ?

編碼全連接層

現(xiàn)在我們可以用Python編寫實(shí)現(xiàn):

from layer import Layer import numpy as np# inherit from base class Layer class FCLayer(Layer):# input_shape = (1,i) i the number of input neurons# output_shape = (1,j) j the number of output neuronsdef __init__(self, input_shape, output_shape):self.input_shape = input_shape;self.output_shape = output_shape;self.weights = np.random.rand(input_shape[1], output_shape[1]) - 0.5;self.bias = np.random.rand(1, output_shape[1]) - 0.5;# returns output for a given inputdef forward_propagation(self, input):self.input = input;self.output = np.dot(self.input, self.weights) + self.bias;return self.output;# computes dE/dW, dE/dB for a given output_error=dE/dY. Returns input_error=dE/dX.def backward_propagation(self, output_error, learning_rate):input_error = np.dot(output_error, self.weights.T);dWeights = np.dot(self.input.T, output_error);# dBias = output_error# update parametersself.weights -= learning_rate * dWeights;self.bias -= learning_rate * output_error;return input_error;

激活層

到目前為止所做的計(jì)算都完全是線性的。用這種模型學(xué)習(xí)是沒有希望的,需要通過將非線性函數(shù)應(yīng)用于某些層的輸出來為模型添加非線性。

現(xiàn)在我們需要為這種新類型的層(激活層)重做整個過程!

不用擔(dān)心,因?yàn)榇藭r沒有可學(xué)習(xí)的參數(shù),過程會快點(diǎn),只需要計(jì)算?E/?X。

我們將f和f'分別稱為激活函數(shù)及其導(dǎo)數(shù)。

前向傳播

正如將看到的,它非常簡單。對于給定的輸入X,輸出是關(guān)于每個X元素的激活函數(shù),這意味著輸入輸出具有相同的大小

反向傳播

給出?E/?Y,需要計(jì)算?E/?X

注意,這里我們使用兩個矩陣之間的每個元素乘法(而在上面的公式中,它是一個點(diǎn)積)

編碼實(shí)現(xiàn)激活層

激活層的代碼非常簡單:

from layer import Layer # inherit from base class Layer class ActivationLayer(Layer):# input_shape = (1,i) i the number of input neuronsdef __init__(self, input_shape, activation, activation_prime):self.input_shape = input_shape;self.output_shape = input_shape;self.activation = activation;self.activation_prime = activation_prime;# returns the activated inputdef forward_propagation(self, input):self.input = input;self.output = self.activation(self.input);return self.output;# Returns input_error=dE/dX for a given output_error=dE/dY.# learning_rate is not used because there is no "learnable" parameters.def backward_propagation(self, output_error, learning_rate):return self.activation_prime(self.input) * output_error;

可以在單獨(dú)的文件中編寫一些激活函數(shù)以及它們的導(dǎo)數(shù),稍后將使用它們構(gòu)建ActivationLayer:

import numpy as np # activation function and its derivative def tanh(x):return np.tanh(x);def tanh_prime(x):return 1-np.tanh(x)**2;

損失函數(shù)

到目前為止,對于給定的層,我們假設(shè)給出了?E/?Y(由下一層給出)。但是最后一層怎么得到?E/?Y?我們通過簡單地手動給出最后一層的?E/?Y,它取決于我們?nèi)绾味x誤差。

網(wǎng)絡(luò)的誤差由自己定義,該誤差衡量網(wǎng)絡(luò)對給定輸入數(shù)據(jù)的好壞程度。有許多方法可以定義誤差,其中一種最常見的叫做MSE - Mean Squared Error:

其中y *和y分別表示期望的輸出實(shí)際輸出。你可以將損失視為最后一層,它將所有輸出神經(jīng)元吸收并將它們壓成一個神經(jīng)元。與其他每一層一樣,需要定義?E/?Y。除了現(xiàn)在,我們終于得到E!

以下是兩個python函數(shù),可以將它們放在一個單獨(dú)的文件中,將在構(gòu)建網(wǎng)絡(luò)時使用。

import numpy as np# loss function and its derivative def mse(y_true, y_pred):return np.mean(np.power(y_true-y_pred, 2));def mse_prime(y_true, y_pred):return 2*(y_pred-y_true)/y_true.size;

網(wǎng)絡(luò)類

到現(xiàn)在幾乎完成了!我們將構(gòu)建一個Network類來創(chuàng)建神經(jīng)網(wǎng)絡(luò),非常容易,類似于第一張圖片!

我注釋了代碼的每一部分,如果你掌握了前面的步驟,那么理解它應(yīng)該不會太復(fù)雜。

from layer import Layerclass Network:def __init__(self):self.layers = [];self.loss = None;self.loss_prime = None;# add layer to networkdef add(self, layer):self.layers.append(layer);# set loss to usedef use(self, loss, loss_prime):self.loss = loss;self.loss_prime = loss_prime;# predict output for given inputdef predict(self, input):# sample dimension firstsamples = len(input);result = [];# run network over all samplesfor i in range(samples):# forward propagationoutput = input[i];for layer in self.layers:# output of layer l is input of layer l+1output = layer.forward_propagation(output);result.append(output);return result;# train the networkdef fit(self, x_train, y_train, epochs, learning_rate):# sample dimension firstsamples = len(x_train);# training loopfor i in range(epochs):err = 0;for j in range(samples):# forward propagationoutput = x_train[j];for layer in self.layers:output = layer.forward_propagation(output);# compute loss (for display purpose only)err += self.loss(y_train[j], output);# backward propagationerror = self.loss_prime(y_train[j], output);# loop from end of network to beginningfor layer in reversed(self.layers):# backpropagate dEerror = layer.backward_propagation(error, learning_rate);# calculate average error on all sampleserr /= samples;print('epoch %d/%d error=%f' % (i+1,epochs,err));

構(gòu)建一個神經(jīng)網(wǎng)絡(luò)

最后!我們可以使用我們的類來創(chuàng)建一個包含任意數(shù)量層的神經(jīng)網(wǎng)絡(luò)!為了簡單起見,我將向你展示如何構(gòu)建......一個XOR。

from network import Network from fc_layer import FCLayer from activation_layer import ActivationLayer from losses import * from activations import * import numpy as np# training data x_train = np.array([[[0,0]], [[0,1]], [[1,0]], [[1,1]]]); y_train = np.array([[[0]], [[1]], [[1]], [[0]]]);# network net = Network(); net.add(FCLayer((1,2), (1,3))); net.add(ActivationLayer((1,3), tanh, tanh_prime)); net.add(FCLayer((1,3), (1,1))); net.add(ActivationLayer((1,1), tanh, tanh_prime));# train net.use(mse, mse_prime); net.fit(x_train, y_train, epochs=1000, learning_rate=0.1);# test out = net.predict(x_train); print(out);

同樣,我認(rèn)為不需要強(qiáng)調(diào)很多事情,只需要仔細(xì)訓(xùn)練數(shù)據(jù),應(yīng)該能夠先獲得樣本維度。例如,對于xor問題,樣式應(yīng)為(4,1,2)。

結(jié)果

$ python xor.py epoch 1/1000 error=0.322980 epoch 2/1000 error=0.311174 epoch 3/1000 error=0.307195 ... epoch 998/1000 error=0.000243 epoch 999/1000 error=0.000242 epoch 1000/1000 error=0.000242 [array([[ 0.00077435]]), array([[ 0.97760742]]), array([[ 0.97847793]]), array([[-0.00131305]])]

卷積層

這篇文章開始很長,所以我不會描述實(shí)現(xiàn)卷積層的所有步驟。但是,這是我做的一個實(shí)現(xiàn):

from layer import Layer from scipy import signal import numpy as np# inherit from base class Layer # This convolutional layer is always with stride 1 class ConvLayer(Layer):# input_shape = (i,j,d)# kernel_shape = (m,n)# layer_depth = output depthdef __init__(self, input_shape, kernel_shape, layer_depth):self.input_shape = input_shape;self.input_depth = input_shape[2];self.kernel_shape = kernel_shape;self.layer_depth = layer_depth;self.output_shape = (input_shape[0]-kernel_shape[0]+1, input_shape[1]-kernel_shape[1]+1, layer_depth);self.weights = np.random.rand(kernel_shape[0], kernel_shape[1], self.input_depth, layer_depth) - 0.5;self.bias = np.random.rand(layer_depth) - 0.5;# returns output for a given inputdef forward_propagation(self, input):self.input = input;self.output = np.zeros(self.output_shape);for k in range(self.layer_depth):for d in range(self.input_depth):self.output[:,:,k] += signal.correlate2d(self.input[:,:,d], self.weights[:,:,d,k], 'valid') + self.bias[k];return self.output;# computes dE/dW, dE/dB for a given output_error=dE/dY. Returns input_error=dE/dX.def backward_propagation(self, output_error, learning_rate):in_error = np.zeros(self.input_shape);dWeights = np.zeros((self.kernel_shape[0], self.kernel_shape[1], self.input_depth, self.layer_depth));dBias = np.zeros(self.layer_depth);for k in range(self.layer_depth):for d in range(self.input_depth):in_error[:,:,d] += signal.convolve2d(output_error[:,:,k], self.weights[:,:,d,k], 'full');dWeights[:,:,d,k] = signal.correlate2d(self.input[:,:,d], output_error[:,:,k], 'valid');dBias[k] = self.layer_depth * np.sum(output_error[:,:,k]);self.weights -= learning_rate*dWeights;self.bias -= learning_rate*dBias;return in_error;

它背后的數(shù)學(xué)實(shí)際上并不復(fù)雜!這是一篇很好的文章,你可以找到?E/?W,?E/?B和?E/?X的解釋和計(jì)算。

如果你想驗(yàn)證你的理解是否正確,請嘗試自己實(shí)現(xiàn)一些網(wǎng)絡(luò)層,如MaxPooling,Flatten或Dropout

GitHub庫

你可以在GitHub庫中找到用于該文章的完整代碼。

?

原文鏈接
本文為云棲社區(qū)原創(chuàng)內(nèi)容,未經(jīng)允許不得轉(zhuǎn)載。

總結(jié)

以上是生活随笔為你收集整理的(Python)零起步数学+神经网络入门的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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