You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Optuna优化卷积自编码器超参数时遇Trials未完成错误求助

问题描述

尝试用Optuna优化卷积自编码器超参数时,持续出现「No trials are completed yet」错误,错误日志如下:

[W 2023-04-22 17:57:07,202] Trial 0 failed with parameters: {'learning_rate': 0.0001, 'weight': 1e-06, 'drop': 0.8, 'conv1': 128, 'conv2': 8, 'conv3': 128, 'fc': 130, 'latent_dim': 100} because of the following error: The value None could not be cast to float..
[W 2023-04-22 17:57:07,228] Trial 0 failed with value None.
ValueError: No trials are completed yet.

相关实现代码:

class Encoder_cae1_hp(nn.Module):
    def __init__(self, hyperparameters=dict):
        super().__init__()
        self.encoder = nn.Sequential(
        
                   nn.Conv1d(1,hyperparameters['conv1'],5, stride=3),
                   nn.Dropout(hyperparameters['drop']),

                   nn.Conv1d(hyperparameters['conv1'], hyperparameters['conv2'], 3, stride=3),
                   nn.LeakyReLU(),
        
                   
                   nn.Conv1d(hyperparameters['conv2'], hyperparameters['conv3'], 4, stride=2),
                   nn.Dropout(hyperparameters['drop']),
                   nn.LeakyReLU(),
        
               
                   nn.Flatten(start_dim=1),
        
                   nn.Linear(2924*hyperparameters['conv3'], hyperparameters['fc']),
        
                   nn.Linear(hyperparameters['fc'], hyperparameters['latent_dim']))
                
    def forward(self, x):
        z = self.encoder(x)
        return z

class Decoder_cae1_hp(nn.Module):
    def __init__(self, hyperparameters=dict):
        super().__init__()

        self.decoder = nn.Sequential(
            nn.Linear(hyperparameters['latent_dim'], hyperparameters['fc']),
            nn.Linear(hyperparameters['fc'], 2924*hyperparameters['conv3']),
           
            nn.Unflatten(dim=1, unflattened_size=(hyperparameters['conv3'], 2924)),
        
        
            nn.ConvTranspose1d(hyperparameters['conv3'], hyperparameters['conv2'], 4, stride=2,output_padding=1),
            nn.LeakyReLU(),
            nn.Dropout(hyperparameters['drop']),
        
            nn.ConvTranspose1d(hyperparameters['conv2'], hyperparameters['conv1'], 3, stride=3, padding =0, output_padding=2),
            nn.LeakyReLU(),
            nn.Dropout(hyperparameters['drop']),
            
            nn.ConvTranspose1d(hyperparameters['conv1'], 1, 5, stride=3, padding =0, output_padding=1)
           
            )
                    
    def forward(self, x):
        reconstruction = self.decoder(x)
        return reconstruction

#%% Hyperparameters
def objective(trial: optuna.trial.Trial) -> float:
    
    learning_rate = trial.suggest_categorical("learning_rate", [1e-5, 1e-4, 1e-3])
    weight = trial.suggest_categorical("weight", [1e-5, 1e-4, 1e-3, 1e-2, 1e-6])
    
    drop = trial.suggest_float("drop", 0.0, 1, step = 0.2)

    conv1 =  trial.suggest_categorical("conv1", [8, 16, 32, 64, 128])
    conv2 =  trial.suggest_categorical("conv2", [8, 16, 32, 64, 128])
    conv3 =  trial.suggest_categorical("conv3", [8, 16, 32, 64, 128])
    
    fc = trial.suggest_categorical("fc", [30, 50, 70, 100, 130, 270, 320])

    latent_dim = trial.suggest_categorical("latent_dim", [20,40,60,80,100])
    train_batch = trial.suggest_categorical("train_batch", [10,20,40,60,80,100])
    loss_fn = nn.MSELoss()

    hyperparameters = {
        'learning_rate': learning_rate, 
        'drop':drop,
        'conv1':conv1, 
        'conv2':conv2,
        'conv3':conv3,
        'fc':fc,
        'weight':weight,
        'latent_dim':latent_dim
        }

#%% 
    data = dataset.linearized_matrices()

    encoder = Encoder_cae1_hp(hyperparameters = hyperparameters) 
    decoder = Decoder_cae1_hp(hyperparameters = hyperparameters) 
    
#%% Train the optimizer   
    train_points, val_points = train_test_split(data, test_size= 0.1, shuffle=True, random_state = 0)

    train_points = dataset.Dataset(train_points, transform = dataset.ToTensor())
    validation_points = dataset.Dataset(val_points, transform = dataset.ToTensor())

    train_points_dl= DataLoader(train_points, batch_size = train_batch, shuffle= True)
    validation_points_dl= DataLoader(validation_points, batch_size = len(validation_points), shuffle=False)

    optimizer = torch.optim.Adam([{'params': encoder.parameters()},{'params': decoder.parameters()}], lr = hyperparameters['learning_rate'], weight_decay = hyperparameters['weight'])

    device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
    print(f'Selected device: {device}')
            
    encoder.to(device)
    decoder.to(device)
            
    try:
        num_epochs = 30
        for epoch in range(num_epochs):
                print(f'################# \n | EPOCH {epoch+1} | \n')
                train_loss = train.train(encoder, decoder, device, train_points_dl, loss_fn, optimizer)
                print(f'\t Average train loss for epoch: {train_loss.data}')
                val_loss, _ = test.test(encoder, decoder, device, validation_points_dl, loss_fn)
                print('\n\t VALIDATION - EPOCH %d/%d - loss: %f\n' % (epoch + 1, num_epochs, val_loss))            
                
                if trial.should_prune():
                     raise optuna.exceptions.TrialPruned()
                trial.report(val_loss)
        return val_loss         
        
    except RuntimeError:
       trial.set_user_attr("constraint", (1,)) 
        
def print_best_callback(study, trial):
    print(f"Best value: {study.best_value}, Best params: {study.best_trial.params}")

#%%
study = optuna.create_study(direction="minimize")
study.optimize(objective, n_trials = 800, gc_after_trial = True, callbacks=[print_best_callback])

测试函数:

def test(encoder, decoder, device, dataloader, loss_fn):
    encoder.eval()
    decoder.eval()
    latent_codes = dict(z = [], subj_id = [])
    with torch.no_grad():
        
        for subj, image_batch in dataloader:  

            image_batch = image_batch.to(device)
            z = encoder(image_batch)             
            reconstruction = decoder(z)         
            latent_codes['z'].append(z.detach().cpu())            
            latent_codes['subj_id'].append(subj) 
            val_loss = loss_fn(reconstruction, image_batch)
    return val_loss.data, latent_codes   
解决思路

1. 修复test函数中val_loss未初始化的问题

当前test函数如果遇到空dataloader或循环未执行的情况,val_loss会是None,直接导致后续类型转换错误。需要初始化损失并计算平均:

def test(encoder, decoder, device, dataloader, loss_fn):
    encoder.eval()
    decoder.eval()
    latent_codes = dict(z = [], subj_id = [])
    val_loss = 0.0
    total_samples = 0
    with torch.no_grad():
        for subj, image_batch in dataloader:  
            batch_size = image_batch.size(0)
            total_samples += batch_size
            image_batch = image_batch.to(device)
            z = encoder(image_batch)             
            reconstruction = decoder(z)         
            latent_codes['z'].append(z.detach().cpu())            
            latent_codes['subj_id'].append(subj) 
            val_loss += loss_fn(reconstruction, image_batch).item() * batch_size
    # 避免除0错误
    val_loss = val_loss / total_samples if total_samples > 0 else float('inf')
    return val_loss, latent_codes   

2. 给objective函数异常分支添加返回值

当前异常分支仅设置用户属性,但未返回值,导致Trial返回None。需返回一个极大值(对应最小化方向)标记该参数组合无效:

try:
    # 原有训练逻辑
    return val_loss         
except RuntimeError:
   trial.set_user_attr("constraint", (1,)) 
   return float('inf')

3. 验证编码器/解码器的维度匹配

日志中的None错误大概率来自卷积/反卷积维度不匹配导致的前向传播失败。需验证不同超参数组合下的维度一致性:

  • 在编码器初始化时添加维度断言(调试用):
# 替换成你的输入实际长度
dummy_input = torch.randn(1, 1, 原始输入长度)
with torch.no_grad():
    temp_encoder = nn.Sequential(
        nn.Conv1d(1,hyperparameters['conv1'],5, stride=3),
        nn.Conv1d(hyperparameters['conv1'], hyperparameters['conv2'], 3, stride=3),
        nn.Conv1d(hyperparameters['conv2'], hyperparameters['conv3'], 4, stride=2),
        nn.Flatten(start_dim=1)
    )
    output = temp_encoder(dummy_input)
    assert output.size(1) == 2924*hyperparameters['conv3'], \
        f"维度不匹配:实际{output.size(1)},预期{2924*hyperparameters['conv3']}"
  • 同理,解码器反卷积输出需与原始输入维度一致,也要做类似验证。

4. 确认train.train函数的返回有效性

检查train.train函数是否确实返回了有效的train_loss张量,避免因返回None导致后续打印train_loss.data时出错。

内容的提问来源于stack exchange,提问作者Leoni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 21:22:03