1. 程式人生 > >PyNest——Part1:neurons and simple neural networks

PyNest——Part1:neurons and simple neural networks

例子 兩個 執行 想象 你在 容易 height 想要 根節點

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的變量中。

  1. import pylab
  2. import nest
  3. neuron = nest.Create("iaf_psc_alpha")

我們現在可以使用id來訪問這個神經元的屬性。 NEST中節點的屬性通常通過形式為{key:value}的鍵值對的Python字典來訪問。 為了查看神經元的屬性,你可以問它的狀態。

nest.GetStatus(neuron)


這將在Python控制臺中打印出相應的字典。 這些屬性中的許多與神經元的動力學無關。 要了解哪些有趣的屬性,請通過幫助臺查看模型的文檔。 如果您已經知道您感興趣的屬性,您可以指定一個鍵或一個鍵列表作為GetStatus的可選參數:

  1. nest.GetStatus(neuron, "I_e")
  2. 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屬性需要一個我們想要記錄的變量的名字列表。 暴露於萬用表的變量因型號而異。 對於特定的模型,您可以通過查看神經元的屬性可記錄來檢查暴露變量的名稱。

  1. multimeter = nest.Create("multimeter")
  2. nest.SetStatus(multimeter, {"withtime":True, "record_from":["V_m"]})

我們現在創建一個尖峰探測器,另一個記錄神經元產生的尖峰事件的設備。 我們使用可選的關鍵字參數params來設置它的屬性。 這是使用SetStatus的替代方法。 屬性withgid指示尖峰檢測器是否記錄它從其接收事件的源ID(即,我們的神經元的ID)。

  1. spikedetector = nest.Create("spike_detector",
  2. params={"withgid": True, "withtime": True})

關於命名的簡短說明:這裏我們稱之為神經元神經元,萬用表萬用表等。 當然,您可以將創建的節點分配給您喜歡的任何變量名稱,但如果選擇反映仿真中的概念的名稱,則該腳本更易於閱讀。

connecting nodes with default connections

現在我們知道如何創建單個節點,我們可以開始連接它們以形成一個小型網絡。

  1. nest.Connect(multimeter, neuron)
  2. nest.Connect(neuron, spikedetector)

技術分享圖片

指定連接參數的順序反映了事件的流程:如果神經元尖峰,它會向尖峰檢測器發送一個事件。 相反,萬用表會定期向神經元發送請求,以便在該時間點詢問其膜電位。 這可以被認為是粘在神經元中的完美電極。

現在我們連接了網絡,我們可以開始模擬。 我們必須通知仿真內核模擬運行的時間。 這裏我們選擇1000ms。

nest.Simulate(1000.0)

恭喜,你剛剛在NEST模擬你的第一個網絡!

extracting and plotting data from devices

模擬完成後,我們可以獲取萬用表記錄的數據。

  1. dmm = nest.GetStatus(multimeter)[0]
  2. Vms = dmm["events"]["V_m"]
  3. ts = dmm["events"]["times"]

在第一行中,我們獲取所有查詢節點的狀態字典列表。 這裏,變量萬用表只是一個節點的ID,所以返回的列表只包含一個字典。 我們通過索引它來提取這個列表的第一個元素(因此最後的[0])。 這種類型的操作在使用PyNEST時非常頻繁地發生,因為大多數函數都被設計為接收和返回列表,而不是單獨的值。 這是為了使項目組(通常情況下設置神經網絡模擬)的操作更方便。

該詞典包含一個名為events的條目,用於保存記錄的數據。 它本身就是一個字典,其中的條目V_m和時間分別存儲在Vms和ts中,分別存儲在第二行和第三行中。 如果您無法想象字典詞典以及您從哪裏提取的內容,請首先嘗試將dmm打印到屏幕上,以便更好地了解其結構,然後在下一步中提取字典事件等。

現在我們準備在一個圖中顯示數據。 為此,我們使用pylab。

  1. import pylab
  2. pylab.figure(1)
  3. pylab.plot(ts, Vms)

第二行打開一個數字(數字1),第三行清除窗口,第四行實際產生該圖。 你還沒有看到它,因為我們還沒有使用pylab.show()。 在我們這樣做之前,我們類似地從尖峰探測器獲取並顯示尖峰。

  1. dSD = nest.GetStatus(spikedetector,keys="events")[0]
  2. evs = dSD["senders"]
  3. ts = dSD["times"]
  4. pylab.figure(2)
  5. pylab.plot(ts, evs, ".")
  6. pylab.show()

在這裏,我們通過使用GetStatus的可選關鍵字參數鍵更簡潔地提取事件。 這會使用關鍵事件而不是整個狀態字典來提取字典元素。 輸出結果應該如圖2所示。如果要將其作為腳本執行,只需將所有行粘貼到名為one-neuron.py的文本文件中即可。 然後,您可以通過在python前加上文件名,或者在Python或ipython提示符前加上run前綴來從命令行運行它。

可以在單個萬用表上收集多個神經元的信息。 這確實使檢索信息復雜化:n個神經元中的每一個神經元的數據將以交錯方式存儲和返回。 幸運的是,Python為我們提供了一個方便的數組操作來輕松分割數據:使用一個步驟(有時稱為步幅)進行數組切片。 為了解釋這個,你必須調整前一部分創建的模型。 以新名稱保存您的代碼,在下一節中您還將使用此代碼。 創建一個額外的神經元,背景電流給定不同的值:

  1. neuron2 = nest.Create("iaf_neuron")
  2. nest.SetStatus(neuron2 , {"I_e": 370.0})

現在將這個新創建的神經元連接到萬用表上:

nest.Connect(multimeter, neuron2)

運行模擬並繪制結果,它們看起來不正確。 要解決這個問題,你必須單獨繪制兩條神經元軌跡。 用以下行替換從萬用表中提取事件的代碼。

  1. pylab.figure(2)
  2. Vms1 = dmm["events"]["V_m"][::2] # start at index 0: till the end: each second entry
  3. ts1 = dmm["events"]["times"][::2]
  4. pylab.plot(ts1, Vms1)
  5. Vms2 = dmm["events"]["V_m"][1::2] # start at index 1: till the end: each second entry
  6. ts2 = dmm["events"]["times"][1::2]
  7. pylab.plot(ts2, Vms2)

connecting nodes with specific connections

一種常用的神經活動模型是泊松過程。 我們現在修改前面的例子,以便神經元接收2個泊松尖峰列車,一個是興奮性的,另一個是抑制性的。 因此,我們需要一個新設備poisson_generator。 創建神經元後,我們創建這兩個發生器,並分別將它們的速率設置為80000Hz和15000Hz。

  1. noise_ex = nest.Create("poisson_generator")
  2. noise_in = nest.Create("poisson_generator")
  3. nest.SetStatus(noise_ex, {"rate": 80000.0})
  4. nest.SetStatus(noise_in, {"rate": 15000.0})

另外,恒定的輸入電流應該設置為0:

nest.SetStatus(neuron, {"I_e": 0.0})

興奮發生器的每個事件應產生1.2pA振幅的突觸後電流,約-2.0pA的抑制事件。 突觸權重可以在字典中定義,該字典使用關鍵字syn_spec(突觸規範)傳遞給Connect函數。 一般來說,可以在突觸詞典中指定確定突觸的所有參數,例如“重量”,“延遲”,突觸模型(“模型”)和特定於突觸模型的參數。

  1. syn_dict_ex = {"weight": 1.2}
  2. syn_dict_in = {"weight": -2.0}
  3. nest.Connect([noise[0]], neuron, syn_spec=syn_dict_ex)
  4. nest.Connect([noise[1]], neuron, syn_spec=syn_dict_in)

技術分享圖片

剩下的代碼仍然像以前一樣。 你應該看到如圖3所示的膜電位。

在引言的下一部分(第2部分:神經元群體)中,我們將看到更多的方法來一次連接許多神經元。

two connected neurons

技術分享圖片

連接神經元沒有額外的魔法。 為了證明這一點,我們從一個具有恒定輸入電流的神經元的原始示例開始,並添加第二個神經元。

  1. import pylab
  2. import nest
  3. neuron1 = nest.Create("iaf_psc_alpha")
  4. nest.SetStatus(neuron1, {"I_e": 376.0})
  5. neuron2 = nest.Create("iaf_psc_alpha")
  6. multimeter = nest.Create("multimeter")
  7. nest.SetStatus(multimeter, {"withtime":True, "record_from":["V_m"]})

我們現在將神經元1連接到神經元2,並記錄來自神經元2的膜電位,以便我們可以觀察由神經元1的尖峰引起的突觸後電位。

  1. nest.Connect(neuron1, neuron2, syn_spec = {"weight":20.0})
  2. 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