<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一文帶你入門深度學習

          共 11898字,需瀏覽 24分鐘

           ·

          2020-12-04 11:08

          點擊上方“Jack Cui”,選擇“設(shè)為星標

          第一時間關(guān)注技術(shù)干貨!


          一、前言

          大家好,我是?Jack。

          承諾的圖解?AI 算法系列教程,今天它來了

          最近,寫了很多 AI 趣味性算法教程,目前寫了 14 篇,其中反響不錯的教程有:

          ???你的紅色高跟鞋,AI 換臉技術(shù)初體驗???讓圖片動起來,特朗普和蒙娜麗莎深情合唱???為藝術(shù)而生的驚艷算法???百年老照片修復算法,那些高顏值的父母!???「完美復刻」的人物肖像畫生成

          讀者們玩得很開心,對 AI 算法、深度學習也來了興趣。

          但僅限于開心地跑包,這最多只能算是「調(diào)包俠」。

          既然來了興致,何不趁熱打鐵,多學些基礎(chǔ)知識,爭取早日邁入「調(diào)參俠」的行列。

          大家一起煉丹,一起修煉。

          圖解 AI 算法系列教程,不僅僅是涉及深度學習基礎(chǔ)知識,還會有強化學習、遷移學習等,再往小了講就比如拆解目標檢測算法,對抗神經(jīng)網(wǎng)絡(GAN)等等。

          如果你喜歡這個 AI 算法系列教程,一定要讓我知道,轉(zhuǎn)發(fā)在看支持,更文更有動力!

          難度會逐漸增加,今天咱先熱熱身,來點輕松的,當作這個系列的開篇。

          二、深度學習

          深度學習(Deep Learning)是近年來發(fā)展十分迅速的研究領(lǐng)域,并且在人 工智能的很多子領(lǐng)域都取得了巨大的成功。從根源來講,深度學習是機器學習的一個分支。

          深度學習就是從有限樣例中通過算法總結(jié)出一般性的規(guī)律,并可以應用到新的未知數(shù)據(jù)上。

          比如,我們可以從一些歷史病例的集合中總結(jié)出癥狀疾病之間的規(guī)律。這樣,當有新的病人時,我們可以利用總結(jié)出來的規(guī)律來判斷這個病人得了什么疾病。

          那想學深度學習,要掌握哪些基礎(chǔ)知識?直接上圖

          理了小半天的思維導圖,建議收藏

          深度學習主要由上圖所示的幾個部分組成,想學一個深度學習算法的原理,就看它是什么樣的網(wǎng)絡結(jié)構(gòu),Loss 是怎么計算的,預處理和后處理都是怎么做的。

          權(quán)重初始化和學習率調(diào)整策略、優(yōu)化算法、深度學習框架就那么多,并且也不是所有都要掌握,比如深度學習框架,Pytorch 玩的溜,就能應付大多數(shù)場景。

          先有個整體的認知,然后再按照這個思維導圖,逐個知識點學習,最后整合到一起,你會發(fā)現(xiàn),你也可以自己實現(xiàn)各種功能的算法了

          深度學習的主要目的是從數(shù)據(jù)中自動學習到有效的特征表示,它是怎么工作的?那得從神經(jīng)元說起。

          隨著神經(jīng)科學、認知科學的發(fā)展,我們逐漸知道人類的智能行為都和大腦活動有關(guān)。

          人腦神經(jīng)系統(tǒng)[1]是一個非常復雜的組織,包含近 860 億個神經(jīng)元,這 860 億的神經(jīng)元構(gòu)成了超級龐大的神經(jīng)網(wǎng)絡

          我們知道,一個人的智力不完全由遺傳決定,大部分來自于生活經(jīng)驗。也就是說人腦神經(jīng)網(wǎng)絡是一個具有學習能力的系統(tǒng)。

          不同神經(jīng)元之間的突觸有強有弱,其強度是可以通過學習(訓練)來不斷改變的,具有一定的可塑性,不同的連接又形成了不同的記憶印痕。

          而深度學習的神經(jīng)網(wǎng)絡,就是受人腦神經(jīng)網(wǎng)絡啟發(fā),設(shè)計的一種計算模型,它從結(jié)構(gòu)、實現(xiàn)機理和功能上模擬人腦神經(jīng)網(wǎng)絡。

          比如下圖就是一個最簡單的前饋神經(jīng)網(wǎng)絡,第 0 層稱為輸入層,最后一層稱為輸出層,其他中間層稱為隱藏層

          那神經(jīng)網(wǎng)絡如何工作的?網(wǎng)絡層次結(jié)構(gòu)、損失函數(shù)、優(yōu)化算法、權(quán)重初始化、學習率調(diào)整都是如何運作的?

          反向傳播給你答案。前方,高能預警

          三、反向傳播

          要想弄懂深度學習原理,必須搞定反向傳播[2]和鏈式求導法則。

          先說思維導圖里的網(wǎng)絡層級結(jié)構(gòu),一個神經(jīng)網(wǎng)絡,可復雜可簡單,為了方便推導,假設(shè),你有這樣一個網(wǎng)絡層:

          第一層是輸入層,包含兩個神經(jīng)元 i1, i2 和截距項 b1(偏置);

          第二層是隱含層,包含兩個神經(jīng)元 h1, h2 和截距項 b2 ;

          第三層是輸出層 o1 和 o2 ,每條線上標的 wi 是層與層之間連接的權(quán)重,激活函數(shù)我們默認為 sigmoid 函數(shù)。

          在訓練這個網(wǎng)絡之前,需要初始化這些 wi 權(quán)重,這就是權(quán)重初始化,這里就有不少的初始化方法,我們選擇最簡單的,隨機初始化

          隨機初始化的結(jié)果,如下圖所示:

          其中,輸入數(shù)據(jù):?i1=0.05, i2=0.10;

          輸出數(shù)據(jù)(期望的輸出) : o1=0.01, o2=0.99;

          初始權(quán)重: w1=0.15, w2=0.20, w3=0.25, w4=0.30, w5=0.40, w6=0.45, w7=0.50, w8=0.55。

          目標:給出輸入數(shù)據(jù) i1, i2(0.05 和 0.10),使輸出盡可能與原始輸出o1, o2(0.01 和 0.99)接近。

          神經(jīng)網(wǎng)絡的工作流程分為兩步:前向傳播反向傳播

          1、前向傳播

          前向傳播是將輸入數(shù)據(jù)根據(jù)權(quán)重,計算到輸出層。

          1)輸入層->隱藏層

          計算神經(jīng)元 h1 的輸入加權(quán)和:

          神經(jīng)元后面,要跟個激活層,從而引入非線性因素,這就像人的神經(jīng)元一樣,讓細胞處于興奮抑制的狀態(tài)。

          數(shù)學模擬的形式就是通過激活函數(shù),大于閾值就激活,反之抑制。

          常用的激活函如思維導圖所示,這里以非常簡單的 sigmoid 激活函數(shù)為例,它的函數(shù)形式如下:

          數(shù)學公式:

          使用 sigmoid 激活函數(shù),繼續(xù)計算,神經(jīng)元 h1 的輸出 o_h1:

          同理,可計算出神經(jīng)元 h2 的輸出 o_h2:

          2)隱藏層->輸出層

          計算輸出層神經(jīng)元 o1 和 o2 的值:

          這樣前向傳播的過程就結(jié)束了,根據(jù)輸入值和權(quán)重,我們得到輸出值為[0.75136079, 0.772928465],與實際值(目標)[0.01, 0.99]相差還很遠,現(xiàn)在我們對誤差進行反向傳播,更新權(quán)值,重新計算輸出。

          2、反向傳播

          前向傳播之后,發(fā)現(xiàn)輸出結(jié)果與期望相差甚遠,這時候就要更新權(quán)重了。

          所謂深度學習的訓練(煉丹),學的就是這些權(quán)重,我們期望的是調(diào)整這些權(quán)重,讓輸出結(jié)果符合我們的期望。

          而更新權(quán)重的方式,依靠的就是反向傳播。

          1)計算總誤差

          一次前向傳播過后,輸出值(預測值)與目標值(標簽值)有差距,那得衡量一下有多大差距。

          衡量的方法,就是用思維導圖中的損失函數(shù)。

          損失函數(shù)也有很多,咱們還是選擇一個最簡單的,均方誤差(MSE loss)。

          均方誤差的函數(shù)公式:

          根據(jù)公式,直接計算預測值與標簽值的總誤差:

          有兩個輸出,所以分別計算 o1 和 o2 的誤差,總誤差為兩者之和:

          2)隱含層->輸出層的權(quán)值更新

          以權(quán)重參數(shù) w5 為例,如果我們想知道 w5 對整體誤差產(chǎn)生了多少影響,可以用整體誤差對 w5 求偏導求出。

          這是鏈式法則,它是微積分中復合函數(shù)的求導法則,就是這個:

          根據(jù)鏈式法則易得:

          下面的圖可以更直觀的看清楚誤差是怎樣反向傳播的:

          現(xiàn)在我們來分別計算每個式子的值:

          計算

          計算:

          這一步實際上就是對sigmoid函數(shù)求導,比較簡單,可以自己推導一下。

          計算

          最后三者相乘:

          這樣我們就計算出整體誤差E(total)對 w5 的偏導值。

          回過頭來再看看上面的公式,我們發(fā)現(xiàn):

          為了表達方便,用來表示輸出層的誤差:

          因此,整體誤差E(total)對w5的偏導公式可以寫成:

          如果輸出層誤差計為負的話,也可以寫成:

          最后我們來更新 w5 的值:

          這個更新權(quán)重的策略,就是思維導圖中的優(yōu)化算法 是學習率,我們這里取0.5。

          如果學習率要根據(jù)迭代的次數(shù)調(diào)整,那就用到了思維導圖中的學習率調(diào)整

          同理,可更新w6,w7,w8:

          3)隱含層->隱含層的權(quán)值更新

          方法其實與上面說的差不多,但是有個地方需要變一下,在上文計算總誤差對 w5 的偏導時,是從out(o1)->net(o1)->w5,但是在隱含層之間的權(quán)值更新時,是out(h1)->net(h1)->w1,而 out(h1) 會接受 E(o1) 和 E(o2) 兩個地方傳來的誤差,所以這個地方兩個都要計算。

          計算

          先計算:

          同理,計算出:

          兩者相加得到總值:

          再計算:

          再計算:

          最后,三者相乘:

          為了簡化公式,用 sigma(h1) 表示隱含層單元 h1 的誤差:

          最后,更新 w1 的權(quán)值:

          同理,額可更新w2,w3,w4的權(quán)值:

          這樣誤差反向傳播法就完成了,最后我們再把更新的權(quán)值重新計算,不停地迭代。

          在這個例子中第一次迭代之后,總誤差E(total)由0.298371109下降至0.291027924。

          迭代10000次后,總誤差為0.000035085,輸出為[0.015912196,0.984065734](原輸入為[0.01,0.99]),證明效果還是不錯的。

          這就是整個神經(jīng)網(wǎng)絡的工作原理,如果你跟著思路,順利看到這里。那么恭喜你,深度學習的學習算是通過了一關(guān)。

          四、Python 實現(xiàn)

          整個過程,可以用 Python 代碼實現(xiàn)。

          #coding:utf-8
          import?random
          import?math

          #
          #???參數(shù)解釋:
          #???"pd_"?:偏導的前綴
          #???"d_"?:導數(shù)的前綴
          #???"w_ho"?:隱含層到輸出層的權(quán)重系數(shù)索引
          #???"w_ih"?:輸入層到隱含層的權(quán)重系數(shù)的索引

          class?NeuralNetwork:
          ????LEARNING_RATE?=?0.5

          ????def?__init__(self,?num_inputs,?num_hidden,?num_outputs,?hidden_layer_weights?=?None,?hidden_layer_bias?=?None,?output_layer_weights?=?None,?output_layer_bias?=?None):
          ????????self.num_inputs?=?num_inputs

          ????????self.hidden_layer?=?NeuronLayer(num_hidden,?hidden_layer_bias)
          ????????self.output_layer?=?NeuronLayer(num_outputs,?output_layer_bias)
          ????????self.init_weights_from_inputs_to_hidden_layer_neurons(hidden_layer_weights)
          ????????self.init_weights_from_hidden_layer_neurons_to_output_layer_neurons(output_layer_weights)

          ????def?init_weights_from_inputs_to_hidden_layer_neurons(self,?hidden_layer_weights):
          ????????weight_num?=?0
          ????????for?h?in?range(len(self.hidden_layer.neurons)):
          ????????????for?i?in?range(self.num_inputs):
          ????????????????if?not?hidden_layer_weights:
          ????????????????????self.hidden_layer.neurons[h].weights.append(random.random())
          ????????????????else:
          ????????????????????self.hidden_layer.neurons[h].weights.append(hidden_layer_weights[weight_num])
          ????????????????weight_num?+=?1

          ????def?init_weights_from_hidden_layer_neurons_to_output_layer_neurons(self,?output_layer_weights):
          ????????weight_num?=?0
          ????????for?o?in?range(len(self.output_layer.neurons)):
          ????????????for?h?in?range(len(self.hidden_layer.neurons)):
          ????????????????if?not?output_layer_weights:
          ????????????????????self.output_layer.neurons[o].weights.append(random.random())
          ????????????????else:
          ????????????????????self.output_layer.neurons[o].weights.append(output_layer_weights[weight_num])
          ????????????????weight_num?+=?1

          ????def?inspect(self):
          ????????print('------')
          ????????print('*?Inputs:?{}'.format(self.num_inputs))
          ????????print('------')
          ????????print('Hidden?Layer')
          ????????self.hidden_layer.inspect()
          ????????print('------')
          ????????print('*?Output?Layer')
          ????????self.output_layer.inspect()
          ????????print('------')

          ????def?feed_forward(self,?inputs):
          ????????hidden_layer_outputs?=?self.hidden_layer.feed_forward(inputs)
          ????????return?self.output_layer.feed_forward(hidden_layer_outputs)

          ????def?train(self,?training_inputs,?training_outputs):
          ????????self.feed_forward(training_inputs)

          ????????#?1.?輸出神經(jīng)元的值
          ????????pd_errors_wrt_output_neuron_total_net_input?=?[0]?*?len(self.output_layer.neurons)
          ????????for?o?in?range(len(self.output_layer.neurons)):

          ????????????#??E/?z?
          ????????????pd_errors_wrt_output_neuron_total_net_input[o]?=?self.output_layer.neurons[o].calculate_pd_error_wrt_total_net_input(training_outputs[o])

          ????????#?2.?隱含層神經(jīng)元的值
          ????????pd_errors_wrt_hidden_neuron_total_net_input?=?[0]?*?len(self.hidden_layer.neurons)
          ????????for?h?in?range(len(self.hidden_layer.neurons)):

          ????????????#?dE/dy??=?Σ??E/?z??*??z/?y??=?Σ??E/?z??*?w??
          ????????????d_error_wrt_hidden_neuron_output?=?0
          ????????????for?o?in?range(len(self.output_layer.neurons)):
          ????????????????d_error_wrt_hidden_neuron_output?+=?pd_errors_wrt_output_neuron_total_net_input[o]?*?self.output_layer.neurons[o].weights[h]

          ????????????#??E/?z??=?dE/dy??*??z?/?
          ????????????pd_errors_wrt_hidden_neuron_total_net_input[h]?=?d_error_wrt_hidden_neuron_output?*?self.hidden_layer.neurons[h].calculate_pd_total_net_input_wrt_input()

          ????????#?3.?更新輸出層權(quán)重系數(shù)
          ????????for?o?in?range(len(self.output_layer.neurons)):
          ????????????for?w_ho?in?range(len(self.output_layer.neurons[o].weights)):

          ????????????????#??E?/?w???=??E/?z??*??z?/?w??
          ????????????????pd_error_wrt_weight?=?pd_errors_wrt_output_neuron_total_net_input[o]?*?self.output_layer.neurons[o].calculate_pd_total_net_input_wrt_weight(w_ho)

          ????????????????#?Δw?=?α?*??E?/?w?
          ????????????????self.output_layer.neurons[o].weights[w_ho]?-=?self.LEARNING_RATE?*?pd_error_wrt_weight

          ????????#?4.?更新隱含層的權(quán)重系數(shù)
          ????????for?h?in?range(len(self.hidden_layer.neurons)):
          ????????????for?w_ih?in?range(len(self.hidden_layer.neurons[h].weights)):

          ????????????????#??E?/?w??=??E/?z??*??z?/?w?
          ????????????????pd_error_wrt_weight?=?pd_errors_wrt_hidden_neuron_total_net_input[h]?*?self.hidden_layer.neurons[h].calculate_pd_total_net_input_wrt_weight(w_ih)

          ????????????????#?Δw?=?α?*??E?/?w?
          ????????????????self.hidden_layer.neurons[h].weights[w_ih]?-=?self.LEARNING_RATE?*?pd_error_wrt_weight

          ????def?calculate_total_error(self,?training_sets):
          ????????total_error?=?0
          ????????for?t?in?range(len(training_sets)):
          ????????????training_inputs,?training_outputs?=?training_sets[t]
          ????????????self.feed_forward(training_inputs)
          ????????????for?o?in?range(len(training_outputs)):
          ????????????????total_error?+=?self.output_layer.neurons[o].calculate_error(training_outputs[o])
          ????????return?total_error

          class?NeuronLayer:
          ????def?__init__(self,?num_neurons,?bias):

          ????????#?同一層的神經(jīng)元共享一個截距項b
          ????????self.bias?=?bias?if?bias?else?random.random()

          ????????self.neurons?=?[]
          ????????for?i?in?range(num_neurons):
          ????????????self.neurons.append(Neuron(self.bias))

          ????def?inspect(self):
          ????????print('Neurons:',?len(self.neurons))
          ????????for?n?in?range(len(self.neurons)):
          ????????????print('?Neuron',?n)
          ????????????for?w?in?range(len(self.neurons[n].weights)):
          ????????????????print('??Weight:',?self.neurons[n].weights[w])
          ????????????print('??Bias:',?self.bias)

          ????def?feed_forward(self,?inputs):
          ????????outputs?=?[]
          ????????for?neuron?in?self.neurons:
          ????????????outputs.append(neuron.calculate_output(inputs))
          ????????return?outputs

          ????def?get_outputs(self):
          ????????outputs?=?[]
          ????????for?neuron?in?self.neurons:
          ????????????outputs.append(neuron.output)
          ????????return?outputs

          class?Neuron:
          ????def?__init__(self,?bias):
          ????????self.bias?=?bias
          ????????self.weights?=?[]

          ????def?calculate_output(self,?inputs):
          ????????self.inputs?=?inputs
          ????????self.output?=?self.squash(self.calculate_total_net_input())
          ????????return?self.output

          ????def?calculate_total_net_input(self):
          ????????total?=?0
          ????????for?i?in?range(len(self.inputs)):
          ????????????total?+=?self.inputs[i]?*?self.weights[i]
          ????????return?total?+?self.bias

          ????#?激活函數(shù)sigmoid
          ????def?squash(self,?total_net_input):
          ????????return?1?/?(1?+?math.exp(-total_net_input))

          ????def?calculate_pd_error_wrt_total_net_input(self,?target_output):
          ????????return?self.calculate_pd_error_wrt_output(target_output)?*?self.calculate_pd_total_net_input_wrt_input();

          ????#?每一個神經(jīng)元的誤差是由平方差公式計算的
          ????def?calculate_error(self,?target_output):
          ????????return?0.5?*?(target_output?-?self.output)?**?2

          ????def?calculate_pd_error_wrt_output(self,?target_output):
          ????????return?-(target_output?-?self.output)

          ????def?calculate_pd_total_net_input_wrt_input(self):
          ????????return?self.output?*?(1?-?self.output)

          ????def?calculate_pd_total_net_input_wrt_weight(self,?index):
          ????????return?self.inputs[index]


          #?文中的例子:

          nn?=?NeuralNetwork(2,?2,?2,?hidden_layer_weights=[0.15,?0.2,?0.25,?0.3],?hidden_layer_bias=0.35,?output_layer_weights=[0.4,?0.45,?0.5,?0.55],?output_layer_bias=0.6)
          for?i?in?range(10000):
          ????nn.train([0.05,?0.1],?[0.01,?0.09])
          ????print(i,?round(nn.calculate_total_error([[[0.05,?0.1],?[0.01,?0.09]]]),?9))


          #另外一個例子,可以把上面的例子注釋掉再運行一下:

          #?training_sets?=?[
          #?????[[0,?0],?[0]],
          #?????[[0,?1],?[1]],
          #?????[[1,?0],?[1]],
          #?????[[1,?1],?[0]]
          #?]

          #?nn?=?NeuralNetwork(len(training_sets[0][0]),?5,?len(training_sets[0][1]))
          #?for?i?in?range(10000):
          #?????training_inputs,?training_outputs?=?random.choice(training_sets)
          #?????nn.train(training_inputs,?training_outputs)
          #?????print(i,?nn.calculate_total_error(training_sets))

          五、其他

          預處理和后處理就相對簡單很多,預處理就是一些常規(guī)的圖像變換操作,數(shù)據(jù)增強方法等。

          后處理每個任務都略有不同,比如目標檢測的非極大值抑制等,這些內(nèi)容可以放在以后再講。

          至于深度學習框架的學習,那就是另外一大塊內(nèi)容了,深度學習框架是一種為了深度學習開發(fā)而生的工具,庫和預訓練模型等資源的總和。

          我們可以用 Python 實現(xiàn)簡單的神經(jīng)網(wǎng)絡,但是復雜的神經(jīng)網(wǎng)絡,還得靠框架,框架的使用可以大幅度降低我們的開發(fā)成本。

          至于學哪種框架,看個人喜好,Pytorch 和 Tensorflow 都行。人生苦短,我選 Pytorch。

          六、學習資料推薦

          學完本文,只能算是深度學習入門,還有非常多的內(nèi)容需要深入學習。

          推薦一些資料,方便感興趣的讀者繼續(xù)研究。

          視頻:

          • 吳恩達的深度學習公開課[3]:https://mooc.study.163.com/university/deeplearning_ai

          書籍:

          • 《神經(jīng)網(wǎng)絡與深度學習》
          • 《PyTorch深度學習實戰(zhàn)》

          開源項目:

          • Pytorch教程 1:https://github.com/yunjey/pytorch-tutorial
          • Pytorch教程 2:https://github.com/pytorch/tutorials

          七、絮叨

          學習的積累是個漫長而又孤獨的過程,厚積才能薄發(fā),有不懂的知識就多看多想,要相信最后勝利的,是堅持下去的那個人。

          本文硬核,如果喜歡,還望轉(zhuǎn)發(fā)、再看多多支持。

          我是 Jack,我們下期見。

          ·················END·················

          參考資料

          [1]

          推薦深度學習書籍: 《神經(jīng)網(wǎng)絡與深度學習》

          [2]

          反向傳播: https://www.cnblogs.com/charlotte77/p/5629865.html

          [3]

          吳恩達的深度學習公開課: https://mooc.study.163.com/university/deeplearning_ai




          推薦閱讀:
          Pandas數(shù)據(jù)可視化原來也這么厲害
          畫圖神器pyecharts-旭日圖
          刷爆網(wǎng)絡的動態(tài)條形圖,3行Python代碼就能搞定
          Python中讀取圖片的6種方式
          2020年11月國內(nèi)大數(shù)據(jù)競賽信息-獎池5000萬
          Python字典詳解-超級完整版
          刷爆網(wǎng)絡的動態(tài)條形圖,3行Python代碼就能搞定
          一個有意思還有用的Python包-漢字轉(zhuǎn)換拼音


          學習交流群



          掃碼關(guān)注本號↓



          瀏覽 30
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  看毛片视频 | 爱爱天堂 | 波多野结衣一区二区三区漫画 | 国产精品黄色电影 | 一级毛片久久久久久久女人18 |