[Python] Web application design for machine learning

■ Introduction

This article is the 22nd day article of "DSL Advent Calendar 2019".

Christmas, New Year's Eve, New Year, and the big events are coming soon. It seems to be the season when it gets buoyant and less busy. How are you all doing? At the end of the Advent calendar, the fact that it is being turned by a small number of people is just before the mental collapse, The solo player who continues to write until today is about to graduate from humans.

The members of this ad-care are related to DSL, but I will participate in the OB frame! I graduated from an undergraduate school and am an engineer at a certain IT venture. I would like to summarize and introduce what I have studied for about half a year after joining the company.

■ Machine learning × Things to be aware of with web apps

Now, in order to perform machine learning on the Web, you need to be aware of the following points.

--You have to keep the web server running while running time-consuming processes such as pre-processing, learning, and prediction. --It may be necessary to operate the graphic memory at the start and end of processing.

In order to deal with this point, it is possible to manage the start and end processing of each process in a multi-process manner. Program the system. ~~ It's annoying. ~~

■ Design concept 1: async / await

First is the non-blocking IO monument async / await. If you have touched the front end, you may use it as a matter of course. In fact, it's also in Python.

However, unlike javascript async / await, functions with async always have a coroutine object. It returns, so it can only be executed inside an event loop.

■ Design concept 2: System of Systems

There is a concept called System of Systems as a concrete method of designing a system. Originally not in software design but in other fields such as business processes Is it like something used? But this time, I'll put this into the process management part.

> 1. Nested system

A system consists of zero or more systems. At this time, the child system is called a subsystem with respect to the parent system. When all subsystems have been booted, the parent system is treated as "booted". When all subsystems are terminated, the parent system is treated as "closed".

subsystem.png

> 2. System status

The system takes the states shown in the table below. The states that can be transitioned from each state are fixed, and it is not possible to transition from initial to running etc. suddenly.

Status Description Transition is possible
initial The state given as the initial value immediately after the system is created ready, disabled
ready A state that indicates that the system is ready to run running
running State when the system is running completed, intermitted, terminated
completed A state indicating that the system has completed execution normally -
disabled It is possible to transition to ready by removing the state indicating that the system cannot be executed and the cause of the inexecutability. ready
intermitted A state that indicates that the system is down, you can go back and forth between interfered and running as many times as you like while the system is running.(It's difficult to actually make it that way) running
terminated The state when the system is forcibly terminated, unlike disabled, cannot be transitioned from here -

The figure below is a simple state transition diagram. If the process proceeds normally without any error on the way, it will take the blue route. If the process cannot proceed due to an unexpected situation, it will be disabled or terminated through the red route. In addition, the transition of the green route is basically started by human judgment and operation.

Untitled Diagram (4).png

> 3. System transition

In the previous section, we introduced each state of the system and defined it. Next, we will define the state transition, or the arrow in the figure. The definition is a bit stubborn, but be sure to keep it solid so you don't have to worry about writing a program. I prepared a table and a figure as before.

transition Description
activate(activation) Execute the prepare function that collects the materials necessary for execution
disable(Invalidation) Change the value of the variable that stores the state to disabled
enable(activation) Change the value of the variable that stores the state to ready
start(start) Execute main function that performs heavy processing such as machine learning and infinite loop
complete(Done) Execute shutdown function to release memory etc.
suspend(Suspension) 実行中のmain関数にSuspensionシグナルを送ります
resume(Resume) 中断中のmain関数にResumeシグナルを送ります
terminate(forced termination) Execute teardown function to release memory etc.

Untitled Diagram (5).png

New words such as prepare function and main function came out, Having these will make it easier to write the program.

As a concrete image, when creating each system by inheriting the original System class, You must always insert super () when overriding activate or start. (Because state changes and logging are performed at each transition) This is annoying, so you can solve it by letting each system-specific process go to another function such as prepare or main.

■ Program example

Although the title mentions machine learning, for the sake of simplicity, this time we will substitute the sleep function as a time-consuming process. First, create the original System class.

class System():
    def __init__(self, name):
        self.name = name
        self.state = "initial"
        self.kwargs = {}
        self.log(self.state)

    def log(self, msg):
        date = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
        line = f"{date}\t[{self.name}]\tpid:{os.getpid():05d}\t{msg}"
        print(line)

    def prepare(self, **kwargs):
        pass

    def main(self):
        pass

    def activate(self):
        self.prepare(**self.kwargs)
        self.state = "ready"
        self.log(self.state)

    def start(self):
        self.state = "running"
        self.log(self.state)
        self.main()
    
    def complete(self):
        self.state = "completed"
        self.log(self.state)

    def transit(self):
        self.activate()
        self.start()
        self.complete()

    async def run(self, **kwargs):
        self.kwargs = kwargs
        executor = ProcessPoolExecutor(max_workers=None)
        loop = asyncio.get_event_loop()
        await loop.run_in_executor(executor, self.transit)

It just runs sleep in parallel, so it doesn't implement all of the states and transitions introduced endlessly: sob :: pray:

The constructor \ _ \ _ init \ _ \ _ names this system and sets the initial state. In transit, the transition of the blue route is executed in order. When implementing disable or terminate I think that you can write beautifully if you put try-except in this part.

In the last run defined as the async function, run_in_executor allows transit to be treated as a coroutine function. Also, in prepare etc., arguments may be taken depending on the user, so as variable length arguments I'd like to pass it to transit and even active, but this run_inexecutor, in the case of multi-process I get an error when I try to pass a variadic argument. Since there is no way, it is stored in the instance variable kwargs.

Next, create a system that executes the "system that executes the sleep function". It's a confusing phrase, but if you want to run multiple systems, I want to avoid writing directly in \ _ \ _ main \ _ \ _, so I will create an appSystem as a wrap system.

class appSystem(System):
    def prepare(self):
        pass

    def main(self):
        sleep1 = sleepSystem("sleepSystem1")
        sleep2 = sleepSystem("sleepSystem2")

        systems = asyncio.gather(
            sleep1.run(sleep=5),
            sleep2.run(sleep=3)
        )

        loop = asyncio.get_event_loop()
        loop.run_until_complete(systems)

Here, the meaning of separating the processes such as activet and prepare, start and main comes out. This time it's just sleep, so there's nothing special to write in prepare. ~~ You can forcibly write the variables stored in the instance ... ~~

Execute sleepSystem1 which sleeps for 5 seconds and sleepSystem2 which sleeps for 3 seconds in main. sleepSystem is a simple system like this:

class sleepSystem(System):
    def prepare(self, sleep=3):
        self.sleep = sleep

    def main(self):
        time.sleep(self.sleep)

After that, add appSystem.run () to the event loop with the main function. 13

def main():
    app = appSystem("appSystem")
    loop = asyncio.get_event_loop()
    loop.run_until_complete(app.run())

if __name__ == "__main__":
    main()

Let's run it.

2019-12-14 16:43:28.843830      [appSystem]     pid:30360       initial
2019-12-14 16:43:29.196505      [appSystem]     pid:21020       ready
2019-12-14 16:43:29.196505      [appSystem]     pid:21020       running
2019-12-14 16:43:29.197501      [sleepSystem1]  pid:21020       initial
2019-12-14 16:43:29.197501      [sleepSystem2]  pid:21020       initial
2019-12-14 16:43:29.799470      [sleepSystem1]  pid:29720       ready
2019-12-14 16:43:29.803496      [sleepSystem1]  pid:29720       running
2019-12-14 16:43:29.872484      [sleepSystem2]  pid:18868       ready
2019-12-14 16:43:29.872484      [sleepSystem2]  pid:18868       running
2019-12-14 16:43:32.873678      [sleepSystem2]  pid:18868       completed
2019-12-14 16:43:34.804446      [sleepSystem1]  pid:29720       completed
2019-12-14 16:43:34.804446      [appSystem]     pid:21020       completed

From left to right, the date, system name, PID, and status. The time when sleepSystem1 and sleepSystem2 entered the running state is almost the same time, In addition, they are separate processes and proceed at the same time, and after 3 to 5 seconds, the completed state transition, And you can see the completed appSystem.

Finally, I will post the entire program.

import asyncio
import time
from datetime import datetime
import os
from concurrent.futures import ProcessPoolExecutor

class System():
    def __init__(self, name):
        self.name = name
        self.state = "initial"
        self.kwargs = {}
        self.log(self.state)

    def log(self, msg):
        date = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
        line = f"{date}\t[{self.name}]\tpid:{os.getpid():05d}\t{msg}"
        print(line)

    def prepare(self, **kwargs):
        pass

    def main(self):
        pass

    def activate(self):
        self.prepare(**self.kwargs)
        self.state = "ready"
        self.log(self.state)

    def start(self):
        self.state = "running"
        self.log(self.state)
        self.main()
    
    def complete(self):
        self.state = "completed"
        self.log(self.state)

    def transit(self):
        self.activate()
        self.start()
        self.complete()

    async def run(self, **kwargs):
        self.kwargs = kwargs
        executor = ProcessPoolExecutor(max_workers=None)
        loop = asyncio.get_event_loop()
        await loop.run_in_executor(executor, self.transit)

class appSystem(System):
    def prepare(self):
        pass

    def main(self):
        sleep1 = sleepSystem("sleepSystem1")
        sleep2 = sleepSystem("sleepSystem2")
        
        systems = asyncio.gather(
            sleep1.run(sleep=5),
            sleep2.run(sleep=3)
        )

        loop = asyncio.get_event_loop()
        loop.run_until_complete(systems)

class sleepSystem(System):
    def prepare(self, sleep=3):
        self.sleep = sleep

    def main(self):
        time.sleep(self.sleep)

def main():
    app = appSystem("appSystem")
    loop = asyncio.get_event_loop()
    loop.run_until_complete(app.run())
    
if __name__ == "__main__":
    main()

■ Finally

It was a rush, but I introduced an example of web application design for machine learning. The program example is only sleep, but it does not implement www server or machine learning. Since the idea itself is the same, I think that there is little time and effort. (~~ If you write too much concretely, it's a company, so it's considerably simplified ~~)

In addition, communication between systems is performed by basic WebSocket. It's a good idea to create a websocketSystem separate from the wwwSystem and make it a subsystem of the appSystem.

So how was it? I haven't used it for a long time yet, but I personally like it because of its beautiful design.

■ Reference

http://itdoc.hitachi.co.jp/manuals/3020/30203M8120/EM810359.HTM

Recommended Posts

[Python] Web application design for machine learning
Web teaching materials for learning Python
<For beginners> python library <For machine learning>
Amplify images for machine learning with python
Why Python is chosen for machine learning
[Shakyo] Encounter with Python for machine learning
An introduction to Python for machine learning
Upgrade the Azure Machine Learning SDK for Python
[Python] Web application from 0! Hands-on (1) -Design, DB construction-
Take the free "Introduction to Python for Machine Learning" online until 4/27 application
Data set for machine learning
Build an interactive environment for machine learning in Python
Learning flow for Python beginners
Python learning plan for AI learning
Python learning memo for machine learning by Chainer from Chapter 2
Python learning memo for machine learning by Chainer Chapters 1 and 2
Machine learning with Python! Preparation
Preparing to start "Python machine learning programming" (for macOS)
[Python] I made a classifier for irises [Machine learning]
Python Machine Learning Programming> Keywords
Checkio's recommendation for learning Python
Web application with Python + Flask ② ③
Beginning with Python machine learning
Memo for building a machine learning environment using Python
Web application with Python + Flask ④
Easy-to-understand explanation of Python web application (Django) even for beginners (6) [MTV design pattern completion]
Build an environment for machine learning using Python on MacOSX
Python beginners publish web applications using machine learning [Part 1] Introduction
Python learning memo for machine learning by Chainer Chapter 7 Regression analysis
Python: Application of supervised learning (regression)
Machine learning algorithm (support vector machine application)
Machine learning with python (1) Overall classification
Machine learning summary by Python beginners
Python: Preprocessing in Machine Learning: Overview
Machine learning meeting information for HRTech
Beginners use Python for web scraping (1)
[Recommended tagging for machine learning # 4] Machine learning script ...?
Beginners use Python for web scraping (4) ―― 1
"Scraping & machine learning with Python" Learning memo
Application development using Azure Machine Learning
[Python machine learning] Recommendation of using Spyder for beginners (as of August 2020)
Learning history for participating in team application development in Python ~ Index page ~
How about Anaconda for building a machine learning environment in Python?
Python learning memo for machine learning by Chainer Chapter 8 Introduction to Numpy
Building a Windows 7 environment for getting started with machine learning with Python
Machine learning
python learning
Python learning memo for machine learning by Chainer Chapter 9 Introduction to scikit-learn
[Python] Web application from 0! Hands-on (2) -Hello World-
[Python] Web application from 0! Hands-on (3) -API implementation-
WEB scraping with Python (for personal notes)
Notes on PyQ machine learning python grammar
First Steps for Machine Learning (AI) Beginners
Use machine learning APIs A3RT from Python
Machine learning with python (2) Simple regression analysis
I installed Python 3.5.1 to study machine learning
[python] Frequently used techniques in machine learning
An introduction to OpenCV for machine learning
"Python Machine Learning Programming" Summary Note (Jupyter)
"Usable" one-hot Encoding method for machine learning
Python: Preprocessing in machine learning: Data acquisition