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

PyTorch中用eval执行优化器字符串为何导致函数报错?

问题:eval执行优化器代码时出现NameError

我编写了如下PyTorch Lightning类:

import torch.optim as optim

class GraphLevelGNN(pl.LightningModule):

    def __init__(self,**model_kwargs):
        super().__init__()

        self.save_hyperparameters()
        self.model = GraphGNNModel(**model_kwargs)
        self.loss_module = nn.BCEWithLogitsLoss()
        self.optimizer = eval('optim.SGD(self.parameters(),lr=0.1)')

    def forward(self, data, mode="train"):
        x, edge_index, batch_idx = data.x, data.edge_index, data.batch
        x = self.model(x, edge_index, batch_idx)
        x = x.squeeze(dim=-1)
        
        if self.hparams.c_out == 1:
            preds = (x > 0).float()
            data.y = data.y.float()
        else:
            preds = x.argmax(dim=-1)

        loss = self.loss_module(x, data.y)
        acc = (preds == data.y).sum().float() / preds.shape[0]

        return loss, acc,preds

    def configure_optimizers(self):
        optimizer = self.optimizer
        return optimizer

    def training_step(self, batch, batch_idx):
        loss, acc, _ = self.forward(batch, mode="train")
        self.log('train_loss', loss,on_epoch=True,logger=True,batch_size=64)
        self.log('train_acc', acc,on_epoch=True,logger=True,batch_size=64)


    def validation_step(self, batch, batch_idx):
        loss, acc,_ = self.forward(batch, mode="val")
        self.log('val_acc', acc,on_epoch=True,logger=True,batch_size=64)
        self.log('val_loss', loss,on_epoch=True,logger=True,batch_size=64)

    def test_step(self, batch, batch_idx):
        loss,acc, preds = self.forward(batch, mode="test")
        self.log('test_acc', acc,on_epoch=True,logger=True,batch_size=64)

我希望将优化器放入Ray Tune对象中以避免硬编码,但发现:在__init__中直接写self.optimizer = optim.SGD(self.parameters(),lr=0.1)时脚本正常运行,换成self.optimizer = eval('optim.SGD(self.parameters(),lr=0.1)')则报错:

File "script.py", line 560, in __init__
    self.optimizer = eval('optim.SGD(self.parameters(),lr=0.1)')
  File "<string>", line 1, in <module>
NameError: name 'optim' is not defined

将字符串中的optim改为torch.optim后仍出现相同错误,想了解为何eval无法将字符串转换为对应代码执行?

原因与解决方法

1. eval找不到optim的核心原因

eval()执行字符串代码时,会使用当前局部作用域查找变量。在__init__方法里,虽然全局导入了import torch.optim as optim,但eval的局部作用域默认不包含全局的optim别名,所以会抛出NameError。哪怕换成torch.optim也不行,因为torch同样不在eval的局部作用域里。

2. 替代eval的安全动态优化器方案

直接用eval处理代码字符串不仅容易出作用域问题,还存在安全风险。如果要配合Ray Tune实现动态优化器配置,推荐以下两种更可靠的方式:

方式一:字典映射优化器类

提前把可用的优化器类存入字典,通过参数指定选择:

import torch.optim as optim

class GraphLevelGNN(pl.LightningModule):
    def __init__(self, optimizer_name="SGD", lr=0.1, **model_kwargs):
        super().__init__()
        self.save_hyperparameters()
        self.model = GraphGNNModel(**model_kwargs)
        self.loss_module = nn.BCEWithLogitsLoss()
        
        # 优化器字典映射
        optimizer_dict = {
            "SGD": optim.SGD,
            "Adam": optim.Adam,
            "AdamW": optim.AdamW
        }
        self.optimizer_cls = optimizer_dict[optimizer_name]
        self.lr = lr

    def configure_optimizers(self):
        # 在configure_optimizers里实例化优化器(Lightning推荐时机)
        return self.optimizer_cls(self.parameters(), lr=self.lr)

这种方式完全避免了eval,配合Ray Tune时,只需在调参搜索空间中指定optimizer_name和lr的可选值即可。

方式二:直接传递优化器类与参数

如果需要更灵活的配置,直接把优化器类和参数作为model_kwargs传入:

class GraphLevelGNN(pl.LightningModule):
    def __init__(self, optimizer_cls=optim.SGD, optimizer_params={"lr":0.1}, **model_kwargs):
        super().__init__()
        self.save_hyperparameters()
        self.model = GraphGNNModel(**model_kwargs)
        self.loss_module = nn.BCEWithLogitsLoss()
        self.optimizer_cls = optimizer_cls
        self.optimizer_params = optimizer_params

    def configure_optimizers(self):
        return self.optimizer_cls(self.parameters(), **self.optimizer_params)

配合Ray Tune时,在调参配置里指定optimizer_cls和optimizer_params的搜索范围即可。

3. Lightning优化器的最佳实践

代码里在__init__中实例化优化器是不推荐的。PyTorch Lightning建议在configure_optimizers方法内实例化优化器,原因如下:

  • 模型参数可能在__init__之后才完成初始化(比如使用延迟初始化场景)
  • 多GPU训练时,Lightning会自动处理优化器的分布式适配逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 14:15:41