如何将多目标二元分类器优化多类从 matlab 转换/实现到 python使用 pymoo?

问题描述

我目前正在与两个学生同事一起使用优化包 pymoo。我们已经在文档中进行了搜索,但我们仍在努力解决一些问题。 主要的挑战是定义和实施我们的问题。该问题包括优化基于蛋白质的分类器。

我们的目标是最小化蛋白质数量并最大化分类器(目标函数)的准确性。我们已经在 matlab 中实现了优化,但我们想在 Python 上复制它。

在 matlab 中,我们有:

X 是一个 mxn 特征矩阵(m=samples,n=features) Y 是一个多类向量(classes: 1,2,3,4)

[m,n]=size(X);
folds=5;
Indices=k_fold(folds,m);

首先,我们为问题定义了选项参数:多目标方法、50 和 5 代的人口规模。这个问题是不受约束的。

options = optimoptions('gamultiobj','PopulationType','bitstring','PopulationSize',50,'PlotFcn',@gaplotpareto,'UseParallel',true,'display','iter','MaxGenerations',5); 

fcn 是接收归一化特征矩阵 Xn 和 Y 的目标函数(索引与 Kfold-cross 验证相关)

fcn=@(Sol)ObjFunc(Sol,Xn,Y,Indices);

通过这种方式,我们可以获得优化的输出包括: BestSol 是找到最佳解的向量。 Fval 是一个 2 列向量,根据用于分类的特征数量匹配最佳解。

[BestSol,Fval] = gamultiobj(fcn,n,[],options);

目标是得到一个二元向量(0 和 1)来表示最佳特征(对于优化的分类器)

整个代码的第一部分是:

[m,m);
options = optimoptions('gamultiobj',5); 
fcn=@(Sol)ObjFunc(Sol,Indices);
[BestSol,options);

在python中

  1. 我们并不完全理解如何正确定义我们的问题类。 我们已经尝试遵循一些示例,但我们并没有很清楚如何根据我们的情况定义目标函数

这是来自 pymoo 文档的示例 https://pymoo.org/problems/index.html#

class SphereWithConstraint(Problem):

    def __init__(self):
        super().__init__(n_var=10,n_obj=1,n_constr=1,xl=0,xu=1)

    def _evaluate(self,x,out,*args,**kwargs):
        out["F"] = np.sum((x - 0.5) ** 2,axis=1)
        out["G"] = 0.1 - out["F"]

在我们的例子中是这样的:

import numpy as np
from pymoo.model.problem import Problem


class ProteinClassifier(Problem):

    def __init__(self):
        super().__init__(n_var= *columns of X*,n_obj=2,n_constr=0)

    def _evaluate(self,**kwargs):
        out["F"] = ??????????
        out["G"] = ??????????

在这个例子中,他们创建了一个二元单目标优化https://pymoo.org/customization/binary_problem.html

import numpy as np
from pymoo.algorithms.so_genetic_algorithm import GA
from pymoo.factory import get_crossover,get_mutation,get_sampling
from pymoo.optimize import minimize
from pymoo.problems.single.knapsack import create_random_knapsack_problem

problem = create_random_knapsack_problem(30)

algorithm = GA(
    pop_size=200,sampling=get_sampling("bin_random"),crossover=get_crossover("bin_hux"),mutation=get_mutation("bin_bitflip"),eliminate_duplicates=True)

res = minimize(problem,algorithm,('n_gen',100),verbose=False)

print("Best solution found: %s" % res.X.astype(int))
print("Function value: %s" % res.F)
print("Constraint violation: %s" % res.CV)

我们想要做一些与此类似的东西,但为了多目标:

Best solution found: [1 0 0 0 1 0 1 1 0 0 1 0 0 0 0 0 0 1 0 1 0 0 1 0 1 0 0 1 0 0]

Function value: [-686]
Constraint violation: [0.]

查看我们发现的 github 源代码 this,并不清楚他们在哪里定义了代码应该在 _evaluate 中作为参数接收的 x(应该是问题类中的装饰器):

def _evaluate(self,**kwargs):
    out["F"] = -anp.sum(self.P * x,axis=1)
    out["G"] = (anp.sum(self.W * x,axis=1) - self.C)

问题源代码this

def evaluate(self,X,return_values_of="auto",return_as_dictionary=False,**kwargs):

    """
    Evaluate the given problem.
    The function values set as defined in the function.
    The constraint values are meant to be positive if infeasible. A higher positive values means "more" infeasible".
    If they are 0 or negative,they will be considered as feasible what ever their value is.

然后定义了一个装饰器:

@abstractmethod
def _evaluate(self,**kwargs):
    pass

方法 def _evaluate(self,**kwargs): 接收参数 x,但我们还没有找到定义和调用的位置。为此,我们无法执行我们的目标函数,甚至无法将特征矩阵作为输入。

-我们如何以及在哪里定义目标函数

-如何在示例中调用和处理 x?

  1. 如何为 GA 对象选择最佳参数?

过去两周我们一直在坚持这一点。我们非常感谢您的帮助

解决方法

我在他们的官方 page 中找到了一些实现。只需向下滚动到最后即可了解有关参数的更多信息并返回页面。

import numpy as np
import autograd.numpy as anp

from pymoo.model.problem import Problem

class MyProblem(Problem):

    def __init__(self,const_1=5,const_2=0.1):

        # define lower and upper bounds -  1d array with length equal to number of variable
        xl = -5 * anp.ones(10)
        xu = 5 * anp.ones(10)

        super().__init__(n_var=10,n_obj=1,n_constr=2,xl=xl,xu=xu,evaluation_of="auto")

        # store custom variables needed for evaluation
        self.const_1 = const_1
        self.const_2 = const_2

    def _evaluate(self,x,out,*args,**kwargs):
        f = anp.sum(anp.power(x,2) - self.const_1 * anp.cos(2 * anp.pi * x),axis=1)
        g1 = (x[:,0] + x[:,1]) - self.const_2
        g2 = self.const_2 - (x[:,2] + x[:,3])

        out["F"] = f
        out["G"] = anp.column_stack([g1,g2])

基本上,您启动 MyProblem 类的实例,然后调用评估方法。

problem = MyProblem()
dict = problem.evaluate(self,return_as_dictionary=True)

Returns dict if `return_as_dictionary` is set True or you specify a values of list of strings to be exited

a,b,c,d,e = problem.evaluate(x,return_values_of=[a,e])

Allowed values are [“F”,“CV”,“G”,“dF”,“dG”,“dCV”,“feasible”] for the this argument.

我不太确定您所说的 GA 对象是什么意思,但我猜它是 g1 和 g2 对象,它们是通过传递 x 参数然后在其上实现上述公式来定义的。