📜 ⬆️ ⬇️

Neurocell code



Hello, dear community GeekTimes! Not so long ago a series of articles devoted to the work on the creation of a model of the nervous system was published here. And the best way to understand the logic of the model is the possibility of studying the program code of its implementation. I not only want to convey my ideas in more detail, but also ask for help from the community. I know that among GT readers there are a lot of professionals in writing software code and your experience, knowledge can help the development of the project. Sometimes there is enough competent advice or recommendation so that the solution of such an unusual task becomes elegant and easy.


Development environment - Unity3D, a very popular game engine. This medium turned out to be very convenient and accessible both in the work with the editor and in the presence of a large number of references, explanations and comments in Russian. Therefore, my modest programming skills were enough to implement my ideas using Unity3D.

There are no plans to change the development environment, as the game engine makes it easy to solve visualization tasks, which is very important at this stage.
')
I want to apologize to those who want to refer to the code for its negligence, the possible neglect of the syntax of the language and possible errors. When I started this work, there was no demonstration of code in the plans. I wanted to test some of my hypotheses.

The code reflects the creative search. In the process of work, I faced another problem, the model did not want to act as I imagined it. And during the day, an idea of ​​how to fix this could come to me. In these moments, I can be inspired by some insight. Returning from work, I eagerly amended, ignoring all the norms in the code, there was no time for that. And as often happens, these insights did not bring results, or did not bring quite the desired result. This was how the project worked, and thanks for the patience of my wife, which allowed me to carry out this work. It is difficult to find time between family, work, your own procrastination and laziness for the routine work of standardizing code. Although it will still have to do sometime.

In my work, I adhered to a somewhat non-typical model of the work of a neuron. A neuron model like a biological neuron could act asynchronously from the work of other neurons. Signals from receptor keys such as, for example, skin receptors may not be synchronized. Therefore, in the first models, under the influence of stereotypical thinking, I singled out in the work of a neuron some phases of the state lasting a certain number of steps (cycles) of the entire system, and the steps of the system were performed simultaneously in all neurons. It did not work properly, and it was also terribly uncomfortable. But it was necessary to somehow synchronize the incoming and outgoing signals, and properly evaluate them.

At a certain point, an idea came that one Internet user subsequently dubbed the “cistern”. The “flush tank” model was surprisingly accurate and applicable to a biological neuron, it explained summation mechanisms very visually, and was more convenient to implement. Now emulated neurons could be completely independent, just like real objects.



This adder model is the most accurate model of the biological neuron I know of. To model in detail the stomach cell will require incredibly large computational power, but all that this cell does is that it produces the appropriate enzyme or hormone if necessary. The attribution of incredible computational properties to a neuron is very popular among modern cyberneticists.

Subsequently, some mechanisms from the reflex theory and the idea of ​​directional orientation of the settings of the outgoing synapses were added to the summation model. The resulting model allowed us to create a theoretical basis that rather simply explained many processes and phenomena occurring in the nervous system. Reflex mechanisms, memory and memory consolidation, self-organization and specialization of neurons, the work of the cerebellum, emotional mechanisms and thinking all in one bottle.

I will not tire. Link to the GitHub repository .

For example, the script code which contains the main logic of the NeironScript.cs neuroelement (sorry for my French):

Lot of code
using UnityEngine; using System.Collections; using System.Collections.Generic; public class NeironScript : MonoBehaviour { public GameObject prefabNeiron; //  public GameObject prefabSinaps; //  public int IndexNeiron = 0; //  private int _TypeIndexNeiron = 0; //   public int TypeIndexNeiron //   { get { return _TypeIndexNeiron; } set { if (value == 0) { _TypeIndexNeiron = value; gameObject.GetComponent<SpriteRenderer>().color = new Color32(255, 255, 0, 255);//,  } if (value == 1) { _TypeIndexNeiron = value; gameObject.GetComponent<SpriteRenderer>().color = new Color32( 0, 255, 0, 255); //,  // } if (value == 2) { _TypeIndexNeiron = value; gameObject.GetComponent<SpriteRenderer>().color = new Color32(0, 255, 255, 255);//,   } if (value == 3) { _TypeIndexNeiron = value; gameObject.GetComponent<SpriteRenderer>().color = new Color32(255, 255, 255, 255);//,   } } } //   0 public float Adder = 0.0f; // public float MaxAdder = 30f; //   public float DampferAdder = 1.0f; //  public float thresholdTop = 1.0f; //   public float AnswerTime = 0.1f; //  public float TimeRepose = 0f; //  public bool IgnoreInput = false; //   public List<GameObject> hitSinaps = new List<GameObject>(); //  public GameObject Area; // private bool _ActionN; //   public bool ActionN //   { get { return _ActionN; } set { _ActionN = value; if (Area != null) { gameObject.GetComponent<LineRenderer>().enabled = value; //  .. bool existAction = Area.GetComponent<AreaScript>().NeironActionList.Contains(gameObject); //existAction = true -        if (_ActionN && (!existAction)) Area.GetComponent<AreaScript>().NeironActionList.Add(gameObject); //     else Area.GetComponent<AreaScript>().NeironActionList.Remove(gameObject); //     } } } //   1 public float thresholdDown = -5.0f; //  public float timeIgnore = 5.0f; //         public float bonusThreshold = 0f; //    public float DempferBonusThreshold = 1.0f; //    public float TimeEvaluation = 5.0f; //  public int LimitRecurrence = 5; //  public float thresholdTopUp = 1.0f; //    public bool TimeEvaluationBool = false; //  public int LimitEvaluationInt = 0; //     public float AdaptationTime = 0; //  public float thresholdAdapt = 1f; //   //   2 public float MaxForceSinaps = 100f; private Vector3 VectorPattern; //  public Vector3 VectorTrend; //  public float Charge = 0.0f; // public float TimeCharge = 0.01f; //    private float changeAngle = 0f; //   public float FocusNeiron = 90f; //  public bool FocusDinamic = true; //   public float StepFocus = 1f; //   public float MaxFocus = 90f; //   public float Plasticity = 1.0f; // public bool PlasticityDinamic = true; //   public float StepPlasticity = 0.01f; //  public float BasicPlasticity = 1.0f; //  (  ) public bool NewNeironDinamic = true; //    private float angleMin = 0f; private bool CorunPlasticRun = false; // END VAR private Vector3 noveltyVector = Vector3.zero; private float noveltyFactor = 0.1f; IEnumerator StartSummator (){ IgnoreInput = true; //    gameObject.GetComponent<SpriteRenderer>().color = new Color32(255, 0, 0, 255); //  ActionN = true; //     yield return new WaitForSeconds(AnswerTime); //  ActionN = false; ExcitationTransfer (); //  yield return new WaitForSeconds(TimeRepose);//  IgnoreInput = false; //     TypeIndexNeiron = _TypeIndexNeiron; //   } IEnumerator repolarizationTime (){ IgnoreInput = true; //    gameObject.GetComponent<SpriteRenderer>().color = new Color32(0, 0, 255, 255);//   yield return new WaitForSeconds(timeIgnore);//  IgnoreInput = false; TypeIndexNeiron = _TypeIndexNeiron;//   } IEnumerator StartModule (){ IgnoreInput = true; //    ActionN = true; // ,      gameObject.GetComponent<SpriteRenderer>().color = new Color32(255, 0, 0, 255);//  yield return new WaitForSeconds(AnswerTime);//  ExcitationTransfer ();//     ActionN = false;//  yield return new WaitForSeconds(TimeRepose);//  IgnoreInput = false;//    TypeIndexNeiron = _TypeIndexNeiron;//  StartCoroutine ("EvaluationTime");//   if ((AdaptationTime > 0) && (thresholdTop > thresholdAdapt)) StartCoroutine ("AdaptationVoid");// ,     =0    //          } IEnumerator EvaluationTime(){ TimeEvaluationBool = true;//    yield return new WaitForSeconds(TimeEvaluation); TimeEvaluationBool = false;//   } IEnumerator AdaptationVoid(){ yield return new WaitForSeconds(AdaptationTime);//  if (thresholdTop > thresholdAdapt) thresholdTop--;// ,     if ((AdaptationTime > 0) && (thresholdTop > thresholdAdapt)) StartCoroutine ("AdaptationVoid");//   } IEnumerator NegativeRepolarization(){ IgnoreInput = true; //    ActionN = true; // for (int i = 0; i < 16; i++) { //   Charge = Area.GetComponent<AreaScript>().Spike2[i]; if (Charge > 0) gameObject.GetComponent<SpriteRenderer>().color = new Color32(255, 0, 0, 255); // else gameObject.GetComponent<SpriteRenderer>().color = new Color32(0, 0, 255, 255); // yield return new WaitForSeconds(TimeCharge); //  / } Charge = 0f;//  TypeIndexNeiron = _TypeIndexNeiron;//  ActionN = false;// IgnoreInput = false;//     } IEnumerator StartAssociative(){ IgnoreInput = true;//   ActionN = true;// StartCoroutine("PositiveRepolarization"); //    yield return new WaitForSeconds(AnswerTime); //  Compass ();//   } IEnumerator StartWhite() { IgnoreInput = true;//   ActionN = true;// StartCoroutine("PositiveRepolarization");//    yield return new WaitForSeconds(AnswerTime); //  ExcitationTransfer ();//     } IEnumerator PositiveRepolarization(){ for (int i = 0; i < 16; i++) { //   Charge = Area.GetComponent<AreaScript>().Spike1[i]; if (Charge > 0) gameObject.GetComponent<SpriteRenderer>().color = new Color32(255, 0, 0, 255); // else gameObject.GetComponent<SpriteRenderer>().color = new Color32(0, 0, 255, 255); // yield return new WaitForSeconds(TimeCharge); //   } Charge = 0f; //  TypeIndexNeiron = _TypeIndexNeiron;//  ActionN = false;//  yield return new WaitForSeconds(TimeRepose);//  IgnoreInput = false;//  StartCoroutine ("EvaluationTime");//  if ((AdaptationTime > 0) && (thresholdTop > thresholdAdapt)) StartCoroutine ("AdaptationVoid");// } IEnumerator PlasticTimeCoruntine (Vector2 PT){//   CorunPlasticRun = true;//    float PlasticBuffer = Plasticity;//   Plasticity = PT.x;//  yield return new WaitForSeconds(PT.y);//   Plasticity = PlasticBuffer;//   CorunPlasticRun = false;//    } public void ActiveNeiron (){ //         if (!IgnoreInput) { if (TypeIndexNeiron == 0) StartCoroutine ("StartSummator");//   if (TypeIndexNeiron == 1) StartCoroutine ("StartModule");//  if (TypeIndexNeiron == 2) StartCoroutine ("StartAssociative");// ,     if (TypeIndexNeiron == 3) StartCoroutine ("StartWhite");//   } } private void Compass (){ if (Area != null){ //    ,         VectorPattern = Vector3.zero; //   //   for (int i = 0; i < Area.GetComponent<AreaScript>().NeironActionList.Count; i++) { //    if (gameObject == Area.GetComponent<AreaScript> ().NeironActionList [i]) continue; //     Vector3 R = Area.GetComponent<AreaScript> ().NeironActionList [i].transform.position - transform.position;//  ,    //       VectorPattern += (Area.GetComponent<AreaScript> ().NeironActionList [i].GetComponent<NeironScript> ().Charge * R.normalized);//R.sqrMagnitude; .normalized //sqrMagnitude;!!!!!!!!!(  ) } if (VectorPattern.sqrMagnitude < 3f) VectorPattern = VectorTrend; //   ,     if (VectorPattern.sqrMagnitude == 0) VectorPattern = new Vector3(Random.Range(-1f, 1f), Random.Range(-1f, 1f), Random.Range(-1f, 1f)); //   ( ),    ,    ,    - VectorPattern.Normalize(); //    if (noveltyVector == Vector3.zero) noveltyVector = -VectorPattern; //  (   )    -     changeAngle = Vector3.Angle(VectorPattern, noveltyVector);//          if (Area != null) Area.SendMessage("MessageOriginality", changeAngle/180);//       VectorTrend = VectorPattern; //  noveltyVector = Vector3.Slerp(noveltyVector, VectorPattern, noveltyFactor);//   //       //         //   noveltyVector = VectorPattern,       (     ) //       ,        gameObject.GetComponent<LineRenderer>().SetPosition(0, transform.position);//    gameObject.GetComponent<LineRenderer>().SetPosition(1, transform.position + VectorTrend * 6); if (PlasticityDinamic) { if (changeAngle < 10) Plasticity -= StepPlasticity; else Plasticity += StepPlasticity; //  if (Plasticity > 1) Plasticity = 1f; if (Plasticity < 0) Plasticity = 0f; //          //    ,         . //..        ,        } if (FocusDinamic){ if (changeAngle < 10) FocusNeiron -= StepFocus; else FocusNeiron = MaxFocus; if (FocusNeiron < 0) FocusNeiron = 0; //         . //        . //       . //   -     ,       } //   if (NewNeironDinamic){ if (!Physics.CheckSphere(transform.position + VectorTrend * 5, 3f)) { //  -     3, //     5    //    if (Area.GetComponent<AreaScript>().Global) NewNeiron(); //     else { if (Area.GetComponent<Collider>().bounds.Contains(transform.position + VectorTrend * 5)) NewNeiron(); //         } } //   Collider[] hitColliders = Physics.OverlapSphere(transform.position + VectorTrend * 5, 3f); //        foreach (Collider value in hitColliders) //     { if (value.tag == "Neiron") //   { bool EnableSinaps = false; //     foreach (GameObject sinapsValue in hitSinaps) //    { if (sinapsValue.GetComponent<SinapsScript>().NeironTarget == value.gameObject) { EnableSinaps = true; //   break; //   } } if (!EnableSinaps) { //    GameObject cSinaps = Instantiate(prefabSinaps, transform.position, transform.rotation) as GameObject;//   cSinaps.transform.parent = transform; cSinaps.GetComponent<SinapsScript>().NeironTarget = value.gameObject; cSinaps.GetComponent<SinapsScript>().Force = 0f; hitSinaps.Add(cSinaps); } } } } //         angleMin = 180f; if (hitSinaps.Count != 0) angleMin = Vector3.Angle(hitSinaps[0].GetComponent<SinapsScript>().NeironTarget.transform.position - transform.position, VectorTrend); foreach(GameObject ShershSinaps in hitSinaps) { float angleShersh = Vector3.Angle(ShershSinaps.GetComponent<SinapsScript>().NeironTarget.transform.position - transform.position, VectorTrend); if (angleShersh < angleMin) angleMin = angleShersh; } if (FocusNeiron < angleMin) FocusNeiron = angleMin; //      ,       . //        , //        . //  foreach(GameObject SinapsCoeff in hitSinaps){ if (SinapsCoeff.GetComponent<SinapsScript>().TypeSinaps == 0){ float angleSinaps = Vector3.Angle(SinapsCoeff.GetComponent<SinapsScript>().NeironTarget.transform.position - transform.position, VectorTrend); if (angleSinaps <= FocusNeiron) SinapsCoeff.GetComponent<SinapsScript>().Force += MaxForceSinaps * Plasticity; else SinapsCoeff.GetComponent<SinapsScript>().Force -= MaxForceSinaps * Plasticity; SinapsCoeff.GetComponent<SinapsScript>().Force = Mathf.Clamp(SinapsCoeff.GetComponent<SinapsScript>().Force, 0, MaxForceSinaps); } } } ExcitationTransfer ();//     } private void NewNeiron (){ GameObject clone = Instantiate(prefabNeiron, transform.position + VectorTrend * 6, transform.rotation) as GameObject; /*  :        (   ), *      ,        *        ,     . *       .... * */ if (Area != null) Area.GetComponent<AreaScript>().amount++;//      clone.GetComponent<NeironScript>().Plasticity = BasicPlasticity;//   clone.GetComponent<NeironScript>().ActionN = false; clone.GetComponent<NeironScript>().IgnoreInput = false; clone.GetComponent<NeironScript>().Adder = 0f; clone.GetComponent<NeironScript>().VectorTrend = Vector3.zero; clone.GetComponent<NeironScript>().Area = Area; clone.GetComponent<NeironScript>().TimeEvaluationBool = false; clone.GetComponent<NeironScript>().LimitEvaluationInt = 0; clone.GetComponent<NeironScript>().Charge = 0.0f; clone.GetComponent<NeironScript>().FocusNeiron = MaxFocus; clone.GetComponent<NeironScript>().Plasticity = BasicPlasticity; clone.GetComponent<NeironScript>().TypeIndexNeiron = 2; clone.GetComponent<NeironScript>().noveltyVector = Vector3.zero; clone.GetComponent<NeironScript>().VectorTrend = Vector3.zero; clone.GetComponent<LineRenderer>().SetPosition(0, clone.transform.position); clone.GetComponent<LineRenderer>().SetPosition(1, clone.transform.position); clone.SendMessage("StopNeiron"); //          ,    GameObject ManagerObj = GameObject.Find("Manager"); //... , Find  ManagerObj.GetComponent<ManagerScript>().EndIndexNeiron++;//  clone.GetComponent<NeironScript>().IndexNeiron = ManagerObj.GetComponent<ManagerScript>().EndIndexNeiron;//     clone.name = "Neiron" + clone.GetComponent<NeironScript>().IndexNeiron;//      foreach (GameObject sd in clone.GetComponent<NeironScript>().hitSinaps) Destroy(sd); //       ,      clone.GetComponent<NeironScript>().hitSinaps.Clear(); //   .  .. } void FixedUpdate(){ //      0.01 if (!IgnoreInput) //     { if (TypeIndexNeiron == 0) //    { if (Adder > thresholdTop) //  { StartCoroutine ("StartSummator"); } } if (TypeIndexNeiron == 1) //   { if (Adder > thresholdTop + bonusThreshold) //  { if (TimeEvaluationBool) //  ? { LimitEvaluationInt++; //  StopCoroutine("EvaluationTime"); //     TimeEvaluationBool = false; //   } else LimitEvaluationInt = 0; //    if ((LimitEvaluationInt > LimitRecurrence) && (bonusThreshold == 0)) thresholdTop += thresholdTopUp; //         -  StopCoroutine ("AdaptationVoid"); // ,       StartCoroutine ("StartModule"); //    } if (Adder < thresholdDown) //     { if (Area != null) StartCoroutine ("repolarizationTime"); //   ,     } } if (TypeIndexNeiron == 2) //  { if (Adder > thresholdTop + bonusThreshold) //    :    { if (TimeEvaluationBool) //      { LimitEvaluationInt++; //   StopCoroutine("EvaluationTime");//   TimeEvaluationBool = false; } else LimitEvaluationInt = 0; //   ,   if ((LimitEvaluationInt > LimitRecurrence) && (bonusThreshold == 0)) thresholdTop += thresholdTopUp; //      ,    StopCoroutine ("AdaptationVoid");// ,   ( -    ) StartCoroutine ("StartAssociative"); //    } if (Adder < thresholdDown) //    { StartCoroutine ("NegativeRepolarization"); //  () } } if (TypeIndexNeiron == 3) //  { if (Adder > thresholdTop + bonusThreshold)//    { if (TimeEvaluationBool)// ... { LimitEvaluationInt++; StopCoroutine("EvaluationTime"); TimeEvaluationBool = false; } else LimitEvaluationInt = 0; if ((LimitEvaluationInt > LimitRecurrence) && (bonusThreshold == 0)) thresholdTop += thresholdTopUp; StopCoroutine ("AdaptationVoid"); StartCoroutine ("StartWhite"); } if (Adder < thresholdDown) { StartCoroutine ("NegativeRepolarization"); } } } if (Mathf.Abs(Adder) <= DampferAdder) Adder = 0f; //  if (Adder > DampferAdder) Adder -= DampferAdder; if (Adder < -DampferAdder) Adder += DampferAdder; if (Mathf.Abs(bonusThreshold) <= DempferBonusThreshold) bonusThreshold = 0f; //   if (bonusThreshold > DempferBonusThreshold) bonusThreshold -= DempferBonusThreshold; if (bonusThreshold < -DempferBonusThreshold) bonusThreshold += DempferBonusThreshold; } private void ExcitationTransfer () //  { foreach (GameObject value in hitSinaps) //    { int T = value.GetComponent<SinapsScript>().TypeSinaps; //  float F = value.GetComponent<SinapsScript>().Force; //  GameObject NT = value.GetComponent<SinapsScript>().NeironTarget;//  if (T == 0) NT.SendMessage("AddSummator", F);//  if (T == 1) NT.SendMessage("AddTActual", F); if (T == 2) NT.SendMessage("ActiveNeiron"); if (T == 3) NT.SendMessage("AddSummator", F); value.GetComponent<SinapsScript>().GoAction = true;//   } } public void AddSummator (float Summ) //      { Adder += Summ; if (Adder > MaxAdder) Adder = MaxAdder; if (Adder < - MaxAdder) Adder = -MaxAdder; } public void AddTActual (float T)//  ,   { bonusThreshold += T; if (bonusThreshold + thresholdTop < 0f) bonusThreshold = - thresholdTop + 0.0001f; } public void StopNeiron(){//  ,     GameOject.SendMessage("StopNeiron") StopAllCoroutines(); } public void plasticSetTime (Vector2 plasticTime){ //  , SendMessage     , Vectir2 -     //     if (!CorunPlasticRun) StartCoroutine("PlasticTimeCoruntine", plasticTime); if (TypeIndexNeiron == 2) thresholdTop = thresholdAdapt; } } 



Communication between neurons is carried out using a messaging system based on SendMessage, and all the processes associated with changing states are rendered to corundines.



In the block diagram, the basic basis of the neuroelement. SendMessage (“AddSummator”, F) - a synapse of direct action with a force F, increases the sum of the adder by a specified number. Every 0.01s, the FixedUpdate () function is triggered in which the modulo adder decreases by the set damper / number. And as there is a check for the excess of the threshold on the adder, if the threshold is exceeded, then coruntine is started. During the operation of coruntine, the mode of ignoring external signals is turned on, but the operation of the damper for the adder continues as well as the ability to replenish the sum. SendMessage (“ActiveNeiron”) - contact synapse (efaps), corinthine will be triggered if it is not currently running, otherwise the signal will be ignored.

Based on this base, further mechanisms related to cell metabolism (addiction and adaptation) were added, as well as the modulation system, which was derived from the work of Eric Kandel. And the idea of ​​a directed transfer of excitation for the sake of checking which I started this project.

Many people were interested in the source code of the project, but not only for this reason, I post the source. The fact is that there is still a lot of work ahead, plans to seriously expand the capabilities and tools, to create a certain environment that allows you to conveniently work with a large array of elements, structure and organize them. I do not have extensive programming experience, but I am sure that a large number of people from the GeekTimes community can give recommendations on the structure, methods, and optimization that will qualitatively improve the project. I plan not to change the development environment, for me the empiricism of the development process is important, as well as the aesthetics of the final result and the Unity game engine so far helped me a lot in this.

Source: https://habr.com/ru/post/398867/


All Articles