Server web pembelajaran mesin "VKF-solver"

Sekarang, di mata masyarakat umum, pembelajaran mesin sangat terkait dengan berbagai pilihan untuk pelatihan jaringan saraf. Jika awalnya ini adalah jaringan yang sepenuhnya terhubung, maka mereka digantikan oleh yang konvolusional dan berulang, sekarang mereka telah menjadi pilihan yang sepenuhnya eksotis seperti GAN dan jaringan LTSM. Selain meningkatnya volume sampel yang diperlukan untuk pelatihan mereka, mereka masih menderita dari ketidakmungkinan menjelaskan mengapa keputusan ini atau itu dibuat. Tetapi ada juga pendekatan struktural untuk pembelajaran mesin, implementasi perangkat lunak salah satunya dijelaskan dalam artikel ini.







Ini adalah pendekatan domestik untuk pembelajaran mesin, yang disebut VKF-metode pembelajaran mesin berdasarkan teori kisi. Sejarah asal dan pilihan nama dijelaskan di bagian paling akhir dari artikel ini.



1. Deskripsi metode



Awalnya, seluruh sistem dibuat oleh penulis di C ++ sebagai aplikasi konsol, kemudian dihubungkan ke database di bawah kendali DBMS MariaDB (menggunakan pustaka mariadb ++), kemudian berubah menjadi pustaka Python (menggunakan paket pybind11).

Beberapa array dipilih sebagai data uji untuk pengujian algoritma pembelajaran mesin dari repositori University of California di Irvine.



Pada array Jamur yang berisi deskripsi dari 8.124 jamur Amerika Utara, sistem menunjukkan hasil 100%. Lebih tepatnya, menggunakan generator angka acak, data awal dibagi menjadi sampel pelatihan (2088 dapat dimakan dan 1944 jamur beracun) dan sampel uji (2120 dapat dimakan dan 1972 beracun). Setelah menghitung sekitar 100 hipotesis tentang alasan untuk dimakan, semua kasus uji diprediksi dengan benar. Karena algoritma menggunakan rantai Markov berpasangan, sejumlah hipotesis yang cukup dapat bervariasi. Cukup sering ternyata cukup untuk menghasilkan 50 hipotesis acak. Saya mencatat bahwa ketika menghasilkan penyebab toksisitas, jumlah hipotesis yang diperlukan dikelompokkan sekitar 120, namun, semua kasus uji dalam kasus ini diprediksi dengan benar. Kaggle.com memiliki kompetisi Klasifikasi Jamurdi mana beberapa penulis telah mencapai akurasi 100%. Tetapi sebagian besar solusi adalah jaringan saraf. Pendekatan kami memungkinkan pemetik jamur untuk mempelajari hanya sekitar 50 aturan. Karena sebagian besar tanda tidak relevan, masing-masing hipotesis juga akan menjadi gabungan dari sejumlah kecil nilai tanda penting, yang membuatnya mudah diingat. Setelah itu, pemetik jamur bisa menggunakan jamur tanpa takut mengambil jamur payung atau melewatkan jamur yang bisa dimakan.



Berikut adalah contoh dari salah satu hipotesis, yang dapat diasumsikan bahwa jamur dapat dimakan:

[('gill_attachment', 'free'), ('gill_spacing', 'close'), ('gill_size', 'broad'), ('stalk_shape ',' memperbesar '), (' stalk_surface_below_ring ',' scaly '), (' veil_type ',' partial '), (' veil_color ',' white '), ('ring_number ',' one '), (' ring_type ',' pendant ')]



Saya menarik perhatian Anda pada fakta bahwa hanya 9 dari 22 tanda yang ditampilkan dalam daftar, karena 13 tanda kesamaan lainnya tidak diamati pada jamur yang dapat dimakan yang memunculkan alasan ini.



Array lain adalah SPECT Hearts. Di sana, akurasi prediksi kasus uji mencapai 86,1%, yang ternyata sedikit lebih tinggi dari hasil (84%) dari sistem pembelajaran mesin CLIP3, berdasarkan pada contoh pelatihan dengan menggunakan pemrograman integer, yang digunakan oleh penulis array. Saya percaya bahwa karena struktur uraian tomogram hati, yang sudah dipra-kode di sana dengan tanda-tanda biner, tidak mungkin meningkatkan kualitas perkiraan secara signifikan.



Penulis baru-baru ini datang dengan (dan diimplementasikan dalam perangkat lunak) perpanjangan dari pendekatannya untuk memproses data yang dijelaskan oleh fitur (numerik) terus menerus. Dalam beberapa hal, pendekatannya mirip dengan sistem pohon keputusan pelatihan C4.5. Varian ini diuji pada larik Kualitas Anggur. Array ini menjelaskan kualitas anggur Portugis. Hasilnya menggembirakan: jika Anda mengambil anggur merah berkualitas tinggi, maka hipotesis sepenuhnya menjelaskan skor tinggi mereka.



2. Pilihan platform



Saat ini, serangkaian server web untuk berbagai jenis tugas (menggunakan bundel Nginx + Gunicorn + Django) sedang dibuat oleh siswa dari Departemen Sistem Cerdas di Universitas Kemanusiaan Negara Rusia.



Namun, saya memutuskan untuk menggambarkan versi pribadi saya di sini (menggunakan sekelompok aiohttp, aiojobs, dan aiomysql). Modul aiomcache tidak digunakan karena masalah keamanan yang diketahui.



Ada beberapa keuntungan dari opsi yang diusulkan:



  1. itu asinkron karena penggunaan aiohttp;
  2. itu memungkinkan Jinja2 templating;
  3. ini bekerja dengan kumpulan koneksi ke database melalui aiomysql;
  4. memungkinkan proses komputasi independen diluncurkan melalui aiojobs.aiohttp.spawn.


Mari kita tunjukkan juga kerugian yang jelas (dibandingkan dengan Django):



  1. tidak ada Object Relational Mapping (ORM);
  2. lebih sulit untuk mengatur penggunaan server proxy Nginx;
  3. tidak ada Bahasa Template Django (DTL).


Masing-masing dari dua opsi ditujukan untuk strategi yang berbeda untuk bekerja dengan server web. Strategi sinkron (dalam Django) ditujukan untuk mode pengguna tunggal, di mana seorang ahli bekerja dengan satu basis data pada suatu waktu. Meskipun prosedur probabilistik metode VKF sangat paralel, namun, ada kemungkinan teoritis bahwa prosedur pembelajaran mesin akan memakan waktu yang cukup lama. Oleh karena itu, opsi yang dibahas dalam catatan ini ditujukan untuk beberapa ahli, yang masing-masing dapat bekerja secara bersamaan (di tab browser yang berbeda) dengan basis data berbeda yang berbeda tidak hanya dalam data, tetapi juga dalam cara mereka disajikan (kisi berbeda pada nilai fitur diskrit, regresi signifikan yang berbeda dan jumlah ambang batas untuk kontinu). Kemudian, ketika memulai percobaan CCF di satu tab, pakar dapat beralih ke yang lain,di mana akan menyiapkan atau menganalisis percobaan dengan data dan / atau parameter yang berbeda.



Untuk menjelaskan beberapa pengguna, percobaan, dan tahapan berbeda di mana mereka berada, ada basis data layanan (vkf) dengan dua tabel (pengguna, eksperimen). Jika tabel pengguna menyimpan login dan kata sandi semua pengguna terdaftar, maka percobaan, selain nama tabel tambahan dan utama dari setiap percobaan, mempertahankan status penyelesaian tabel ini. Kami membuang aiohttp_session karena kami masih perlu menggunakan proxy Nginx untuk melindungi data penting.



Berikut adalah struktur tabel percobaan:



  • id int (11) BUKAN KUNCI PRIMER NULL
  • expName varchar (255) BUKAN NULL
  • encoder varchar (255)
  • goodEncoder tinyint (1)
  • lattices varchar (255)
  • goodLattices tinyint (1)
  • varchar kompleks (255)
  • goodComplex tinyint (1)
  • verges varchar (255)
  • goodVerges tinyint (1)
  • vergesTotal int (11)
  • kereta varchar (255) TIDAK NULL
  • goodTrains tinyint (1)
  • tests varchar(255)
  • goodTests tinyint(1)
  • hypotheses varchar(255) NOT NULL
  • goodHypotheses tinyint(1)
  • type varchar(255) NOT NULL


Perlu dicatat bahwa ada beberapa urutan persiapan data untuk percobaan VKF, yang, sayangnya, sangat berbeda untuk kasus-kasus yang terpisah dan berkelanjutan. Kasus atribut campuran menggabungkan persyaratan dari kedua jenis.



diskrit: => goodLattices (semi-otomatis)

diskrit: goodLattices => goodEncoder (otomatis)

diskrit: goodEncoder => goodTrains (semi-otomatis)

diskrit: goodEncoder, goodTrains => goodHypotheses (otomatis)

diskrit: goodEncoder => goodTests (semi-otomatis),

diskrit goodEncoder, goodHypotheses => (otomatis)

terus-menerus: => goodVerges (manual)

terus-menerus: goodVerges => goodTrains (manual)

terus menerus: goodTrains => goodComplex (otomatis)

terus-menerus: goodComplex, goodTrains => goodHypotheses (otomatis)

berkelanjutan: goodVerges => goodTests (manual)

kontinu: goodTests, goodComplex, goodHypotheses => (otomatis)



Perpustakaan pembelajaran mesin itu sendiri bernama vkf.cpython -36m-x86_64-linux-gnu.so di Linux atau vkf.cp36-win32.pyd di Windows. (36 adalah versi Python tempat perpustakaan ini dibangun).



Istilah "otomatis" berarti karya perpustakaan ini, "semi-otomatis" berarti karya perpustakaan tambahan vkfencoder.cpython-36m-x86_64-linux-gnu.so. Akhirnya, mode "manual" adalah panggilan program yang khusus memproses data percobaan tertentu dan sekarang ditransfer ke perpustakaan vkfencoder.



3. Detail implementasi



Saat membuat server web, kami menggunakan pendekatan "Lihat / Model / Kontrol"



. Kode python terletak di 5 file:



  1. app.py - file peluncuran aplikasi
  2. control.py - file dengan prosedur untuk bekerja dengan pemecah VKF
  3. models.py - file dengan kelas untuk memproses data dan bekerja dengan database
  4. settings.py - file pengaturan aplikasi
  5. views.py - file dengan visualisasi dan penanganan rute (rute).


File app.py memiliki bentuk standar:



#! /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()


Saya tidak berpikir ada sesuatu untuk dijelaskan di sini. File selanjutnya dalam urutan inklusi dalam proyek adalah 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()


Saya telah mempersingkat file ini demi catatan ini, meninggalkan kelas-kelas yang melayani rute utilitas:



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


Kelas yang tersisa menangani rute yang bertanggung jawab untuk langkah pembelajaran mesin:



  1. kelas Siapkan memproses rute '/ percobaan / {nama}' dan mengumpulkan nama-nama tabel layanan dan parameter numerik yang diperlukan untuk menjalankan prosedur metode VKF. Setelah menyimpan informasi ini dalam database, pengguna diarahkan ke rute '/ vkf / {name}'.
  2. kelas Hasilkan memproses rute '/ vkf / {name}' dan memulai berbagai tahapan prosedur induksi metode VKF, tergantung pada kesiapan data oleh ahli.
  3. kelas Prediksi memproses rute '/ tests / {name}' dan memulai prosedur metode prediksi VKF dengan analogi.


Untuk mentransfer sejumlah besar parameter ke formulir vkf.html, konstruksi dari aiohttp_jinja2 digunakan



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




Perhatikan juga penggunaan panggilan spawn dari paket aiojobs.aiohttp:



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


Ini diperlukan untuk memanggil coroutine dengan aman dari kelas yang ditentukan dalam file models.py yang memproses data pengguna dan eksperimen yang disimpan dalam DB yang dikelola oleh MariaDB:



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)




Sekali lagi, beberapa kelas pembantu tersembunyi:



  1. Kelas Pengguna sesuai dengan pengunjung situs. Ini memungkinkan Anda untuk mendaftar dan masuk sebagai ahli.
  2. Kelas Pakar memungkinkan Anda untuk memilih salah satu percobaan.


Kelas yang tersisa sesuai dengan prosedur utama:



  1. Kelas Eksperimen memungkinkan Anda untuk menentukan nama-nama tabel utama dan tambahan dan parameter yang diperlukan untuk melakukan percobaan ICF.
  2. Kelas Solver bertanggung jawab atas generalisasi induktif dalam metode VKF.
  3. Kelas Predictor bertanggung jawab untuk prediksi dengan analogi dalam metode VKF.


Penting untuk mencatat penggunaan create_pool () dari paket aiomysql. Ini memungkinkan Anda untuk bekerja dengan database dalam banyak koneksi. Rutin sure_future () dan kumpulkan () dari modul asyncio juga diperlukan untuk menunggu eksekusi selesai.



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()


Saat membaca dari sebuah tabel, baris = cur.fetchone () mengembalikan masa depan, jadi row.result () mengembalikan catatan database dari mana nilai-nilai bidang dapat diambil (misalnya, str (row.result () [2]) mengambil nama tabel dengan pengkodean nilai fitur diskrit).




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])


Parameter sistem utama diimpor dari file .env atau (jika tidak ada) dari file 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)


Penting untuk dicatat bahwa localhost harus ditentukan oleh ip-address, jika tidak aiomysql akan mencoba untuk terhubung ke database melalui soket Unix, yang mungkin tidak berfungsi di Windows. Terakhir, mainkan file terakhir (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()


Saya menyimpan file ini secara keseluruhan, karena di sini Anda dapat melihat nama-nama, urutan panggilan dan argumen prosedur metode VKF dari perpustakaan vkf.cpython-36m-x86_64-linux-gnu.so. Semua argumen setelah dbname dapat dihilangkan, karena default di pustaka CPython diatur dengan nilai standar.



4. Komentar



Mengantisipasi pertanyaan programmer profesional tentang mengapa logika mengendalikan percobaan VKF dibawa keluar (melalui banyak jika), dan tidak disembunyikan melalui polimorfisme menjadi tipe, jawabannya harus sebagai berikut: sayangnya, pengetikan dinamis dari bahasa Python tidak memungkinkan pengalihan keputusan tentang jenis objek yang digunakan untuk sistem. , dalam hal apa pun, urutan bersarang ini jika terjadi. Oleh karena itu, penulis lebih suka menggunakan sintaksis eksplisit (seperti C) untuk membuat logika setransparan (dan seefisien) mungkin.



Biarkan saya mengomentari komponen yang hilang:



  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.



Penulis telah terlibat dalam tugas penambangan data selama lebih dari 30 tahun. Setelah lulus dari Fakultas Mekanika dan Matematika Universitas Negeri Moskow Lomonosov, ia diundang ke sekelompok peneliti di bawah kepemimpinan Doctor of Technical Sciences, prof. VK. Finn (VINITI AN USSR). Sejak awal tahun 80-an abad terakhir, Viktor Konstantinovich telah mengeksplorasi penalaran yang masuk akal dan formalisasi mereka dengan menggunakan logika multivalued.



Ide-ide kunci yang diusulkan oleh V.K. Finn, berikut ini dapat dipertimbangkan:



  1. menggunakan operasi kesamaan biner (awalnya, operasi persimpangan dalam aljabar Boolean);
  2. gagasan untuk membuang kemiripan yang dihasilkan dari sekelompok contoh pelatihan jika itu tertanam dalam deskripsi contoh tanda yang berlawanan (contoh tandingan);
  3. gagasan untuk memprediksi properti (target) yang diselidiki dari contoh-contoh baru dengan memperhitungkan pro dan kontra;
  4. gagasan memeriksa kelengkapan seperangkat hipotesis dengan menemukan alasan (di antara kesamaan yang dihasilkan) untuk ada / tidaknya properti target dalam contoh pelatihan.


Perlu dicatat bahwa V.K. Finn menghubungkan beberapa idenya dengan penulis asing. Mungkin, hanya logika argumentasi dengan hak penuh yang dianggap diciptakan olehnya secara independen. Ide akuntansi untuk sampel tandingan V. K. Finn meminjam, katanya, dari K.R. Popper. Dan asal-usul memeriksa kelengkapan generalisasi induktif adalah miliknya (sepenuhnya tidak jelas, menurut saya) karya-karya ahli matematika dan ahli logika Amerika C.S. Menembus. Dia menganggap generasi hipotesis tentang penyebab menggunakan operasi kesamaan untuk dipinjam dari ide-ide ekonom, filsuf dan ahli logika Inggris D.S. Pabrik. Oleh karena itu, ia menciptakan serangkaian ide yang berjudul "metode DSM" untuk menghormati D.S. Pabrik.



Aneh, tetapi muncul pada akhir 70-an abad XX dalam tulisan-tulisan prof. Rudolf Wille (FRG), bagian yang jauh lebih berguna dari teori aljabar kisi "Analisis konsep formal" (AFP) tidak digunakan oleh V.K. Salam Finn. Menurut pendapat saya, alasan untuk ini adalah nama yang tidak menguntungkan, yang, seperti orang yang pertama kali lulus dari Fakultas Filsafat, dan kemudian aliran teknik dari Fakultas Mekanika dan Matematika dari Universitas Negeri Moskow, menyebabkan penolakan.



Sebagai penerus karya gurunya, penulis menamai pendekatannya "VKF-metode" untuk menghormatinya. Namun, ada decoding lain - metode pembelajaran mesin formal kombinatorial probabilistik berdasarkan teori kisi.



Sekarang V.K. Finna bekerja di Pusat Pameran. A A. Dorodnicyn RAS FRC IU RAS dan di Departemen Sistem Cerdas Universitas Negeri Rusia untuk Kemanusiaan.



Informasi lebih lanjut tentang matematika pemecah-VKF dapat ditemukan dalam disertasi penulis atau ceramah videonya di Universitas Negeri Ulyanovsk (penulis berterima kasih kepada A.B. Verevkin dan N.G. Baranet karena telah mengatur kuliah dan memproses catatan mereka).



Paket lengkap file sumber disimpan di Bitbucket .



File sumber (dalam C ++) untuk perpustakaan vkf sedang dalam proses menyetujui penempatan mereka di savannah.nongnu.org. Jika ya, tautan unduhan akan ditambahkan di sini.



Akhirnya, satu catatan terakhir: Saya mulai belajar Python pada 6 April 2020. Sampai saat itu, satu-satunya bahasa yang diprogramnya adalah C ++. Tetapi keadaan ini tidak membebaskannya dari tuduhan bahwa kode itu mungkin tidak akurat.



Penulis berterima kasih kepada Tatyana A. Volkovarobofreakuntuk dukungan, saran dan kritik yang membangun, yang memungkinkan untuk meningkatkan presentasi secara signifikan (dan bahkan secara signifikan meningkatkan kode). Namun, tanggung jawab untuk kesalahan dan keputusan yang tersisa dibuat (bahkan bertentangan dengan sarannya) adalah semata-mata penulis.



All Articles