原創(chuàng)文章,轉(zhuǎn)載請注明出處:https://blog.csdn.net/weixin_37864449/article/details/126772830?spm=1001.2014.3001.5502
如上動態(tài)圖所示,脈沖網(wǎng)絡(luò)由脈沖神經(jīng)元連接而成,脈沖神經(jīng)元輸入為脈沖,輸出也是脈沖,脈沖神經(jīng)元內(nèi)部有電動勢v,v在沒有接收到任何輸入時會隨著時間指數(shù)衰減到某個穩(wěn)定的電動勢(平衡電壓),而某一時刻接收到輸入脈沖時電動勢會增加某個值,當(dāng)電動勢增加的速度快過衰減的速度時(如頻繁有脈沖輸入),神經(jīng)元內(nèi)部的電動勢會越來越大,直到達(dá)到某個發(fā)放閾值后該脈沖神經(jīng)元會發(fā)放脈沖,此后脈沖神經(jīng)元電動勢迅速置為靜息電動勢,電動勢變化過程如下圖二所示。電動勢變化的規(guī)律又稱為神經(jīng)電位動力學(xué)。
圖二 神經(jīng)元膜電壓變化
一、脈沖神經(jīng)元模型
脈沖神經(jīng)元電位動力學(xué)數(shù)學(xué)模型最簡單常用的是漏電積分-放電(leaky integrate-and-fire ( LIF ))模型,這個模型工作過程與生物神經(jīng)元充電、漏電、放電過程類似,更精確的描述生物神經(jīng)動力學(xué)模型是Hodgkin-huxley模型,但該模型微分方程復(fù)雜難以直觀理解,雖然Hodgkin-huxley模型更精確描述了生物神經(jīng)元電位動力學(xué)變化過程,但有觀點認(rèn)為該模型對數(shù)據(jù)擬合能力沒有LIF模型好(https://www.youtube.com/watch?v=GTXTQ_sOxak 25:24),總而言之,LIF是基于生物神經(jīng)元動力學(xué)特性簡化后的數(shù)學(xué)模型,簡單好用,下面詳細(xì)討論LIF模型。
我們知道,每個脈沖神經(jīng)元內(nèi)部有電壓v,當(dāng)沒有接收到任何脈沖輸入時,電壓v會隨著時間指數(shù)穩(wěn)定到平衡電壓,這個過程用LIF模型描述為:
求解這個微分方程,可以得到:
這里是任意常數(shù),?控制指數(shù)下降速率,
?越小?越快指數(shù)變化到,分析這個方程可以看到,初始時t=0時刻v=,其中取恰當(dāng)?shù)闹稻涂梢允沟扔诿}沖神經(jīng)元初始時刻電壓,當(dāng)t=∞時v=,該方程控制了電壓v隨時間指數(shù)穩(wěn)定到平衡電壓。?
上面是連續(xù)電壓的變化方程,然而計算機只能模擬離散過程,取離散時間間隔為時,則:
故微分方程的離散形式為:
另外,當(dāng)某個時刻神經(jīng)元接收到一個脈沖輸入時,則要累積該脈沖到電壓中,最簡單的方式是讓當(dāng)前的電壓加上某個值,通常這個值跟連接該輸入脈沖的突觸權(quán)重有關(guān),電壓更新過程為:
神經(jīng)元內(nèi)部有一個發(fā)放閾值,當(dāng)神經(jīng)元電壓v>
時,神經(jīng)元會發(fā)放一個脈沖,此后神經(jīng)元電壓會立刻置為靜息電位:
為更好的理解LIF模型控制的神經(jīng)元膜電壓變化,下面附上由for循環(huán)實現(xiàn)的python代碼:
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(5, 4))
ax = plt.subplot(111)
# Function that runs the simulation
# tau: time constant (in ms)
# t0, t1, t2: time of three input spikes
# w: input synapse weight
# threshold: threshold value to produce a spike
# reset: reset value after a spike
def LIF(tau=10, t0=20, t1=30, t2=35, w=0.8, threshold=1.0, reset=0.0):
# Spike times, keep sorted because it's more efficient to pop the last value off the list
times = [t0, t1, t2]
times.sort(reverse=True)
# set some default parameters
duration = 100 # total time in ms
dt = 0.1 # timestep in ms
alpha = np.exp(-dt / tau) # this is the factor by which V decays each time step
V_rec = [] # list to record membrane potentials
V = 0.0 # initial membrane potential
T = np.arange(np.round(duration / dt)) * dt # array of times
spikes = [] # list to store spike times
# run the simulation
# plot everything (T is repeated because we record V twice per loop)
ax.clear()
for t in times:
ax.axvline(t, ls=':', c='b')
for t in T:
V_rec.append(V) # record
V *= alpha # integrate equations
if times and t > times[-1]: # if there has been an input spike
V +=w
times.pop() # remove that spike from list
V_rec.append(V) # record V before the reset so we can see the spike
if V > threshold: # if there should be an output spike
V = reset
spikes.append(t)
ax.plot(np.repeat(T, 2), V_rec, '-k', lw=2)
for t in spikes:
ax.axvline(t, ls='--', c='r')
ax.axhline(threshold, ls='--', c='g')
ax.set_xlim(0, duration)
ax.set_ylim(-1, 2)
ax.set_xlabel('Time (ms)')
ax.set_ylabel('Voltage')
plt.tight_layout()
plt.show()
LIF()
?運行結(jié)果為:
綠色虛線表示發(fā)放閾值,黑色為神經(jīng)元電壓,藍(lán)色虛線表示神經(jīng)元接收到輸入脈沖的時刻,紅色虛線表示神經(jīng)發(fā)放了一個脈沖。代碼里設(shè)置神經(jīng)元平衡電壓為0,靜息電位為0,發(fā)放閾值為1。
更復(fù)雜一些,我們可以讓發(fā)放閾值也能發(fā)生變化,下面代碼演示了當(dāng)神經(jīng)元發(fā)放脈沖時,發(fā)放閾值會增加某個值,且發(fā)放閾值動力學(xué)模型也是LIF模型。
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(5, 4))
ax = plt.subplot(111)
# Function that runs the simulation
# tau: time constant (in ms)
# t0, t1, t2: time of three input spikes
# w: input synapse weight
# threshold: threshold value to produce a spike
# reset: reset value after a spike
def LIF2(tau=10, taut=20, t0=20, t1=30, t2=35, w=0.8, threshold=1.0, dthreshold=0.5, reset=0.0):
# Spike times, keep sorted because it's more efficient to pop the last value off the list
times = [t0, t1, t2]
times.sort(reverse=True)
# set some default parameters
duration = 100 # total time in ms
dt = 0.1 # timestep in ms
alpha = np.exp(-dt/tau) # this is the factor by which V decays each time step
beta = np.exp(-dt/taut) # this is the factor by which Vt decays each time step
V_rec = [] # list to record membrane potentials
Vt_rec = [] # list to record threshold values
V = 0.0 # initial membrane potential
Vt = threshold
T = np.arange(np.round(duration/dt))*dt # array of times
spikes = [] # list to store spike times
# clear the axis and plot the spike times
ax.clear()
for t in times:
ax.axvline(t, ls=':', c='b')
# run the simulation
for t in T:
V_rec.append(V) # record
Vt_rec.append(Vt)
V *= alpha # integrate equations
Vt = (Vt-threshold)*beta+threshold
if times and t>times[-1]: # if there has been an input spike
V += w
times.pop() # remove that spike from list
V_rec.append(V) # record V before the reset so we can see the spike
Vt_rec.append(Vt)
if V>Vt: # if there should be an output spike
V = reset
Vt += dthreshold
spikes.append(t)
# plot everything (T is repeated because we record V twice per loop)
ax.plot(np.repeat(T, 2), V_rec, '-k', lw=2)
ax.plot(np.repeat(T, 2), Vt_rec, '--g', lw=2)
for t in spikes:
ax.axvline(t, ls='--', c='r')
ax.set_xlim(0, duration)
ax.set_ylim(-1, 2)
ax.set_xlabel('Time (ms)')
ax.set_ylabel('Voltage')
plt.tight_layout()
plt.show()
#display(fig)
LIF2()
?運行結(jié)果為:
二、脈沖神經(jīng)網(wǎng)絡(luò)前向傳播過程
有了上面的知識后,我們來簡單模擬一下脈沖神經(jīng)網(wǎng)絡(luò)前向傳播的過程:
三、脈沖神經(jīng)網(wǎng)絡(luò)突觸權(quán)重學(xué)習(xí)方法(STDP)
前面我們知道了脈沖神經(jīng)元內(nèi)部的電動力學(xué)特性及其方程,接下來我們來學(xué)習(xí)如何更新脈沖神經(jīng)網(wǎng)絡(luò)的連接權(quán)重,區(qū)別于傳統(tǒng)的梯度下降方法,脈沖神經(jīng)網(wǎng)絡(luò)通常使用的是更具生物學(xué)特性的STDP(spike timing dependent plasticity)學(xué)習(xí)策略。在解釋STDP之前,我們先來看看一些概念:
如上圖所示,脈沖神經(jīng)元連接有前突觸和后突觸之分,索引j 神經(jīng)元稱為前突觸,若神經(jīng)元j產(chǎn)生了一個脈沖,則稱神經(jīng)元j產(chǎn)生了一個突觸前脈沖,索引i 神經(jīng)元稱為后突觸,同理神經(jīng)元i產(chǎn)生的脈沖稱為突觸后脈沖。j與i的連接權(quán)重為?,神經(jīng)元i接收到來自神經(jīng)元j的一個脈沖后,神經(jīng)元i要累積該脈沖到電壓中,即神經(jīng)元i當(dāng)前的電壓加上某個值,該值的大小與
有關(guān),那么該如何更新
呢?
的更新在脈沖神經(jīng)網(wǎng)絡(luò)中最常用的方法是STDP方法,STDP更新突觸權(quán)重的方式是:若突觸前脈沖比突觸后脈沖到達(dá)時間早,會導(dǎo)致Long-Term Potentiation(LTP)效應(yīng),即
權(quán)重會增加。反之,若突觸前脈沖比突觸后脈沖到達(dá)時間晚,會引起LTD,即
權(quán)重會減小。在神經(jīng)科學(xué)實驗中,人們多次發(fā)現(xiàn)和驗證了STDP是大腦突觸權(quán)重更新的方式,突觸權(quán)重更新意味著學(xué)習(xí)和信息的存儲,也意味著大腦發(fā)育過程中神經(jīng)元回路的發(fā)展和完善。
根據(jù)上面的定義,STDP更新權(quán)重的公式可寫成:
也就是說,突觸權(quán)重 的變化是某個函數(shù) W的所有突觸前尖峰時間
和突觸后尖峰時間
差的總和。一個常用的函數(shù) W 是:
舉個例子:
然而使用該定義需要事先知道前突觸脈沖和后突觸脈沖一段時間內(nèi)各自發(fā)放脈沖的時間表,因此直接使用這個方程更新權(quán)重將非常低效,因為我們必須對每個神經(jīng)元先記錄好它的脈沖發(fā)放時間表,然后對所有尖峰對時間差求和。這在生物學(xué)上也是不現(xiàn)實的,因為神經(jīng)元無法記住之前的所有尖峰時間。事實證明,有一種更有效、生理上更合理的方法可以達(dá)到同樣的效果,該方法可以在突觸前脈沖發(fā)放或突觸后脈沖發(fā)放就立刻更新權(quán)重。
我們先定義兩個新變量 和
,它們分別為突觸前脈沖發(fā)放后的活動“痕跡”變量和突觸后脈沖發(fā)放后的活動“痕跡”變量(如下圖所示):
?痕跡變化由LIF模型控制:
當(dāng)發(fā)放突觸前脈沖時,會更新突觸前活動痕跡變量并根據(jù)規(guī)則修改權(quán)重w:?
??同理當(dāng)突觸后脈沖發(fā)放時:
這個更新公式可以理解為:當(dāng)突觸前脈沖到達(dá)了,突觸后脈沖痕跡還未衰減到0,說明突觸后脈沖是比突觸前脈沖早到達(dá)的,所以權(quán)重應(yīng)該削弱,削弱量為, 需要說明的是通常
為負(fù)數(shù)(
為負(fù)數(shù)的原因是在更新痕跡時,初始
=0,突觸后脈沖發(fā)放時,
會加
?,
通常是某個較小的負(fù)數(shù)常數(shù));同理當(dāng)突觸后脈沖發(fā)生時,突觸前脈沖痕跡還未衰減到0時,說明突觸前脈沖是比突觸后脈沖早到達(dá)的,所以權(quán)重應(yīng)該增強,增強量為
,這里通常
為正數(shù)。
四、泊松脈沖編碼
最后,我們看一下泊松脈沖編碼。由于脈沖神經(jīng)網(wǎng)絡(luò)接收的是脈沖信號,所以需要對初始輸入數(shù)據(jù)進(jìn)行脈沖編碼,其中輸入數(shù)據(jù)脈沖編碼一個比較常用的方式是泊松脈沖編碼,更詳細(xì)的泊松脈沖編碼講解可參考:https://www.youtube.com/watch?v=4r_gc4vf8eE 。
泊松脈沖編碼首先需要設(shè)置脈沖速率ρ0 ,ρ0 可以是常數(shù),也可以是時間函數(shù)。編碼過程可描述為:取時間間隔為Δt ,則每個時間間隔脈沖發(fā)放的概率為pF=ρ0*Δt ,電腦在每個時間間隔生成一個(0,1)范圍內(nèi)均勻分布的隨機數(shù),隨機數(shù)小于ρ0*Δt 則在該時間間隔內(nèi)產(chǎn)生一個脈沖。
泊松脈沖編碼可以這樣應(yīng)用:把輸入時間序列值看成脈沖速率ρ0 ,如t1時刻輸入為a, t2時刻輸入為b,t3時刻輸入為c,若t1時刻0-1隨機數(shù)大于或等于a*Δt ,則t1時刻神經(jīng)元不發(fā)放脈沖,t2時刻0-1隨機數(shù)小于b*Δt ,則t2時刻神經(jīng)元發(fā)放脈沖,t3時刻0-1隨機數(shù)大于或等于c*Δt ,則t3時刻神經(jīng)元不發(fā)放脈沖,所以a,b,c編碼后的脈沖序列為無脈沖,脈沖,無脈沖。
最后,推薦一個可以用來學(xué)習(xí)脈沖神經(jīng)網(wǎng)絡(luò)特性的編程工具包:brian2
python安裝方式:pip install?brian2文章來源:http://www.zghlxwxcb.cn/news/detail-407456.html
教程:Introduction to Brian part 1: Neurons — Brian 2 2.5.1 documentation文章來源地址http://www.zghlxwxcb.cn/news/detail-407456.html
到了這里,關(guān)于一文通俗入門·脈沖神經(jīng)網(wǎng)絡(luò)(SNN)·第三代神經(jīng)網(wǎng)絡(luò)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!