/NN_Server

Back-end of the project of intelligence system of neural networks at the department of IIT BSUIR. Implemented with using Python3+TensorFlow+Keras.

Primary LanguagePython

NeuralNetworks_Server

Проект состоит из нескольких частей - RESTful сервер для взаимодействия с нейронными сетями, нейронная сеть LeNet и простой клиент для общения с сервером и его тестирования.

Полный список всех необходимых для работы пакетов:

  1. Для 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].
  2. Для Ubuntu: python3.5-dev, python3-pip, python3-tk, net-tools.

Если вы используете Ubuntu 16.04 или выше, для установки всех пакетов можно воспользоваться install_packages.sh (проверено в Ubuntu 16.04). По умолчанию будет установлен TensorFlow для CPU. Если у вас есть видеокарта nvidia, вы можете установить TensorFlowGPU. Для этого необходимо при запуске install_packages.sh передать параметр gpu. Например:

./install_packages.sh gpu

Docker-образ

Вы так же можете собрать docker-образ моего проекта с помощью Dockerfile либо загрузить уже собранный образ из моего Google Drive.


Установка Docker и сборка образа

Если вы используете Ubuntu 16.04 или выше, для установки docker-engine можно воспользоваться install_docker.sh. После установки, проверьте статус docker с помощью команды:

sudo systemctl status docker

Результат должен быть примерно такой:

● docker.service - Docker Application Container Engine
   Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
   Active: active (running) since Чцв 2018-11-22 03:01:32 +03; 14h ago
     Docs: https://docs.docker.com
 Main PID: 1183 (dockerd)
    Tasks: 24
   Memory: 349.8M
      CPU: 2min 3.238s
   CGroup: /system.slice/docker.service
           ├─1183 /usr/bin/dockerd -H fd://
           └─1220 docker-containerd -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --metrics-interval=0

Затем вам необходимо в терминале перейти в папку, куда вы клонировали данный репозиторий (или скачали и распаковали его) и выполнить:

sudo docker build -t nn_server:v0.1 .

Где -t - запуск терминала, . - директория, из которой вызывается docker build (точка - значит в текущей директории находятся все файлы для образа), nn_server:v0.1 - метка образа и его версия.

После успешного выполнения данной операции вы можете вывести список имеющихся образов, выполнив:

sudo docker images

В полученном списке вы увидите наш образ - nn_server:v0.1.


Запуск docker-образа

Если вы загрузили уже собранный образ из моего Google Drive, то перед запуском вам необходимо его сначала распаковать. Это можно сделать так (находясь в папке со скачанным .tar архивом):

sudo docker load < nn_server.tar

или

sudo docker load --input nn_server.tar

Убедиться в том, что образ успешно распакован, вы можете выполнив sudo docker images.

Теперь образ готов к запуску. Для этого необходимо выполнить:

sudo docker run -ti --rm -p 5000:5000 nn_server:v0.1 python3 nn_server.py

Где -t - запуск терминала, -i - интерактивный режим, --rm - удалить контейнер после завершения его работы, -p 5000:5000 - пробросить все подключения на порт 5000 к машине-хосту в контейнер на порт 5000 (вы так же можете явно указать другой адрес, к которому нужно будет подключиться извне: -p 127.0.0.1:5000:5000).

В результате запустится RESTful-сервер и можно к нему обращаться по указанному в терминале адресу (если вы не указали другой при запуске образа).

RESTful-сервер

Данный сервер предоставляет REST-api для взаимодействия с нейронными сетями. На данный момент имеется только одна сеть - LeNet для классификации рукописных цифр.

Сервер реализован с помощью Flask, а многопоточный режим (production-версия) с помощью gevent.pywsgi.WSGIServer. Также сервер имеет ограничение на размер принимаемых данных в теле запроса равное 16 Мб. Реализация находится в модуле nn_server.py.

Запустить WSGI сервер можно выполнив run_nn_server.sh (запуск без аргументов командной строки) или python3 nn_server.py.

Сервер поддерживает аргументы командной строки, которые немного упрощают его запуск. Аргументы имеют следующую структуру: [ключ(-и)] [адрес:порт].

Возможные ключи:

  1. -d - запуск тестового Flask сервера (если ключ не указывать - будет запущен WSGI сервер)
  2. -s - запуск сервера с поддержкой https (используется самоподписанный сертификат, получен с помощью openssl)

Допустимые варианты адрес:порт:

  1. host:port - запуск на указанном host и port
  2. localaddr:port - запуск с автоопределением адреса машины в локальной сети и указанным port
  3. host:0 или localaddr:0 - если port = 0, то будет выбран любой доступный порт автоматически

Список возможных комбинаций аргументов командной строки и их описание:

  1. без аргументов - запуск WSGI сервера с автоопределением адреса машины в локальной сети и портом 5000. Например: python3 rest_server.py
  2. host:port - запуск WSGI сервера на указанном host и port. Например: python3 nn_server.py 192.168.2.102:5000
  3. -d - запуск тестового Flask сервера на 127.0.0.1:5000. Например: python3 nn_server.py -d
  4. -d host:port - запуск тестового Flask сервера на указанном host и port. Например: python3 nn_server.py -d 192.168.2.102:5000
  5. -d localaddr:port - запуск тестового Flask сервера с автоопределением адреса машины в локальной сети и портом port. Например: python3 nn_server.py -d localaddr:5000
  6. -s - запуск WSGI сервера с поддержкой https, автоопределением адреса машины в локальной сети и портом 5000. Например: python3 nn_server.py -s
  7. -s host:port - запуск WSGI сервера с поддержкой https на указанном host и port. Например: python3 nn_server.py -s 192.168.2.102:5000
  8. -s -d - запуск тестового Flask сервера с поддержкой https на 127.0.0.1:5000. Например: python3 nn_server.py -s -d
  9. -s -d host:port - запуск тестового Flask сервера с поддержкой https на указанном host и port. Например: python3 nn_server.py -s -d 192.168.2.102:5000
  10. -s -d localaddr:port - запуск тестового Flask сервера с поддержкой https, автоопределением адреса машины в локальной сети и портом port. Например: python3 nn_server.py -s -d localaddr:5000

Сервер может сам выбрать доступный порт, для этого нужно указать в host:port или localaddr:port порт 0 (например: python3 nn_server.py -d localaddr:0).

Всего поддерживается 5 запросов:

  1. GET-запрос на /list_nn вернёт информацию об имеющихся нейронных сетях и их адресах
  2. GET-запрос на /lenet/about вернёт информацию о сети LeNet
  3. GET-запрос на /lenet/train запустит обучение сети в фоне (т.е. в отдельном потоке) на наборе рукописных цифр MNIST (передать в URL параметр training_sample=mnist) или на предварительно созданном наборе данных data/training_sample.npz (передать в URL параметр training_sample=other) (после запуска, на запросы 3, 4 и 5 сервер будет отвечать ошибкой с пояснением, что сеть на данный момент обучается и недоступна для использования)
  4. GET-запрос на /lenet/train/status вернёт последний результат обучения сети LeNet (точность классификации и дата последнего обучения)
  5. POST-запрос на /lenet/classify принимает .jpg/.png/.bmp/.tiff файл и возвращает распознанную цифру в виде строки

Описание сервера

  1. Сервер имеет базовую http-авторизацию. Т.е. для получения доступа к серверу надо в каждом запросе добавить заголовок, содержащий логин:пароль, закодированный с помощью base64 (логин: test_nn, пароль: lenet). Пример на python:
import requests
import base64

auth = base64.b64encode('test_nn:lenet'.encode())
headers = {'Authorization' : "Basic " + auth.decode()}

Выглядеть это будет так:

Authorization: Basic dGVzdF9ubjpsZW5ldA==
  1. В запросе на запуск обучения сети (который под номером 3) сервер ожидает параметр training_sample в URL запроса. Данный параметр определят используемую обучающую выборку: training_sample=mnist - использовать в качестве обучающей выборки набор рукописных цифр MNIST, training_sample=other - использовать предварительно созданную обучающую выборку data/training_sample.npz из своих данных (с помощью lenet.py -c). Пример на python:
# Отправка запроса серверу
response = requests.post('http://' + addr + '/lenet/train?training_sample=mnist', headers=headers, json=data)

# Разбор ответа
data = response.json()
number = data.get('number')
print(number)
  1. В запросе на классификацию (который под номером 5) сервер ожидает .jpg/.png/.bmp/.tiff файл (цветной либо чёрно-белый, размером от 28х28 пикселей) с изображением рукописной цифры (цифра должна быть на светлом (в идеале - белом) фоне, примеры можно найти в images/*.jpg), который передаётся в json с помощью кодировки base64 (т.е. открывается .jpg/.png/.bmp/.tiff файл, читается в массив байт, потом кодирутеся base64, полученный массив декодируется из байтовой формы в строку utf-8 и помещается в json), в python это выглядит так:
# Формирование запроса
auth = base64.b64encode('test_nn:lenet'.encode())
headers = {'Authorization' : "Basic " + auth.decode()}

with open('images/1.jpg', 'rb') as f_image:
    img_data = f_image.read()
data = base64.b64encode(data)
data = {'image' : data.decode()}

# Отправка запроса серверу
response = requests.post('http://' + addr + '/lenet/classify', headers=headers, json=data)

# Разбор ответа
data = response.json()
number = data.get('number')
print(number)

Передаваемые данные в каждом запросе

Все передаваемые данные обёрнуты в json (в том числе и ответы с ошибками).

  1. Сервер передаёт клиенту:
{
'text' : ['LeNet url:/lenet',
          'Сеть1 url:/сеть1',
          'Сеть2 url:/сеть2']
}
  1. Сервер передаёт клиенту:
{
'text' : 'Описание сети LeNet'
}
  1. Сервер передаёт клиенту:
{
'text' : 'Запущено обучение сети.'
}
  1. Сервер передаёт клиенту:
{
'accuracy' : '99.32', 
'datetime' : '2018-11-21 17:39:08'
}
  1. Клиент в теле запроса должен отправить:
{
'image' : '/9j/4AAQSkZJRgABAQE...'
}

Сервер ему передаст:

{
'number' : '1'
}

В случае возникновения ошибки, сервер передаст клиенту, например (код ответа 401):

{
'error': 'Unauthorized access.'
}

Переопределены следующие коды ответов: 400, 401, 404, 405, 406, 415, 500.


Примеры запросов

  1. GET-запрос на /list_nn

Пример запроса, который формирует python-requests:

GET /list_nn HTTP/1.1
Host: 192.168.2.83:5000
Connection: keep-alive
Accept-Encoding: gzip, deflate
Authorization: Basic dGVzdF9ubjpsZW5ldA==
User-Agent: python-requests/2.9.1

Пример запроса, который формирует curl (curl -v -u test_nn:lenet -i http://192.168.2.83:5000/list_nn):

GET /list_nn HTTP/1.1
Host: 192.168.2.83:5000
Authorization: Basic dGVzdF9ubjpsZW5ldA==
User-Agent: curl/7.47.0

В обоих случаях сервер ответил:

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 305
Date: Fri, 21 Nov 2018 15:13:21 GMT

{
'text' : ['LeNet url:/lenet',
          'Сеть1 url:/сеть1',
          'Сеть2 url:/сеть2']
}

  1. GET-запрос на /lenet/about

Пример запроса, который формирует python-requests:

GET /lenet/about HTTP/1.1
Host: 192.168.2.83:5000
Authorization: Basic dGVzdF9ubjpsZW5ldA==
User-Agent: python-requests/2.9.1
Connection: keep-alive
Accept-Encoding: gzip, deflate

Пример запроса, который формирует curl (curl -v -u test_nn:lenet -i http://192.168.2.83:5000/lenet/about):

GET /lenet/about HTTP/1.1
Host: 192.168.2.83:5000
Authorization: Basic dGVzdF9ubjpsZW5ldA==
User-Agent: curl/7.47.0

В обоих случаях сервер ответил:

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 1086
Date: Fri, 21 Nov 2018 15:43:06 GMT

{
'text' : 'Описание сети LeNet'
}

  1. GET-запрос на /lenet/train

Пример запроса, который формирует python-requests:

GET /lenet/train?training_sample=mnist HTTP/1.1
Host: 192.168.2.83:5000
Authorization: Basic dGVzdF9ubjpsZW5ldA==
User-Agent: python-requests/2.9.1
Connection: keep-alive
Accept-Encoding: gzip, deflate

Пример запроса, который формирует curl (curl -v -u test_nn:lenet -i http://192.168.2.83:5000/lenet/train?training_sample=other):

GET /lenet/train?training_sample=other HTTP/1.1
Host: 192.168.2.83:5000
Authorization: Basic dGVzdF9ubjpsZW5ldA==
User-Agent: curl/7.47.0

В обоих случаях сервер ответил:

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 1086
Date: Fri, 21 Nov 2018 15:43:06 GMT

{
'text' : 'Запущено обучение сети.'
}

  1. GET-запрос на /lenet/train/status

Пример запроса, который формирует python-requests:

GET /lenet/train/status HTTP/1.1
Host: 192.168.2.83:5000
Authorization: Basic dGVzdF9ubjpsZW5ldA==
User-Agent: python-requests/2.9.1
Connection: keep-alive
Accept-Encoding: gzip, deflate

Пример запроса, который формирует curl (curl -v -u test_nn:lenet -i http://192.168.2.83:5000/lenet/train/status):

GET /lenet/train/status HTTP/1.1
Host: 192.168.2.83:5000
Authorization: Basic dGVzdF9ubjpsZW5ldA==
User-Agent: curl/7.47.0

В обоих случаях сервер ответил:

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 1086
Date: Fri, 21 Nov 2018 15:43:06 GMT

{
'accuracy' : '99.32', 
'datetime' : '2018-11-21 17:39:08'
}

  1. POST-запрос на /lenet/classify

Пример запроса, который формирует python-requests:

POST /lenet/classify HTTP/1.1
Host: 192.168.2.83:5000
User-Agent: python-requests/2.9.1
Accept: */*
Content-Length: 10739
Connection: keep-alive
Content-Type: application/json
Authorization: Basic dGVzdGJvdDp0ZXN0
Accept-Encoding: gzip, deflate

{
'image' : '/9j/4AAQSkZJRgABAQE...'
}

Пример запроса, который формирует 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):

POST /lenet/classify HTTP/1.1
Host: 192.168.2.83:5000
Authorization: Basic dGVzdGJvdDp0ZXN0
User-Agent: curl/7.47.0
Accept: */*
Content-Type: application/json
Content-Length: 10739

{
'image' : '/9j/4AAQSkZJRgABAQE...'
}

Сервер ответил:

HTTP/1.1 200 OK
Content-Length: 81
Date: Fri, 02 Nov 2018 15:57:13 GMT
Content-Type: application/json

{
'number' : '1'
}

Нейронная сеть LeNet

Сеть LeNet - это свёрточная нейронная сеть (convolutional neural network, CNN), была представлена в 1998 году французским исследователем Яном Лекуном (Yann LeCun) для решения задачи классификации изображений (так же может использоваться для распознавания звуковых образов и др.). Данная модель сети состоит из трёх типов слоёв: свёрточные (convolutional) слои, субдискретизирующие (subsampling, подвыборка) слои и слои "обычной" нейронной сети – перцептрона.

Первые два типа слоёв (convolutional и subsampling), чередуясь между собой, формируют входной вектор признаков для многослойного перцептрона.

Свёрточный слой реализует идею так называемых локальных рецептивных полей, т.е. каждый выходной нейрон соединен только с определённой (небольшой) областью входной матрицы и таким образом моделирует некоторые особенности человеческого зрения. Своё название свёрточная сеть получила по названию операции – свёртка, она часто используется для обработки изображений. Неформально эту операцию можно описать следующим образом – окном размера ядра g (например, 5х5) проходим с заданным шагом (обычно 1) всё изображение, на каждом шаге поэлементно умножаем содержимое окна на ядро g, результат суммируется и записывается в матрицу результата. При этом в зависимости от метода обработки краёв исходной матрицы результат может быть меньше исходного изображения (valid), такого же размера (same) или большего размера (full).

Субдискретизирующие (subsampling) слои выполняют уменьшение размера входной карты признаков (обычно в 2 раза). Это можно делать разными способами, в данной реализации используется метод выбора максимального элемента (max-pooling) - вся карта признаков разделяется на ячейки 2х2 элемента, из которых выбираются максимальные по значению. Использование этого слоя позволяет улучшить распознавание образцов с изменённым масштабом (уменьшенных или увеличенных).

В моей реализации, сеть LeNet используется для классификации рукописных цифр. В текущем варианте обучена на наборе данных MNIST. Cостоит из 7 слоёв:

  1. Входной слой: матрица изображения
  2. Слой свертки: 75 карт признаков, ядро свертки 5х5, функция активации ReLU
  3. Слой подвыборки (субдискретизации): размер окна 2х2, метод наибольшего значения
  4. Слой свертки: 100 карт признаков, ядро свертки 5х5, функция активации ReLU
  5. Слой подвыборки (субдискретизации): размер пула 2х2, метод наибольшего значения
  6. Полносвязный слой: 500 нейронов, преобразует двумерный результат работы сети в одномерный, функция активации ReLU
  7. Полносвязный выходной слой: 10 нейронов, которые соответствуют классам рукописных цифр от 0 до 9, функция активации SoftMax При обучении ипользовался оптимизатор adam и метод вычисления значения функции потери categorical_crossentropy. Проблема переобучения решается с помощью промежуточных слоёв Dropout. Точность классификации после 10 эпох обучения варьируется от 99.3% до 99.7%.

Реализация находится в модуле lenet.py. Он представляет собой класс LeNet с тремя public-методами: train(), classify() и create_training_sample(). Модель обученной сети и её веса находятся в data/lenet_model.json и data/lenet_weights.h5. Набор данных для обучения - в data/mnist.npz и/или data/training_sample.npz.


Так же данный класс поддерживает создание обучающей выборки на основе любых изображений цифр. Реализация находится в методе create_training_sample().

Изображения должны быть в формате .jpg/.png/.bmp/.tiff, цветные и/или чёрно-белые, размером от 28х28 пикселей. На одном изображении может быть только одна цифра на светлом (в идеале - белом) фоне (примеры можно найти в images/*.jpg). Каждое изображение в своём имени должно содержать метку класса (т.е. цифру, которая на изображении; метка определяется по первому символу в названии). Например: 0_1399.jpg - на изображении цифра 0; 7_81491.jpg - на изображении цифра 7.

При создании обучающей выборки над каждым изображением выполняются следующие преобразования (которые так же выполняются для изображения, которое передаётся в параметрах методу classify()):

  • конвертирование в чёрно-белое;
  • обрезание всех светлых/белых рамок/полос так, что бы цифра занимала полностью всё изображение;
  • выранивание длины и ширины (по максимальному из них);
  • добавление белой рамки шириной 3 пикселя;
  • уменьшение размера до 28х28 пикселей (как у изображений из набора данных MNIST)
  • инвертирование цвета.

Для удобства создания своей обучающей выборки, модуль lenet.py поддерживает аргументы командной строки (так же вы можете просто импортировать его в свой код на python и легко использовать). Список возможных комбинаций аргументов командной строки и их описание:

  1. без аргументов - запуск обучения сети на обучающей выборке MNIST. Например: python3 lenet.py
  2. training_sample.npz - запуск обучения сети на обучающей выборке training_sample.npz. Например: python3 lenet.py data/training_sample.npz
  3. -c - создать обучающую выборку на основе изображений из data/source_images. Например: python3 lenet.py -c
  4. -c my_data/images - создать обучающую выборку на основе изображений из my_data/images. Например: python3 lenet.py -c my_data/images
  5. -c training_sample.npz - создать обучающую выборку на основе изображений из data/source_images и сохранить в training_sample.npz. Например: python3 lenet.py -c training_sample.npz
  6. -c my_data/images training_sample.npz - создать обучающую выборку на основе изображений из my_data/images и сохранить в training_sample.npz. Например: python3 lenet.py -c my_data/images training_sample.npz

Клиент для общения с RESTful сервером

Это простой клиент, использующий пакет requests для отправки запросов серверу и получения ответов. Для своей работы требует только установленного python3 и пакета requests. Если вы используете Ubuntu 16.04 или выше, для установки этих пакетов можно воспользоваться install_packages_client.sh (он будет полезен, если вы запускаете сервер из docker-образа или на другом копьютере, что бы не устанавливать полный набор пакетов, которые требует сервер). Реализация находится в модуле nn_client.py.

Данный клиент можно использовать двумя способами:

  1. Как самостоятельное консольное приложение.
  2. В составе другого приложения из кода python.

Использование клиента как самостоятельное консольное приложение

В этом варианте клиент можно запустить, выполнив в терминале python3 nn_client.py и после этого выбрав нужный пункт из предложенного меню. Так же клиент поддерживает аргументы командной строки. Они имеют следующую структуру: [host:port] [имя_сети операция_над_сетью]

Возможные значения аргумента имя_сети:

  1. list_nn - получить список имеющихся нейронных сетей и их адреса
  2. lenet - использовать сеть LeNet, которая предназначена для классификации рукописных цифр

Возможные значения аргумента операция_над_сетью:

  1. classify - классифирует изображение (или другой объект, в случае появления новых нейронных сетей в составе сервера), если сеть это поддерживает
  2. status - получить статус сети (точность работы и дату последнего обучения)
  3. about - получить информацию о сети
  4. train - запустить обучение сети (при этом на большинство запросов к этой сети сервер будет отвечать ошибкой, что сеть на данный момент недоступна, пока не закончится процесс обучения)

Список возможных комбинаций аргументов командной строки и их описание:

  1. без аргументов - запуск с автоопределением адреса машины в локальной сети и портом 5000. Например: python3 nn_client.py
  2. host:port - запуск с подключением к указанному host и port. Например: python3 nn_client.py 192.168.2.102:5000
  3. host:port list_nn - получить список имеющихся нейронных сетей и их адреса. Например: python3 nn_client.py 192.168.2.102:5000 list_nn
  4. host:port lenet classify - классифицировать изображение с цифрой с помощью сети LeNet (будет предложено выбрать цифру из каталога images). Например: python3 nn_client.py 192.168.2.102:5000 lenet classify
  5. 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
  6. host:port lenet status - получить статус сети LeNet. Например: python3 nn_client.py 192.168.2.102:5000 lenet status
  7. host:port lenet about - получить информацию о сети LeNet. Например: python3 nn_client.py 192.168.2.102:5000 lenet status
  8. host:port lenet train - запустить обучение сети LeNet на наборе данных MNIST. Например: python3 nn_client.py 192.168.2.102:5000 lenet train
  9. host:port lenet train other - запустить обучение сети LeNet на предварительно созданном наборе данных. Например: python3 nn_client.py 192.168.2.102:5000 lenet train other
  10. list_nn - получить список имеющихся нейронных сетей и их адреса. Например: python3 nn_client.py list_nn
  11. lenet classify - классифицировать изображение с цифрой с помощью сети LeNet (host определяется автоматически, port = 5000). Например: python3 nn_client.py lenet classify
  12. lenet classify image.jpg - классифицировать image.jpg/.png/.bmp/.tiff с помощью сети LeNet (host определяется автоматически, port = 5000). Например: python3 nn_client.py lenet classify my_folder/my_number.jpg
  13. lenet status - получить статус сети LeNet (host определяется автоматически, port = 5000). Например: python3 nn_client.py lenet status
  14. lenet about - получить информацию о сети LeNet (host определяется автоматически, port = 5000). Например: python3 nn_client.py lenet about
  15. lenet train - запустить обучение сети LeNet на наборе данных MNIST (host определяется автоматически, port = 5000). Например: python3 nn_client.py lenet train
  16. lenet train other - запустить обучение сети LeNet на предварительно созданном наборе данных (host определяется автоматически, port = 5000). Например: python3 nn_client.py lenet train other

Использование клиента в составе другого приложения из кода python

Для этого необходимо импортировать из модуля nn_client.py функцию access_to_nn_server() и вызвать её из своего кода в необходимом месте. Функция имеет вид:

access_to_nn_server(host, port, name_nn, type_operation, login=None, password=None, https=False, data=None)

Описание аргументов:

  1. host - адрес хоста сервера
  2. port - порт сервера
  3. name_nn - имя запрашиваемой нейронной сети
  4. type_operation - тип операции над сетью
  5. login - логин для подключения к серверу (если не задавать, используется test_nn)
  6. password - пароль для подключения к серверу (если не задавать, используется lenet)
  7. https - True, что бы включить режим https
  8. data - передаваемые данные для нейронной сети (например, бинарная строка с изображением)
  9. возвращает строку с ответом сервера, либо строку с ошибкой (начинается с [E]), либо list со списком сетей и их адресами при запросе list_nn, либо tuple с точностью обучения сети в % и датой последнего обучения при запросе lenet status

Поддерживаемые значения для name_nn:

  1. list_nn - получить список имеющихся нейронных сетей и их адреса
  2. lenet - действия над сетью LeNet

Поддерживаемые значения для type_operation:

  1. classify - классифицировать изображение
  2. status - получить статус сети (точность классификации и дата последнего обучения)
  3. train - запустить обучение сети (LeNet: на наборе данных MNIST или своём предварительно созданном наборе данных)
  4. about - получить информацию о сети

data должна содержать:

  1. Для lenet classify - изображение .jpg/.png/.bmp/.tiff с рукописной цифрой в виде бинарной строки
  2. Для lenet train - значение mnist (набор данных MNIST) или other (свой предварительно созданный набор данных) для выбора соответствующей обучающей выборки
  3. В остальных случаях data не используется

Пример использования (подробнее можете посмотреть в nn_client.py в функции main()):

name_nn = 'lenet'
type_operation = 'classify'
number_image = '1'
data = None
if type_operation == 'classify': # Если выбрана классификация, будет загружено изображение цифры 1
    img_path = 'images/' + number_image + '.jpg'
    with open(img_path, 'rb') as f_image:
        data = f_image.read()
try:
    result = access_to_nn_server('127.0.0.1', '5000', name_nn, type_operation, data=data)
except requests.exceptions.RequestException as e: # Если возникла ошибка при отправке/получении запроса/ответа
    print('\n[E] ' + str(e) + '\n')
    return
if isinstance(result, tuple): # Если был запрос на статус сети
    print('Результат обработки запроса: точность классификации %s%%, дата последнего обучения %s' % (result[0], result[1]))
elif isinstance(result, list): # Если был запрос на список имеющихся сетей
    print('Результат обработки запроса: %s' % result)
elif result.find('[E]') != -1: # Если сервер вернул ошибку либо переданы некорректные данные
    print(result)
else:
    print('Результат запроса: ' + result)

Если у вас возникнут вопросы, можете написать мне: vladsklim@gmail.com