ixxmu / mp_duty

抓取网络文章到github issues保存
https://archives.duty-machine.now.sh/
103 stars 30 forks source link

mlr3超参数调优的多种方法 #4700

Closed ixxmu closed 5 months ago

ixxmu commented 5 months ago

https://mp.weixin.qq.com/s/-cgvnzcArFBjYLQi_wNw0w

ixxmu commented 5 months ago

mlr3超参数调优的多种方法 by 医学和生信笔记



在读本推文前,需要对mlr3有一些基本了解,强烈建议你先读mlr3入门教程合集:mlr3教程汇总(但是有点过时了,可以看看基础部分,实践部分请看2023年及以后的推文)

本文主要给大家展示mlr3进行超参数调优的操作,不涉及数据的预处理过程,如果大家想看数据预处理但是不包含调参的基本操作,可以参考推文:使用mlr3搞定二分类资料的多个模型评价和比较

关于更多数据预处理(特征工程)的知识,可参考历史推文:

后续会给大家带来更多精彩的使用教程。

加载R包和数据

rm(list = ls())
library(mlr3verse)
## Loading required package: mlr3

# 减少屏幕输出
lgr::get_logger("mlr3")$set_threshold("warn")
lgr::get_logger("bbotk")$set_threshold("warn")

为了方便演示,就用自带的鸢尾花数据集,如果大家想要导入自己的数据并建立任务,可以参考上面的推文,都已经给出了详细的教程。

task <- tsk("iris")

在正式建立模型之前,一定要进行探索性数据分析,主要就是看看你的数据分布,数据类型,数据彼此之间的关系等,非常重要!!可以参考之前的推文:

这里就不给大家演示了。

超参数调优4种方法

这里以支持向量机为例。

既然是超参数调优,那就必须设置调整哪些超参数,在mlr3里常见的有4种方式。其实官方也没有明确的分类,只是mlr3使用起来非常灵活,我记录下方便自己记忆.

这部分内容在以前的推文中也详细介绍过,大家可以参考:mlr3:超参数调优

第1种

首先是在选择算法的时候设置,使用to_tune表示要调整这个参数,并设定范围。这种形式和tidymodels的做法一样:

# 选择算法并设置要调整的超参数
learner <- lrn("classif.svm", type = "C-classification", kernel = "radial",
              cost = to_tune(0.110), # 需要调整,并设定范围
              gamma = to_tune(05# 需要调整,并设定范围
              )

# 执行调参
set.seed(123)
instance <- tune(tuner = tnr("grid_search", resolution = 5),
                 task = task,
                 learner = learner,
                 resampling = rsmp ("holdout"),
                 measure = msr("classif.acc"),
                 store_models = T
                 )

# 查看最优的超参数
instance$result_learner_param_vals
## $type
## [1] "C-classification"
## 
## $kernel
## [1] "radial"
## 
## $cost
## [1] 2.575
## 
## $gamma
## [1] 2.5

# 应用到算法上
learner$param_set$values <- instance$result_learner_param_vals
learner
## <LearnerClassifSVM:classif.svm>: Support Vector Machine
## * Model: -
## * Parameters: type=C-classification, kernel=radial, cost=2.575,
##   gamma=2.5
## * Packages: mlr3, mlr3learners, e1071
## * Predict Types:  [response], prob
## * Feature Types: logical, integer, numeric
## * Properties: multiclass, twoclass

# 重新建模,训练,预测
pred <- learner$train(task)$predict(task)

如果以上代码有很多地方你都看不懂,你可能需要翻看历史推文:mlr3:超参数调优

可视化调参结果:

library(ggplot2)
autoplot(instance,type = "performance")+
  theme(legend.position = "none")

第2种

第二种和第一种差不多,先不设定范围,后面再设置范围,也是和tidymodels很像:

# 选择算法
learner <- lrn("classif.svm", type = "C-classification", kernel = "radial")

# 选择调整的超参数及范围
learner$param_set$values$cost = to_tune(0.110)
learner$param_set$values$gamma = to_tune(05)

# 执行调参
set.seed(123)

instance <- tune(tuner = tnr("grid_search", resolution = 5),
                 task = tsk("iris"),
                 learner = learner,
                 resampling = rsmp ("holdout"),
                 measure = msr("classif.ce")
                 )

# 查看最好的超参数
instance$result_learner_param_vals

# 应用到算法上
learner$param_set$values <- instance$result_learner_param_vals
learner

# 重新建模,训练,预测
pred <- learner$train(task)$predict(task)

第3种

以上2种方法都有一个问题:你不知道每个算法里有哪些超参数可以调整,你也不知道它们的类型和范围,并且即使知道你也不会拼写......

所有这就有了第3种,也是我推荐大家使用的方法:

# 选择算法
learner <- lrn("classif.svm", type = "C-classification", kernel = "radial")

# 查看有哪些超参数
learner$param_set
## <ParamSet>
##                  id    class lower upper nlevels          default parents
##  1:       cachesize ParamDbl  -Inf   Inf     Inf               40        
##  2:   class.weights ParamUty    NA    NA     Inf                         
##  3:           coef0 ParamDbl  -Inf   Inf     Inf                0  kernel
##  4:            cost ParamDbl     0   Inf     Inf                1    type
##  5:           cross ParamInt     0   Inf     Inf                0        
##  6: decision.values ParamLgl    NA    NA       2            FALSE        
##  7:          degree ParamInt     1   Inf     Inf                3  kernel
##  8:         epsilon ParamDbl     0   Inf     Inf              0.1        
##  9:          fitted ParamLgl    NA    NA       2             TRUE        
## 10:           gamma ParamDbl     0   Inf     Inf   <NoDefault[3]>  kernel
## 11:          kernel ParamFct    NA    NA       4           radial        
## 12:              nu ParamDbl  -Inf   Inf     Inf              0.5    type
## 13:           scale ParamUty    NA    NA     Inf             TRUE        
## 14:       shrinking ParamLgl    NA    NA       2             TRUE        
## 15:       tolerance ParamDbl     0   Inf     Inf            0.001        
## 16:            type ParamFct    NA    NA       2 C-classification        
##                value
##  1:                 
##  2:                 
##  3:                 
##  4:                 
##  5:                 
##  6:                 
##  7:                 
##  8:                 
##  9:                 
## 10:                 
## 11:           radial
## 12:                 
## 13:                 
## 14:                 
## 15:                 
## 16: C-classification

这样就列出了这个算法支持的所有超参数以及它们的名字(id)类型(class)取值范围(lower/upper)等,非常方便!

然后再通过以下方法设定超参数网格:

search_space <- ps(
  cost = p_dbl(0.110),
  gamma = p_dbl(05)
)

接下来进行调参:

set.seed(123)

instance <- tune(tuner = tnr("grid_search", resolution = 5),
                 task = task,
                 learner = learner,
                 resampling = rsmp("cv",folds=3),
                 measure = msr("classif.acc"),
                 search_space = search_space
                 )

# 查看最好的超参数
instance$result_learner_param_vals
## $type
## [1] "C-classification"
## 
## $kernel
## [1] "radial"
## 
## $cost
## [1] 2.575
## 
## $gamma
## [1] 1.25

# 应用到算法上
learner$param_set$values <- instance$result_learner_param_vals
learner
## <LearnerClassifSVM:classif.svm>: Support Vector Machine
## * Model: -
## * Parameters: type=C-classification, kernel=radial, cost=2.575,
##   gamma=1.25
## * Packages: mlr3, mlr3learners, e1071
## * Predict Types:  [response], prob
## * Feature Types: logical, integer, numeric
## * Properties: multiclass, twoclass

# 重新建模,训练,预测
pred <- learner$train(task)$predict(task)

第4种

这种和第3种非常像。这个方法在以后还会经常用到,非常强大!被称为自动调参器.

# 选择算法
learner <- lrn("classif.svm", type = "C-classification", kernel = "radial")

# 查看有哪些超参数
#learner$param_set

# 设定超参数网格
search_space <- ps(
  cost = p_dbl(0.110),
  gamma = p_dbl(05)
)

# 建立自动调参器
at <- auto_tuner(
  tuner = tnr("grid_search", resolution = 5),
  learner = learner,
  resampling = rsmp("cv",folds=3),
  measure = msr("classif.acc"),
  search_space = search_space
)

# 执行调参
set.seed(123)
at_res <- at$train(task)

# 查看最好的超参数
at_res$tuning_result$learner_param_vals[[1]]
## $type
## [1] "C-classification"
## 
## $kernel
## [1] "radial"
## 
## $cost
## [1] 2.575
## 
## $gamma
## [1] 1.25

# 应用到算法上
learner$param_set$values <- at_res$tuning_result$learner_param_vals[[1]]
learner
## <LearnerClassifSVM:classif.svm>: Support Vector Machine
## * Model: -
## * Parameters: type=C-classification, kernel=radial, cost=2.575,
##   gamma=1.25
## * Packages: mlr3, mlr3learners, e1071
## * Predict Types:  [response], prob
## * Feature Types: logical, integer, numeric
## * Properties: multiclass, twoclass

# 重新建模,训练,预测
pred <- learner$train(task)$predict(task)

以上就是在没有预处理的情况下常见的超参数调优方法,如果看不懂的地方可以你先看之前写过的mlr3入门教程合集:mlr3教程汇总(但是有点过时了,可以看看基础部分,实践部分看2023年更新的,之前的部分代码会报错)

以上4种方法我其实最喜欢的是第3种,因为和tidymodels非常相似,学习起来可以互相结合,更方便记忆,而且只有这种方法可以实现非常多的可视化(autoplot即可,不用自己提取数据),这个我们后面还会详细说。

欢迎大家评论区留言或者加入QQ群交流。后台回复mlr3即可获取mlr3推文合集.