Eine bessere Methode zur Implementierung der Alpha-Synapse-Funktion in MATLAB

8

Ich habe ein undichtes Integrations- und Feuerneuronensystem implementiert, das eine Ausgabe in Form einer Alpha-Funktion alpha = t/tau * exp(1 - (t/tau)) liefert. Der Codeabschnitt, den ich für die Implementierung verwende, benötigt jedoch mindestens 80% der Laufzeit (etwa 4 s von insgesamt 5 s). Im Laufe des Programms wird dieser Prt mindestens 30000 Mal aufgerufen, während die computealphasynapseoutput Funktion mindestens 1,5 Millionen Mal aufgerufen wird. Also möchte ich die Laufzeit dieses Teils reduzieren. Ich habe versucht, arrayfun zu implementieren, aber das dauert viel mehr Zeit als dies.

Kann jemand eine effizientere Implementierung für diesen Code vorschlagen?

Um die Alpha-Synapse zu implementieren, habe ich den folgenden Code verwendet:

%Vor%

Die Funktion computealphasynapse ist wie folgt implementiert:

%Vor%

Bearbeiten:

  

Ich habe das Kopfgeld für diese Frage endlich an gnovice vergeben   für seine tolle Antwort. Es hat mir geholfen, ganze 40 Sekunden abzurasieren   von meiner Simulationszeit (von 68 bis 28 s). Ich hoffe, es funktioniert für Menschen   auch in der Zukunft. Ich möchte auch MrAzzaman und bestätigen    qbzenker um sich die Zeit zu nehmen, die Frage zu beantworten und   lehrte mich ein paar coole neue Ansätze. Auch andere, die kommentiert und   half mir. Danke

    
anyanwu 21.05.2017, 10:53
quelle

3 Antworten

2

Diese Lösung mag etwas seltsam und sehr spezifisch für das Problem sein, aber sehr effizient. Die Idee besteht darin, die Formel zur Berechnung der summierten Alpha-Synapsenausgabe so zu reorganisieren, dass die durchgeführten Berechnungen minimiert werden, wobei speziell die Anzahl der mit exp , was rechenintensiv ist. Hier ist die Neuformulierung für ein einzelnes Neuron:

Für das Ergebnis haben wir eine Funktion der Zeit f(t) (die eine Exponentialfunktion für den aktuellen Zeitpunkt t berechnet) mal eine lineare Funktion in t mit den zeitinvarianten Parametern A und B . Beachten Sie, dass A und B nur von den Spike-Zeiten abhängen und eine Exponentialfunktion über alle vorherigen Spike-Vorkommen addieren. Wir können diese zwei Parameter A und B für jedes Neuron speichern, und wenn ein neuer Spike in einem Neuron auftritt, berechnen wir einfach ein neues Paar Terme und fügen sie zu den bestehenden Werten für A und B hinzu. .

Hier ist der Vorbehalt: Beachten Sie die Werte der Exponenten. Für A und B ist der Wert ts/tau , und wenn er zu groß wird, könnte die Berechnung überlaufen, was zu Inf führt. Für die Parameter, die wir hier verwenden, wird das nicht passieren. Der Wert von ts ist maximal 1 (da wir nur eine Sekunde simulieren) und der kleinste Wert von tau ist 0,01 Sekunden. Der Exponent wird höchstens 100 sein und Werte ergeben, die groß sind (etwa 10 ^ 43), aber leicht von einem double Variable. Ebenso wird der Exponent in f(t) den größten negativen Wert von -99 haben, was zu sehr kleinen Werten führt (etwa 10 ^ -43), aber immer noch leicht von einer double Variable ohne Unterlauf auf 0 gehandhabt werden kann Beachten Sie, dass die Verwendung kleinerer tau -Werte oder eine längere Simulationszeit zu Problemen führen kann.

Also, wie setzen wir das um? Hier sind die relevanten Codeabschnitte, die Sie hinzufügen / ändern müssen (beachten Sie, dass Sie spikeTimesArray nicht einmal mehr benötigen):

%Vor%

Und wie gut geht es? Hier sind einige Messungen, die ich gemacht habe (unter Verwendung von timeit ) mit unterschiedlichen durchschnittlichen Auslösefrequenzen für 1101 Neuronen simuliert mit einem Zeitschritt von 0,1 ms für eine Sekunde (10001 Zeitpunkte):

Je mehr Spitzen aufgetreten sind, desto länger dauert die Fertigstellung der ursprünglichen Lösung. Die für die umformulierte Lösung benötigte Zeit war jedoch nahezu konstant und überschritt niemals 0,6 Sekunden. Ich kann auch bestätigen, dass die Ausgaben für die beiden Ansätze gleich sind (maximale Unterschiede liegen in der Größenordnung von 10 ^ -13 für die synaptischen Wellenformen).

    
gnovice 11.07.2017, 07:08
quelle
2

Ich testete den folgenden Code mit einer Reihe zufällig erzeugter Schusszeiten und -tau, und er lief konstant ungefähr 7-8x schneller. Es ist ein bisschen seltsam, aber ertragen Sie mit mir.

Die Grundidee ist, dass MATLAB bei Operationen mit Matrizen hervorragend ist, aber ziemlich langsam sein kann, wenn Sie diese Operationen aufbrechen müssen, zum Beispiel mit Ihrer for-Schleife. Die Idee ist dann, zu versuchen, das gesamte Zellenarray auf einmal zu machen. Dies wäre einfacher, wenn Sie ändern könnten, wie die Feuerzeiten gespeichert werden (d. H. Nicht in einem Zellenfeld), aber ich habe mit dem, was Sie haben, auskommen lassen.

Im Grunde werden wir das Zellenfeld der Feuerzeiten in einen großen Vektor umwandeln, die synaptische Ausgabe für alle auf einmal berechnen und sie dann nach ihrem Neuron summieren. So bekommen wir zum Beispiel folgendes:

%Vor%

wobei der neuronInd Vektor der entsprechende Neuronenindex jeder Feuerzeit ist. Dies ist der Vektor, der, wenn Sie ihn erstellen könnten, wenn Ihr Array für die Feuerzeiten erstellt wurde, würde dieser ganze Prozess viel schneller sein. So wie es ist, ist der Prozess zur Berechnung von neuronInd etwas undurchsichtig.

Unabhängig davon berechnen wir dies wie folgt:

%Vor%

Hoffe, das hilft.

    
MrAzzaman 08.07.2017 04:26
quelle
1

Dieser Code gibt mir eine signifikante Beschleunigung unter den richtigen Bedingungen (typischerweise niedrige maximale Anzahl von Spike-Zeiten für ein gegebenes Neuron zu einer gegebenen Zeit und eine Anzahl von Neuronen & gt; 5). Bei einer geringen Anzahl von Neuronen ähnelt es der Leistung Ihres obigen Codes.

Beachten Sie, dass ich diesen Code nicht mit Ihren echten Eingaben getestet habe, so dass Sie möglicherweise etwas optimieren müssen, damit es funktioniert. Außerdem ist es möglicherweise langsamer mit Ihren Daten als die Dummy-Daten, die ich verwendet habe. Die Idee hinter der Beschleunigung ist vectorization -  im Wesentlichen Operationen an dem gesamten Vektor, anstatt ihn über eine Menge von for-Schleifen aufzuteilen.

Dies erfordert, dass Sie spikeTimesArray anstelle von fehlenden Werten eine Matrix mit NaN s erstellen. So etwas wie das:

%Vor%

würde

werden %Vor%

und statt For-Schleifen verwenden Sie einfach die gesamte Vektoroperation:

%Vor%

Beachten Sie, dass ich bei dieser Implementierung davon ausgehe, dass spikeTimesArray2 eine NxM -Matrix ist, wobei N der Anzahl der maximalen Spikes für ein bestimmtes Neuron entspricht und M der Gesamtzahl der Neuronen entspricht. Außerdem ist tau_syn ein Zeilenvektor.

    
qbzenker 09.07.2017 14:02
quelle

Tags und Links