文章目录  
 【人工智能概论】 K折交叉验证 一. 简单验证及其缺点  
   二. K折交叉验证 2.1 K折交叉验证的思路 2.2 小细节 2.3 K折交叉验证的缺点 2.4 K折交叉验证的代码   
 
简单验证: 将原始数据集随机划分成训练集和验证集两部分,例,将数据按照7:3的比例分成两部分,70%的样本用于训练模型;30%的样本用于模型验证,如下图。 
 
数据都只被用了一次; 验证集上计算出来的评估指标与原始分组有很大关系; 对于时序序列,要保存时序信息,往往不能打乱数据的顺序对数据进行随机截取,这就带来了问题,比如总用春、夏、秋的数据做训练,用冬的数据做测试,这显然是有问题的,是不能容忍的。 为了解决简单交叉验证的不足,引出K折交叉验证,其既可以解决数据集的数据量不够大的问题,也可以解决参数调优的问题。。 首先,将全部样本划分成k个大小相等的样本子集; 依次遍历这k个子集,每次把当前子集作为验证集,其余所有样本作为训练集,进行模型的训练和评估; 最后把k次评估指标的平均值作为最终的评估指标。在实际实验中,k通常取10,如下图。 
 
K折交叉验证中有这样一个细节,下一折的训练不是在上一折的基础上进行的,即每训练新的一折都要重新初始化模型参数。 因为K折交叉验证执行一次训练的总轮数是每一折的训练轮数(epochs)与总折数(K)的乘积,因此训练的成本会翻倍。 import  torch
import  random
from  torch. utils. data import  DataLoader,  TensorDataset
from  Model. ReconsModel. Recoder import  ReconsModel,  Loss_function
from  Model. ModelConfig import  ModelConfig
def  get_Kfold_data ( k,  i,  x) :   
    fold_size =  x. size( 0 )  //  k  
    val_start =  i *  fold_size  
    if  i !=  k -  1 :   
        val_end =  ( i +  1 )  *  fold_size  
        valid_data =  x[ val_start:  val_end] 
        train_data =  torch. cat( ( x[ 0 :  val_start] ,  x[ val_end: ] ) ,  dim= 0 ) 
    else :   
        valid_data =  x[ val_start: ]   
        train_data =  x[ 0 :  val_start] 
    return  train_data,  valid_data
def  train ( model,  train_data,  valid_data,  batch_size,  lr, epochs) : 
    
    train_loader =  DataLoader( TensorDataset( train_data) ,  batch_size,  shuffle= True ) 
    valid_loader =  DataLoader( TensorDataset( valid_data) ,  batch_size,  shuffle= True ) 
    
    criterion =  Loss_function( ) 
    optimizer =  torch. optim. Adam( params= model. parameters( ) ,  lr= lr) 
    
    train_loss =  [ ] 
    valid_loss =  [ ] 
    for  epoch in  range ( epochs) : 
        tra_loss =  0 
        val_loss =  0 
        for  i ,  data in  enumerate ( train_loader) : 
            
            data =  torch. stack( data) 
            data =  data. squeeze( 0 ) 
            optimizer. zero_grad( )   
            recon,  mu,  log_std =  model( data,  if_train= True )   
            
            loss =  criterion. loss_function( recon,  data,  mu,  log_std) 
            
            loss. backward( ) 
            optimizer. step( ) 
            tra_loss =  tra_loss +  loss. item( ) 
        tra_loss =  tra_loss /  len ( train_data) 
        train_loss. append( tra_loss) 
        
        with  torch. no_grad( ) : 
            for  i,  data in  enumerate ( valid_loader) : 
                
                data =  torch. stack( data) 
                data =  data. squeeze( 0 ) 
                optimizer. zero_grad( ) 
                recon,  mu,  log_std =  model( data,  if_train= False ) 
                test_loss =  criterion. loss_function( recon,  data,  mu,  log_std) . item( ) 
                val_loss =  val_loss +  test_loss
            val_loss =  val_loss /  len ( valid_data) 
            valid_loss. append( val_loss) 
        print ( '第 %d 轮, 训练的平均误差为%.3f, 测试的平均误差为%.3f 。' % ( epoch+ 1 ,  tra_loss,  val_loss) ) 
    return  train_loss,  valid_loss
def  k_test ( config,  datas) :  
    valid_loss_sum =  0 
    for  i in  range ( config. k) : 
        model =  ReconsModel( config)  
        print ( '-' * 25 , '第' , i+ 1 , '折' , '-' * 25 ) 
        train_data ,  valid_data =  get_Kfold_data( config. k,  i,  datas)  
        train_loss,  valid_loss =  train( model,  train_data,  valid_data,  config. batch_size,  config. lr,  config. epochs) 
        
        train_loss_ave =  sum ( train_loss) / len ( train_loss) 
        valid_loss_ave =  sum ( valid_loss) / len ( valid_loss) 
        print ( '-*-*-*- 第 %d 折, 平均训练损失%.3f,平均检验损失%.3f -*-*-*-' % ( i+ 1 ,  train_loss_ave, valid_loss_ave) ) 
        valid_loss_sum =  valid_loss_sum +  valid_loss_ave
    valid_loss_k_ave =  valid_loss_sum /  config. k  
    print ( '*'  *  60 ,  ) 
    print ( '基于K折交叉验证的验证损失为%.4f' % valid_loss_k_ave) 
if  __name__ ==  "__main__" : 
    
    X =  torch. rand( 5000 ,  16 ,  38 )   
    
    index =  [ i for  i in  range ( len ( X) ) ] 
    random. shuffle( index) 
    X =  X[ index]   
    config =  ModelConfig( ) 
    config. load( './Model/config.json' ) 
    k_test( config,  X)