在clus上运行具有不同参数的python项目

2024-04-20 02:13:12 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个python3项目,其目录结构如下:

project/
    run.py
    package/
        a.py
        b.py
        constants.py

模块ab使用各种公共变量/超参数。我需要在一个集群上运行项目的多个实例,使用不同的超参数。我将作业提交给集群,集群再安排它们。在

我试过以下方法:

1.我在package内有一个constants.py,我在提交每个作业之前修改了它。假设我要运行5组不同的超参数。这种方法的问题是集群需要一段时间来调度我的作业,当它最终调度时,所有作业将使用存储在constants.py中的最后修改的参数(即第5次运行的参数),而不是我想要的5个不同的集。在

2.接下来,我在run.py中使用了^{},但是无法将参数传递给包内的a和{},尽管尝试了类似this SO thread的各种方法。在

所以我不得不采用的方法是在run.py中使用argparse,导入run.py中的“常量”,重新初始化它们,然后在ab中的任何需要的地方导入常量。通过这种方式,我可以为run.py编写多个sh脚本,并在集群上调度它们。在

我相信应该有更好的(更像Python)的方法来做这件事。建议?谢谢。在


Tags: 项目方法runpy目录projectpackage参数
2条回答

因为我不太明白,这里至少有一个MCVE的开头。项目方向结构:

project/
    __init__.py
    run.py
    package/
        __init__.py
        a.py
        b.py
        constants.py

package目录(内部目录)开始:

初始化py

^{pr2}$

a.py

from . import constants

class ModelA:
    def __init__(self, a, b):
        print("Instantiating Model A with {0} {1}".format(a, b))
        print("    Pi:{0} hbar{1}".format(constants.pi, constants.hbar))

b.py

from . import constants

class ModelB:
    def __init__(self, a, b):
        print("Instantiating Model B with {0} {1}".format(a, b))
        print("    Pi:{0} hbar{1}".format(constants.hbar, constants.pi))

常量.py

hbar = 1
pi = 3.14

注意,init包含的内容纯粹是为了方便将project作为一个包导入,并在其下立即提供ModelA和{}名称。我可以很容易地留下一个空的__init__.py文件,然后from project.package.a import ModelA。在

很像在projectdir中的操作方式。top dir(project)有一个空的init_uu.py文件和一个:

运行.py

#!/usr/bin/evn python

import argparse
import package

parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument(' param1', dest='param1')
parser.add_argument(' param2', dest='param2')

args = parser.parse_args()

package.ModelA(args.param1, args.param2)
package.ModelB(args.param2, args.param1)

请注意,在环境管理可以发挥作用的集群上运行时,shebang链接可能不是必需的,并且取决于具体情况。在

从终端运行这个可以让你

$:> python3 project/run.py  param1 10  param2 100
Instantiating Model A with 10 100
    Pi:3.14 hbar1
Instantiating Model B with 100 10
    Pi:1 hbar3.14

现在,用这些简化的术语(希望能打破这个例子)来改进你所拥有的,或者重建你正在尝试做的事情,然后发回哪个部分不工作以及原因。在


编辑

让我用一句话作为解决方案的开场白:这样做是在给自己设置一个失败的机会。在我看来,你有一个run.py文件,在这个文件中,你想解析通过终端发送来的参数,并用它们来设置程序执行的全局状态。几乎在任何时候都不应该这样做(我所知道的唯一例外是有时并且只有有时在连接到数据库时可以用于为引擎或会话设置全局状态,但即使这样,它通常也不是唯一或最佳的解决方案)。
这就是你想要模块和包的原因。应该没有理由不能解析run.py中的输入,并且**调用**任何子模块中的功能。ab中的函数有多少个参数,或者它们是否接受并使用所有发送的参数,或者不使用这些参数,这都没有什么区别。您可以编辑上面的示例,使类A和B只需要1、3或10,或者A 5和B none参数,它仍然可以工作。在

a.py

from . import constants
from project.run import args

print("from A", args)

class ModelA:
    def __init__(self, a, b):
        print("Instantiating Model A with {0} {1}".format(a, b))
        print("    Pi:{0} hbar{1}".format(constants.pi, constants.hbar))

b.py

from . import constants
from project.run import args

print("from B", args)

class ModelB:
    def __init__(self, a, b):
        print("Instantiating Model B with {0} {1}".format(a, b))
        print("    Pi:{0} hbar{1}".format(constants.hbar, constants.pi))

运行.py

#!/usr/bin/evn python
import argparse
from . import package

parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument(' param1', dest='param1')
parser.add_argument(' param2', dest='param2')

args = parser.parse_args()

if __name__ == "__main__":
    package.ModelA(args.param1, args.param2)
    package.ModelB(args.param2, args.param1)

然后调用它作为

$:> python3 -m project.run  param1 10  param2 100
from A Namespace(param1='10', param2='100')
from B Namespace(param1='10', param2='100')
Instantiating Model A with 10 100
    Pi:3.14 hbar1
Instantiating Model B with 100 10
    Pi:1 hbar3.14

注意,变化不大。实际上,我们从run.py导入args,方法是使用绝对导入路径,而不是相对路径,然后我们将执行代码移到if __name__ == "__main__":中,这样就不会在每次导入时调用它——只调用使脚本成为“main”程序的那个。唯一更大和重要的区别是脚本的调用。终端命令python3 -m project.run将导入该模块,然后将其作为脚本运行,而之前使用的python3 project/run.py将尝试将run.py作为脚本运行。当第一次导入模块时,它的__package__值被设置;当__package__被设置时,它启用显式的相对导入,因此from project.run import ...语句可以工作,因为现在python知道它必须去哪里寻找这些值。而当run.py像脚本一样运行时,当在旧的run.py中调用import package语句时,Python会进入package/目录,但它不知道它可能需要返回一个级别(到run.py)来搜索其中定义的值,并将它们导入到package/目录中的较低级别。在

我建议使用可以为每个实例指定的环境变量

可能没有实际的常量,或者至少有一些config.py

import os 

my_val=os.environ.get('MY_VAL', 'default value')

然后,当您在多个实例上运行代码时,您需要在每次执行之间导出适当的变量。在

如果您要将应用程序容器化,那么使用Docker,您将能够传入-e MY_VAL="some value"并将其加载到代码中

相关问题 更多 >