Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/sql-server-2008/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 创建大量对象(神经元)并使用字典随机连接_Python_Multithreading_Neural Network_Julia_Perceptron - Fatal编程技术网

Python 创建大量对象(神经元)并使用字典随机连接

Python 创建大量对象(神经元)并使用字典随机连接,python,multithreading,neural-network,julia,perceptron,Python,Multithreading,Neural Network,Julia,Perceptron,我在实验中试图用以下标准创建一种新的神经网络: 每个神经元必须是一个独立的对象 每个神经元都应该有自己的线程 网络必须部分随机连接(启动时) 神经元必须异步运行以计算其输出、更新其权重等 以下是我在Julia和Python中的实现尝试: Python import random import itertools import time import signal from threading import Thread from multiprocessing import Pool imp

我在实验中试图用以下标准创建一种新的神经网络:

  • 每个神经元必须是一个独立的对象
  • 每个神经元都应该有自己的线程
  • 网络必须部分随机连接(启动时)
  • 神经元必须异步运行以计算其输出、更新其权重等
以下是我在Julia和Python中的实现尝试:

Python

import random
import itertools
import time
import signal
from threading import Thread
from multiprocessing import Pool
import multiprocessing

POTENTIAL_RANGE = 110000 # Resting potential: -70 mV Membrane potential range: +40 mV to -70 mV --- Difference: 110 mV = 110000 microVolt --- https://en.wikipedia.org/wiki/Membrane_potential
ACTION_POTENTIAL = 15000 # Resting potential: -70 mV Action potential: -55 mV --- Difference: 15mV = 15000 microVolt --- https://faculty.washington.edu/chudler/ap.html
AVERAGE_SYNAPSES_PER_NEURON = 8200 # The average number of synapses per neuron: 8,200 --- http://www.ncbi.nlm.nih.gov/pubmed/2778101

# https://en.wikipedia.org/wiki/Neuron

class Neuron():

    neurons = []

    def __init__(self):
        self.connections = {}
        self.potential = 0.0
        self.error = 0.0
        #self.create_connections()
        #self.create_axon_terminals()
        Neuron.neurons.append(self)
        self.thread = Thread(target = self.activate)
        #self.thread.start()
        #self.process = multiprocessing.Process(target=self.activate)

    def fully_connect(self):
        for neuron in Neuron.neurons[len(self.connections):]:
            if id(neuron) != id(self):
                self.connections[id(neuron)] = round(random.uniform(0.1, 1.0), 2)

    def partially_connect(self):
        if len(self.connections) == 0:
            neuron_count = len(Neuron.neurons)
            for neuron in Neuron.neurons[len(self.connections):]:
                if id(neuron) != id(self):
                    if random.randint(1,neuron_count/100) == 1:
                        self.connections[id(neuron)] = round(random.uniform(0.1, 1.0), 2)
            print "Neuron ID: " + str(id(self))
            print "    Potential: " + str(self.potential)
            print "    Error: " + str(self.error)
            print "    Connections: " + str(len(self.connections))

    def activate(self):
        while True:
            '''
            for dendritic_spine in self.connections:
                if dendritic_spine.axon_terminal is not None:
                    dendritic_spine.potential = dendritic_spine.axon_terminal.potential
                    print dendritic_spine.potential
                self.neuron_potential += dendritic_spine.potential * dendritic_spine.excitement
            terminal_potential = self.neuron_potential / len(self.axon_terminals)
            for axon_terminal in self.axon_terminals:
                axon_terminal.potential = terminal_potential
            '''
            #if len(self.connections) == 0:
            #   self.partially_connect()
            #else:
            self.partially_connect()
            pass

            '''
            if abs(len(Neuron.neurons) - len(self.connections) + 1) > 0:
                self.create_connections()

            if abs(len(Neuron.neurons) - len(self.axon_terminals) + 1) > 0:
                self.create_axon_terminals()
            '''

class Supercluster():

    def __init__(self,size):
        for i in range(size):
            Neuron()
        print str(size) + " neurons created."
        self.n = 0
        self.build_connections()
        #pool = Pool(4, self.init_worker)
        #pool.apply_async(self.build_connections(), arguments)
        #map(lambda x: x.partially_connect(),Neuron.neurons)
        #map(lambda x: x.create_connections(),Neuron.neurons)
        #map(lambda x: x.create_axon_terminals(),Neuron.neurons)

    def build_connections(self):
        for neuron in Neuron.neurons:
            self.n += 1
            #neuron.thread.start()
            neuron.partially_connect()
            print "Counter: " + str(self.n)

Supercluster(10000)
def build_connections(self):
    for neuron in Neuron.neurons:
        self.n += 1
        #neuron.thread.start()
        neuron.partially_connect()
        print "Counter: " + str(self.n)
朱莉娅

global neurons = []

type Neuron
    connections::Dict{UInt64,Float16}
    potential::Float16
    error::Float16

    function Neuron(arg1,arg2,arg3)
        self = new(arg1,arg2,arg3)
        push!(neurons, self)
    end

end

function fully_connect(self)
    for neuron in neurons
        if object_id(neuron) != object_id(self)
            self.connections[object_id(neuron)] = rand(1:100)/100
            #push!(self.connections, rand(1:100)/100)
        end
    end
end

function partially_connect(self)
    if isempty(self.connections)
        neuron_count = length(neurons)
        for neuron in neurons
            if object_id(neuron) != object_id(self)
                if rand(1:neuron_count/100) == 1
                    self.connections[object_id(neuron)] = rand(1:100)/100
                    #push!(self.connections, rand(1:100)/100)
                end
            end
        end
        println("Neuron ID: ",object_id(self))
        println("    Potential: ",self.potential)
        println("    Error: ",self.error)
        println("    Connections: ",length(self.connections))
    end
end

function Build()
    for i = 1:10000
        Neuron(Dict(),0.0,0.0)
    end
    println(length(neurons), " neurons created.")
    n = 0
    @parallel for neuron in neurons
        n += 1
        partially_connect(neuron)
        println("Counter: ",n)
    end
end

Build()
n = 0
@parallel for neuron in neurons
    n += 1
    partially_connect(neuron)
    println("Counter: ",n)
首先这些部分在每个神经元之间部分地、随机地建立连接,花费了太多的时间。如何加快此过程/部件的速度

Python

import random
import itertools
import time
import signal
from threading import Thread
from multiprocessing import Pool
import multiprocessing

POTENTIAL_RANGE = 110000 # Resting potential: -70 mV Membrane potential range: +40 mV to -70 mV --- Difference: 110 mV = 110000 microVolt --- https://en.wikipedia.org/wiki/Membrane_potential
ACTION_POTENTIAL = 15000 # Resting potential: -70 mV Action potential: -55 mV --- Difference: 15mV = 15000 microVolt --- https://faculty.washington.edu/chudler/ap.html
AVERAGE_SYNAPSES_PER_NEURON = 8200 # The average number of synapses per neuron: 8,200 --- http://www.ncbi.nlm.nih.gov/pubmed/2778101

# https://en.wikipedia.org/wiki/Neuron

class Neuron():

    neurons = []

    def __init__(self):
        self.connections = {}
        self.potential = 0.0
        self.error = 0.0
        #self.create_connections()
        #self.create_axon_terminals()
        Neuron.neurons.append(self)
        self.thread = Thread(target = self.activate)
        #self.thread.start()
        #self.process = multiprocessing.Process(target=self.activate)

    def fully_connect(self):
        for neuron in Neuron.neurons[len(self.connections):]:
            if id(neuron) != id(self):
                self.connections[id(neuron)] = round(random.uniform(0.1, 1.0), 2)

    def partially_connect(self):
        if len(self.connections) == 0:
            neuron_count = len(Neuron.neurons)
            for neuron in Neuron.neurons[len(self.connections):]:
                if id(neuron) != id(self):
                    if random.randint(1,neuron_count/100) == 1:
                        self.connections[id(neuron)] = round(random.uniform(0.1, 1.0), 2)
            print "Neuron ID: " + str(id(self))
            print "    Potential: " + str(self.potential)
            print "    Error: " + str(self.error)
            print "    Connections: " + str(len(self.connections))

    def activate(self):
        while True:
            '''
            for dendritic_spine in self.connections:
                if dendritic_spine.axon_terminal is not None:
                    dendritic_spine.potential = dendritic_spine.axon_terminal.potential
                    print dendritic_spine.potential
                self.neuron_potential += dendritic_spine.potential * dendritic_spine.excitement
            terminal_potential = self.neuron_potential / len(self.axon_terminals)
            for axon_terminal in self.axon_terminals:
                axon_terminal.potential = terminal_potential
            '''
            #if len(self.connections) == 0:
            #   self.partially_connect()
            #else:
            self.partially_connect()
            pass

            '''
            if abs(len(Neuron.neurons) - len(self.connections) + 1) > 0:
                self.create_connections()

            if abs(len(Neuron.neurons) - len(self.axon_terminals) + 1) > 0:
                self.create_axon_terminals()
            '''

class Supercluster():

    def __init__(self,size):
        for i in range(size):
            Neuron()
        print str(size) + " neurons created."
        self.n = 0
        self.build_connections()
        #pool = Pool(4, self.init_worker)
        #pool.apply_async(self.build_connections(), arguments)
        #map(lambda x: x.partially_connect(),Neuron.neurons)
        #map(lambda x: x.create_connections(),Neuron.neurons)
        #map(lambda x: x.create_axon_terminals(),Neuron.neurons)

    def build_connections(self):
        for neuron in Neuron.neurons:
            self.n += 1
            #neuron.thread.start()
            neuron.partially_connect()
            print "Counter: " + str(self.n)

Supercluster(10000)
def build_connections(self):
    for neuron in Neuron.neurons:
        self.n += 1
        #neuron.thread.start()
        neuron.partially_connect()
        print "Counter: " + str(self.n)
朱莉娅

global neurons = []

type Neuron
    connections::Dict{UInt64,Float16}
    potential::Float16
    error::Float16

    function Neuron(arg1,arg2,arg3)
        self = new(arg1,arg2,arg3)
        push!(neurons, self)
    end

end

function fully_connect(self)
    for neuron in neurons
        if object_id(neuron) != object_id(self)
            self.connections[object_id(neuron)] = rand(1:100)/100
            #push!(self.connections, rand(1:100)/100)
        end
    end
end

function partially_connect(self)
    if isempty(self.connections)
        neuron_count = length(neurons)
        for neuron in neurons
            if object_id(neuron) != object_id(self)
                if rand(1:neuron_count/100) == 1
                    self.connections[object_id(neuron)] = rand(1:100)/100
                    #push!(self.connections, rand(1:100)/100)
                end
            end
        end
        println("Neuron ID: ",object_id(self))
        println("    Potential: ",self.potential)
        println("    Error: ",self.error)
        println("    Connections: ",length(self.connections))
    end
end

function Build()
    for i = 1:10000
        Neuron(Dict(),0.0,0.0)
    end
    println(length(neurons), " neurons created.")
    n = 0
    @parallel for neuron in neurons
        n += 1
        partially_connect(neuron)
        println("Counter: ",n)
    end
end

Build()
n = 0
@parallel for neuron in neurons
    n += 1
    partially_connect(neuron)
    println("Counter: ",n)
其次,当我的目标是创造至少一百万个神经元时,给每个神经元分配自己的线程是个好主意吗?这意味着它将像一百万根线

我在这里试图做的是在严格意义上模仿生物神经网络,而不是使用矩阵计算

添加:

新版本的
部分连接
功能符合以下回答:

def partially_connect(self):
    if len(self.connections) == 0:
        neuron_count = len(Neuron.neurons)
        #for neuron in Neuron.neurons:
        elected = random.sample(Neuron.neurons,100)
        for neuron in elected:
            if id(neuron) != id(self):
                #if random.randint(1,neuron_count/100) == 1:
                self.connections[id(neuron)] = round(random.uniform(0.1, 1.0), 2)
        print "Neuron ID: " + str(id(self))
        print "    Potential: " + str(self.potential)
        print "    Error: " + str(self.error)
        print "    Connections: " + str(len(self.connections))

性能显著提高。

看看下面的代码:

def partially_connect(self):
    if len(self.connections) == 0:
        neuron_count = len(Neuron.neurons)
        for neuron in Neuron.neurons[len(self.connections):]:
            if id(neuron) != id(self):
                if random.randint(1,neuron_count/100) == 1:
                    self.connections[id(neuron)] = round(random.uniform(0.1, 1.0), 2)
根据你对我的评论的回复,这里有几件事:

  • 当您使用类似于
    L[0://code>的语法时,您正在制作列表的副本。slice语法为每个函数调用生成
    Neuron.neurons
    数组的浅拷贝。这是一个O(n)操作,由于在
    build\u connections
    函数中为每个神经元调用
    partially\u connect
    一次,因此它是O(n²)。(哎呀!)

  • 您正在使用Python进行工作,这些工作可以而且应该在库中完成(我们希望使用C!)。查看例如
    random.paretovariate()
    random.sample()
    函数。您可以轻松计算
    num\u connections=random.paretovariate(1.0)*100
    ,然后说
    connected\u nodes=random.sample(神经元,num\u connections)
    。从连接的节点中过滤出
    self
    ,就完成了

  • 我认为,通过消除n²行为和使用内置库例程,可以大大提高性能

    添加

    响应你的补充,考虑这个:

    def partially_connect(self):
        if len(self.connections) == 0:
            elected = random.sample(Neuron.neurons,100)
            try:
                elected.remove(self)
            except ValueError:
                pass
    
            for neuron in elected:
                self.connections[id(neuron)] = round(random.uniform(0.1, 1.0), 2)
    
    (我现在忽略了指纹。)

    我不知道如果不迭代所有神经元寻找匹配的
    id()。我建议您存储对连接对象的引用作为键,并使用权重作为值:

    self.connections = [n:round(random.uniform(0.1, 1.0), 2) for n in elected]
    
    当然,这假设您需要遍历从源到目标的链接


    至于线程解决方案,我没有一个好的建议。通过谷歌搜索,我找到了一些旧的电子邮件线程(呵呵!),其中提到405和254等数字是线程创建限制。我没有看到任何文档说“Python线程现在是无限的!”或其他什么,所以我怀疑您必须改变实现解决方案的方式。

    在Julia中,如果性能重要:不要使用全局变量(请参见
    神经元
    数组),也不要使用非类型数组(再次,请参见
    神经元
    数组)。看。您还应该分析以确定瓶颈所在的位置。我强烈建议您在不使用
    @并行
    的情况下尝试它,直到您能够快速获得它为止

    我亲自研究了一下,除此之外,我还发现了一些令人惊讶的瓶颈:

    • rand(1:neuron_count/100)
      创建浮点范围,而不是整数范围。这是一个巨大的瓶颈,分析立即发现了这一点。使用
      rand(1:neuron\u count÷100)
    • 最好不要调用
      object\u id
      ,只需使用
      !(神经元===自身)
      。或者更好,将
      神经元作为数组和要修改的条目的整数索引传递
    解决了这些问题后,我成功地将程序的执行时间从大约140秒降到了4秒(在去掉了不太可能有用的
    @parallel
    ,并注释掉文本显示之后)。几乎所有的运行时间都只是用来生成随机数;您可以一次生成一个大的池,而不是一个接一个地生成它们,从而加速这一过程

    这使用ProgressMeter包(必须安装)来显示进度

    using ProgressMeter
    
    type Neuron
        connections::Dict{UInt64,Float16}
        potential::Float16
        error::Float16
    end
    
    function fully_connect(self, neurons)
        for neuron in neurons
            if object_id(neuron) != object_id(self)
                self.connections[object_id(neuron)] = rand(1:100)/100
                #push!(self.connections, rand(1:100)/100)
            end
        end
    end
    
    function partially_connect(self, neurons)
        if isempty(self.connections)
            neuron_count = length(neurons)
            for neuron in neurons
                if !(neuron === self)
                    if rand(1:neuron_count÷100) == 1
                        self.connections[object_id(neuron)] = rand(1:100)/100
                        #push!(self.connections, rand(1:100)/100)
                    end
                end
            end
    #         println("Neuron ID: ",object_id(self))
    #         println("    Potential: ",self.potential)
    #         println("    Error: ",self.error)
    #         println("    Connections: ",length(self.connections))
        end
    end
    
    function Build()
        neurons = [Neuron(Dict(),0.0,0.0) for i = 1:10000]
        println(length(neurons), " neurons created.")
        @showprogress 1 "Connecting neurons..." for neuron in neurons
            partially_connect(neuron, neurons)
        end
        neurons
    end
    
    neurons = Build()
    

    不幸的是,我不能回答你的问题,但我只是一个建议——也许用更少的粗体和斜体字?这有点难读。祝你好运:)是的,你不能做一百万个线程。你为什么要这么做?由于全局解释器锁定,Python无法进入多线程以提高性能。@DonkeyKong感谢您的建议:)这可能是使用tornado或asyncio的微线程(也称为协程)的一个很好的候选。每个神经元都可以通过一些套接字(甚至通过WebSocket)与超星系团通信,它们各自可以运行子协同路由、定期回调等。同样,协同路由可以使大部分代码无阻塞,这意味着您可以将构建连接“延迟”到io_循环,而io_循环将异步执行,让你的for循环非常快。异步编程需要很多时间来理解,但它确实非常强大。祝你好运。
    [len(self.connections):]
    来自我的旧版本,我忘了删除。我现在删除了,但仍然没有表现上的差异。我如何摆脱O(n²)并使其变得O(n)复杂?不过,我还是不明白。您的第二个语句使用了
    random.sample()
    极大地提高了性能。谢谢!但我