{"id":15519711,"url":"https://github.com/mertyildiran/plexus","last_synced_at":"2025-07-19T07:04:14.174Z","repository":{"id":57453427,"uuid":"56610247","full_name":"mertyildiran/Plexus","owner":"mertyildiran","description":"a novel object-oriented approach to the artificial neural networks inspired by synaptic plasticity between biological neurons","archived":false,"fork":false,"pushed_at":"2020-07-26T15:52:04.000Z","size":346,"stargazers_count":12,"open_issues_count":0,"forks_count":6,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-30T07:32:19.590Z","etag":null,"topics":["architecture-free","artificial-neural-networks","bio-inspired","biology","layerless","modular","neurons"],"latest_commit_sha":null,"homepage":"https://pypi.python.org/pypi/plexus","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mertyildiran.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-04-19T15:45:24.000Z","updated_at":"2024-01-13T23:55:12.000Z","dependencies_parsed_at":"2022-09-26T17:50:42.928Z","dependency_job_id":null,"html_url":"https://github.com/mertyildiran/Plexus","commit_stats":null,"previous_names":["mertyildiran/supercluster"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mertyildiran%2FPlexus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mertyildiran%2FPlexus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mertyildiran%2FPlexus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mertyildiran%2FPlexus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mertyildiran","download_url":"https://codeload.github.com/mertyildiran/Plexus/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249319594,"owners_count":21250578,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["architecture-free","artificial-neural-networks","bio-inspired","biology","layerless","modular","neurons"],"created_at":"2024-10-02T10:22:29.179Z","updated_at":"2025-04-17T06:31:11.993Z","avatar_url":"https://github.com/mertyildiran.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://s2.gifyu.com/images/smaller.gif\" alt=\"Plexus\"/\u003e\n\u003c/p\u003e\n\n## Core Principles\n\nThese are the core principles of **object-oriented** approach to the current state of artificial neural networks that is inspired by **synaptic plasticity** between **biological** neurons:\n\n - Unlike the current ANN implementations, **neurons** must be **objects** not tensors between matrices.\n - Just the current ANN implementations, **neurons** should be **GPU accelerated** (ideally) to provide the necessary parallelism.\n - While the current ANN implementations can only create special cases, a **Plexus Network** must be **architecture-free** (i.e. adaptive) to create a generalized solution of all machine learning problems.\n - Instead of dealing with decision of choosing an ANN layer combination(such as Convolution, Pooling or Recurrent layers), the network must have a **layerless design**.\n - There must be fundamentally two types of neurons: **sensory neuron**, **interneuron**.\n - Input of the network must be made of sensory neurons. Any interneuron can be picked as a **motor neuron** (an element of the output). There are literally no difference between an interneuron and a motor neuron except the intervene of the network for igniting the wick of learning process through the motor neurons. Any non-motor interneuron can be assumed as a **cognitive neuron** which collectively forms the cognition of network.\n - There can be arbitrary amount of I/O groups in a single network.\n - Instead of batch size, iteration, and epoch concepts, training examples must be fed on time basis with a manner like; *learn first sample for X seconds, OK done? then learn second sample for Y seconds*. By this approach, you can assign importance factors to your samples with maximum flexibility.\n - **Network** must be **retrainable**.\n - Network must be **modular**. In other words: You must be able to train a small network and then plug that network into a bigger network (we are talking about some kind of **self-fusing** here).\n - Neurons must exhibit the characteristics of **cellular automata** just like Conway's Game of Life.\n - **Number of neurons** in the network can be increased or decreased (**scalability**).\n - There must be **no** need for a network-wide **oscillation**. Yet the execution of neurons should follow a path very similar to flow of electric current nevertheless.\n - Network should use **randomness** and/or **uncertainty principle** flawlessly. Consciousness is an emergent property from cellular level to macro scale, the network. But it's also an emergent property for the neuron from quantum level uncertainty to cellular mechanisms. In such a way that **randomness** is the cause of the illusion of consciousness.\n - Most importantly, the network **must and can not iterate** through the whole dataset. Besides that, it's also generally impossible to iterate the whole dataset on real life situations if the system is continuous like in robotics. Because of that; the network must be designed to handle such a **continuous data stream** that literally endless and must be designed to handle that data stream chunk by chunk. Therefore, when you are feeding the network, use a diverse feed but not a grouped feed (*like 123123123123123123 but not like 111111222222333333*).\n\n### Activation function\n\nThe activation function that used by Plexus is Sigmoid:\n\n\u003cp align=\"left\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/mertyildiran/Plexus/master/docs/img/activation.png\" alt=\"Activation function\"/\u003e\n\u003c/p\u003e\n\u003c!-- LaTeX of above image:  \\sigma (x) = \\frac{1}{1 + e^{-x}}  --\u003e\n\nand the derivative of the Sigmoid function:\n\n\u003cp align=\"left\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/mertyildiran/Plexus/master/docs/img/activation_derivative.png\" alt=\"Derivative of the activation function\"/\u003e\n\u003c/p\u003e\n\u003c!-- LaTeX of above image:  \\sigma ' (x) = x \\times (1 - x)  --\u003e\n\nImplementation of this algorithm in Python programming language is publicly accessible through this link: https://github.com/mertyildiran/Plexus/blob/master/plexus/plexus.py\n\nYou can directly skip to [Application](https://github.com/mertyildiran/Plexus#application) part if you are not willing to understand the mathematical and algorithmic background.\n\n## Basics\n\nPlexus Network has only two classes; **Network** and **Neuron**. In a Plexus Network, there are many instances of Neuron class but there is only one instance of Network class.\n\nWhen you crate a new Plexus Network you give these five parameters to the Network class: *size of the network*, *input dimension*, *output dimension*, *connectivity rate*, *precision*. The network accordingly builds itself.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/mertyildiran/Plexus/master/docs/img/init.png\" alt=\"Network init function\"/\u003e\n\u003c/p\u003e\n\u003c!-- LaTeX of above image:  \\Theta (n,i,o,c, \\rho )  --\u003e\n\n - **size** is literally equal to total number of neurons in the network. All neurons are referenced in an instance variable called `Network.neurons`\n - **input dimension** specifies the number of sensory neurons. Sensory neurons are randomly selected from neurons.\n - **output dimension** specifies the number of motor neurons. Motor neurons are randomly selected from non-sensory neurons.\n - number of neurons multiplied by **connectivity rate** gives the average number of subscriptions made by a single neuron.\n\n \u003cp align=\"center\"\u003e\n   \u003cimg src=\"https://raw.githubusercontent.com/mertyildiran/Plexus/master/docs/img/connectivity.png\" alt=\"Connectivity\"/\u003e\n \u003c/p\u003e\n \u003c!-- LaTeX of above image:   c  \\leftarrow  n \\times c --\u003e\n\n - **precision** simply defines the precision of the all calculations will be made by neurons (how many digits after the decimal point).\n\nAfter the network has been successfully created. It will ignite itself automatically. Ignition in simple terms, no matter if you have plugged in some data or not, it will fire the neurons with using some mechanism very similar to flow of electric current (*will be explained later on this paper*).\n\n### Anatomy of a Single Neuron\n\nA single neuron in a Plexus Network, takes the network as the only parameter and stores these seven very important information (in it's instance variables): *subscriptions*, *publications*, *potential*, *desired_potential*, *loss* and *type*\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/mertyildiran/Plexus/master/docs/img/neuron_init.png\" alt=\"Neuron init function\"/\u003e\n\u003c/p\u003e\n\u003c!-- LaTeX of above image:  \\Xi ( \\Theta )  --\u003e\n\nThere are eventually there types of neurons:\n\n - `Neuron.type = 1` means it's a sensory neuron.\n - `Neuron.type = 2` means it's a motor neuron.\n - `Neuron.type = 0` means it's neither a sensory nor a motor neuron. It means it's an cognitive interneuron (or just cognitive neuron).\n\nFunctionality of a neuron is relative to its type.\n\n**subscriptions** is neuron's indirect data feed. Each non-sensory neuron subscribes to some other neurons of any type. For sensory neurons, subscriptions are completely meaningless and empty by default because it gets its data feed from outside world by assignments of the network. Subscriptions are literally the Plexus Network equivalent of **Dendrites** in biological neurons. *subscriptions* is a dictionary that holds **Neuron(reference)** as key and **Weight** as value.\n\n**publications** holds literally the mirror data of *subscriptions* in the target neurons. In other words; any subscription creates also a publication reference in the target neuron. Similarly, *publications* is the Plexus Network equivalent of **Axons** in biological neurons.\n\n**potential** *`p`* is the overall total potential value of all subscriptions multiplied by the corresponding weights. Only in sensory neurons, it is directly assigned by the network. Value of **potential** may only be updated by the neuron's itself and its being calculated by this simple formula each time when the neuron is fired:\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/mertyildiran/Plexus/master/docs/img/total_potential.png\" alt=\"Total potential\"/\u003e\n\u003c/p\u003e\n\u003c!-- LaTeX of above image:  t = \\sum_{i=0}^{n} p_{i} \\times w_{i}  --\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/mertyildiran/Plexus/master/docs/img/apply_activation.png\" alt=\"Apply activation\"/\u003e\n\u003c/p\u003e\n\u003c!-- LaTeX of above image:  p =  \\varphi (t)  --\u003e\n\n**desired_potential** *`p'`* is the ideal value of the neuron's potential that is desired to eventually reach. For sensory neurons, it is meaningless. For motor neurons, it is assigned by the network. If it's **None** then the neuron does not learn anything and just calculates potential when it's fired.\n\n**loss** *`l`* is calculated not just at the output but in every neuron except sensory ones and it is equal to absolute difference (*distance*) between desired potential and current potential.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/mertyildiran/Plexus/master/docs/img/calc_of_loss.png\" alt=\"Calculation of loss\"/\u003e\n\u003c/p\u003e\n\u003c!-- LaTeX of above image:  l = \\left | \\Delta p \\right | = \\left | p' - p \\right |  --\u003e\n\nAll numerical values inside a neuron are floating point numbers and all the calculations obey to the precision that given at start.\n\n### Sensory and Motor Neurons\n\nInput Layer in classical neural networks renamed as **Sensory Neurons** in Plexus networks, and Target/Output Layer renamed as **Motor Neurons**. This naming convention is necessary cause the built of the relevance of artificial neural networks with biological neural networks and Neuroscience.\n\nThe difference of sensory neurons from the cognitive neurons (that neither sensory nor motor ones) is, they do not actually fire. They just stand still for the data load. They do not have any subscriptions to the other neurons (literally no subscriptions). But they can be subscribed by the other neurons, including motor ones. They do not learn, they do not consume any CPU resources. They just stored in the memory. You can assign an image, a frame of a video, or a chunk of an audio to a group of sensory neurons.\n\nThe difference of motor neurons form the other neurons is, they are only responsible to the network. They act as the fuse of the learning and calculation of the loss. The network dictates a desired potential on each motor neuron. The motor neuron calculates its potential, compares it with desired potential, calculates the loss then tries to update its weights randomly many times and if it fails, it blames its subscriptions. So just like the network, motor neurons are also able to dictate a desired potential on the other non-motor neurons. This is why any neuron holds an additional potential variable called **desired_potential**.\n\n### Partially Subscribe\n\nOn the second phase of the network initiation, any non-sensory neurons are forced to subscribe to some non-motor neurons which are selected by random sampling. Length of this sample is also selected by random sampling (*rounds to nearest integer*) is done from a normal distribution. Such a normal distribution that, the average number of subscriptions is the mean, and square root of the mean is the standard deviation. (*e.g. if neurons on average has 100 subscriptions then the mean is 100 and the standard deviation is 10*)\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/mertyildiran/Plexus/master/docs/img/normal_distribution.png\" alt=\"Normal distribution\"/\u003e\n\u003c/p\u003e\n\u003c!-- LaTeX of above image:  P(x) = \\frac{1}{{ \\sqrt {2\\pi c } }} \\ e^{ - \\frac{( x - c )^2}{2c}}  --\u003e\n\n## Algorithm\n\nEven so the Python implementation of Plexus Network is easy to understand, it will be helpful for readers to explain the algorithm in pseudocode;\n\n### Initiation\n\n```pascal\nprocedure initiate the network is\n    connectivity ← size * connectivity_rate;\n    connectivity_sqrt ← sqrt(connectivity);\n    connectivity_sqrt_sqrt ← sqrt(connectivity_sqrt);\n    for item in size, do\n        create neuron;\n    end\n    pick sensory neurons randomly;\n    pick motor neurons randomly;\n    determine non-sensory neurons;\n    determine non-motor neurons;\n    initiate subscriptions;\n    initiate instance variables;\n    ignite the network;\n```\n\nInitiation is nothing more than a **make the assignments for once** phase until the ignition. The final step (ignition) never stops but can be paused (if user wants).\n\n### Initiate Subscriptions\n\n```pascal\nprocedure initiate subscriptions is\n    for neuron in neurons, do\n        if neuron is not a sensory neuron, then\n            call neuron.partially_subscribe();\n        end\n    end\n    return True;\n```\n\n### Partially Subscribe\n\n```pascal\nprocedure partially subscribe is\n    sample ← randomly sample approximately \"connectivity\" units of a neuron from within all non-motor neurons;\n    for neuron in sample, do\n        if neuron is not self, then\n            establish a subscription;    // weight is randomly assigned\n            establish a publication;\n        end\n    end\n    return True;\n```\n\nThe time complexity of the procedure **initiate subscriptions** is **O(n\u003csup\u003e2\u003c/sup\u003e)**, so this may take a while if the size of the network and connectivity is big.\n\n### Ignite\n\n```pascal\nprocedure ignite subscriptions is\n    create an empty ban_list;\n    while network is not frozen, do\n        if next_queue is empty, then\n            get the output of network and print it;\n            increase the wave_counter;\n            if first_queue is empty, then\n                for neuron in sensory neurons, do\n                    for target_neuron in neuron.publications, do\n                        append target_neuron to first_queue;\n                    end\n                end\n                copy first_queue to next_queue;\n            end\n        end\n        copy next_queue to current_queue;\n        empty next_queue;\n        for neuron in ban_list, do\n            if neuron.ban_counter \u003e connectivity_sqrt_sqrt, then\n                remove the neuron from current_queue;\n            end\n        end\n        while current_queue is not empty, do\n            neuron ← select a random neuron from current_queue;\n            remove the neuron from current_queue;\n            if neuron.ban_counter \u003c= connectivity_sqrt_sqrt, then\n                call neuron.fire();\n                append the neuron to ban_list;\n                increase neuron.ban_counter;\n                for target_neuron in neuron.publications, do\n                    append target_neuron to next_queue;\n                end\n            end\n        end\n    end\n```\n\nProcedure **ignite** regulates the firing order of neurons and creates an effect very similar to flow of electric current, network wide. It continuously runs until the network frozen, nothing else can stop it. It fires the neurons step by step through adding them to a queue.\n\nIt generates its first queue from the publications of sensory neurons. Time complexity of `if next_queue is empty, then` block is **O(n\u003csup\u003e2\u003c/sup\u003e)** but it can be ignored (unless there are too many sensory neurons) because it runs once per wave.\n\nIt eliminates banned neurons with `for neuron in ban_list, do` block. Function of `ban_counter` is giving neurons `connectivity_sqrt_sqrt` amount of chance after they added to `ban_list`. Then it fires the neurons inside current_queue, one by one, choosing them randomly.\n\nAfter a neuron fired, it adds the fired neuron to `ban_list` and lastly copies the publications of that neuron to `next_queue` so execution(firing process) can follow the path through the connections.\n\nEach execution from first sensory neuron to last motor neuron symbolizes one wave. Every time a wave finished, procedure falls into `if next_queue is empty, then` block so wave starts over from the sensory neurons.\n\n`ban_counter` and `connectivity_sqrt_sqrt` comparison creates execution loops inside cognitive neurons and these loops act like **memory units** which is a pretty important concept. Because loops create the relation between currently fed data and previously learned data. Without these loops the network fails on both classification and regression problems.\n\nBecause `neuron.fire()` has a time complexity of **O(n\u003csup\u003e2\u003c/sup\u003e)**, each turn inside `while network is not frozen, do` block, has a time complexity of **O(n\u003csup\u003e4\u003c/sup\u003e)**. But don't worry because it will approximate to **O(n\u003csup\u003e3\u003c/sup\u003e)** because of the probabilistic nature of fire function and the network will fire more than a million of neurons per minute. By the way, `while network is not frozen, do` block is ignored because it's an endless loop under normal conditions.\n\n### Fire\n\n```pascal\nprocedure fire is\n    if self is not a sensory neuron, then\n        potential ← calculate potential;\n        increase fire counter;\n        if desired_potential is not None, then\n\n            loss ← calculate loss;\n            if loss = 0, then\n                desired_potential ← None;\n                return True;\n            end\n            if blame_lock is not empty, then\n                if (wave_counter - blame_lock) \u003c connectivity, then\n                    return True;\n                else\n                    blame_lock ← None;\n            end\n\n            try connectivity times:\n                generate new weights randomly;\n                calculate new potential and new loss according to these weights;\n                if loss_new \u003c loss_current, then return True;\n            end\n\n            try sqrt(connectivity) times:\n                generate hypothetical potentials for neurons in subscriptions randomly;\n                calculate new potential and new loss according to these hypothetical potentials;\n                if loss_new \u003c loss_current, then\n                    apply these hypothetical potentials as \"desired_potential\"s;\n                    return True;\n                end\n            end\n\n            if (still) not improved, then\n                either create some new subscriptions;\n                or break some of the subscriptions;\n                return True;\n            end\n\n        end\n    end\n```\n\nProcedure **fire** handles all feedforwarding, backpropagation and learning process by itself. **fire** function is an instance method of Neuron class. This procedure is by far the most important one in the Plexus Network. It's basically the core function and CPU spends most of its time to execute fire functions again and again.\n\nIf `desired_potential` is not assigned to a value, then it just calculates the potential and finishes.\n\nIf `desired_potential` is assigned to a value, then first it calculates the **loss**. If loss is equal to zero, then the current state of the neuron is perfectly well and there is nothing to learn.\n\nIf `blame_lock` is not empty, then it will pass this function **connectivity times** with this control statement: `if blame_lock is not empty, then`.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/mertyildiran/Plexus/master/docs/img/improved.png\" alt=\"Neuron improved\"/\u003e\n\u003c/p\u003e\n\u003c!-- LaTeX of above image:  if \\ \\ l' - l \u003c 0 \\ \\ \\ \\  then \\ \\   \\Xi ' \u003e  \\Xi \\ \\ \\ \\ \\checkmark  --\u003e\n\nIt tries to improve the current state of the neuron by **updating its weights randomly**, *connectivity times*. If it's improved, then break.\n\nIt tries to improve the current state of the neuron by **dictating randomly generated hypothetical potentials over the subscriptions**, *square root of connectivity times*. If it's improved, then break.\n\nIf it still is not improved, then it either creates some new subscriptions or breaks some of the subscriptions it currently has and hopes it will lead the neuron to new improvements in the future.\n\nOn the first wave, the **fire** function is only meaningful for motor neurons but after the first wave `desired_potential` dictation will spread throughout the cognitive neurons.\n\n### Load\n\n```pascal\nprocedure load (input, output) is\n    if output is None, then\n        for neuron in motor neurons, do\n            neuron.desired_potential ← None;\n        end\n    end\n    if (number of sensory neurons is not equal to input length), then\n        raise an error but do not interrupt the network;\n    else\n        for neuron in sensory neurons, do\n            neuron.potential ← load from the input;\n        end\n    end\n    if (number of motor neurons is not equal to output length), then\n        raise an error but do not interrupt the network;\n    else\n        for neuron in motor neurons, do\n            neuron.desired_potential ← load from the output;\n        end\n    end\n```\n\nProcedure **load** is the only method that you can feed your data to the network. You should call that function and load your data in real time. Also you should do it periodically and continuously, like every 3 seconds. If you leave second parameter empty then this procedure will automatically assume that you are testing the network, so it will replace `desired_potential` values of motor neurons with `None`. Otherwise, it means you are training the network so it will load the input data to sensory neurons and it will load the output data to `desired_potential` values of motor neurons.\n\n## Application\n\n### Installation of the Python Package\n\n```Shell\npip install plexus\n```\n\nIf you want to install Plexus on development mode:\n\n```Shell\ngit clone https://github.com/mertyildiran/Plexus.git\ncd Plexus/\npip install -e .\n```\n\nor alternatively:\n\n```Shell\nmake dev\n```\n\nand test the installation with:\n\n```Shell\nmake cpp\n```\n\n### Examples\n\n#### Binary Classification Example\n\n\u003csup\u003e*(you can alternatively run this example with `python3 examples/classification_binary.py` command using a pre-written script version of below commands)*\u003c/sup\u003e\n\nSuppose you need to train the network to figure out that the elements of given arrays are bigger than 0.5 or not (like `[0.9, 0.6, 1.0, 0.8]` or `[0.1, 0.3, 0.0, 0.4]`) and suppose it's a 4-element array. So let's create a network according to your needs:\n\n```python\nimport cplexus as plexus\n\nSIZE = 14\nINPUT_SIZE = 4\nOUTPUT_SIZE = 2\nCONNECTIVITY = 1\nPRECISION = 2\nRANDOMLY_FIRE = False\nDYNAMIC_OUTPUT = True\nVISUALIZATION = False\nnet = plexus.Network(\n    SIZE,\n    INPUT_SIZE,\n    OUTPUT_SIZE,\n    CONNECTIVITY,\n    PRECISION,\n    RANDOMLY_FIRE,\n    DYNAMIC_OUTPUT,\n    VISUALIZATION\n)\n```\n\nIf you want to visualize the network using [PyQtGraph](http://www.pyqtgraph.org/) enable `VISUALIZATION = False`. Because our network is automatically initiated and ignited, now all we have to do is training the network. So let's train our network with 80 samples:\n\n```python\nPRECISION = 2\nTRAINING_SAMPLE_SIZE = 20\nfor i in range(1, TRAINING_SAMPLE_SIZE):\n    if (i % 2) == 0:\n        output = [1.0, 0.0]\n        generated_list = generate_list_bigger()\n        notify_the_load(generated_list, output, TRAINING_DURATION)\n        net.load(generated_list, output)\n    else:\n        output = [0.0, 1.0]\n        generated_list = generate_list_smaller()\n        notify_the_load(generated_list, output, TRAINING_DURATION)\n        net.load(generated_list, output)\n    time.sleep(TRAINING_DURATION)\n```\n\nYou should load your data one by one from each kind, respectively. Because it will prevent over fitting to one specific kind. You must wait a short time like `TRAINING_DURATION = 0.01` seconds (which is a reasonable duration in such a case), after each load.\n\n`output[0]` will converge to detect **bigger than 0.5** inputs.\n\n`output[1]` will converge to detect **smaller than 0.5** inputs.\n\nBefore the testing you should define a criteria called `DOMINANCE_THRESHOLD` so you can catch the decision making. Now let's test the network:\n\n```python\nerror = 0\nerror_divisor = 0\nfor i in repeat(None, TESTING_SAMPLE_SIZE):\n    binary_random = random.randint(0, 1)\n    if binary_random == 0:\n        generated_list = generate_list_bigger()\n        expected = [1.0, 0.0]\n    else:\n        generated_list = generate_list_smaller()\n        expected = [0.0, 1.0]\n\n    net.load(generated_list)\n    time.sleep(TRAINING_DURATION)\n\n    output = net.output\n    error += abs(expected[0] - output[0])\n    error += abs(expected[1] - output[1])\n    error_divisor += 2\n```\n\nWith the `while` loop given above, you will be able to check the output by giving enough time to propagate your input throught the network. By giving `net.load()` only one parameter here, you automatically disable the training.\n\nNow freeze your network and calculate the overall error:\n\n```python\nnet.freeze()\nerror = error / error_divisor\n```\n\nwhich outputs:\n\n```text\nOverall error: 0.010249996604397894\n```\n\n#### Classifying Prime Numbers Example\n\nThis example is quite simple to the previous example but this time we are teaching the network to understand if the given number is prime or not. Which is a relatively complex problem.\n\nRun `python3 examples/classification_prime.py 1 -l cpp` to see the result. You will observe that the network is able to learn the solution for such a complex problem in the matter of seconds.\n\n#### Sequence Basic Example\n\nIn this example, instead of classification, we will train the network to detect a pattern in given sequence. The magic here is; without even changing anything related to network, just by changing logic we feed the data into the network, the network automatically turns into a [Recurrent Neural Network](https://en.wikipedia.org/wiki/Recurrent_neural_network).\n\nRun `python3 examples/sequence_basic.py` to see the output. This is the output you should see:\n\n```text\n___ PLEXUS NETWORK BASIC SEQUENCE RECOGNITION EXAMPLE ___\n\nCreate a Plexus network with 14 neurons, 4 of them sensory, 1 of them motor, 1 connectivity rate, 2 digit precision\n\nPrecision of the network will be 0.01\nEach individual non-sensory neuron will subscribe to 14 different neurons\n14 neurons created\n4 neuron picked as sensory neuron\n1 neuron picked as motor neuron\nNetwork has been ignited\n\n*** LEARNING ***\n\nGenerate The Dataset (20 Items Long) To Recognize a Sequence \u0026 Learn for 0.1 Seconds Each\nLoad Input: [1.0, 0.0, 0.0, 0.0]\tOutput: [0.0]\tand wait 0.1 seconds\nLoad Input: [0.0, 1.0, 0.0, 0.0]\tOutput: [0.0]\tand wait 0.1 seconds\nLoad Input: [0.0, 0.0, 1.0, 0.0]\tOutput: [0.0]\tand wait 0.1 seconds\nLoad Input: [0.0, 0.0, 0.0, 1.0]\tOutput: [0.0]\tand wait 0.1 seconds\nLoad Input: [1.0, 0.0, 0.0, 0.0]\tOutput: [0.0]\tand wait 0.1 seconds\nLoad Input: [0.0, 1.0, 0.0, 0.0]\tOutput: [0.0]\tand wait 0.1 seconds\nLoad Input: [0.0, 0.0, 1.0, 0.0]\tOutput: [0.0]\tand wait 0.1 seconds\nLoad Input: [0.0, 0.0, 0.0, 1.0]\tOutput: [1.0]\tand wait 0.1 seconds\nLoad Input: [1.0, 0.0, 0.0, 0.0]\tOutput: [0.0]\tand wait 0.1 seconds\nLoad Input: [0.0, 1.0, 0.0, 0.0]\tOutput: [0.0]\tand wait 0.1 seconds\nLoad Input: [0.0, 0.0, 1.0, 0.0]\tOutput: [0.0]\tand wait 0.1 seconds\nLoad Input: [0.0, 0.0, 0.0, 1.0]\tOutput: [0.0]\tand wait 0.1 seconds\nLoad Input: [1.0, 0.0, 0.0, 0.0]\tOutput: [0.0]\tand wait 0.1 seconds\nLoad Input: [0.0, 1.0, 0.0, 0.0]\tOutput: [0.0]\tand wait 0.1 seconds\nLoad Input: [0.0, 0.0, 1.0, 0.0]\tOutput: [0.0]\tand wait 0.1 seconds\nLoad Input: [0.0, 0.0, 0.0, 1.0]\tOutput: [1.0]\tand wait 0.1 seconds\n...\n```\n\nby looking at this output, you should be able to see the pattern. Now on testing stage you can see how successful the network is on detecting the pattern:\n\n```text\n*** TESTING ***\n\nTest the network with random data (20 times)\nLoad Input: ([1.0, 0.0, 0.0, 0.0], [0.0])\tRESULT: 0.019999999552965164\nLoad Input: ([0.0, 1.0, 0.0, 0.0], [0.0])\tRESULT: 0.0\nLoad Input: ([0.0, 0.0, 1.0, 0.0], [0.0])\tRESULT: 0.019999999552965164\nLoad Input: ([0.0, 0.0, 0.0, 1.0], [0.0])\tRESULT: 0.019999999552965164\nLoad Input: ([1.0, 0.0, 0.0, 0.0], [0.0])\tRESULT: 0.0\nLoad Input: ([0.0, 1.0, 0.0, 0.0], [0.0])\tRESULT: 0.0\nLoad Input: ([0.0, 0.0, 1.0, 0.0], [0.0])\tRESULT: 0.05999999865889549\nLoad Input: ([0.0, 0.0, 0.0, 1.0], [1.0])\tRESULT: 0.6600000262260437\nLoad Input: ([1.0, 0.0, 0.0, 0.0], [0.0])\tRESULT: 0.019999999552965164\nLoad Input: ([0.0, 1.0, 0.0, 0.0], [0.0])\tRESULT: 0.0\nLoad Input: ([0.0, 0.0, 1.0, 0.0], [0.0])\tRESULT: 0.05999999865889549\nLoad Input: ([0.0, 0.0, 0.0, 1.0], [0.0])\tRESULT: 0.6600000262260437\nLoad Input: ([1.0, 0.0, 0.0, 0.0], [0.0])\tRESULT: 0.019999999552965164\nLoad Input: ([0.0, 1.0, 0.0, 0.0], [0.0])\tRESULT: 0.0\nLoad Input: ([0.0, 0.0, 1.0, 0.0], [0.0])\tRESULT: 0.0\nLoad Input: ([0.0, 0.0, 0.0, 1.0], [1.0])\tRESULT: 0.9800000190734863\n...\n```\n\nand the overall error:\n\n```text\nNetwork is now frozen\n\n1786760 waves are executed throughout the network\n\nIn total: 66110093 times a random non-sensory neuron is fired\n\n\nOverall error: 0.040124996623490006\n```\n\n#### CatDog Example\n\n\u003csup\u003e*(you can alternatively run this example with `python3 examples/catdog.py` command using a pre-written script version of below commands)*\u003c/sup\u003e\n\nSuppose you need to train the network to figure out that the given image (32x32 RGB) is an image of a cat or a dog and map them to blue and red respectively. So let's create a network according to your needs:\n\n```python\nSIZE = 32 * 32 * 3 + 3 + 256\nINPUT_SIZE = 32 * 32 * 3\nOUTPUT_SIZE = 3\nCONNECTIVITY = 0.005\nPRECISION = 3\nTRAINING_DURATION = 3\nRANDOMLY_FIRE = False\nDYNAMIC_OUTPUT = False\nVISUALIZATION = False\nnet = plexus.Network(\n    SIZE,\n    INPUT_SIZE,\n    OUTPUT_SIZE,\n    CONNECTIVITY,\n    PRECISION,\n    RANDOMLY_FIRE,\n    DYNAMIC_OUTPUT,\n    VISUALIZATION\n)\n```\n\nWe will plug in 32x32 RGB to the network so we need 3072 sensory neurons. 3 motor neurons for see how RGB our result is and 256 cognitive neurons to train. We need 3 digits precision because we need to store 255 different values between 0.0 and 1.0 range.\n\nExplaining the answer of *How to load CIFAR-10 dataset and use it* is out of the scope of this paper but you can easily understand it by reading the code: `examples/catdog.py` Once you get the numpy array of CIFAR-10 (or any other image data) just normalize it and load:\n\n```python\nTRAINING_SAMPLE_SIZE = 20\nfor i in range(1, TRAINING_SAMPLE_SIZE):\n    if (i % 2) == 0:\n        cat = random.sample(cats, 1)[0]\n        cat_normalized = np.true_divide(cat, 255).flatten()\n        blue_normalized = np.true_divide(blue, 255).flatten()\n        cv2.imshow(\"Input\", cat)\n        net.load(cat_normalized, blue_normalized)\n    else:\n        dog = random.sample(dogs, 1)[0]\n        dog_normalized = np.true_divide(dog, 255).flatten()\n        red_normalized = np.true_divide(red, 255).flatten()\n        cv2.imshow(\"Input\", dog)\n        net.load(dog_normalized, red_normalized)\n    show_output(net)\n```\n\nYou will get an **Overall error** as the result very similar to examples above although this time the input length was 768 times bigger. This is because Plexus Network amalgamates the problems from all levels of difficulty on a single medium. It makes easy problems relatively hard, and hard problems relatively easy.\n\nWhen you run this example, you will get a slightly better result when compared to flipping a coin. You will most likely get an **Overall error** between 0.35 - 0.45 which is the proof that the network is able to learn something.\n\nBy the way, don't forget that; Plexus Network does not iterate over the dataset and furthermore it runs in real-time. Also you have trained the network just for 4-5 minutes. Now let's see what happens if we train our network for a long period of time:\n\n#### Note\n\nImplementation of GPU acceleration and saving the trained network to disk are in work-in-progress (WIP) state. Therefore some parts of the implementation are subject to change.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmertyildiran%2Fplexus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmertyildiran%2Fplexus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmertyildiran%2Fplexus/lists"}