PyNest——Part1:neurons and simple neural networks
neurons and simple neural networks
pynest – nest模擬器的界面
神經模擬工具(NEST:www.nest-initiative.org)專為仿真點神經元的大型異構網絡而設計。 它是根據GPL許可證發布的開源軟件。 該模擬器帶有Python的接口[4]。 圖1說明了用戶的模擬腳本(mysimulation.py)和NEST模擬器之間的交互。 [2]包含該接口實現的技術詳細描述,本文的部分內容均基於此參考。 仿真內核使用C ++編寫,以獲得最高性能的仿真。
您可以從Python提示符或ipython內部以交互方式使用PyNEST。 當你在探索PyNEST時,這是非常有用的,試圖學習一個新的功能或調試一個例程。 一旦退出探索模式,您會發現它可以節省大量時間在文本文件中編寫模擬。 這些可以依次從命令行或Python或ipython提示符運行。
無論是交互式,半交互式還是純粹執行的腳本,首先需要將NEST的功能導入Python解釋器。
import nest
和Python的其他所有模塊一樣,可以提供可用的函數。
dir(nest)
一個這樣的命令是nest.Models?,它將返回您可以使用的所有可用模型的列表。 如果你想獲得更多關於特定命令的信息,你可以使用IPython的標準幫助系統。
nest.Models?
這將返回幫助文本(docstring),解釋這個特定函數的用法。 NEST內還有一個幫助系統。 您可以使用nest.helpdesk()在瀏覽器中打開幫助頁面,並且可以使用nest.help(object)獲取特定對象的幫助頁面。
creating nodes
NEST中的神經網絡由兩種基本元素類型組成:節點和連接。 節點是神經元,設備或子網絡。 設備用於刺激神經元或從它們進行記錄。 節點可以安排在子網絡中以構建分層網絡,例如圖層,列和區域 - 我們將在後面的課程中討論。 現在我們將在我們啟動NEST時出現的默認子網絡中工作,這就是所謂的根節點。
首先,根子網絡是空的。 使用Create命令創建新節點,該命令將參數作為所需節點類型的型號名稱,以及可選的要創建的節點數量和初始化參數。 該函數返回新節點的句柄列表,您可以將其分配給變量供以後使用。 這些句柄是整數,稱為ids。 許多PyNEST函數期望或返回一個id列表(參見第8節)。 因此,使用單個函數調用將函數應用於大型節點集很容易。
在導入NEST以及Pylab接口到Matplotlib [[3]](#3)後,我們將使用它來顯示結果,我們可以開始創建節點。 作為第一個例子,我們將創建一個類型為iaf_psc_alpha的神經元。 該神經元是具有α形突觸後電流的整合火焰神經元。 該函數返回所有創建的神經元的id的列表,在本例中只有一個,我們將其存儲在名為neuron的變量中。
import pylab
import nest
neuron = nest.Create("iaf_psc_alpha")
我們現在可以使用id來訪問這個神經元的屬性。 NEST中節點的屬性通常通過形式為{key:value}的鍵值對的Python字典來訪問。 為了查看神經元的屬性,你可以問它的狀態。
nest.GetStatus(neuron)
這將在Python控制臺中打印出相應的字典。 這些屬性中的許多與神經元的動力學無關。 要了解哪些有趣的屬性,請通過幫助臺查看模型的文檔。 如果您已經知道您感興趣的屬性,您可以指定一個鍵或一個鍵列表作為GetStatus的可選參數:
nest.GetStatus(neuron, "I_e")
nest.GetStatus(neuron, ["V_reset", "V_th"])
在第一種情況下,我們查詢常數背景電流I_e的值; 結果以包含一個元素的元組的形式給出。 在第二種情況下,我們查詢重置電位和神經元閾值的值,並將結果作為嵌套元組接收。 如果為節點列表調用GetStatus,則外部元組的維度是節點列表的長度,內部元組的維度是指定的鍵的數量。
要修改字典中的屬性,我們使用SetStatus。 在以下示例中,背景電流設置為376.0pA,這是導致神經元周期性尖峰的值。
nest.SetStatus(neuron, {"I_e": 376.0})
請註意,我們可以通過在字典中給出多個以逗號分隔的鍵:值對來同時設置多個屬性。 另外請註意,NEST是類型敏感的 - 如果某個特定屬性是double類型的,那麽您確實需要明確寫入小數點:
nest.SetStatus(neuron, {"I_e": 376})
將導致錯誤。 這很方便地保護我們避免發生整數除法錯誤,這很難被發現。
接下來我們創建一個萬用表,這是一種我們可以用來記錄神經元膜電壓隨時間變化的器件。 我們設置其屬性的時間,以便它也將記錄膜電壓采樣的時間點。 record_from屬性需要一個我們想要記錄的變量的名字列表。 暴露於萬用表的變量因型號而異。 對於特定的模型,您可以通過查看神經元的屬性可記錄來檢查暴露變量的名稱。
multimeter = nest.Create("multimeter")
nest.SetStatus(multimeter, {"withtime":True, "record_from":["V_m"]})
我們現在創建一個尖峰探測器,另一個記錄神經元產生的尖峰事件的設備。 我們使用可選的關鍵字參數params來設置它的屬性。 這是使用SetStatus的替代方法。 屬性withgid指示尖峰檢測器是否記錄它從其接收事件的源ID(即,我們的神經元的ID)。
spikedetector = nest.Create("spike_detector",
params={"withgid": True, "withtime": True})
關於命名的簡短說明:這裏我們稱之為神經元神經元,萬用表萬用表等。 當然,您可以將創建的節點分配給您喜歡的任何變量名稱,但如果選擇反映仿真中的概念的名稱,則該腳本更易於閱讀。
connecting nodes with default connections
現在我們知道如何創建單個節點,我們可以開始連接它們以形成一個小型網絡。
nest.Connect(multimeter, neuron)
nest.Connect(neuron, spikedetector)
指定連接參數的順序反映了事件的流程:如果神經元尖峰,它會向尖峰檢測器發送一個事件。 相反,萬用表會定期向神經元發送請求,以便在該時間點詢問其膜電位。 這可以被認為是粘在神經元中的完美電極。
現在我們連接了網絡,我們可以開始模擬。 我們必須通知仿真內核模擬運行的時間。 這裏我們選擇1000ms。
nest.Simulate(1000.0)
恭喜,你剛剛在NEST模擬你的第一個網絡!
extracting and plotting data from devices
模擬完成後,我們可以獲取萬用表記錄的數據。
dmm = nest.GetStatus(multimeter)[0]
Vms = dmm["events"]["V_m"]
ts = dmm["events"]["times"]
在第一行中,我們獲取所有查詢節點的狀態字典列表。 這裏,變量萬用表只是一個節點的ID,所以返回的列表只包含一個字典。 我們通過索引它來提取這個列表的第一個元素(因此最後的[0])。 這種類型的操作在使用PyNEST時非常頻繁地發生,因為大多數函數都被設計為接收和返回列表,而不是單獨的值。 這是為了使項目組(通常情況下設置神經網絡模擬)的操作更方便。
該詞典包含一個名為events的條目,用於保存記錄的數據。 它本身就是一個字典,其中的條目V_m和時間分別存儲在Vms和ts中,分別存儲在第二行和第三行中。 如果您無法想象字典詞典以及您從哪裏提取的內容,請首先嘗試將dmm打印到屏幕上,以便更好地了解其結構,然後在下一步中提取字典事件等。
現在我們準備在一個圖中顯示數據。 為此,我們使用pylab。
import pylab
pylab.figure(1)
pylab.plot(ts, Vms)
第二行打開一個數字(數字1),第三行清除窗口,第四行實際產生該圖。 你還沒有看到它,因為我們還沒有使用pylab.show()。 在我們這樣做之前,我們類似地從尖峰探測器獲取並顯示尖峰。
dSD = nest.GetStatus(spikedetector,keys="events")[0]
evs = dSD["senders"]
ts = dSD["times"]
pylab.figure(2)
pylab.plot(ts, evs, ".")
pylab.show()
在這裏,我們通過使用GetStatus的可選關鍵字參數鍵更簡潔地提取事件。 這會使用關鍵事件而不是整個狀態字典來提取字典元素。 輸出結果應該如圖2所示。如果要將其作為腳本執行,只需將所有行粘貼到名為one-neuron.py的文本文件中即可。 然後,您可以通過在python前加上文件名,或者在Python或ipython提示符前加上run前綴來從命令行運行它。
可以在單個萬用表上收集多個神經元的信息。 這確實使檢索信息復雜化:n個神經元中的每一個神經元的數據將以交錯方式存儲和返回。 幸運的是,Python為我們提供了一個方便的數組操作來輕松分割數據:使用一個步驟(有時稱為步幅)進行數組切片。 為了解釋這個,你必須調整前一部分創建的模型。 以新名稱保存您的代碼,在下一節中您還將使用此代碼。 創建一個額外的神經元,背景電流給定不同的值:
neuron2 = nest.Create("iaf_neuron")
nest.SetStatus(neuron2 , {"I_e": 370.0})
現在將這個新創建的神經元連接到萬用表上:
nest.Connect(multimeter, neuron2)
運行模擬並繪制結果,它們看起來不正確。 要解決這個問題,你必須單獨繪制兩條神經元軌跡。 用以下行替換從萬用表中提取事件的代碼。
pylab.figure(2)
Vms1 = dmm["events"]["V_m"][::2] # start at index 0: till the end: each second entry
ts1 = dmm["events"]["times"][::2]
pylab.plot(ts1, Vms1)
Vms2 = dmm["events"]["V_m"][1::2] # start at index 1: till the end: each second entry
ts2 = dmm["events"]["times"][1::2]
pylab.plot(ts2, Vms2)
connecting nodes with specific connections
一種常用的神經活動模型是泊松過程。 我們現在修改前面的例子,以便神經元接收2個泊松尖峰列車,一個是興奮性的,另一個是抑制性的。 因此,我們需要一個新設備poisson_generator。 創建神經元後,我們創建這兩個發生器,並分別將它們的速率設置為80000Hz和15000Hz。
noise_ex = nest.Create("poisson_generator")
noise_in = nest.Create("poisson_generator")
nest.SetStatus(noise_ex, {"rate": 80000.0})
nest.SetStatus(noise_in, {"rate": 15000.0})
另外,恒定的輸入電流應該設置為0:
nest.SetStatus(neuron, {"I_e": 0.0})
興奮發生器的每個事件應產生1.2pA振幅的突觸後電流,約-2.0pA的抑制事件。 突觸權重可以在字典中定義,該字典使用關鍵字syn_spec(突觸規範)傳遞給Connect函數。 一般來說,可以在突觸詞典中指定確定突觸的所有參數,例如“重量”,“延遲”,突觸模型(“模型”)和特定於突觸模型的參數。
syn_dict_ex = {"weight": 1.2}
syn_dict_in = {"weight": -2.0}
nest.Connect([noise[0]], neuron, syn_spec=syn_dict_ex)
nest.Connect([noise[1]], neuron, syn_spec=syn_dict_in)
剩下的代碼仍然像以前一樣。 你應該看到如圖3所示的膜電位。
在引言的下一部分(第2部分:神經元群體)中,我們將看到更多的方法來一次連接許多神經元。
two connected neurons
連接神經元沒有額外的魔法。 為了證明這一點,我們從一個具有恒定輸入電流的神經元的原始示例開始,並添加第二個神經元。
import pylab
import nest
neuron1 = nest.Create("iaf_psc_alpha")
nest.SetStatus(neuron1, {"I_e": 376.0})
neuron2 = nest.Create("iaf_psc_alpha")
multimeter = nest.Create("multimeter")
nest.SetStatus(multimeter, {"withtime":True, "record_from":["V_m"]})
我們現在將神經元1連接到神經元2,並記錄來自神經元2的膜電位,以便我們可以觀察由神經元1的尖峰引起的突觸後電位。
nest.Connect(neuron1, neuron2, syn_spec = {"weight":20.0})
nest.Connect(multimeter, neuron2)
這裏使用了1ms的默認延遲。 如果除權重外還指定了延遲,則可使用以下快捷方式:
nest.Connect(neuron1, neuron2, syn_spec={"weight":20, "delay":1.0})
如果您像以前一樣模擬網絡並繪制膜電位,您應該可以看到由神經元1的尖峰引起的神經元2的突觸後電位,如圖4所示。
command overview
這些是我們在這份講義中為例子介紹的功能; 本介紹的以下部分將增加更多內容。
Getting information about NEST
Models(mtype="all", sel=None)
:
返回所有可用模型(節點和突觸)的列表。 使用mtype =“節點”僅查看節點模型,mtype =“突觸”僅查看突觸模型。 sel可以是一個字符串,用於過濾結果列表並只返回包含它的模型。helpdesk(browser="firefox")
:
在給定的瀏覽器中打開NEST文檔頁面。help(obj=None,pager="less")
:
打開給定對象的幫助頁面。
Nodes
Create(model, n=1, params=None)
:
在當前的子網絡中創建n個類型模型的實例。 新節點的參數可以以參數形式給出(單個字典或大小為n的字典列表)。 如果省略,則使用模型的默認值。GetStatus(nodes, keys=None)
:
返回給定節點列表的參數字典列表。 如果給出鍵,則會返回值列表。 鍵也可以是一個列表,在這種情況下返回的列表包含值列表。SetStatus(nodes, params, val=None)
:
將給定節點的參數設置為參數,該參數可以是單個字典,也可以是與節點大小相同的字典列表。 如果給定val,則params必須是屬性的名稱,該屬性在節點上設置為val。 val可以是單個值,也可以是與節點大小相同的列表。
Connections
這是Connect函數文檔的縮寫版本,請參閱NEST的完整版和連接管理的在線幫助以獲取簡介和工作示例。
連接(pre,post,conn_spec = None,syn_spec = None,model =無):
將pre神經元連接到post神經元。pre和post中的神經使用指定的連接(默認為“one_to_one”)和突觸類型(默認為“static_synapse”)進行連接。 細節取決於連接規則。 註意:Connect不會遍歷子網,它只會連接顯式指定的節點。 突觸前神經元,以GID列表的形式給出 - 突觸後神經元,以GID列表形式給出conn_spec - 指定連接規則的名稱或字典,見下文syn_spec - 指定突觸的名稱或字典,參見下文
連接
連接可以指定為包含連接規則名稱(默認值:“one_to_one”)的字符串,也可以指定規則和規則特定參數(例如“indegree”)的字典,必須給出連接規則。 此外,字典中還可以包含允許自連接(“autapses”,默認值:True)和一對神經元(“multapses”,默認值:True)之間的多個連接的開關。
突觸
可以將突觸模型及其屬性插入為描述一個突觸模型的字符串(突觸模型在synapsedict中列出)或作為字典插入,如下所述。如果沒有指定突觸模型,將使用默認模型“static_synapse”。突觸字典中的可用鍵是“模型”,“體重”,“延遲”,“受體類型”和特定於所選突觸模型的參數。所有參數都是可選的,如果未指定,將使用當前突觸模型確定的默認值。 “模型”確定突觸類型,取自NEST中的預定義突觸類型或通過CopyModel()手動創建的突觸。所有其他參數可以是標量或分布。在標量參數的情況下,除了必須用整數初始化的“receptor_type”之外,所有的鍵都會加倍。分布式參數用指定分布(“分布”,如“正常”)和分布特定參數(如“mu”和“sigma”)的另一個字典進行初始化。
模擬控制
模擬(T):
模擬網絡t毫秒。
PyNest——Part1:neurons and simple neural networks