{"id":19704250,"url":"https://github.com/dbklim/nn_server","last_synced_at":"2025-02-27T13:45:00.351Z","repository":{"id":115095727,"uuid":"130727795","full_name":"dbklim/NN_Server","owner":"dbklim","description":"Back-end of the project of intelligence system of neural networks at the department of IIT BSUIR. Implemented with using Python3+TensorFlow+Keras.","archived":false,"fork":false,"pushed_at":"2019-01-20T02:47:59.000Z","size":15084,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-10T11:47:54.556Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dbklim.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-04-23T16:45:41.000Z","updated_at":"2019-04-02T18:07:56.000Z","dependencies_parsed_at":null,"dependency_job_id":"1daf6802-3dc8-49a8-b571-f35c27f6a53a","html_url":"https://github.com/dbklim/NN_Server","commit_stats":null,"previous_names":["dbklim/nn_server"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dbklim%2FNN_Server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dbklim%2FNN_Server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dbklim%2FNN_Server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dbklim%2FNN_Server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dbklim","download_url":"https://codeload.github.com/dbklim/NN_Server/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241019975,"owners_count":19895352,"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":[],"created_at":"2024-11-11T21:21:34.821Z","updated_at":"2025-02-27T13:45:00.328Z","avatar_url":"https://github.com/dbklim.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# NeuralNetworks_Server\n\nПроект состоит из нескольких частей - RESTful сервер для взаимодействия с нейронными сетями, нейронная сеть LeNet и простой клиент для общения с сервером и его тестирования.\n\nПолный список всех необходимых для работы пакетов:\n1. Для Python3.5: decorator, Flask v1.0.2, Flask-HTTPAuth v3.2.4, gevent v1.3.7, h5py, Keras v2.2.4, numpy, pillow, requests, tensorflow[-gpu].\n2. Для Ubuntu: python3.5-dev, python3-pip, python3-tk, net-tools.\n\nЕсли вы используете Ubuntu 16.04 или выше, для установки всех пакетов можно воспользоваться `install_packages.sh` (проверено в Ubuntu 16.04). По умолчанию будет установлен [TensorFlow](https://www.tensorflow.org/install/) для CPU. Если у вас есть видеокарта nvidia, вы можете установить [TensorFlowGPU](https://www.tensorflow.org/install/gpu). Для этого необходимо при запуске `install_packages.sh` передать параметр `gpu`. Например:\n```\n./install_packages.sh gpu\n```\n\n---\n\n**Docker-образ**\n\nВы так же можете собрать docker-образ моего проекта с помощью Dockerfile либо загрузить уже собранный образ из моего [Google Drive](https://drive.google.com/open?id=1ajrIDBafK8--QxXbEUqig3OLYE1s0K1w).\n\n---\n\n**Установка Docker и сборка образа**\n\nЕсли вы используете Ubuntu 16.04 или выше, для установки docker-engine можно воспользоваться `install_docker.sh`. После установки, проверьте статус docker с помощью команды:\n```\nsudo systemctl status docker\n```\n\nРезультат должен быть примерно такой:\n```\n● docker.service - Docker Application Container Engine\n   Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)\n   Active: active (running) since Чцв 2018-11-22 03:01:32 +03; 14h ago\n     Docs: https://docs.docker.com\n Main PID: 1183 (dockerd)\n    Tasks: 24\n   Memory: 349.8M\n      CPU: 2min 3.238s\n   CGroup: /system.slice/docker.service\n           ├─1183 /usr/bin/dockerd -H fd://\n           └─1220 docker-containerd -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --metrics-interval=0\n```\n\nЗатем вам необходимо в терминале перейти в папку, куда вы клонировали данный репозиторий (или скачали и распаковали его) и выполнить:\n```\nsudo docker build -t nn_server:v0.1 .\n```\nГде `-t` - запуск терминала, `.` - директория, из которой вызывается `docker build` (точка - значит в текущей директории находятся все файлы для образа), `nn_server:v0.1` - метка образа и его версия.\n\nПосле успешного выполнения данной операции вы можете вывести список имеющихся образов, выполнив:\n```\nsudo docker images\n```\nВ полученном списке вы увидите наш образ - `nn_server:v0.1`.\n\n---\n\n**Запуск docker-образа**\n\nЕсли вы загрузили уже собранный образ из моего [Google Drive](https://drive.google.com/open?id=1ajrIDBafK8--QxXbEUqig3OLYE1s0K1w), то перед запуском вам необходимо его сначала распаковать. Это можно сделать так (находясь в папке со скачанным .tar архивом):\n```\nsudo docker load \u003c nn_server.tar\n```\nили\n```\nsudo docker load --input nn_server.tar\n```\n\nУбедиться в том, что образ успешно распакован, вы можете выполнив `sudo docker images`.\n\nТеперь образ готов к запуску. Для этого необходимо выполнить:\n```\nsudo docker run -ti --rm -p 5000:5000 nn_server:v0.1 python3 nn_server.py\n```\nГде `-t` - запуск терминала, `-i` - интерактивный режим, `--rm` - удалить контейнер после завершения его работы, `-p 5000:5000` - пробросить все подключения на порт `5000` к машине-хосту в контейнер на порт `5000` (вы так же можете явно указать другой адрес, к которому нужно будет подключиться извне: `-p 127.0.0.1:5000:5000`).\n\nВ результате запустится RESTful-сервер и можно к нему обращаться по указанному в терминале адресу (если вы не указали другой при запуске образа).\n\n# RESTful-сервер\n\nДанный сервер предоставляет REST-api для взаимодействия с нейронными сетями. На данный момент имеется только одна сеть - LeNet для классификации рукописных цифр. \n\nСервер реализован с помощью [Flask](http://flask.pocoo.org/), а многопоточный режим (production-версия) с помощью [gevent.pywsgi.WSGIServer](http://flask.pocoo.org/docs/1.0/deploying/wsgi-standalone/). Также сервер имеет ограничение на размер принимаемых данных в теле запроса равное 16 Мб. Реализация находится в модуле `nn_server.py`.\n\nЗапустить WSGI сервер можно выполнив `run_nn_server.sh` (запуск без аргументов командной строки) или `python3 nn_server.py`.\n\nСервер поддерживает аргументы командной строки, которые немного упрощают его запуск. Аргументы имеют следующую структуру: `[ключ(-и)] [адрес:порт]`.\n\nВозможные ключи:\n1. `-d` - запуск тестового Flask сервера (если ключ не указывать - будет запущен WSGI сервер)\n2. `-s` - запуск сервера с поддержкой https (используется самоподписанный сертификат, получен с помощью openssl)\n\nДопустимые варианты `адрес:порт`:\n1. `host:port` - запуск на указанном `host` и `port`\n2. `localaddr:port` - запуск с автоопределением адреса машины в локальной сети и указанным `port`\n3. `host:0` или `localaddr:0` - если `port = 0`, то будет выбран любой доступный порт автоматически\n\nСписок возможных комбинаций аргументов командной строки и их описание: \n1. без аргументов - запуск WSGI сервера с автоопределением адреса машины в локальной сети и портом `5000`. Например: ```python3 rest_server.py```\n2. `host:port` - запуск WSGI сервера на указанном `host` и `port`. Например: ```python3 nn_server.py 192.168.2.102:5000```\n3. `-d` - запуск тестового Flask сервера на `127.0.0.1:5000`. Например: ```python3 nn_server.py -d```\n4. `-d host:port` - запуск тестового Flask сервера на указанном `host` и `port`. Например: ```python3 nn_server.py -d 192.168.2.102:5000```\n5. `-d localaddr:port` - запуск тестового Flask сервера с автоопределением адреса машины в локальной сети и портом `port`. Например: ```python3 nn_server.py -d localaddr:5000```\n6. `-s` - запуск WSGI сервера с поддержкой https, автоопределением адреса машины в локальной сети и портом `5000`. Например: ```python3 nn_server.py -s```\n7. `-s host:port` - запуск WSGI сервера с поддержкой https на указанном `host` и `port`. Например: ```python3 nn_server.py -s 192.168.2.102:5000```\n8. `-s -d` - запуск тестового Flask сервера с поддержкой https на `127.0.0.1:5000`. Например: ```python3 nn_server.py -s -d```\n9. `-s -d host:port` - запуск тестового Flask сервера с поддержкой https на указанном `host` и `port`. Например: ```python3 nn_server.py -s -d 192.168.2.102:5000```\n10. `-s -d localaddr:port` - запуск тестового Flask сервера с поддержкой https, автоопределением адреса машины в локальной сети и портом `port`. Например: ```python3 nn_server.py -s -d localaddr:5000```\n\nСервер может сам выбрать доступный порт, для этого нужно указать в `host:port` или `localaddr:port` порт `0` (например: ```python3 nn_server.py -d localaddr:0```).\n\nВсего поддерживается 5 запросов:\n1. GET-запрос на `/list_nn` вернёт информацию об имеющихся нейронных сетях и их адресах\n2. GET-запрос на `/lenet/about` вернёт информацию о сети LeNet\n3. GET-запрос на `/lenet/train` запустит обучение сети в фоне (т.е. в отдельном потоке) на наборе рукописных цифр MNIST (передать в URL параметр `training_sample=mnist`) или на предварительно созданном наборе данных `data/training_sample.npz` (передать в URL параметр `training_sample=other`) (после запуска, на запросы 3, 4 и 5 сервер будет отвечать ошибкой с пояснением, что сеть на данный момент обучается и недоступна для использования)\n4. GET-запрос на `/lenet/train/status` вернёт последний результат обучения сети LeNet (точность классификации и дата последнего обучения)\n5. POST-запрос на `/lenet/classify` принимает .jpg/.png/.bmp/.tiff файл и возвращает распознанную цифру в виде строки\n\n---\n\n**Описание сервера**\n\n1. Сервер имеет базовую http-авторизацию. Т.е. для получения доступа к серверу надо в каждом запросе добавить заголовок, содержащий логин:пароль, закодированный с помощью `base64` (логин: `test_nn`, пароль: `lenet`). Пример на python:\n```\nimport requests\nimport base64\n\nauth = base64.b64encode('test_nn:lenet'.encode())\nheaders = {'Authorization' : \"Basic \" + auth.decode()}\n```\n\nВыглядеть это будет так:\n```\nAuthorization: Basic dGVzdF9ubjpsZW5ldA==\n```\n\n2. В запросе на запуск обучения сети (который под номером 3) сервер ожидает параметр `training_sample` в URL запроса. Данный параметр определят используемую обучающую выборку: `training_sample=mnist` - использовать в качестве обучающей выборки набор рукописных цифр MNIST, `training_sample=other` - использовать предварительно созданную обучающую выборку `data/training_sample.npz` из своих данных (с помощью `lenet.py -c`). Пример на python:\n```\n# Отправка запроса серверу\nresponse = requests.post('http://' + addr + '/lenet/train?training_sample=mnist', headers=headers, json=data)\n\n# Разбор ответа\ndata = response.json()\nnumber = data.get('number')\nprint(number)\n```\n\n3. В запросе на классификацию (который под номером 5) сервер ожидает .jpg/.png/.bmp/.tiff файл (цветной либо чёрно-белый, размером от 28х28 пикселей) с изображением рукописной цифры (цифра должна быть на светлом (в идеале - белом) фоне, примеры можно найти в `images/*.jpg`), который передаётся в json с помощью кодировки `base64` (т.е. открывается .jpg/.png/.bmp/.tiff файл, читается в массив байт, потом кодирутеся `base64`, полученный массив декодируется из байтовой формы в строку `utf-8` и помещается в json), в python это выглядит так:\n```\n# Формирование запроса\nauth = base64.b64encode('test_nn:lenet'.encode())\nheaders = {'Authorization' : \"Basic \" + auth.decode()}\n\nwith open('images/1.jpg', 'rb') as f_image:\n    img_data = f_image.read()\ndata = base64.b64encode(data)\ndata = {'image' : data.decode()}\n\n# Отправка запроса серверу\nresponse = requests.post('http://' + addr + '/lenet/classify', headers=headers, json=data)\n\n# Разбор ответа\ndata = response.json()\nnumber = data.get('number')\nprint(number)\n```\n\n---\n\n**Передаваемые данные в каждом запросе**\n\nВсе передаваемые данные обёрнуты в json (в том числе и ответы с ошибками).\n1. Сервер передаёт клиенту:\n```\n{\n'text' : ['LeNet url:/lenet',\n          'Сеть1 url:/сеть1',\n          'Сеть2 url:/сеть2']\n}\n```\n2. Сервер передаёт клиенту:\n```\n{\n'text' : 'Описание сети LeNet'\n}\n```\n3. Сервер передаёт клиенту:\n```\n{\n'text' : 'Запущено обучение сети.'\n}\n```\n4. Сервер передаёт клиенту:\n```\n{\n'accuracy' : '99.32', \n'datetime' : '2018-11-21 17:39:08'\n}\n```\n5. Клиент в теле запроса должен отправить:\n```\n{\n'image' : '/9j/4AAQSkZJRgABAQE...'\n}\n```\nСервер ему передаст:\n```\n{\n'number' : '1'\n}\n```\n\nВ случае возникновения ошибки, сервер передаст клиенту, например (код ответа 401):\n```\n{\n'error': 'Unauthorized access.'\n}\n```\nПереопределены следующие коды ответов: 400, 401, 404, 405, 406, 415, 500.\n\n---\n\n**Примеры запросов**\n\n1. GET-запрос на `/list_nn`\n\nПример запроса, который формирует `python-requests`:\n```\nGET /list_nn HTTP/1.1\nHost: 192.168.2.83:5000\nConnection: keep-alive\nAccept-Encoding: gzip, deflate\nAuthorization: Basic dGVzdF9ubjpsZW5ldA==\nUser-Agent: python-requests/2.9.1\n```\n\nПример запроса, который формирует curl (`curl -v -u test_nn:lenet -i http://192.168.2.83:5000/list_nn`):\n```\nGET /list_nn HTTP/1.1\nHost: 192.168.2.83:5000\nAuthorization: Basic dGVzdF9ubjpsZW5ldA==\nUser-Agent: curl/7.47.0\n```\n\nВ обоих случаях сервер ответил:\n```\nHTTP/1.1 200 OK\nContent-Type: application/json\nContent-Length: 305\nDate: Fri, 21 Nov 2018 15:13:21 GMT\n\n{\n'text' : ['LeNet url:/lenet',\n          'Сеть1 url:/сеть1',\n          'Сеть2 url:/сеть2']\n}\n```\n\n---\n\n2. GET-запрос на `/lenet/about`\n\nПример запроса, который формирует `python-requests`:\n```\nGET /lenet/about HTTP/1.1\nHost: 192.168.2.83:5000\nAuthorization: Basic dGVzdF9ubjpsZW5ldA==\nUser-Agent: python-requests/2.9.1\nConnection: keep-alive\nAccept-Encoding: gzip, deflate\n```\n\nПример запроса, который формирует curl (`curl -v -u test_nn:lenet -i http://192.168.2.83:5000/lenet/about`):\n```\nGET /lenet/about HTTP/1.1\nHost: 192.168.2.83:5000\nAuthorization: Basic dGVzdF9ubjpsZW5ldA==\nUser-Agent: curl/7.47.0\n```\n\nВ обоих случаях сервер ответил:\n```\nHTTP/1.1 200 OK\nContent-Type: application/json\nContent-Length: 1086\nDate: Fri, 21 Nov 2018 15:43:06 GMT\n\n{\n'text' : 'Описание сети LeNet'\n}\n```\n\n---\n\n3. GET-запрос на `/lenet/train`\n\nПример запроса, который формирует `python-requests`:\n```\nGET /lenet/train?training_sample=mnist HTTP/1.1\nHost: 192.168.2.83:5000\nAuthorization: Basic dGVzdF9ubjpsZW5ldA==\nUser-Agent: python-requests/2.9.1\nConnection: keep-alive\nAccept-Encoding: gzip, deflate\n```\n\nПример запроса, который формирует curl (`curl -v -u test_nn:lenet -i http://192.168.2.83:5000/lenet/train?training_sample=other`):\n```\nGET /lenet/train?training_sample=other HTTP/1.1\nHost: 192.168.2.83:5000\nAuthorization: Basic dGVzdF9ubjpsZW5ldA==\nUser-Agent: curl/7.47.0\n```\n\nВ обоих случаях сервер ответил:\n```\nHTTP/1.1 200 OK\nContent-Type: application/json\nContent-Length: 1086\nDate: Fri, 21 Nov 2018 15:43:06 GMT\n\n{\n'text' : 'Запущено обучение сети.'\n}\n```\n\n---\n\n4. GET-запрос на `/lenet/train/status`\n\nПример запроса, который формирует `python-requests`:\n```\nGET /lenet/train/status HTTP/1.1\nHost: 192.168.2.83:5000\nAuthorization: Basic dGVzdF9ubjpsZW5ldA==\nUser-Agent: python-requests/2.9.1\nConnection: keep-alive\nAccept-Encoding: gzip, deflate\n```\n\nПример запроса, который формирует curl (`curl -v -u test_nn:lenet -i http://192.168.2.83:5000/lenet/train/status`):\n```\nGET /lenet/train/status HTTP/1.1\nHost: 192.168.2.83:5000\nAuthorization: Basic dGVzdF9ubjpsZW5ldA==\nUser-Agent: curl/7.47.0\n```\n\nВ обоих случаях сервер ответил:\n```\nHTTP/1.1 200 OK\nContent-Type: application/json\nContent-Length: 1086\nDate: Fri, 21 Nov 2018 15:43:06 GMT\n\n{\n'accuracy' : '99.32', \n'datetime' : '2018-11-21 17:39:08'\n}\n```\n\n---\n\n5. POST-запрос на `/lenet/classify`\n\nПример запроса, который формирует `python-requests`:\n```\nPOST /lenet/classify HTTP/1.1\nHost: 192.168.2.83:5000\nUser-Agent: python-requests/2.9.1\nAccept: */*\nContent-Length: 10739\nConnection: keep-alive\nContent-Type: application/json\nAuthorization: Basic dGVzdGJvdDp0ZXN0\nAccept-Encoding: gzip, deflate\n\n{\n'image' : '/9j/4AAQSkZJRgABAQE...'\n}\n```\n\nПример запроса, который формирует curl (`curl -v -u test_nn:lenet -i -H \"Content-Type: application/json\" -X POST -d '{'image' : '/9j/4AAQSkZJRgABAQE...'}' http://192.168.2.83:5000/lenet/classify`):\n```\nPOST /lenet/classify HTTP/1.1\nHost: 192.168.2.83:5000\nAuthorization: Basic dGVzdGJvdDp0ZXN0\nUser-Agent: curl/7.47.0\nAccept: */*\nContent-Type: application/json\nContent-Length: 10739\n\n{\n'image' : '/9j/4AAQSkZJRgABAQE...'\n}\n```\n\nСервер ответил:\n```\nHTTP/1.1 200 OK\nContent-Length: 81\nDate: Fri, 02 Nov 2018 15:57:13 GMT\nContent-Type: application/json\n\n{\n'number' : '1'\n}\n```\n\n# Нейронная сеть LeNet\n\nСеть LeNet - это свёрточная нейронная сеть (convolutional neural network, CNN), была представлена в 1998 году французским исследователем Яном Лекуном (Yann LeCun) для решения задачи классификации изображений (так же может использоваться для распознавания звуковых образов и др.). Данная модель сети состоит из трёх типов слоёв: свёрточные (convolutional) слои, субдискретизирующие (subsampling, подвыборка) слои и слои \"обычной\" нейронной сети – перцептрона. \n\nПервые два типа слоёв (convolutional и subsampling), чередуясь между собой, формируют входной вектор признаков для многослойного перцептрона. \n\nСвёрточный слой реализует идею так называемых локальных рецептивных полей, т.е. каждый выходной нейрон соединен только с определённой (небольшой) областью входной матрицы и таким образом моделирует некоторые особенности человеческого зрения.\nСвоё название свёрточная сеть получила по названию операции – свёртка, она часто используется для обработки изображений. Неформально эту операцию можно описать следующим образом – окном размера ядра g (например, 5х5) проходим с заданным шагом (обычно 1) всё изображение, на каждом шаге поэлементно умножаем содержимое окна на ядро g, результат суммируется и записывается в матрицу результата. При этом в зависимости от метода обработки краёв исходной матрицы результат может быть меньше исходного изображения (valid), такого же размера (same) или большего размера (full).\n\nСубдискретизирующие (subsampling) слои выполняют уменьшение размера входной карты признаков (обычно в 2 раза). Это можно делать разными способами, в данной реализации используется метод выбора максимального элемента (max-pooling) - вся карта признаков разделяется на ячейки 2х2 элемента, из которых выбираются максимальные по значению. Использование этого слоя позволяет улучшить распознавание образцов с изменённым масштабом (уменьшенных или увеличенных).\n\nВ моей реализации, сеть LeNet используется для классификации рукописных цифр. В текущем варианте обучена на наборе данных MNIST. Cостоит из 7 слоёв:\n1. Входной слой: матрица изображения\n2. Слой свертки: 75 карт признаков, ядро свертки 5х5, функция активации `ReLU`\n3. Слой подвыборки (субдискретизации): размер окна 2х2, метод наибольшего значения\n4. Слой свертки: 100 карт признаков, ядро свертки 5х5, функция активации `ReLU`\n5. Слой подвыборки (субдискретизации): размер пула 2х2, метод наибольшего значения\n6. Полносвязный слой: 500 нейронов, преобразует двумерный результат работы сети в одномерный, функция активации `ReLU`\n7. Полносвязный выходной слой: 10 нейронов, которые соответствуют классам рукописных цифр от 0 до 9, функция активации `SoftMax`\nПри обучении ипользовался оптимизатор `adam` и метод вычисления значения функции потери `categorical_crossentropy`. Проблема переобучения решается с помощью промежуточных слоёв `Dropout`. Точность классификации после 10 эпох обучения варьируется от 99.3% до 99.7%.\n\nРеализация находится в модуле `lenet.py`. Он представляет собой класс `LeNet` с тремя public-методами: `train()`, `classify()` и `create_training_sample()`. Модель обученной сети и её веса находятся в `data/lenet_model.json` и `data/lenet_weights.h5`. Набор данных для обучения - в `data/mnist.npz` и/или `data/training_sample.npz`.\n\n---\n\nТак же данный класс поддерживает создание обучающей выборки на основе любых изображений цифр. Реализация находится в методе `create_training_sample()`.\n\nИзображения должны быть в формате .jpg/.png/.bmp/.tiff, цветные и/или чёрно-белые, размером от 28х28 пикселей. На одном изображении может быть только одна цифра на светлом (в идеале - белом) фоне (примеры можно найти в `images/*.jpg`). Каждое изображение в своём имени должно содержать метку класса (т.е. цифру, которая на изображении; метка определяется по первому символу в названии). Например: `0_1399.jpg` - на изображении цифра 0; `7_81491.jpg` - на изображении цифра 7.\n\nПри создании обучающей выборки над каждым изображением выполняются следующие преобразования (которые так же выполняются для изображения, которое передаётся в параметрах методу `classify()`):\n  - конвертирование в чёрно-белое;\n  - обрезание всех светлых/белых рамок/полос так, что бы цифра занимала полностью всё изображение;\n  - выранивание длины и ширины (по максимальному из них);\n  - добавление белой рамки шириной 3 пикселя;\n  - уменьшение размера до 28х28 пикселей (как у изображений из набора данных MNIST)\n  - инвертирование цвета.\n\nДля удобства создания своей обучающей выборки, модуль `lenet.py` поддерживает аргументы командной строки (так же вы можете просто импортировать его в свой код на python и легко использовать). Список возможных комбинаций аргументов командной строки и их описание: \n1. без аргументов - запуск обучения сети на обучающей выборке MNIST. Например: ```python3 lenet.py```\n2. `training_sample.npz` - запуск обучения сети на обучающей выборке `training_sample.npz`. Например: ```python3 lenet.py data/training_sample.npz```\n3. `-c` - создать обучающую выборку на основе изображений из `data/source_images`. Например: ```python3 lenet.py -c```\n4. `-c my_data/images` - создать обучающую выборку на основе изображений из `my_data/images`. Например: ```python3 lenet.py -c my_data/images```\n5. `-c training_sample.npz` - создать обучающую выборку на основе изображений из `data/source_images` и сохранить в `training_sample.npz`. Например: ```python3 lenet.py -c training_sample.npz```\n6. `-c my_data/images training_sample.npz` - создать обучающую выборку на основе изображений из `my_data/images` и сохранить в `training_sample.npz`. Например: ```python3 lenet.py -c my_data/images training_sample.npz```\n\n\n# Клиент для общения с RESTful сервером\n\nЭто простой клиент, использующий пакет requests для отправки запросов серверу и получения ответов. Для своей работы требует только установленного python3 и пакета requests. Если вы используете Ubuntu 16.04 или выше, для установки этих пакетов можно воспользоваться `install_packages_client.sh` (он будет полезен, если вы запускаете сервер из docker-образа или на другом копьютере, что бы не устанавливать полный набор пакетов, которые требует сервер). Реализация находится в модуле `nn_client.py`.\n\nДанный клиент можно использовать двумя способами:\n1. Как самостоятельное консольное приложение.\n2. В составе другого приложения из кода python.\n\n---\n\n**Использование клиента как самостоятельное консольное приложение**\n\nВ этом варианте клиент можно запустить, выполнив в терминале `python3 nn_client.py` и после этого выбрав нужный пункт из предложенного меню. Так же клиент поддерживает аргументы командной строки. Они имеют следующую структуру: \n`[host:port] [имя_сети операция_над_сетью]`\n\nВозможные значения аргумента `имя_сети`:\n1. `list_nn` - получить список имеющихся нейронных сетей и их адреса\n2. `lenet` - использовать сеть LeNet, которая предназначена для классификации рукописных цифр\n\nВозможные значения аргумента `операция_над_сетью`:\n1. `classify` - классифирует изображение (или другой объект, в случае появления новых нейронных сетей в составе сервера), если сеть это поддерживает\n2. `status` - получить статус сети (точность работы и дату последнего обучения)\n3. `about` - получить информацию о сети\n4. `train` - запустить обучение сети (при этом на большинство запросов к этой сети сервер будет отвечать ошибкой, что сеть на данный момент недоступна, пока не закончится процесс обучения)\n\nСписок возможных комбинаций аргументов командной строки и их описание:\n1. без аргументов - запуск с автоопределением адреса машины в локальной сети и портом `5000`. Например: `python3 nn_client.py`\n2. `host:port` - запуск с подключением к указанному `host` и `port`. Например: `python3 nn_client.py 192.168.2.102:5000`\n3. `host:port list_nn` - получить список имеющихся нейронных сетей и их адреса. Например: `python3 nn_client.py 192.168.2.102:5000 list_nn`\n4. `host:port lenet classify` - классифицировать изображение с цифрой с помощью сети LeNet (будет предложено выбрать цифру из каталога `images`). Например: `python3 nn_client.py 192.168.2.102:5000 lenet classify`\n5. `host:port lenet classify image.jpg` - классифицировать изображение из файла `image.jpg/.png/.bmp/.tiff` с помощью сети LeNet. Например: `python3 nn_client.py 192.168.2.102:5000 lenet classify my_folder/my_number.jpg` \n6. `host:port lenet status` - получить статус сети LeNet. Например: `python3 nn_client.py 192.168.2.102:5000 lenet status`\n7. `host:port lenet about` - получить информацию о сети LeNet. Например: `python3 nn_client.py 192.168.2.102:5000 lenet status`\n8. `host:port lenet train` - запустить обучение сети LeNet на наборе данных MNIST. Например: `python3 nn_client.py 192.168.2.102:5000 lenet train`\n9. `host:port lenet train other` - запустить обучение сети LeNet на предварительно созданном наборе данных. Например: `python3 nn_client.py 192.168.2.102:5000 lenet train other`\n10. `list_nn` - получить список имеющихся нейронных сетей и их адреса. Например: `python3 nn_client.py list_nn`\n11. `lenet classify` - классифицировать изображение с цифрой с помощью сети LeNet (`host` определяется автоматически, `port = 5000`). Например: `python3 nn_client.py lenet classify`\n12. `lenet classify image.jpg` - классифицировать `image.jpg/.png/.bmp/.tiff` с помощью сети LeNet (`host` определяется автоматически, `port = 5000`). Например: `python3 nn_client.py lenet classify my_folder/my_number.jpg`\n13. `lenet status` - получить статус сети LeNet (`host` определяется автоматически, `port = 5000`). Например: `python3 nn_client.py lenet status`\n14. `lenet about` - получить информацию о сети LeNet (`host` определяется автоматически, `port = 5000`). Например: `python3 nn_client.py lenet about`\n15. `lenet train` - запустить обучение сети LeNet на наборе данных MNIST (`host` определяется автоматически, `port = 5000`). Например: `python3 nn_client.py lenet train`\n16. `lenet train other` - запустить обучение сети LeNet на предварительно созданном наборе данных (`host` определяется автоматически, `port = 5000`). Например: `python3 nn_client.py lenet train other`\n            \n---\n\n**Использование клиента в составе другого приложения из кода python**\n\nДля этого необходимо импортировать из модуля `nn_client.py` функцию `access_to_nn_server()` и вызвать её из своего кода в необходимом месте. Функция имеет вид:\n```\naccess_to_nn_server(host, port, name_nn, type_operation, login=None, password=None, https=False, data=None)\n```\n\nОписание аргументов:\n1. `host` - адрес хоста сервера\n2. `port` - порт сервера\n3. `name_nn` - имя запрашиваемой нейронной сети\n4. `type_operation` - тип операции над сетью\n5. `login` - логин для подключения к серверу (если не задавать, используется `test_nn`)\n6. `password` - пароль для подключения к серверу (если не задавать, используется `lenet`)\n7. `https` - `True`, что бы включить режим https\n8. `data` - передаваемые данные для нейронной сети (например, бинарная строка с изображением)\n9. возвращает строку с ответом сервера, либо строку с ошибкой (начинается с `[E]`), либо `list` со списком сетей и их адресами при запросе `list_nn`, либо `tuple` с точностью обучения сети в % и датой последнего обучения при запросе `lenet status`\n    \nПоддерживаемые значения для `name_nn`:\n1. `list_nn` - получить список имеющихся нейронных сетей и их адреса \n2. `lenet` - действия над сетью LeNet\n\nПоддерживаемые значения для `type_operation`:\n1. `classify` - классифицировать изображение\n2. `status` - получить статус сети (точность классификации и дата последнего обучения) \n3. `train` - запустить обучение сети (LeNet: на наборе данных MNIST или своём предварительно созданном наборе данных)\n4. `about` - получить информацию о сети\n\n`data` должна содержать:\n1. Для `lenet classify` - изображение `.jpg/.png/.bmp/.tiff` с рукописной цифрой в виде бинарной строки\n2. Для `lenet train` - значение `mnist` (набор данных MNIST) или `other` (свой предварительно созданный набор данных) для выбора соответствующей обучающей выборки\n3. В остальных случаях `data` не используется\n\nПример использования (подробнее можете посмотреть в `nn_client.py` в функции `main()`):\n```\nname_nn = 'lenet'\ntype_operation = 'classify'\nnumber_image = '1'\ndata = None\nif type_operation == 'classify': # Если выбрана классификация, будет загружено изображение цифры 1\n    img_path = 'images/' + number_image + '.jpg'\n    with open(img_path, 'rb') as f_image:\n        data = f_image.read()\ntry:\n    result = access_to_nn_server('127.0.0.1', '5000', name_nn, type_operation, data=data)\nexcept requests.exceptions.RequestException as e: # Если возникла ошибка при отправке/получении запроса/ответа\n    print('\\n[E] ' + str(e) + '\\n')\n    return\nif isinstance(result, tuple): # Если был запрос на статус сети\n    print('Результат обработки запроса: точность классификации %s%%, дата последнего обучения %s' % (result[0], result[1]))\nelif isinstance(result, list): # Если был запрос на список имеющихся сетей\n    print('Результат обработки запроса: %s' % result)\nelif result.find('[E]') != -1: # Если сервер вернул ошибку либо переданы некорректные данные\n    print(result)\nelse:\n    print('Результат запроса: ' + result)\n```\n\n---\n\nЕсли у вас возникнут вопросы, можете написать мне: vladsklim@gmail.com\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdbklim%2Fnn_server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdbklim%2Fnn_server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdbklim%2Fnn_server/lists"}