减少 dask XGBoost 内存消耗

问题描述

我正在编写一个简单的脚本代码来在我的数据集上训练 XGBoost 预测器。 这是我正在使用的代码

import dask.dataframe as dd
import dask_ml
from dask.distributed import Client,LocalCluster
import sys
from dask_ml.model_selection import train_test_split
import dask
import xgboost
import dask_xgboost

def start_cluster(n_workers=1,threads_per_worker=2,memory_limit="12GB",processes=False):
    cluster = LocalCluster(
        n_workers=n_workers,threads_per_worker=threads_per_worker,memory_limit=memory_limit,processes=processes
    )
    client = Client(cluster)  # use default n_threads and mem
    print(client)
    print(client.cluster)
    print("Client infos:",client.scheduler_info())
    return client

client = start_cluster()

dask_df = dd.read_parquet('./sample_dataset',engine='pyarrow')

dask_df=dask_df.drop(
    ['mapped_tweet_id','mapped_creator_id','mapped_engager_id','engagement_retweet_timestamp','engagement_comment_timestamp','engagement_reply_timestamp','mapped_tweet_links','mapped_domains','mapped_tweet_hashtags'
    ],axis=1
)

y = dask_df['engagement_like_timestamp']>0

dask_df=dask_df.drop(
    [
     'engagement_like_timestamp',],axis=1
)

X_train,X_test,y_train,y_test = train_test_split(dask_df,y,test_size=0.2,shuffle= True)

params = {'objective': 'binary:logistic','max_depth': 4,'eta': 0.01,'subsample': 0.5,'min_child_weight': 0.5}

bst = dask_xgboost.train(client,params,X_train,num_boost_round=10)

它运行良好,但我不断收到与 dask (distributed.utils_perf - WARNING - full garbage collections took 36% cpu time recently (threshold: 10%)) 相关的常见垃圾收集器警告

我分析了可用的仪表板,我注意到我的代码不断增加内存使用量,直到达到 80% 限制(我更改了 .config 文件夹中的标准设置),然后由于垃圾而开始变慢收集器。

这里有一个例子:

Dashboard

它基本上会一直这样,直到它饱和所有可用内存。我使用的数据集非常大,这就是我使用 dask 的原因。然而,它似乎基本上是将整个数据集加载到内存中(我不知道这个假设是否正确,但似乎是因为 read-parquet 任务)。

代码非常简单,似乎没有什么大问题。

来自以下问题中图书馆的作者 (Dask Github Issue ) 他说:

同样值得注意的是这个错误信息

distributed.utils_perf - 警告 - 完全垃圾收集占用了 47% 最近的 cpu 时间(阈值:10%)是最常见的(但不是唯一的) 您正在运行的代码错误,与此无关 达斯克。 dask 正好可以让您知道诸如此类的事情 正在发生的事情。

但是,正如我已经说过的,代码非常简单。

  1. 如何删除此警告?这确实降低了我代码性能
  2. 我使用 dask 来“分块”工作,因为我的数据集太大而无法放入内存。然而,它似乎正在将所有内容加载到内存中,这使得 dask 的使用变得毫无用处。我怎样才能“强制”它按预期工作(分块)?

解决方法

能否请您尝试使用 xgboost.daskXGboost now has native Dask support (please read our blog)

这里有一些文档: https://xgboost.readthedocs.io/en/latest/tutorials/dask.html

以下是该站点的一些示例代码:

import xgboost as xgb
import dask.array as da
import dask.distributed

cluster = dask.distributed.LocalCluster(n_workers=4,threads_per_worker=1)
client = dask.distributed.Client(cluster)

# X and y must be Dask dataframes or arrays
num_obs = 1e5
num_features = 20
X = da.random.random(
    size=(num_obs,num_features),chunks=(1000,num_features)
)
y = da.random.random(
    size=(num_obs,1),1)
)

dtrain = xgb.dask.DaskDMatrix(client,X,y)

output = xgb.dask.train(client,{'verbosity': 2,'tree_method': 'hist','objective': 'reg:squarederror'
                         },dtrain,num_boost_round=4,evals=[(dtrain,'train')])

你能告诉我们你在哪里提到使用 dask 和 xgboost 的先前方法吗?如果它在我们的文档中,我很乐意纠正它!