CUML随机森林模型无法在多GPU Dask集群上正常训练
CUML 0.18多GPU随机森林训练问题排查与修正
核心错误定位
- 变量名拼写错误:单变量拆分时传入的
feature、label与前期定义的features、labels不匹配,会直接触发未定义变量报错 - 分布式参数逻辑误解:CUML 0.18版本的分布式随机森林实现为数据并行模式,
n_estimators参数为单个worker上训练的树数量,而非全集群总树数;预测阶段默认需要每个worker对全量测试集完成推理,再通过多数投票聚合结果 - 预测流程逻辑错误:将测试集拆分为分布式分区传入predict接口时,每个分区只会被分配到单个worker完成推理,无多节点投票聚合,最终精度接近随机猜测水平
- 数据分区错位风险:单独拆分特征、标签的分布式分区时,易出现索引不匹配导致的特征与标签错位问题
- 析构报错原因:该报错为版本已知边界bug,当训练流程因上述逻辑错误提前中断、内部单节点RF实例未完成完整初始化时,析构方法会访问未初始化的
treelite_model属性,触发属性不存在的异常
修正后的可运行代码
import pandas as pd import cudf from cuml.metrics import accuracy_score from dask.distributed import Client, wait import dask_cudf from cuml.dask.ensemble import RandomForestClassifier as cumlDaskRF # 集群连接:远程集群使用现有调度地址,本地测试可替换为LocalCUDACluster c = Client('node0:8786') # 获取集群worker总数 workers = c.has_what().keys() n_workers = len(workers) # 模型参数配置 max_depth = 12 n_bins = 16 n_trees_per_worker = 100 # 单worker树数,3个worker时总树数300,适配Iris数据集规模 # 数据读取与预处理 pdf = pd.read_csv('/data/iris.csv', header=0, delimiter=',') cdf = cudf.from_pandas(pdf) features = cdf.iloc[:, [0, 1, 2, 3]].astype('float32') labels = cdf.iloc[:, 4].astype('category').cat.codes.astype('int32') # 合并特征与标签后转分布式数据集,保证分区严格对齐 combined_cdf = cudf.concat([features, labels.rename('label')], axis=1) combined_dask = dask_cudf.from_cudf(combined_cdf, npartitions=n_workers) # 分布式拆分训练、测试集 train_dask, test_dask = combined_dask.random_split([0.8, 0.2], random_state=42) X_train_dask = train_dask.iloc[:, :-1] y_train_dask = train_dask.iloc[:, -1].astype('int32') # 测试集落地为单节点cudf格式,用于全量广播推理 test_cdf = test_dask.compute() X_test = test_cdf.iloc[:, :-1].astype('float32') y_test = test_cdf.iloc[:, -1].astype('int32') # 模型训练 cuml_model = cumlDaskRF( max_depth=max_depth, n_estimators=n_trees_per_worker, n_bins=n_bins, n_streams=8 ) cuml_model.fit(X_train_dask, y_train_dask) wait(cuml_model.rfs) # 等待所有worker本地训练任务完成 # 推理与精度评估 cuml_y_pred = cuml_model.predict(X_test).compute().to_array() print("CuML accuracy: ", accuracy_score(y_test.to_array(), cuml_y_pred))
已训练决策树的提取方法
- 分布式模型的
rfs属性存储了每个worker上本地单节点随机森林实例的Dask Future对象 - 通过Client的
gather方法可将所有worker上的本地RF实例拉取到客户端 - 每个本地RF实例支持两种树导出方式:
- 调用
get_trees()方法直接获取内部树的结构参数 - 调用
convert_to_treelite()方法导出为通用Treelite格式,用于跨框架评估、可视化或部署
- 调用
- 注意该版本下树结构底层为C++侧存储,无Python层逐节点遍历的原生接口,需基于导出的Treelite格式做二次解析,才能完成单棵树的逐节点评估
内容的提问来源于stack exchange,提问作者nomad
相关产品推荐
相关产品推荐

