機械学習ウェブサーバー「VKF-solver」

現在、一般大衆の目には、機械学習はニューラルネットワークをトレーニングするためのさまざまなオプションと強く関連しています。最初はこれらが完全に接続されたネットワークでしたが、次に畳み込みおよび反復ネットワークに置き換えられた場合、今ではGANやLTSMネットワークなどの完全にエキゾチックなオプションになっています。トレーニングに必要なサンプル量の増加に加えて、彼らはまだ決定がなされた理由を説明できないことに苦しんでいます。ただし、機械学習への構造的アプローチもあります。その1つのソフトウェア実装については、この記事で説明します。







これは、格子理論に基づく機械学習のVKF法と呼ばれる、機械学習への国内的なアプローチです。発生の歴史と名前の選択は、この記事の最後に説明されています。



1.メソッドの説明



当初、システム全体はコンソールアプリケーションとしてC ++で作成者によって作成され、次にMariaDB DBMSの制御下でデータベースに接続され(mariadb ++ライブラリを使用)、次にPythonライブラリに変更されました(pybind11パッケージを使用)。

カリフォルニア大学アーバイン校のリポジトリから、機械学習アルゴリズムをテストするためのテストデータとしていくつかのアレイが選択されました。



キノコの配列では、8124の北米のキノコの説明が含まれ、システムは100%の結果を示しました。より正確には、乱数ジェネレータは初期データをトレーニングサンプル(2088食用および1944毒キノコ)とテストサンプル(2120食用および1972毒)に分割しました。食用の原因について約100の仮説を計算した後、すべてのテストケースが正しく予測されました。アルゴリズムはペアのマルコフ連鎖を使用するため、十分な数の仮説が変化する可能性があります。多くの場合、50のランダムな仮説を生成するのに十分でした。毒性の原因を生成する場合、必要な仮説の数は約120にグループ化されますが、この場合、すべてのテストケースが正しく予測されます。 Kaggle.comにはキノコ分類コンテストがありますかなりの数の著者が100%の精度を達成しました。しかし、ほとんどのソリューションはニューラルネットワークです。私たちのアプローチでは、きのこピッカーは約50のルールしか学習できません。ほとんどの機能は重要ではないため、各仮説は重要な機能の少数の値の結合となり、覚えやすくなります。その後、キノコピッカーは、毒キノコを取るか、食用キノコを逃すことを恐れずにキノコを探すことができます。



キノコが食用であると見なすことができるとする仮説の例を以下に示します:

[( 'gill_attachment'、 'free')、( 'gill_spacing'、 'close')、( 'gill_size'、 'broad')、( 'stalk_shape '、'拡大 ')、(' stalk_surface_below_ring '、'うろこ状 ')、(' veil_type '、'部分的 ')、(' veil_color '、'白 ')、('ring_number '、' one ')、(' ring_type '、' pendant ')]



この理由の原因となった食用キノコでは、類似の残りの13の兆候が観察されないため、22の兆候のうち9のみがリストに表示されているという事実に注目します。



別の配列はSPECT Heartsでした。そこで、テストケースの予測精度は86.1%に達しました。これは、配列の作成者が使用した整数プログラミングを使用したトレーニング例のカバレッジに基づくと、CLIP3機械学習システムの結果(84%)よりわずかに高いことがわかりました。心臓の断層像の記述の構造は、すでにバイナリ符号で事前にコード化されているため、予測の質を大幅に向上させることはできないと思います。



著者はごく最近、連続的な(数値)機能によって記述されたデータを処理するための彼のアプローチの拡張を思いつきました(そしてソフトウェアに実装しました)。いくつかの側面では、そのアプローチは、決定木を学習するC4.5システムに似ています。このバリアントは、Wine Qualityアレイでテストされました。この配列は、ポルトガルのワインの品質を表しています。結果は有望です。高品質の赤ワインを飲んだ場合、仮説はそれらの高いスコアを完全に説明します。



2.プラットフォームの選択



現在、ロシア国立人道大学のインテリジェントシステム学部の学生の努力により、さまざまなタイプのタスク(Nginx + Gunicorn + Djangoバンドルを使用)用の一連のWebサーバーが作成されています。



ただし、ここでは自分のバージョンについて説明することにしました(aiohttp、aiojobs、およびaiomysqlバンドルを使用)。既知のセキュリティ問題のため、aiomcacheモジュールは使用されません。



提案されたオプションにはいくつかの利点があります。



  1. aiohttpを使用しているため、非同期です。
  2. Jinja2テンプレートの処理を可能にします。
  3. aiomysqlを介したデータベースへの接続プールで機能します。
  4. aiojobs.aiohttp.spawnを介して独立したコンピューティングプロセスを起動できます。


(Djangoと比較した)明らかな欠点も指摘しましょう:



  1. オブジェクトリレーショナルマッピング(ORM)なし。
  2. Nginxプロキシサーバーの使用を整理するのはより困難です。
  3. Djangoテンプレート言語(DTL)はありません。


2つのオプションはそれぞれ、Webサーバーを操作するためのさまざまな戦略を目的としています。同期戦略(Djangoの場合)は、エキスパートが一度に1つのデータベースを操作するシングルユーザーモードを対象としています。 CCF法の確率的手順は著しく並列化されていますが、それにもかかわらず、理論的には、機械学習手順にかなりの時間がかかる場合は除外されません。したがって、このノートで説明されているオプションは、複数のエキスパートを対象としています。各エキスパートは、データだけでなく、それらを表現する方法も異なる(異なるブラウザタブで)異なるデータベースで同時に作業できます(個別の属性の値の異なるラティス、異なる有意な回帰と数)連続のしきい値)。次に、1つのタブでVKF実験を開始すると、エキスパートは別のタブに切り替えることができます。他のデータやパラメータを使用して実験を準備または分析する場所。



複数のユーザー、実験、およびそれらが配置されているさまざまな段階を説明するために、2つのテーブル(ユーザー、実験)を持つサービスデータベース(vkf)があります。ユーザーテーブルにすべての登録済みユーザーのログインとパスワードが格納されている場合、実験は、各実験の補助テーブルとメインテーブルの名前に加えて、これらのテーブルの完全性のステータスを保持します。重要なデータを保護するためにNginxプロキシを使用する必要があるため、aiohttp_sessionを破棄しました。



以下は実験テーブルの構造です。



  • id int(11)NOT NULL PRIMARY KEY
  • expName varchar(255)NOT NULL
  • エンコーダーvarchar(255)
  • goodEncoder tinyint(1)
  • ラティスvarchar(255)
  • goodLattices tinyint(1)
  • 複合varchar(255)
  • goodComplex tinyint(1)
  • verges varchar(255)
  • goodVerges tinyint(1)
  • vergesTotal int(11)
  • varchar(255)をトレーニングします
  • goodTrains tinyint(1)
  • tests varchar(255)
  • goodTests tinyint(1)
  • hypotheses varchar(255) NOT NULL
  • goodHypotheses tinyint(1)
  • type varchar(255) NOT NULL


CCF実験のデータ準備にはいくつかのシーケンスがあることに注意してください。これは、残念ながら、離散ケースと連続ケースでは根本的に異なります。大文字と小文字が混在するケースでは、両方のタイプの要件が組み合わされます。



個別:=> goodLattices(半自動)

個別:goodLattices => goodEncoder(自動)

個別:goodEncoder => goodTrains(半自動)

個別:goodEncoder、goodTrains => goodHypotheses(自動)

個別:goodEncoder => goodTests(半自動)、

個別goodEncoder、goodHypotheses =>(自動)

連続:=> goodVerges(手動)

連続:goodVerges => goodTrains(手動)

継続的:goodTrains => goodComplex(自動)

継続的:goodComplex、goodTrains => goodHypotheses(自動)

継続的:goodVerges => goodTests(手動)

継続的:goodTests、goodComplex、goodHypotheses =>(自動)



機械学習ライブラリ自体はvkf.cpythonという名前ですLinuxでは-36m-x86_64-linux-gnu.so、Windowsではvkf.cp36-win32.pyd。(36は、このライブラリがビルドされたPythonのバージョンです)。



「自動」という用語はこのライブラリの操作を意味し、「半自動」は補助ライブラリvkfencoder.cpython-36m-x86_64-linux-gnu.soの操作を意味します。最後に、「手動」モードは、特定の実験のデータを特別に処理し、vkfencoderライブラリに転送されるプログラムの呼び出しです。



3.実装の詳細



Webサーバーを作成するときは、「表示/モデル/コントロール」アプローチを使用し



ます。Pythonコードは5つのファイルにあります。



  1. app.py-アプリケーション起動ファイル
  2. control.py-VKFソルバーを操作するための手順を含むファイル
  3. models.py-データを処理し、データベースを操作するためのクラスを含むファイル
  4. settings.py-アプリケーション設定を含むファイル
  5. views.py-ルート(ルート)の視覚化と処理を含むファイル


app.pyファイルの標準形式は次のとおりです。



#! /usr/bin/env python
import asyncio
import jinja2
import aiohttp_jinja2

from settings import SITE_HOST as siteHost
from settings import SITE_PORT as sitePort

from aiohttp import web
from aiojobs.aiohttp import setup

from views import routes

async def init(loop):
    app = web.Application(loop=loop)
    # install aiojobs.aiohttp
    setup(app)
    # install jinja2 templates
    aiohttp_jinja2.setup(app, 
        loader=jinja2.FileSystemLoader('./template'))
    # add routes from api/views.py
    app.router.add_routes(routes)
    return app

loop = asyncio.get_event_loop()
try:
    app = loop.run_until_complete(init(loop))
    web.run_app(app, host=siteHost, port=sitePort)
except:
    loop.stop()


ここで何か説明が必要だとは思いません。プロジェクトに含める順序の次のファイルは、views.pyです。



import aiohttp_jinja2
from aiohttp import web#, WSMsgType
from aiojobs.aiohttp import spawn#, get_scheduler
from models import User
from models import Expert
from models import Experiment
from models import Solver
from models import Predictor

routes = web.RouteTableDef()

@routes.view(r'/tests/{name}', name='test-name')
class Predict(web.View):
    @aiohttp_jinja2.template('tests.html')
    async def get(self):
        return {'explanation': 'Please, confirm prediction!'}

    async def post(self):
        data = await self.request.post()
        db_name = self.request.match_info['name']
        analogy = Predictor(db_name, data)
        await analogy.load_data()
        job = await spawn(self.request, analogy.make_prediction())
        return await job.wait()

@routes.view(r'/vkf/{name}', name='vkf-name')
class Generate(web.View):
    #@aiohttp_jinja2.template('vkf.html')
    async def get(self):
        db_name = self.request.match_info['name']
        solver = Solver(db_name)
        await solver.load_data()
        context = { 'dbname': str(solver.dbname),
                    'encoder': str(solver.encoder),
                    'lattices': str(solver.lattices),
                    'good_lattices': bool(solver.lattices),
                    'verges': str(solver.verges),
                    'good_verges': bool(solver.good_verges),
                    'complex': str(solver.complex),
                    'good_complex': bool(solver.good_complex),
                    'trains': str(solver.trains),
                    'good_trains': bool(solver.good_trains),
                    'hypotheses': str(solver.hypotheses),
                    'type': str(solver.type)
            }
        response = aiohttp_jinja2.render_template('vkf.html', 
            self.request, context)
        return response
            
    async def post(self):
        data = await self.request.post()
        step = data.get('value')
        db_name = self.request.match_info['name']
        if step is 'init':
            location = self.request.app.router['experiment-name'].url_for(
                name=db_name)
            raise web.HTTPFound(location=location)
        solver = Solver(db_name)
        await solver.load_data()
        if step is 'populate':
            job = await spawn(self.request, solver.create_tables())
            return await job.wait()                
        if step is 'compute':
            job = await spawn(self.request, solver.compute_tables())
            return await job.wait()                
        if step is 'generate':
            hypotheses_total = data.get('hypotheses_total')
            threads_total = data.get('threads_total')
            job = await spawn(self.request, solver.make_induction(
                hypotheses_total, threads_total))
            return await job.wait()                

@routes.view(r'/experiment/{name}', name='experiment-name')
class Prepare(web.View):
    @aiohttp_jinja2.template('expert.html')
    async def get(self):
        return {'explanation': 'Please, enter your data'}

    async def post(self):
        data = await self.request.post()
        db_name = self.request.match_info['name']
        experiment = Experiment(db_name, data)
        job = await spawn(self.request, experiment.create_experiment())
        return await job.wait()


このメモのために、このファイルを短くして、ユーティリティルートを提供するクラスを省略しました。



  1. Auth '/' . , SignIn, '/signin'. , '/user/{name}'.
  2. SignIn '/signin' .
  3. Select '/user/{name}' , . '/vkf/{name}' '/experiment/{name}' ( ).


残りのクラスは、機械学習ステップを担当するルートを処理します。



  1. Prepareクラスはルート '/実験/ {名前}'を処理し、サービステーブルの名前とVKFメソッドのプロシージャを実行するために必要な数値パラメーターを収集します。この情報をデータベースに保存した後、ユーザーは「/ vkf / {name}」ルートにリダイレクトされます。
  2. Generateクラスは、ルート '/ vkf / {name}'を処理し、専門家によるデータの準備状況に応じて、VKFメソッド誘導手順のさまざまな段階を開始します。
  3. Predictクラスは、ルート「/ tests / {name}」を処理し、VKF予測メソッドの手順を類推して開始します。


多数のパラメーターをvkf.htmlフォームに転送するには、aiohttp_jinja2からの構成を使用します



response = aiohttp_jinja2.render_template('vkf.html', self.request, context)
return response




また、aiojobs.aiohttpパッケージからのspawn呼び出しの使用にも注意してください。



job = await spawn(self.request, 
    solver.make_induction(hypotheses_total, threads_total))
return await job.wait()


これは、MariaDBが管理するDBに保存されているユーザーデータと実験データを処理するmodels.pyファイルで定義されたクラスからコルーチンを安全に呼び出すために必要です。



import aiomysql
from aiohttp import web

from settings import AUX_NAME as auxName
from settings import AUTH_TABLE as authTable
from settings import AUX_TABLE as auxTable
from settings import SECRET_KEY as secretKey
from settings import DB_HOST as dbHost

from control import createAuxTables
from control import createMainTables
from control import computeAuxTables
from control import induction
from control import prediction

class Experiment():
    def __init__(self, dbName, data, **kw):
        self.encoder = data.get('encoder_table')
        self.lattices = data.get('lattices_table')
        self.complex = data.get('complex_table')
        self.verges = data.get('verges_table')
        self.verges_total = data.get('verges_total')
        self.trains = data.get('training_table')
        self.tests = data.get('tests_table')
        self.hypotheses = data.get('hypotheses_table')
        self.type = data.get('type')
        self.auxname = auxName
        self.auxtable = auxTable
        self.dbhost = dbHost
        self.secret = secretKey
        self.dbname = dbName

    async def create_db(self, pool):
        async with pool.acquire() as conn:
            async with conn.cursor() as cur:
                await cur.execute("CREATE DATABASE IF NOT EXISTS " +
                    str(self.dbname)) 
                await conn.commit() 
        await createAuxTables(self)
 
    async def register_experiment(self, pool):
        async with pool.acquire() as conn:
            async with conn.cursor() as cur:
                sql = "INSERT INTO " + str(self.auxname) + "." + 
                    str(self.auxtable)
                sql += " VALUES(NULL, '" 
                sql += str(self.dbname) 
                sql += "', '" 
                sql += str(self.encoder) 
                sql += "', 0, '" #goodEncoder
                sql += str(self.lattices) 
                sql += "', 0, '" #goodLattices
                sql += str(self.complex) 
                sql += "', 0, '" #goodComplex 
                sql += str(self.verges_total) 
                sql += "', 0, " #goodVerges
                sql += str(self.verges_total) 
                sql += ", '" 
                sql += str(self.trains) 
                sql += "', 0, '" #goodTrains 
                sql += str(self.tests) 
                sql += "', 0, '" #goodTests 
                sql += str(self.hypotheses) 
                sql += "', 0, '" #goodHypotheses 
                sql += str(self.type)
                sql += "')"
                await cur.execute(sql)
                await conn.commit() 

    async def create_experiment(self, **kw):
        pool = await aiomysql.create_pool(host=self.dbhost, 
            user='root', password=self.secret)
        task1 = self.create_db(pool=pool)
        task2 = self.register_experiment(pool=pool)
        tasks = [asyncio.ensure_future(task1), 
            asyncio.ensure_future(task2)]
        await asyncio.gather(*tasks)
        pool.close()
        await pool.wait_closed()
        raise web.HTTPFound(location='/vkf/' + self.dbname)        

class Solver():
    def __init__(self, dbName, **kw):
        self.auxname = auxName
        self.auxtable = auxTable
        self.dbhost = dbHost
        self.dbname = dbName
        self.secret = secretKey

    async def load_data(self, **kw):    
        pool = await aiomysql.create_pool(host=dbHost, 
            user='root', password=secretKey, db=auxName)
        async with pool.acquire() as conn:
            async with conn.cursor() as cur:
                sql = "SELECT * FROM "
                sql += str(auxTable)
                sql += " WHERE  expName='"
                sql += str(self.dbname)
                sql += "'"
                await cur.execute(sql)
                row = cur.fetchone()
                await cur.close()
        pool.close()
        await pool.wait_closed()
        self.encoder = str(row.result()[2])
        self.good_encoder = bool(row.result()[3])
        self.lattices = str(row.result()[4])
        self.good_lattices = bool(row.result()[5])
        self.complex = str(row.result()[6])
        self.good_complex = bool(row.result()[7])
        self.verges = str(row.result()[8])
        self.good_verges = bool(row.result()[9])
        self.verges_total = int(row.result()[10])
        self.trains = str(row.result()[11])
        self.good_trains = bool(row.result()[12])
        self.hypotheses = str(row.result()[15])
        self.good_hypotheses = bool(row.result()[16])
        self.type = str(row.result()[17])

    async def create_tables(self, **kw):
        await createMainTables(self)
        pool = await aiomysql.create_pool(host=self.dbhost, user='root', 
            password=self.secret, db=self.auxname)
        async with pool.acquire() as conn:
            async with conn.cursor() as cur:
                sql = "UPDATE "
                sql += str(self.auxtable)
                sql += " SET encoderStatus=1 WHERE dbname='"
                sql += str(self.dbname)
                sql += "'"
                await cur.execute(sql) 
                await conn.commit() 
                await cur.close()
        pool.close()
        await pool.wait_closed()
        raise web.HTTPFound(location='/vkf/' + self.dbname)        

    async def compute_tables(self, **kw):
        await computeAuxTables(self)
        pool = await aiomysql.create_pool(host=self.dbhost, user='root', 
            password=self.secret, db=self.auxname)
        async with pool.acquire() as conn:
            async with conn.cursor() as cur:
                sql = "UPDATE "
                sql += str(self.auxtable)
                sql += " SET complexStatus=1 WHERE dbname='"
                sql += str(self.dbname)
                sql += "'"
                await cur.execute(sql) 
                await conn.commit() 
                await cur.close()
        pool.close()
        await pool.wait_closed()
        raise web.HTTPFound(location='/vkf/' + self.dbname)        

    async def make_induction(self, hypotheses_total, threads_total, **kw):
        await induction(self, hypotheses_total, threads_total)
        pool = await aiomysql.create_pool(host=self.dbhost, user='root', 
            password=self.secret, db=self.auxname)
        async with pool.acquire() as conn:
            async with conn.cursor() as cur:
                sql = "UPDATE "
                sql += str(self.auxtable)
                sql += " SET hypothesesStatus=1 WHERE dbname='"
                sql += str(self.dbname)
                sql += "'"
                await cur.execute(sql) 
                await conn.commit() 
                await cur.close()
        pool.close()
        await pool.wait_closed()
        raise web.HTTPFound(location='/tests/' + self.dbname)        

class Predictor():
    def __init__(self, dbName, data, **kw):
        self.auxname = auxName
        self.auxtable = auxTable
        self.dbhost = dbHost
        self.dbname = dbName
        self.secret = secretKey
        self.plus = 0
        self.minus = 0

    async def load_data(self, **kw):    
        pool = await aiomysql.create_pool(host=dbHost, user='root', 
            password=secretKey, db=auxName)
        async with pool.acquire() as conn:
            async with conn.cursor() as cur:
                sql = "SELECT * FROM "
                sql += str(auxTable)
                sql += " WHERE dbname='"
                sql += str(self.dbname)
                sql += "'"
                await cur.execute(sql) 
                row = cur.fetchone()
                await cur.close()
        pool.close()
        await pool.wait_closed()
        self.encoder = str(row.result()[2])
        self.good_encoder = bool(row.result()[3])
        self.complex = str(row.result()[6])
        self.good_complex = bool(row.result()[7])
        self.verges = str(row.result()[8])
        self.trains = str(row.result()[11])
        self.tests = str(row.result()[13])
        self.good_tests = bool(row.result()[14])
        self.hypotheses = str(row.result()[15])
        self.good_hypotheses = bool(row.result()[16])
        self.type = str(row.result()[17])

    async def make_prediction(self, **kw):
        if self.good_tests and self.good_hypotheses:
            await induction(self, 0, 1)
            await prediction(self)
            message_body = str(self.plus)
            message_body += " correct positive cases. "
            message_body += str(self.minus)
            message_body += " correct negative cases."
            raise web.HTTPException(body=message_body)
        else:
            raise web.HTTPFound(location='/vkf/' + self.dbname)




ここでも、いくつかのヘルパークラスは非表示になっています。



  1. Userクラスはサイト訪問者に対応します。エキスパートとして登録およびログインできます。
  2. Expertクラスでは、実験の1つを選択できます。


残りのクラスは、主な手順に対応しています。



  1. Experimentクラスを使用すると、キーテーブルと補助テーブルの名前、およびICF実験の実行に必要なパラメーターを指定できます。
  2. ソルバークラスは、ICFメソッドの帰納的な一般化を担当します。
  3. Predictorクラスは、CCFメソッドのアナロジーによる予測を担当します。


aiomysqlパッケージのcreate_pool()コンストラクトの使用に注意することが重要です。複数の接続でデータベースを操作できます。実行が完了するのを待つには、asyncioモジュールのEnsure_future()およびGather()ルーチンも必要です。



pool = await aiomysql.create_pool(host=self.dbhost, 
    user='root', password=self.secret)
task1 = self.create_db(pool=pool)
task2 = self.register_experiment(pool=pool)
tasks = [asyncio.ensure_future(task1), 
    asyncio.ensure_future(task2)]
await asyncio.gather(*tasks)
pool.close()
await pool.wait_closed()


テーブルから読み取る場合、row = cur.fetchone()はフューチャーを返すため、row.result()はフィールドレコードを取得できるデータベースレコードを返します(たとえば、str(row.result()[2])はテーブル名を取得します離散特徴の値のコーディング)。




pool = await aiomysql.create_pool(host=dbHost, user='root', 
    password=secretKey, db=auxName)
async with pool.acquire() as conn:
    async with conn.cursor() as cur:
        await cur.execute(sql) 
        row = cur.fetchone()
        await cur.close()
pool.close()
await pool.wait_closed()
self.encoder = str(row.result()[2])


主要なシステムパラメータは、.envファイルから、または(欠落している場合は)settings.pyファイルからインポートされます。



from os.path import isfile
from envparse import env

if isfile('.env'):
    env.read_envfile('.env')

AUX_NAME = env.str('AUX_NAME', default='vkf')
AUTH_TABLE = env.str('AUTH_TABLE', default='users')
AUX_TABLE = env.str('AUX_TABLE', default='experiments')
DB_HOST = env.str('DB_HOST', default='127.0.0.1')
DB_HOST = env.str('DB_PORT', default=3306)
DEBUG = env.bool('DEBUG', default=False)
SECRET_KEY = env.str('SECRET_KEY', default='toor')
SITE_HOST = env.str('HOST', default='127.0.0.1')
SITE_PORT = env.int('PORT', default=8080)


localhostはip-addressで指定する必要があることに注意してください。そうしないと、aiomysqlはUnixソケットを介してデータベースに接続しようとしますが、Windowsでは機能しない場合があります。最後に、最後のファイル(control.py)を再生してみましょう。



import os
import asyncio
import vkf

async def createAuxTables(db_data):
    if  db_data.type is not "discrete":
        await vkf.CAttributes(db_data.verges, db_data.dbname, 
            '127.0.0.1', 'root', db_data.secret)
    if  db_data.type is not "continuous":
        await vkf.DAttributes(db_data.encoder, db_data.dbname, 
            '127.0.0.1', 'root', db_data.secret)
        await vkf.Lattices(db_data.lattices, db_data.dbname, 
            '127.0.0.1', 'root', db_data.secret) 

async def createMainTables(db_data):
    if  db_data.type is "continuous":
        await vkf.CData(db_data.trains, db_data.verges, 
            db_data.dbname, '127.0.0.1', 'root', db_data.secret)
        await vkf.CData(db_data.tests, db_data.verges, 
            db_data.dbname, '127.0.0.1', 'root', db_data.secret)
    if  db_data.type is "discrete":
        await vkf.FCA(db_data.lattices, db_data.encoder, 
            db_data.dbname, '127.0.0.1', 'root', db_data.secret)
        await vkf.DData(db_data.trains, db_data.encoder, 
            db_data.dbname, '127.0.0.1', 'root', db_data.secret)
        await vkf.DData(db_data.tests, db_data.encoder, 
            db_data.dbname, '127.0.0.1', 'root', db_data.secret)
    if  db_data.type is "full":
        await vkf.FCA(db_data.lattices, db_data.encoder, 
            db_data.dbname, '127.0.0.1', 'root', db_data.secret)
        await vkf.FData(db_data.trains, db_data.encoder, db_data.verges, 
            db_data.dbname, '127.0.0.1', 'root', db_data.secret)
        await vkf.FData(db_data.tests, db_data.encoder, db_data.verges, 
            db_data.dbname,'127.0.0.1', 'root', db_data.secret)

async def computeAuxTables(db_data):
    if  db_data.type is not "discrete":
        async with vkf.Join(db_data.trains, db_data.dbname, '127.0.0.1', 
            'root', db_data.secret) as join:
            await join.compute_save(db_data.complex, db_data.dbname, 
                '127.0.0.1', 'root', db_data.secret)
        await vkf.Generator(db_data.complex, db_data.trains, db_data.verges, 
            db_data.dbname, db_data.dbname, db_data.verges_total, 1, 
            '127.0.0.1', 'root', db_data.secret)

async def induction(db_data, hypothesesNumber, threadsNumber):
    if  db_data.type is not "discrete":
        qualifier = await vkf.Qualifier(db_data.verges, 
            db_data.dbname, '127.0.0.1', 'root', db_data.secret)
        beget = await vkf.Beget(db_data.complex, db_data.dbname, 
            '127.0.0.1', 'root', db_data.secret)
    if  db_data.type is not "continuous":
        encoder = await vkf.Encoder(db_data.encoder, db_data.dbname, 
            '127.0.0.1', 'root', db_data.secret)
    async with vkf.Induction() as induction: 
        if  db_data.type is "continuous":
            await induction.load_continuous_hypotheses(qualifier, beget, 
                db_data.trains, db_data.hypotheses, db_data.dbname, 
                '127.0.0.1', 'root', db_data.secret)
        if  db_data.type is "discrete":
            await induction.load_discrete_hypotheses(encoder, 
                db_data.trains, db_data.hypotheses, db_data.dbname, 
                '127.0.0.1', 'root', db_data.secret)
        if  db_data.type is "full":
            await induction.load_full_hypotheses(encoder, qualifier, beget, 
                db_data.trains, db_data.hypotheses, db_data.dbname, 
                '127.0.0.1', 'root', db_data.secret)
        if hypothesesNumber > 0:
            await induction.add_hypotheses(hypothesesNumber, threadsNumber)
            if  db_data.type is "continuous":
                await induction.save_continuous_hypotheses(qualifier, 
                    db_data.hypotheses, db_data.dbname, '127.0.0.1', 'root', 
                    db_data.secret)
            if  db_data.type is "discrete":
                await induction.save_discrete_hypotheses(encoder, 
                    db_data.hypotheses, db_data.dbname, '127.0.0.1', 'root', 
                    db_data.secret)
            if  db_data.type is "full":
                await induction.save_full_hypotheses(encoder, qualifier, 
                    db_data.hypotheses, db_data.dbname, '127.0.0.1', 'root', 
                    db_data.secret)

async def prediction(db_data):
    if  db_data.type is not "discrete":
        qualifier = await vkf.Qualifier(db_data.verges, 
            db_data.dbname, '127.0.0.1', 'root', db_data.secret)
        beget = await vkf.Beget(db_data.complex, db_data.dbname, 
            '127.0.0.1', 'root', db_data.secret)
    if  db_data.type is not "continuous":
        encoder = await vkf.Encoder(db_data.encoder, 
            db_data.dbname, '127.0.0.1', 'root', db_data.secret)
    async with vkf.Induction() as induction: 
        if  db_data.type is "continuous":
            await induction.load_continuous_hypotheses(qualifier, beget, 
                db_data.trains, db_data.hypotheses, db_data.dbname, 
                '127.0.0.1', 'root', db_data.secret)
        if  db_data.type is "discrete":
            await induction.load_discrete_hypotheses(encoder, 
                db_data.trains, db_data.hypotheses, db_data.dbname, 
                '127.0.0.1', 'root', db_data.secret)
        if  db_data.type is "full":
            await induction.load_full_hypotheses(encoder, qualifier, beget, 
                db_data.trains, db_data.hypotheses, db_data.dbname, 
                '127.0.0.1', 'root', db_data.secret)
        if  db_data.type is "continuous":
            async with vkf.TestSample(qualifier, induction, beget, 
                db_data.tests, db_data.dbname, '127.0.0.1', 'root', 
                db_data.secret) as tests:
                #plus = await tests.correct_positive_cases()
                db_data.plus = await tests.correct_positive_cases()
                #minus = await tests.correct_negative_cases()
                db_data.minus = await tests.correct_negative_cases()
        if  db_data.type is "discrete":
            async with vkf.TestSample(encoder, induction, 
                db_data.tests, db_data.dbname, '127.0.0.1', 'root', 
                db_data.secret) as tests:
                #plus = await tests.correct_positive_cases()
                db_data.plus = await tests.correct_positive_cases()
                #minus = await tests.correct_negative_cases()
                db_data.minus = await tests.correct_negative_cases()
        if  db_data.type is "full":
            async with vkf.TestSample(encoder, qualifier, induction, 
                beget, db_data.tests, db_data.dbname, '127.0.0.1', 
                'root', db_data.secret) as tests:
                #plus = await tests.correct_positive_cases()
                db_data.plus = await tests.correct_positive_cases()
                #minus = await tests.correct_negative_cases()
                db_data.minus = await tests.correct_negative_cases()


ここでは、vkf.cpython-36m-x86_64-linux-gnu.soライブラリのVKFメソッドプロシージャの名前、呼び出し順序、および引数を確認できるため、このファイル全体を保存しました。CPythonライブラリのデフォルトには標準値が設定されているため、dbname以降の引数はすべて省略できます。



4.コメント



VKF実験を制御するロジックが(多数のifを介して)導出され、ポリモーフィズムによって型に隠されない理由についてのプロのプログラマーの質問を予想して、次のように答えるべきです:残念ながら、Python言語の動的型付けでは、システムに使用されるオブジェクトの型に関する決定を変えることができませんつまり、ネストされたifのこのシーケンスはとにかく発生します。したがって、著者は、ロジックを可能な限り透過的(かつ効率的)にするために、明示的な(Cのような)構文を使用することを好みました。



不足しているコンポーネントについてコメントさせてください。



  1. vkfencoder.cpython-36m-x86_64-linux-gnu.so (web- , , ). vkfencoder.cpython-36m-x86_64-linux-gnu.so.
  2. - MariaDB ( DBeaver 7.1.1 Community, ). Django, ORM .


5.



著者は30年以上にわたってデータマイニングタスクに携わっています。モスクワ州立大学の力学と数学を卒業した後 ロモノソフ、彼は技術科学博士、教授によって率いる研究者のグループに招待されました。VK。フィン(VINITI AN SSSR)。前世紀の80年代の初め以来、Viktor Konstantinovichは、多価論理によるもっともらしい推論とその形式化を模索してきました。



V.K.によって提案された主要なアイデア フィン、以下を考慮することができます:



  1. バイナリー相似演算(最初はブール代数の交差演算)を使用します。
  2. 反対の記号の例の説明(反例)に埋め込まれている場合、トレーニング例のグループの生成された類似性を破棄するという考え;
  3. 長所と短所を考慮して、新しい例の調査された(ターゲット)プロパティを予測するアイデア;
  4. トレーニング例でのターゲットプロパティの存在/不在の理由を(生成された類似点の中で)見つけることにより、一連の仮説の完全性をチェックするアイデア。


なお、V.K。フィンは彼の考えのいくつかを外国の作家に帰している。おそらく、議論の論理だけが彼によって独立して発明されたと正当に考えられています。V.K.による反例の説明の考え方 フィンランド人はK.R.から借りたと彼は言った。ポッパー。そして帰納的一般化の完全性をチェックすることの起源は彼にあります(私の意見では完全に曖昧です)アメリカの数学者と論理学者のC.S. ピアス。彼は、類似性の演算を使用した原因に関する仮説の生成を、イギリスの経済学者、哲学者、論理学者D.S.のアイデアから借りたと考えています。工場。したがって、彼はD.S.に敬意を表して彼が作成した一連のアイデアに「DSM方式」というタイトルを付けました。工場。



奇妙ですが、20世紀の70年代後半に教授の作品で登場しました。 Rudolf Wille(FRG)、格子の代数理論のより有用なセクション「Analysis of formal concepts」(AFP)は、V.K。よろしく。私の意見では、この理由は残念なことに、最初に哲学部を卒業し、次にモスクワ州立大学の力学と数学部のエンジニアリングストリームを卒業した人物として、拒否を引き起こしています。



彼の教師の仕事の後継者として、著者は彼のアプローチに敬意を表して「VKF法」と名付けました。ただし、別の復号化があります-格子理論に基づく機械学習の確率的組み合わせ形式的方法。



今V.K. Finnaはエキシビションセンターで働いています。 A.A. Dorodnicyn RAS FRC IU RASおよび人文科学のためのロシア国立大学のインテリジェントシステム学科。



VKFソルバーの数学の詳細については、著者論文またはウリヤノフスク州立大学での彼のビデオ講義を参照してください(講義の整理とメモの処理について、著者はA. B. VerevkinとN. G. Baranetsに感謝しています)。



ソースファイルの完全なパッケージは、Bitbucketに保存されます



vkfライブラリのソースファイル(C ++)は、savannah.nongnu.orgでの配置に同意する過程にあります。はいの場合、ダウンロードリンクがここに追加されます。



最後に、最後の注意点:2020年4月6日からPythonの学習を始めました。それ以前は、彼がプログラミングした唯一の言語はC ++でした。しかし、この状況はコードが不正確であるかもしれないという非難から彼を解放しません。



著者はTatyana A. Volkovaに感謝しますロボフリークサポート、建設的な提案、批評のために、プレゼンテーションを大幅に改善することができました(コードを大幅に改善することさえできました)。ただし、作成者は残りのエラーと(彼女のアドバイスに反して)行われた決定に対して単独で責任を負います。



All Articles