一个GPU版本的遗传算法迭代xgboost最优参数的示例,这里用的是自定义损失函数

一个简单的遗传算法迭代xgboost最优参数的示例,这里用的是自定义损失函数

import pandas as pd
import numpy as np
import xgboost as xgb
from sko.GA import GA
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report
from sklearn import metrics
from log_color import log,LogLevel
from tqdm import tqdm
# from matplotlib import pyplot as plt

train_df = pd.read_csv('./train_v2.csv')
test_df =pd.read_csv('./test_v2.csv')

x = train_df.drop(['user_id','merchant_id','label'],axis=1)
y = train_df['label']

# ## 混合打乱数据
# y_to_numpy = y.to_numpy()
# x_to_numpy = x.to_numpy()
# m,n = x_to_numpy.shape
# y_to_numpy = y_to_numpy.reshape((m,1))
# xy = np.c_[x_to_numpy,y_to_numpy]

# for i in tqdm(range(20),desc="随机打乱数据"):
#     np.random.shuffle(xy)

# x,y = xy[:,0:13],xy[:,13:14]

# log(f"x.shape:{x.shape},y.shape:{y.shape}",LogLevel.INFO)

x_train, x_val, y_train, y_val = train_test_split(x, y, test_size=0.2, random_state = 42)

gamma = 0
### 自动计算alpha值的取值范围 取负例的比例
train_Y = y_train 

alpha = (train_Y==0).sum()/train_Y.size

def logistic_obj(p, dtrain):
   y = dtrain.get_label()
   p = 1.0 / (1.0 + np.exp(-p))
   grad = p * (1 - p) * (alpha * gamma * y * (1 - p) ** gamma * np.log(p) / (1 - p) - alpha * y * (
               1 - p) ** gamma / p - gamma * p ** gamma * (1 - alpha) * (1 - y) * np.log(1 - p) / p + p ** gamma * (
                                     1 - alpha) * (1 - y) / (1 - p))
   hess = p * (1 - p) * (p * (1 - p) * (
               -alpha * gamma ** 2 * y * (1 - p) ** gamma * np.log(p) / (1 - p) ** 2 + alpha * gamma * y * (
                   1 - p) ** gamma * np.log(p) / (1 - p) ** 2 + 2 * alpha * gamma * y * (1 - p) ** gamma / (
                           p * (1 - p)) + alpha * y * (1 - p) ** gamma / p ** 2 - gamma ** 2 * p ** gamma * (
                           1 - alpha) * (1 - y) * np.log(1 - p) / p ** 2 + 2 * gamma * p ** gamma * (1 - alpha) * (
                           1 - y) / (p * (1 - p)) + gamma * p ** gamma * (1 - alpha) * (1 - y) * np.log(
           1 - p) / p ** 2 + p ** gamma * (1 - alpha) * (1 - y) / (1 - p) ** 2) - p * (
                                     alpha * gamma * y * (1 - p) ** gamma * np.log(p) / (1 - p) - alpha * y * (
                                         1 - p) ** gamma / p - gamma * p ** gamma * (1 - alpha) * (1 - y) * np.log(
                                 1 - p) / p + p ** gamma * (1 - alpha) * (1 - y) / (1 - p)) + (1 - p) * (
                                     alpha * gamma * y * (1 - p) ** gamma * np.log(p) / (1 - p) - alpha * y * (
                                         1 - p) ** gamma / p - gamma * p ** gamma * (1 - alpha) * (1 - y) * np.log(
                                 1 - p) / p + p ** gamma * (1 - alpha) * (1 - y) / (1 - p)))
   return grad, hess

# class Myobj(xgb.core.):
#     def __call__(self,preds,label):
#         grad,hess = logistic_obj(preds,label)
#         return grad,hess
   
#     def create_obj(self):
#         return self

def XGBoostAUC(p):
   etas = [0.0001,0.001,0.01,0.1]
   sampling_methods = ["uniform","gradient_based"]
   # tree_methods = ["auto","exact","approx","hist"]
   w1,w2,w3,w4,w5,w6,w7,w8,w9,w10,w11,w12,w13,w14,w15,w16,w17 = p
   params = { #"objective":Myobj()
               "learning_rate":w1 #0.1
              , "n_estimators":int(w2)#11 #即基评估器的数量。这个参数对随机森林模型的精确性影响是单调的,n_estimators越 大,模型的效果往往越好。但是相应的,任何模型都有决策边  n_estimators达到一定的程度之后,随机森林的 精确性往往不在上升或开始波动,并且,n_estimators越大,需要的计算量和内存也越大,训练的时间也会越来越 长。对于这个参数,我们是渴望在训练难度和模型效果之间取得平衡。
              , "max_depth":int(w3) #构建树的深度,越大越容易过拟合
              , "min_child_weight":w4 #0.8 #越大min_child_weight,算法越保守。范围:[0,无穷大] 孩子节点中最小的样本权重和。如果一个叶子节点的样本权重和小于min_child_weight则拆分过程结束
#                , "num_class ":1#类别数,与 multisoftmax 并用
               , "gamma":w5 #损失下降多少才进行分裂, 控制叶子节点的个数
              , "subsample":w6#0.8 #随机采样训练样本
              #, "colsample_bytree":1 #生成树时进行的列采样
#                , "objective":'binary:logistic' # {'binary:logistic'}是二分类的问题,{'multi:softmax',}是多分类的问题 这个是优化目标,必须得有,因为xgboost里面有求一阶导数和二阶导数,其实就是这个。
              , "nthread":5 #cpu 线程数
              , "scale_pos_weight":(train_Y==0).sum()/(train_Y==1).sum() #负样本总数/正样本总数 。若训练负样本总数是500 ,正样本总数100,那么设置 scale_pos_weigh为 5
              , "lambda":w7#2 # 正则化参数
              , "eta":etas[int(w8)] #0.001 # 如同学习率
               , "verbosity":1 # 打印消息的详细程度。有效值为 0(静默)、1(警告)、2(信息)、3(调试)。
#                , metrics='auc'
              , "eval_metric":"auc"
#                , "silent ": 0 # ,设置成1则没有运行信息输出,最好是设置为0.
              , "seed":int(w9)
              , "max_delta_step":w10 #范围:[0,无穷大] ,我们允许每个叶子输出的最大增量步长。如果该值设置为0,则表示没有约束。如果将其设置为正值,则可以帮助使更新步骤更加保守。通常不需要此参数,但当类别极度不平衡时,它可能有助于逻辑回归。将其设置为 1-10 的值可能有助于控制更新。
               ,"subsample":w11
               ,"sampling_method":sampling_methods[int(w12)]
               ,'colsample_bytree':w13
               , 'colsample_bylevel':w14
               , 'colsample_bynode':w15
               ,"gpu_id":0 # 使用GPU的参数1
               ,"tree_method":"gpu_hist"#tree_methods[int(w16)]# #使用GPU的参数2
               ,"max_leaves":int(w16) #要添加的最大节点数。不被树方法使用
               ,"num_parallel_tree":int(w17) #每次迭代期间构建的并行树的数量。此选项用于支持增强随机森林
       }
   dtrain = xgb.DMatrix(x_train,label=y_train)
   clf = xgb.train(params=params
                   ,dtrain=dtrain
                   ,num_boost_round=100
                   ,evals=[(dtrain,"train")]
                   ,verbose_eval=False # 不显示训练信息就改False
                   ,obj=logistic_obj
                   )
   dtest = xgb.DMatrix(x_val,label=y_val)
   lr_proba = clf.predict(dtest)
   lr_proba = np.nan_to_num(lr_proba,0)
   fpr,tpr,threshold = metrics.roc_curve(y_val, lr_proba)
   roc_auc = metrics.auc(fpr,tpr)
   dtrain=None
   clf = None
   dtest = None
   lr_proba = None
   fpr,tpr,threshold = None,None,None
   log(f"本次迭代AUC分数为:[{roc_auc}],本次X值为:[{p}]",LogLevel.PASS)

   return -roc_auc


ga = GA(func=XGBoostAUC
       , n_dim=17 #待求解的自变量数量
       , size_pop=10 #种群初始化个体数量 
       , max_iter=5 # 进化迭代次数
       , prob_mut=0.01 #变异概率
       , lb=[0.1,5,1,0,0,0,0,0,10,0,0,0,0,0,0,0,1] # 自变量下限
       ,ub=[1,20,20,100,1,1,100,3,100,10,1,1,1,1,1,10,10] # 自变量上限
       ,precision=[0.1,1,1,0.1,0.1,0.1,0.1,1,1,0.1,0.1,1,0.1,0.1,0.1,1,1] #精度
       #,early_stop = True # 当出现两个相同值时是否早停退出
      )
best_x,best_y = ga.run()
print('best_x:', best_x,'\n','best_y:',best_y)


opt_x_log = pd.DataFrame({
   "best_x":[best_x]
   ,"best_y":[best_y]
})
print(f"优化结果表:{opt_x_log}")
opt_x_log.to_csv("best_x2.csv")


### 保存参数表
w1,w2,w3,w4,w5,w6,w7,w8,w9,w10,w11,w12,w13,w14,w15,w16,w17 = best_x

etas = [0.0001,0.001,0.01,0.1]
sampling_methods = ["uniform","gradient_based"]
params = { #"objective":Myobj()
               "learning_rate":w1 #0.1
              , "n_estimators":int(w2)#11 #即基评估器的数量。这个参数对随机森林模型的精确性影响是单调的,n_estimators越 大,模型的效果往往越好。但是相应的,任何模型都有决策边  n_estimators达到一定的程度之后,随机森林的 精确性往往不在上升或开始波动,并且,n_estimators越大,需要的计算量和内存也越大,训练的时间也会越来越 长。对于这个参数,我们是渴望在训练难度和模型效果之间取得平衡。
              , "max_depth":int(w3) #构建树的深度,越大越容易过拟合
              , "min_child_weight":w4 #0.8 #越大min_child_weight,算法越保守。范围:[0,无穷大] 孩子节点中最小的样本权重和。如果一个叶子节点的样本权重和小于min_child_weight则拆分过程结束
               
#               
#                , "num_class ":1#类别数,与 multisoftmax 并用
               , "gamma":w5 #损失下降多少才进行分裂, 控制叶子节点的个数
              , "subsample":w6#0.8 #随机采样训练样本
              #, "colsample_bytree":1 #生成树时进行的列采样
#                , "objective":'binary:logistic' # {'binary:logistic'}是二分类的问题,{'multi:softmax',}是多分类的问题 这个是优化目标,必须得有,因为xgboost里面有求一阶导数和二阶导数,其实就是这个。
              , "nthread":5 #cpu 线程数
              , "scale_pos_weight":(train_Y==0).sum()/(train_Y==1).sum() #负样本总数/正样本总数 。若训练负样本总数是500 ,正样本总数100,那么设置 scale_pos_weigh为 5
              , "lambda":w7#2 # 正则化参数
              , "eta":etas[int(w8)] #0.001 # 如同学习率
               , "verbosity":1 # 打印消息的详细程度。有效值为 0(静默)、1(警告)、2(信息)、3(调试)。
#                , metrics='auc'
              , "eval_metric":"auc"
#                , "silent ": 0 # ,设置成1则没有运行信息输出,最好是设置为0.
              , "seed":int(w9)
              , "max_delta_step":w10 #范围:[0,无穷大] ,我们允许每个叶子输出的最大增量步长。如果该值设置为0,则表示没有约束。如果将其设置为正值,则可以帮助使更新步骤更加保守。通常不需要此参数,但当类别极度不平衡时,它可能有助于逻辑回归。将其设置为 1-10 的值可能有助于控制更新。
               ,"subsample":w11
               ,"sampling_method":sampling_methods[int(w12)]
               ,'colsample_bytree':w13
               , 'colsample_bylevel':w14
               , 'colsample_bynode':w15
               ,"gpu_id":0 # 使用GPU的参数1
               ,"tree_method":"gpu_hist"#tree_methods[int(w16)]# #使用GPU的参数2
               ,"max_leaves":int(w16) #要添加的最大节点数。不被树方法使用
               ,"num_parallel_tree":int(w17) #每次迭代期间构建的并行树的数量。此选项用于支持增强随机森林


       }
params.update({"best_auc":best_y})
best_params_table = pd.DataFrame({k:[v] for k,v in params.items()})
best_params_table.to_csv("best_params_table.csv")

  • 11
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个使用GPU进行Jacobi迭代计算的程序示例,使用CUDA编写: ```cpp #include <stdio.h> #include <stdlib.h> #include <cuda_runtime.h> #define N 1024 // 矩阵维度 // 使用共享内存进行Jacobi迭代计算 __global__ void jacobi_kernel(float *A, float *b, float *x, float *x_new) { __shared__ float s_x[N]; int idx = blockIdx.x * blockDim.x + threadIdx.x; if (idx < N) { s_x[threadIdx.x] = x[idx]; __syncthreads(); float sum = 0.0f; for (int j = 0; j < N; j++) { if (j != idx) { sum += A[idx * N + j] * s_x[j]; } } x_new[idx] = (b[idx] - sum) / A[idx * N + idx]; } } // 主函数 int main() { float *A, *b, *x, *x_new; float *d_A, *d_b, *d_x, *d_x_new; int size = N * N * sizeof(float); int bsize = N * sizeof(float); A = (float*)malloc(size); b = (float*)malloc(bsize); x = (float*)malloc(bsize); x_new = (float*)malloc(bsize); // 初始化矩阵和向量 for (int i = 0; i < N; i++) { b[i] = 1.0f; x[i] = 0.0f; for (int j = 0; j < N; j++) { if (i == j) { A[i * N + j] = 2.0f; } else if (i == j + 1 || i == j - 1) { A[i * N + j] = -1.0f; } else { A[i * N + j] = 0.0f; } } } // 在GPU上分配内存 cudaMalloc((void**)&d_A, size); cudaMalloc((void**)&d_b, bsize); cudaMalloc((void**)&d_x, bsize); cudaMalloc((void**)&d_x_new, bsize); // 将数据从主机内存复制到GPU内存 cudaMemcpy(d_A, A, size, cudaMemcpyHostToDevice); cudaMemcpy(d_b, b, bsize, cudaMemcpyHostToDevice); cudaMemcpy(d_x, x, bsize, cudaMemcpyHostToDevice); // 迭代计算 int num_iter = 1000; int threads_per_block = 256; int num_blocks = (N + threads_per_block - 1) / threads_per_block; for (int iter = 0; iter < num_iter; iter++) { jacobi_kernel<<<num_blocks, threads_per_block>>>(d_A, d_b, d_x, d_x_new); cudaMemcpy(d_x, d_x_new, bsize, cudaMemcpyDeviceToDevice); } // 将结果从GPU内存复制回主机内存 cudaMemcpy(x, d_x, bsize, cudaMemcpyDeviceToHost); // 打印结果 for (int i = 0; i < N; i++) { printf("%f\n", x[i]); } // 释放内存 free(A); free(b); free(x); free(x_new); cudaFree(d_A); cudaFree(d_b); cudaFree(d_x); cudaFree(d_x_new); return 0; } ``` 上述程序中,`jacobi_kernel`函数使用共享内存进行Jacobi迭代计算,每个线程处理矩阵的一行。在主函数中,首先初始化矩阵和向量,然后在GPU上分配内存并将数据从主机内存复制到GPU内存。接着进行迭代计算,每次迭代调用`jacobi_kernel`函数,并将结果从GPU内存复制回主机内存。最后打印输出结果并释放内存。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值