Skip to main content

用于多目标预测的深度学习框架

项目描述

标识

用于多目标预测的深度学习框架

派皮版本 PyPi 版本 Alt PyPi Python 版本 GitHub 许可证

GitHub 问题 GitHub 星星


这是 DeepMTP 的官方存储库,一个可用于多目标预测 (MTP) 问题的深度学习框架。MTP 可以看作是一个涵盖机器学习许多子领域的总称,包括多标签分类 (MLC)、多变量回归 (MTR)、多任务学习 (MTL)、二元预测 (DP) 和矩阵补全。 MC)。实现主要是用 Python 编写的,使用 Pytorch 来实现神经网络。目标是让任何用户都能够只使用几行代码来训练模型。

最新更新

  • [12/6/2022] DeepMTP 现已在PyPI中可用
  • [1/6/2022] DeepMTP 的第一个实现现已上线!!!

安装 DeepMTP

框架使用gpu加速,所以强烈推荐使用GPU。本地安装可以使用pip

从 Pypi 安装

# create and activate a conda environment
conda create -n DeepMTP_env python=3.8
conda activate DeepMTP_env

# if a gpu is available
pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu113

# if a gpu is NOT available
pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cpu

# install DeepMTP
pip install DeepMTP

从源安装

# download from the github repository
git clone https://github.com/diliadis/DeepMTP.git
cd DeepMTP
conda env create -f environment.yml
conda activate DeepMTP_env

# open one of the notebooks in the DEMO folder

背景

什么是MTP??

多目标预测 (MTP) 是机器学习任务的总称,涉及同时预测多个目标变量。这些包括:

  • 多标签分类
  • 多元回归
  • 多任务学习
  • 分层多标签分类
  • 二元预测
  • 零样本学习
  • 矩阵完成
  • (混合)矩阵完成
  • 冷启动协同过滤

尽管有显着的相似之处,但在过去的二十年里,所有这些领域都分别发展成不同的研究领域。为了更好地理解这些异同,熟悉该领域中使用的术语和主要概念非常重要。

标识

标识

多目标预测问题的特征是实例 $x \in X$ 和目标 $t \in T$ 具有以下属性:

  1. 一个训练数据集 $\mathcal{D}$ 包含三元组 $(x_{i},t_{j},y_{ij})$,其中 $x_i \in \mathcal{X}$ 表示一个实例,$t_j \in \mathcal{T}$ 表示一个目标,$y_{ij} \in \mathcal{Y}$ 是量化实例与目标之间关系的分数,其中 $i\in{1,\ldots,n }$ 和 $j\in{1,\ldots,m}$。分数可以排列在一个通常不完整的 $n\times m$ 矩阵 $\mathbf{Y}$ 中。

  2. 分数集 $\mathcal{Y}$ 由名义、有序或实数值组成。

  3. 在测试期间,目标是预测任何未观察到的实例-目标对 $(\mathbf{x},\mathbf{t}) \in \mathcal{X} \times \mathcal{T}$ 的分数。

使用上面的正式定义,我们可以简化我们需要在多目标预测问题中识别的基本组件:

  1. 实例、目标和分数量化了它们之间的关系。
  2. 分数值的类型。
  3. 可能可用于实例的任何辅助信息(功能)。
  4. 可能可用于目标的任何辅助信息(功能)。
  5. 测试集包含新的实例,在训练集中从未见过。
  6. 测试集包含新的目标,在训练集中从未见过。

DeepMTP 是如何工作的?

DeepMTP 框架基于灵活的两分支神经网络架构,可以适应不同 MTP 问题设置的特定需求。这两个分支旨在将实例和目标的任何可用辅助信息(特征)作为输入,然后分别输出两个嵌入向量 $p_{x}$ 和 $q_{t}$。然后嵌入可以连接并通过一系列具有单个输出节点的全连接层(预测实例-目标对的分数)。或者,一种更直接且成本更低的方法用简单的点积替换一系列全连接层。就两个嵌入向量 $p_{x}$ 和 $q_{t}$ 允许的大小而言,MLP 版本允许不同的大小,而点积版本需要相同的大小。

标识

标识

为了更好地解释神经网络如何适应不同的情况,我们将展示同一一般任务的不同版本,即预测化合物和蛋白质靶标之间的相互作用。

处理实例和/或目标的缺失功能

点击展开!
  1. 在第一个示例中,用户提供蛋白质的特征,但不提供化学化合物的特征。在这种情况下,第一个分支使用蛋白质的辅助信息,第二个分支使用化合物的单热编码特征。交互矩阵填充了实际值,因此这被认为是回归任务。

标识

标识

  1. 在第二个示例中,只有蛋白质的辅助信息可用。这可以看作与上一个示例相反,因此按照相同的过程,第一个分支使用单热编码特征,第二个分支使用实际复合特征。

标识

标识

  1. 在第三个示例中,为蛋白质和化合物提供了辅助信息,因此两个分支都可以使用它。

标识

标识

  1. 在本小节的第四个也是最后一个示例中,我们缺少实例和目标的特征。这在我们的化合物-蛋白质相互作用预测任务中不是一个现实的设置,但在推荐系统领域有很多应用。在神经网络方面,一个热编码向量用于两个分支。

标识

标识

处理不同类型的输入特征

点击展开!

在机器学习的当前状态下,研究人员试图从不同类型的数据中提取有用的信息。在神经网络领域,当表格数据可用时,通常会选择一系列全连接层。对于其他类型的输入则不能这样说。例如,在图像处理领域,卷积神经网络能够利用图像。DeepMTP 框架的两个分支内部的网络可以使用不同类型的子架构来更好地处理不同类型的输入。在下面的示例中,我们假设蛋白质特征采用标准向量的形式,并且化合物由它们的 2d 图像表示。DeepMTP 通过在第一个分支中使用全连接神经网络和在第二个分支中使用卷积神经网络来适应。

标识

标识

处理不同的验证设置

点击展开!

前面所有的例子和图只显示了训练集。为了展示测试时发生的情况,我们将介绍 MTP 问题设置中可能出现的 4 种不同情况(称为验证设置)。

  1. 设置 A:完成交互矩阵中的缺失值

在设置 A 中,测试集包含我们在训练集中观察到的实例和目标的子集。此设置通常在交互矩阵包含缺失值时选择,并且在实例和目标特征不可用时成为唯一的验证选择。

标识

标识

  1. 设置 B:预测新实例

In setting B the test set contains instances never before observed in the training set. This setting is the default option for popular MTP problem settings like multi-label classification and multivariate regression. In order to generalize to new instances, their side information has to be provided!

标识

标识

  1. Setting C: predict for novel targets

In setting C the test set contains targets never before observed in the training set. This setting can be seen as the reverse of Setting B, as we can easily switch the instances and targets and arrive in Setting C. In order to generalize to new targets, their side information has to be provided!

标识

标识

  1. Setting D: predict for pairs of novel instances and targets

最后,在设置 D 中,测试集包含在训练集中从未观察到的新实例和目标对。与其他任务相比,这通常被认为是最困难的泛化任务。为了推广到成对的新实例和目标,必须提供两者的辅助信息!

标识

标识

你只需要几行代码

from DeepMTP.dataset import load_process_MLC
from DeepMTP.main import DeepMTP
from DeepMTP.utils.utils import generate_config

# load dataset
data = load_process_MLC(dataset_name='yeast', variant='undivided', features_type='numpy')
# process and split
train, val, test, data_info = data_process(data, validation_setting='B', verbose=True)

# generate a configuration for the experiment
config = generate_config(...)

# initialize model
model = DeepMTP(config)
# train, validate, test
validation_results = model.train(train, val, test)

# generate predictions from the trained model
results, preds = model.predict(train, return_predictions=True ,verbose=True)

输入数据

加载 DeepMTP 原生提供的数据集之一 在上面的示例中,多标签分类数据集是由框架提供的内置函数之一加载的。更具体地说,可用的功能如下:
功能 描述
load_process_MLC() 用户可以加载MULAN存储库中可用的多标签分类数据集。可以通过在dataset_name参数中指定有效名称来访问不同的数据集。
load_process_MTR() 用户可以加载MULAN存储库中可用的多元回归数据集。可以通过在dataset_name参数中指定有效名称来访问不同的数据集。
load_process_MTL() the user can load the multi-task learning dataset dog, a crowdsourcing dataset first introduced in Liu et a. More specifically, the dataset contains 800 images of dogs who have been partially labelled by 52 annotators with one of 5 possible breeds. To modify this multi-class problem to a binary problem, we modify the task so that the prediction involves the correct or incorrect labelling by the annotator. In a future version of the software another dataset of the same type will be added.
load_process_MC() the user can load the matrix completion dataset MovieLens 100K, a movie rating prediction dataset available by the the GroupLens lab that contains 100k ratings from 1000 users on 1700 movies. In a future version of the software larger versions of the movielens dataset will be added
load_process_DP() 用户可以在此处加载可用的二元预测数据集。这些是四个不同的生物网络数据集(ernsrndpiedpii),可以通过在dataset_name参数中指定四个关键字之一来访问它们。
以与 DeepMTP 兼容的格式创建自定义 MTP 数据集

在多目标预测问题的最抽象视图中,最多需要三个数据集。其中包括交互矩阵、实例特征和目标特征。考虑到火车、val、测试拆分时,总数增加到 9 个可能的数据源。为了对这些信息进行分组并避免在data_process函数中传递 9 个不同的参数,框架使用具有 3 个键值对的单个字典{'train':{}, 'val':{}, 'test':{}}。这些值也应该是具有 3 个键值对的字典{'y':{}, 'X_instance':{}, 'X_target':{}}。组合时,字典可以具有以下形式:{'train':{}, 'val':{}, 'test':{}}

标识

标识

框架支持的输入格式的详细解释可以在这里找到

配置选项

在上面的代码片段中,函数 generate_config 显示为没有任何特定参数。在实践中,该函数提供了许多参数,这些参数定义了两分支神经网络架构的多个特征、训练、验证、测试等方面。以下部分可以用作用户的备忘单,解释其含义和基本原理每个参数。

参数名称 描述
训练
num_epochs 允许训练的最大 epoch 数
learning_rate 用于确定优化过程每次迭代的步长的学习率
decay Adam 优化器使用的权重衰减(L2 惩罚)
compute_mode 将用于实际训练神经网络的设备。有效的选项是cpu用户想要慢速训练还是想要在系统的 gpu 上cuda:id训练id
num_workers 用于数据加载的子进程数。较大的值通常会提高性能,但经过一个点训练速度会变差
train_batchsize 构成训练集中批次的样本数
val_batchsize 组成来自验证集和测试集的批次的样本数量
patience 允许网络继续训练的时期数,同时观察到更差的整体性能
return_results_per_target 是否分别返回每个目标的性能
evaluate_train 是否计算训练集的性能指标
evaluate_val 是否计算验证集的性能指标
eval_every_n_epochs 指示何时计算性能指标的时间间隔
use_early_stopping 训练时是否使用早停
指标
metrics 将计算的性能指标。对于分类任务,可用指标是['hamming_loss', 'auroc', 'f1_score', 'aupr', 'accuracy', 'recall', 'precision'],而对于回归任务,可用指标是['RMSE', 'MSE', 'MAE', 'R2', 'RRMSE']
metrics_average 将用于计算指标的平均策略。可用的选项是 ['macro', 'micro', 'instance']
metric_to_optimize_early_stopping 提前停止例程将用于跟踪的指标。该值可以是loss可用的性能指标或其中之一。
metric_to_optimize_best_epoch_selection 将用于确定最佳配置的验证指标。该值可以是loss可用的性能指标或其中之一。
打印 - 保存 - 记录
verbose 是否在终端打印有用
use_tensorboard_logger 是否将结果记录在 Tensoboard 可以读取和可视化的文件中
wandb_project_name 定义将记录实验结果的 wandb 项目的名称
wandb_project_entity 定义 wandb 帐户的用户名
results_path 定义所有相关信息将保存到的路径
experiment_name 定义当前实验的名称。此名称将用于本地保存和 wandb 保存
save_model 是否保存验证性能最好的epoch模型
通用架构架构
enable_dot_product_version 是否使用两个分支架构的点积版本。在点积版本中,两个嵌入用于计算点积。如果值为 False,则首先将两个嵌入连接起来,然后传递给另一系列的全连接层
batch_norm 在两个分支的全连接层之间使用批量标准化的选项
dropout_rate 两个分支的层使用的dropout量
实例分支架构
instance_branch_architecture 将在实例分支中使用的架构类型。目前,有两种可用的选项MLP:使用基本的全连接前馈神经网络,使用CONV卷积神经网络
instance_branch_input_dim 实例分支的输入维度
instance_train_transforms 可用于训练样本的 Pytorch 兼容转换。在使用具有卷积架构的图像时很有用
instance_inference_transforms 可用于验证和测试样本的 Pytorch 兼容转换。在使用具有卷积架构的图像时很有用
instance_branch_params 包含配置实例分支中存在的架构所需的所有超参数的字典。包含如下键值对:
目标分支架构
target_branch_architecture 将在目标分支中使用的架构类型。目前,有两种可用的选项MLP:使用基本的全连接前馈神经网络,使用CONV卷积神经网络
target_branch_input_dim 目标分支的输入维度
target_train_transforms 可用于验证和测试样本的 Pytorch 兼容转换。在使用具有卷积架构的图像时很有用
target_inference_transforms 可用于验证和测试样本的 Pytorch 兼容转换。在使用具有卷积架构的图像时很有用
instance_branch_params 包含配置目标分支中存在的体系结构所需的所有超参数的字典。
组合分支架构
comb_mlp_nodes_per_layer 定义组合分支中的节点数。如果是列表,则每个元素定义相应层中的节点数。如果是 int,则使用相同数量的节点 'comb_mlp_branch_layers' 次。(仅在 时使用enable_dot_product_version == False
comb_mlp_branch_layers 组合分支中的层数。(仅在 时使用enable_dot_product_version == False
embedding_size 两个分支输出的嵌入的大小。(仅在 时使用enable_dot_product_version == True
预训练模型
load_pretrained_model 是否加载预训练模型
pretrained_model_path 带有预训练模型的 .pt 文件的路径(仅在 时使用load_pretrained_model == True
其他
additional_info 包含所有其他相关信息的字典。可用作 wandb 中实验的日志附加信息
validation_setting 具体示例的验证设置

实例和目标分支超参数

如前所述,定义实例或目标分支架构所需的所有超参数都作为键值对传递到instance_branch_paramsandtarget_branch_params中。

钥匙 描述
instance_branch_params字典中当前支持的可能键名
instance_branch_nodes_per_layer MLP定义实例分支版本中的节点数。如果是list,每个元素定义了对应层的节点数。如果是int,则使用相同数量的节点instance_branch_layers次数
instance_branch_layers 实例分支的 MLP 版本中的层数。(仅在instance_branch_nodes_per_layer为 int 时使用)
instance_branch_conv_architecture 实例分支中使用的卷积架构的类型。
instance_branch_conv_architecture_version 实例分支中使用的特定类型的卷积架构的版本。
instance_branch_conv_architecture_dense_layers 在实例分支的卷积架构结束时使用的密集层数
instance_branch_conv_architecture_last_layer_trained 使用预训练架构时,用户可以定义在训练期间将被冻结的最后一层
target_branch_params字典中当前支持的可能键名
target_branch_nodes_per_layer MLP定义目标分支版本中的节点数。如果是list,每个元素定义了对应层的节点数。如果是int,则使用相同数量的节点target_branch_layers次数
target_branch_layers 目标分支的 MLP 版本中的层数。(仅在target_branch_nodes_per_layer为 int 时使用)
target_branch_conv_architecture 目标分支中使用的卷积架构的类型。
target_branch_conv_architecture_version 目标分支中使用的特定类型的卷积架构的版本。
target_branch_conv_architecture_dense_layers 在目标分支的卷积架构末端使用的密集层数
target_branch_conv_architecture_last_layer_trained 使用预训练架构时,用户可以定义在训练期间将被冻结的最后一层

记录结果

DeepMTP 提供了多种选项来保存和记录性能指标和其他与配置相关的信息。

只需打印到 .txt 文件

默认的“记录”方法将 3 个半结构化表写入summary.txt目录的实验子文件夹中的results_path文件。

标识

张量板

第二个选项使用 tensorboard 工具。这最适合希望在本地保留结果同时还具有绘图和实验比较的用户。设置use_tensorboard_logger=True会将必要的文件保存在results_path. 要启动张量板,用户只需在设置为该值tensorboard --logdir=runs的终端中运行(默认设置为)。如果未显示错误,则用户将自动重定向到显示类似于以下屏幕截图的 Web 浏览器:runsresults_path./results/

标识

权重和偏差

第三个也是功能更丰富的选项使用权重和偏差框架。这最适合希望将结果保持在线但还需要创建免费帐户的用户。要成功登录到 wandb,用户必须设置有效的用户名wandb_project_entity并将项目名称设置为wandb_project_name. 如果在此过程中没有显示错误,用户可以导航到https://wandb.ai/wandb_project_entity/wandb_project_name类似于以下屏幕截图的内容:

标识

超参数优化

为了进一步自动化 DeepMTP,我们决定对不同的流行超参数优化 (HPO) 方法进行基准测试(结果论文将在不久的将来发表)。根据结果​​,我们得出结论,对于 DeepMTP 考虑的大多数 MTP 问题设置,Hyperband 是一个可行的选择。

超频带

任何标准 HPO 方法的核心步骤之一是对给定配置的性能评估。这对于训练和测试相对便宜的简单模型来说是可以管理的,但对于需要数小时甚至数天来训练的更复杂的模型来说,这可能是一个重要的瓶颈。这在深度学习中尤为明显,因为在越来越大的数据集上训练有数百万个参数的大型神经网络可能认为传统的黑盒 HPO 方法不切实际。

为了解决这个问题,已经设计了多保真 HPO 方法,以在早期阶段就丢弃没有希望的超参数配置。为此,评估过程适用于支持对超参数配置进行更便宜的评估,例如评估所提供数据集的子样本(特征方面或实例方面)或仅在一定数量的时期内执行训练过程在迭代学习器的情况下。随后对更有希望的候选人进行评估,以增加预算,直到达到最大可分配预算。

这种方法的一个流行代表是 Hyperband。Hyperband 建立在连续减半 (SH) 的基础上,其中一组 n 个候选者首先在小预算下进行评估。基于这些低保真性能估计,$\frac{n}{\eta}$ ($\eta \geq 2)$ 最佳候选者被保留,而其余配置已被丢弃。迭代地增加评估预算并用增加的预算重新评估剩余的候选人,同时丢弃劣质的候选人,从而减少浪费在劣质候选人上的资源。作为回报,人们更关注有前途的候选人。

尽管连续减半策略的效率很高,但众所周知,它受到勘探-开发权衡的影响。简单来说,静态预算 $\mathcal{B}$ 意味着用户必须手动决定是探索多个配置 $n$ 还是给每个配置足够的预算来开发。不正确的决定可能导致对搜索空间的探索不充分(小$n$)或早期拒绝有希望的配置(大$n$)。Hyperband 通过使用不同的 SH 初始化重复连续减半策略,改变预算和初始候选配置的数量,克服了探索-利用权衡。rf

将 Hyperband 与 DeepMTP 相结合

DeepMTP 原生提供了基本的 Hyperband 实现,因此代码只需要修改

from DeepMTP.dataset import load_process_MLC
from DeepMTP.main import DeepMTP
from DeepMTP.utils.utils import generate_config
from DeepMTP.simple_hyperband import BaseWorker
from DeepMTP.simple_hyperband import HyperBand
import ConfigSpace.hyperparameters as CSH


# define the configuration space
cs= CS.ConfigurationSpace()
# REALLY IMPORTANT: all hyperparameters for the instance or target branch should have the 'instance_' or 'target_' prefix
lr= CSH.UniformFloatHyperparameter('learning_rate', lower=1e-6, upper=1e-3, default_value="1e-3", log=True)
embedding_size= CSH.UniformIntegerHyperparameter('embedding_size', lower=8, upper=2048, default_value=64, log=False)
instance_branch_layers= CSH.UniformIntegerHyperparameter('instance_branch_layers', lower=1, upper=2, default_value=1, log=False)
instance_branch_nodes_per_layer= CSH.UniformIntegerHyperparameter('instance_branch_nodes_per_layer', lower=8, upper=2048, default_value=64, log=False)
target_branch_layers = CSH.UniformIntegerHyperparameter('target_branch_layers', lower=1, upper=2, default_value=1, log=False)
target_branch_nodes_per_layer = CSH.UniformIntegerHyperparameter('target_branch_nodes_per_layer', lower=8, upper=2048, default_value=64, log=False)
dropout_rate = CSH.UniformFloatHyperparameter('dropout_rate', lower=0.0, upper=0.9, default_value=0.4, log=False)
batch_norm = CSH.CategoricalHyperparameter('batch_norm', [True, False])
cs.add_hyperparameters(
    [
        lr,
        embedding_size,
        instance_branch_layers,
        instance_branch_nodes_per_layer,
        target_branch_layers,
        target_branch_nodes_per_layer,
        dropout_rate,
        batch_norm,
    ]
)

#adding condition on the hyperparameter values
cond = CS.GreaterThanCondition(dropout_rate, instance_branch_layers, 1)
cond2 = CS.GreaterThanCondition(batch_norm, instance_branch_layers, 1)
cond3 = CS.GreaterThanCondition(dropout_rate, target_branch_layers, 1)
cond4 = CS.GreaterThanCondition(batch_norm, target_branch_layers, 1)
cs.add_condition(CS.OrConjunction(cond, cond3))
cs.add_condition(CS.OrConjunction(cond2, cond4))

# load dataset
data = load_process_MLC(dataset_name='yeast', variant='undivided', features_type='numpy')
# process and split
train, val, test, data_info = data_process(data, validation_setting='B', verbose=True)

# initialize the minimal configuration
config = {    
    'hpo_results_path': './hyperband/',
    'instance_branch_input_dim': data_info['instance_branch_input_dim'],
    'target_branch_input_dim': data_info['target_branch_input_dim'],
    'validation_setting': data_info['detected_validation_setting'],
    'enable_dot_product_version': True,
    'problem_mode': data_info['detected_problem_mode'],
    'compute_mode': 'cuda:1',
    'train_batchsize': 512,
    'val_batchsize': 512,
    'num_epochs': 6,
    'num_workers': 8,
    'metrics': ['hamming_loss', 'auroc'],
    'metrics_average': ['macro'],
    'patience': 10,
    'evaluate_train': True,
    'evaluate_val': True,
    'verbose': True,
    'results_verbose': False,
    'use_early_stopping': True,
    'use_tensorboard_logger': True,
    'wandb_project_name': 'DeepMTP_v2',
    'wandb_project_entity': 'diliadis',
    'metric_to_optimize_early_stopping': 'loss',
    'metric_to_optimize_best_epoch_selection': 'loss',
    'instance_branch_architecture': 'MLP',
    'target_branch_architecture': 'MLP',
    'save_model': True,
    'eval_every_n_epochs': 10,
    'additional_info': {'eta': 3, 'max_budget': 9}
    }

# initialize the BaseWorker that will be used by Hyperband's optimizer
worker = BaseWorker(train, val, test, data_info, config, 'loss')
# initialize the optimizers
hb = HyperBand(
    base_worker=worker,
    configspace=cs,
    eta=config['additional_info']['eta'],
    max_budget=config['additional_info']['max_budget'],
    direction='min',
    verbose=True
)
# start-up the optimizer
best_overall_config = hb.run_optimizer()

# load the best model and generate predictions on the test set
best_model = DeepMTP(best_overall_config.info['config'], best_overall_config.info['model_dir'])
best_model_results = best_model.predict(test, verbose=True)

演示

加载内置数据集 在 Colab 中打开
多标签分类 (MLC)