机器学习Web服务器“ VKF-solver”

现在,在公众眼中,机器学习与用于训练神经网络的各种选择密切相关。如果起初它是完全连接的网络,然后被卷积和递归网络取代,那么现在它已成为非常特殊的选择,例如GAN和LTSM网络。除了训练所需的样本量不断增加之外,他们还无法解释做出决定的原因。但是,还有一些机器学习的结构化方法,本文将介绍其中一种的软件实现。







这是一种国内的机器学习方法,称为基于格理论的机器学习的VKF方法。本文的结尾部分说明了出现的历史和名称的选择。



1.方法说明



最初,整个系统由作者使用C ++作为控制台应用程序创建,然后将其连接到MariaDB DBMS下的数据库(使用mariadb ++库),然后将其转换为Python库(使用pybind11包)。

从加利福尼亚大学欧文分校的知识库中选择了几个阵列作为测试机器学习算法的测试数据。



在包含对8,124个北美蘑菇的描述的Mushrooms数组上,系统显示了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','一个'),('ring_type','吊坠')]



我提请您注意以下事实:列表中仅显示22个标志中的9个,因为在引起该原因的可食用蘑菇中未观察到其余13个相似标志。



另一个阵列是SPECT Hearts。在那里,测试用例的预测准确性达到86.1%,结果略高于CLIP3机器学习系统的结果(84%),该结果基于使用数组作者使用整数编程的训练示例覆盖率而得出。我相信,由于心脏断层图像的描述结构已经预先用二进制符号进行了编码,因此不可能显着改善预后质量。



作者最近想出了(并用软件实现)他的方法的扩展,该方法用于处理由连续(数字)特征描述的数据。在某些方面,其方法类似于学习决策树的C4.5系统。此变体已在Wine Quality阵列上进行了测试。这个数组描述了葡萄牙葡萄酒的质量。结果令人鼓舞:如果您选择高品质的红酒,那么这些假设就可以充分说明其高分。



2.平台选择



当前,通过俄罗斯国家人道主义大学智能系统系学生的努力,正在创建一系列用于各种类型任务的Web服务器(使用Nginx + Gunicorn + Django软件包)。



但是,我决定在这里描述我的个人版本(使用aiohttp,aiojobs和aiomysql捆绑包)。由于已知的安全问题,未使用aiomcache模块。



提议的选项有几个优点:



  1. 由于使用aiohttp是异步的;
  2. 它允许Jinja2模板;
  3. 它通过aiomysql与数据库连接池一起使用;
  4. 它允许通过aiojobs.aiohttp.spawn启动独立的计算过程。


我们指出了明显的缺点(与Django相比):



  1. 没有对象关系映射(ORM);
  2. 难以组织Nginx代理服务器的使用;
  3. 没有Django模板语言(DTL)。


这两个选项中的每一个都针对使用Web服务器的不同策略。同步策略(在Django上)针对单用户模式,在该模式下,专家可以在任何给定时间使用单个数据库。尽管CCF方法的概率过程显着并行化,但是从理论上讲,机器学习过程将花费大量时间的情况并没有排除在外。因此,本注释中讨论的选项针对的是几位专家,每位专家都可以同时(在不同的浏览器选项卡中)使用不同的数据库,这些数据库不仅数据不同,而且呈现方式也不同(离散特征值的不同格,不同的显着回归和数量)连续的阈值)。然后,在一个标签中启动CCF实验时,专家可以切换到另一个标签,在哪里准备或分析具有不同数据和/或参数的实验。



为了说明几个用户,实验以及他们所处的不同阶段,有一个带有两个表(用户,实验)的服务数据库(vkf)。如果用户表中存储了所有注册用户的登录名和密码,则除了每个实验的辅助表和主表的名称外,实验还会保留这些表的完整状态。我们放弃了aiohttp_session,因为您仍然需要使用Nginx代理服务器来保护关键数据。



这是实验表的结构:



  • id int(11)非空主键
  • expName varchar(255)非空
  • 编码器varchar(255)
  • goodEncoder tinyint(1)
  • 格子varchar(255)
  • good格子tinyint(1)
  • 复杂varchar(255)
  • goodComplex tinyint(1)
  • 韦尔加尔(255)
  • goodVerges tinyint(1)
  • 总计int(11)
  • 训练varchar(255)NOT NULL
  • 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类将处理路由'/实验/ {name}',并收集服务表的名称和运行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()


为了安全地从models.py文件中定义的类调用协程,该类处理存储在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)




同样,一些帮助器类被隐藏:



  1. User类对应于站点访问者。它使您可以注册和登录为专家。
  2. Expert类可让您选择其中一种实验。


其余的类对应于主要过程:



  1. Experiment类允许您指定键和辅助表的名称以及进行ICF实验所需的参数。
  2. Solver类负责VKF方法中的归纳概括。
  3. Predictor类负责通过VKF方法中的类比进行预测。


重要的是要注意使用aiomysql包的create_pool()构造。它使您可以在多个连接中使用数据库。还需要asyncio模块中的sure_future()和collect()例程来等待执行完成。



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)


重要的是要注意,本地主机必须由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方法过程的参数。dbname之后的所有参数都可以省略,因为CPython库中的默认值设置为标准值。



4.评论



预见到专业程序员的问题,为什么控制VKF实验的逻辑为什么会被带出(通过多个if),而不是通过多态隐藏到类型中,答案应该如下:不幸的是,Python语言的动态类型不允许将关于对象类型的决定转移到系统上,也就是说,嵌套的ifs序列仍然会发生。因此,作者倾向于使用显式(类似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年。莫斯科国立大学力学与数学系毕业后以M.V. 罗蒙诺索夫(Lomonosov)在技术科学博士(Professional Sciences)的领导下应邀参加了一组研究人员。VK。芬恩(苏联维尼提)。自上世纪80年代初以来,Viktor Konstantinovich一直在通过多值逻辑探索合理的推理及其形式化。



V.K.提出的关键思想 Finn,可以考虑以下内容:



  1. 使用二进制相似性运算(最初是布尔代数中的交集运算);
  2. 如果将一组训练示例的生成相似性嵌入相反符号示例的描述中(反示例),则应丢弃该想法;
  3. 通过考虑利弊来预测新示例的调查(目标)属性的想法;
  4. 通过在训练示例中找到目标属性存在/不存在的原因(在生成的相似性中)来检查一组假设的完整性的想法。


应该指出的是 Finn将他的一些想法归功于外国作家。也许只有论辩的逻辑才被他合理地认为是独立发明的。反例会计的想法V.K. 他说,芬兰人从K.R. 波普尔。检查归纳概括的完整性的起源属于他(在我看来是完全模糊的)美国数学家和逻辑学家C.S. 刺穿。他认为使用相似运算的原因的假说的产生可以借鉴英国经济学家,哲学家和逻辑学家D.S. 磨。因此,他以为纪念D.S. 磨。



奇怪,但出现在20世纪70年代后期的教授作品中。 Rudolf Wille(德国)并未使用V.K.芬恩的问候。在我看来,其原因是一个不幸的名字,就像一个人首先从哲学系毕业,然后从莫斯科国立大学的力学和数学系的工程学专业毕业一样,这引起了人们的反对。



作为他老师工作的追随者,作者称赞他的方法“ VKF方法”。但是,还有另一种解码方式-基于晶格理论的概率组合形式机器学习方法。



现在V.K. Finn在CC中工作。 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表示感谢robofreak支持,建设性的建议和批评,这些都可以极大地改善演示文稿(甚至可以极大地改进代码)。但是,其余错误和做出的决定(甚至与她的建议相反)的责任完全由作者承担。



All Articles