}/**/ // увеличиваем состояние нейрона и запускаем разряды // не делать async Task! так как в этом случае мы тупо встанем в зависон public int IncState(int state, NCoords coords) { //return Task.Run(() => //{ // счетчики потоков надо ставить в самой функции SpikeAsync так как разряды, затухания, повторения все в ней //Interlocked.Increment(ref NNet.Threads); var newState = Interlocked.Add(ref _state, state); // в этом месте значение _state может увеличится другим потоком, но нам как бы пофиг. либо этот либо тот процесс получат в newState значение выше порога и запустят разряд //Net.LogInformation(321, "Neuron IncState {coords} + {state} = {newstate}", coords, state, _state); if (_checkState() && _isStarted == 0) { Net.LogInformation(321, "Neuron IncState {coords} activated!!!!!", coords); // просто метим как активный IsActive = 1; // надо где то прописать что появился активный нейрон (пофигу елси 1 нейрон засунем в очередь несколько раз на том конце разберемся) Net.Queue.Enqueue(new QueueNeuron { Neuron = this, Coords = coords }); } //Interlocked.Decrement(ref NNet.Threads); //}); return(newState); }
public int MaxZ; // { get; set; } public bool Test(NCoords coords) { if ( MinX <= coords.X && coords.X <= MaxX && MinY <= coords.Y && coords.Y <= MaxY && MinZ <= coords.Z && coords.Z <= MaxZ ) { return(true); } return(false); }
// тупой вариант расчета новых состояний (нарушает закон сохранения - сеть быстро "взрывается") private void _evalNewStates() { // пропускаем ток var s = 0; // суммируем скока заряда ушло (если нейрон с положительным зарядом то тут всегда будет >0, так как связи всегда положительные. и наоборот) foreach (var o in Output) { var coord = new NCoords(o.Neuron, Net.LenX, Net.LenY, Net.LenZ); var state = (int)(_state * o.WeightSum); s += state; Net.Neurons[coord.Z][coord.Y][coord.X].IncState(state, coord); } // уменьшаем свое состояние _decreaseState(s); }
// вариант с распределением существующего заряда равномерно в зависимости от веса private void _evalNewStates2() { var s = _state; // _state может меняться в процессе // если выход всего 1, то результат (state0+state1) / 2 для обоих состояний (оно выравнивается всегда) #region one output if (Output.Count == 1) { var o = Output[0]; var coord = new NCoords(o.Neuron, Net.LenX, Net.LenY, Net.LenZ); var n = Net.Neurons[coord.Z][coord.Y][coord.X]; var ts = n.State; if (s > 0) { if (ts > 0) // + => + { if (s <= ts) // заряд активного нейрона меньше целевого, тут ничего не должно происходить (возможно уменьшение веса связи???) { return; } //var ns = (s + ts) / 2; //_state -= s - (s + ts) / 2 => _state -= (s-ts)/2 Interlocked.Add(ref _state, -(s - ts) / 2); n.IncState((s - ts) / 2, coord); } else // + => - { } } else { } return; } #endregion // если выходов больше, то foreach (var o in Output) { } }
public async Task SubscribeClientAsync(HttpContext httpContext) { //_logger.LogInformation(1113, "NNetServer SubscribeClient start"); var webSocket = await httpContext.WebSockets.AcceptWebSocketAsync(); //Socket = socket; // Добавляем его в список клиентов LockerWS.EnterWriteLock(); try { Clients.Add(webSocket); } finally { LockerWS.ExitWriteLock(); } while (webSocket.State == WebSocketState.Open) { //_logger.LogInformation(1113, "NNetServer SubscribeClient begin action"); try { //var token = CancellationToken.None; var buffer = new ArraySegment <Byte>(new Byte[4096]); // не очень хорошо ограничивать вход 4 кб! расчетные модули могут посылать больше инфы за 1 раз var received = await webSocket.ReceiveAsync(buffer, CancellationToken.None); switch (received.MessageType) { case WebSocketMessageType.Text: var request = Encoding.UTF8.GetString(buffer.Array, buffer.Offset, buffer.Count); //_logger.LogInformation(1113, "NNetServer SubscribeClient request = {request}", request); var tmp = JsonConvert.DeserializeObject <WSRequest>(request); switch (tmp.Action.ToLower()) { // подписка на изменения в сети case "subscribe": if (tmp.ArgsInt.Count < 6) { await SendErrorAsync(webSocket, "Число аргументов ArgsInt должно быть >= 6", tmp.Action); return; } if (tmp.ArgsInt.Count % 6 != 0) { await SendErrorAsync(webSocket, "Число аргументов ArgsInt должно быть кратно 6", tmp.Action); return; } var val = new List <NRange>(); for (var i = 0; i < tmp.ArgsInt.Count; i = i + 6) { // обязательно проверить кто раньше первый или второй и это важно // нем пох кто меньше надо найти меньший угол и больший в кубе var min = new NCoords( Math.Min(tmp.ArgsInt[i + 0], tmp.ArgsInt[i + 3]), Math.Min(tmp.ArgsInt[i + 1], tmp.ArgsInt[i + 4]), Math.Min(tmp.ArgsInt[i + 2], tmp.ArgsInt[i + 5])); var max = new NCoords( Math.Max(tmp.ArgsInt[i + 0], tmp.ArgsInt[i + 3]), Math.Max(tmp.ArgsInt[i + 1], tmp.ArgsInt[i + 4]), Math.Max(tmp.ArgsInt[i + 2], tmp.ArgsInt[i + 5])); /*var min = new NCoords(tmp.ArgsInt[i + 0], tmp.ArgsInt[i + 1], tmp.ArgsInt[i + 2]); * var max = new NCoords(tmp.ArgsInt[i + 3], tmp.ArgsInt[i + 4], tmp.ArgsInt[i + 5]); * if (max.ToSingle(LenX, LenY) < min.ToSingle(LenX, LenY)) * { * var t = min; min = max; max = t; * }*/ val.Add(new NRange() { MinX = min.X, MinY = min.Y, MinZ = min.Z, MaxX = max.X, MaxY = max.Y, MaxZ = max.Z }); } // доки https://docs.microsoft.com/ru-ru/dotnet/articles/standard/collections/threadsafe/how-to-add-and-remove-items // очень маловероятно что 1 клиент 2 раза сможет вызвать подписку больше 1 раза в одно и то же время! Subscribers.AddOrUpdate(webSocket, val, (key, existingVal) => { // If this delegate is invoked, then the key already exists. // Here we make sure the city really is the same city we already have. // (Support for multiple cities of the same name is left as an exercise for the reader.) existingVal.AddRange(val); return(existingVal); }); // сразу отправим полные данные о выбранных нейронах await SendNeuronsAsync(webSocket, val, tmp.Action); break; // полная отписка case "unsubscribe": List <NRange> tmp1; Subscribers.TryRemove(webSocket, out tmp1); await SendMessageAsync(webSocket, "OK", tmp.Action); break; // запрос конфигурации сети case "getnetconfig": await SendConfigAsync(webSocket, tmp.Action); break; case "start": Start(); await SendMessageAsync(webSocket, "OK", tmp.Action); break; case "stop": Stop(); await SendMessageAsync(webSocket, "OK", tmp.Action); break; case "setinput": if (tmp.ArgsInt.Count != 7) { await SendErrorAsync(webSocket, "Число аргументов ArgsInt должно быть = 7", tmp.Action); return; } var inputs = new Dictionary <NCoords, int>(); { var i = 0; // обязательно проверить кто раньше первый или второй и это важно // нам пох кто меньше надо найти меньший угол и больший в кубе var min = new NCoords( Math.Min(tmp.ArgsInt[i + 0], tmp.ArgsInt[i + 3]), Math.Min(tmp.ArgsInt[i + 1], tmp.ArgsInt[i + 4]), Math.Min(tmp.ArgsInt[i + 2], tmp.ArgsInt[i + 5])); var max = new NCoords( Math.Max(tmp.ArgsInt[i + 0], tmp.ArgsInt[i + 3]), Math.Max(tmp.ArgsInt[i + 1], tmp.ArgsInt[i + 4]), Math.Max(tmp.ArgsInt[i + 2], tmp.ArgsInt[i + 5])); for (var z = min.Z; z <= max.Z; z++) { for (var y = min.Y; y <= max.Y; y++) { for (var x = min.X; x <= max.X; x++) { inputs[new NCoords(x, y, z)] = tmp.ArgsInt[i + 6]; } } } } SetInputs(inputs); await SendMessageAsync(webSocket, "OK", tmp.Action); break; } break; } } catch (Exception e) { //Error = e; //_logger.LogInformation(1113, "NNetServer SubscribeClient error {error}.", e.Message); await SendErrorAsync(webSocket, e.Message, null); } //_logger.LogInformation(1113, "NNetServer SubscribeClient end action"); }/**/ //_logger.LogInformation(1113, "NNetServer SubscribeClient before removing"); LockerWS.EnterWriteLock(); try { Clients.Remove(webSocket); } finally { LockerWS.ExitWriteLock(); } List <NRange> tmp2; Subscribers.TryRemove(webSocket, out tmp2); //_logger.LogInformation(1113, "NNetServer SubscribeClient end"); }
// создаем выходные связи для нейрона (рандомно) private List <NRelation> _createOutputForNeuron(int x, int y, int z) { if (NEED_STAT_WEIGHT) { MinWeight = 0; MaxWeight = 0; } var output = new List <NRelation>(); // по оси Z распределение норм тут не надо замыкать последний слой на первый var minZ = z - MAX_DEEP_RELATIONS_Z; if (minZ < 1) { minZ = 1; } var maxZ = z + MAX_DEEP_RELATIONS_Z; if (maxZ > LenZ - 1) { maxZ = LenZ - 1; } // а вот по икс и игрек хотелось бы замкнуть первые нейроны на последние var minY = y - maxDeepRelationsY; /*if (minY < 0) minY = 0;*/ var maxY = y + maxDeepRelationsY; // if (maxY > LenY - 1) maxY = LenY - 1; var minX = x - maxDeepRelationsX; /*if (minX < 0) minX = 0;*/ var maxX = x + maxDeepRelationsX; // if (maxX > LenX - 1) maxX = LenX - 1; /*if (z==0 && y==1 && x==2) * _logger.LogInformation(2111, "NNet _createOutputForNeuron {x}-{xx} {y}-{yy} {z}-{zz}", minX, maxX, minY, maxY, minZ, maxZ); * /**/ for (var zz = minZ; zz <= maxZ; zz++) // первый слой входы (входы исключительно на другие слои) { for (var yy = minY; yy <= maxY; yy++) { for (var xx = minX; xx <= maxX; xx++) { // замыкания по оси икс и игрек var yyy = yy; var xxx = xx; if (yy < 0) { yyy = LenY + yy; } if (yy > LenY - 1) { yyy = yy - (LenY); } if (xx < 0) { xxx = LenX + xx; } if (xx > LenX - 1) { xxx = xx - (LenX); } // связь на себя не допускаем, тока косвенная - через другие нейроны if (x == xxx && yyy == y && z == zz) { continue; } var coords = new NCoords(xxx, yyy, zz); var o = new NRelation() { Neuron = coords.ToSingle(LenX, LenY), Weight = _rand.NextFloat(MIN_INIT_WEIGHT, MAX_INIT_WEIGHT), WeightChange = 0 }; if (NEED_STAT_WEIGHT) { // здесь не надо юзать WeightSum так как WeightChange==0 if (MinWeight > o.Weight) { MinWeight = o.Weight; } if (MaxWeight < o.Weight) { MaxWeight = o.Weight; } } /*if (z == 0 && y == 1 && x == 2) * { * _logger.LogInformation(1111, "NNet _createOutputForNeuron for ({x}, {y}, {z}) => {n} ({xx}, {yy}, {zz})", x, y, z, (new NCoords(xxx, yyy, zz)).ToSingle(LenX, LenY), xxx, yyy, zz); * }/**/ o.SetNeuron(Neurons[zz][yyy][xxx]); output.Add(o); } } } return(output); }