AI项目用Wingman库。
项目描述
Wingman
Wingman是一个用于管理深度学习项目的Python库。目前,Wingman能够自动处理
- 自动保存和版本控制权重
- 平滑WanbB集成
- 流行torch模块的构建块
- 平滑处理命令行参数和*.yaml配置文件
安装
pip3 install jj-wingman
Wingman默认不包含PyTorch要求,因此默认禁用了所有torch功能。如果您希望使用Wingman的PyTorch功能,请为您的机器安装兼容的Pytorch版本。这通常通过以下方式完成:
pip3 install torch
哲学
Wingman被设计成非常易于集成到您的深度学习项目中。Wingman不会通过包装器包装您的模型或围绕Wingman设计模型,而是适应您的项目,您是决定何时以及在哪里使用Wingman的人。
模块
Wingman有多个核心模块和静态函数,所有这些都可以独立使用或结合使用。
from wingman import Wingman
这是Wingman的核心模块,Wingman需要在您的项目目录中某个可访问的位置有一个最简单的config.yaml
文件,这可以通过在命令行上运行wingman-generate-yaml [可选的文件名]
来生成。最简单的yaml文件如下
# wingman required params
debug: false
save_directory: 'weights'
model_id: null
ckpt_number: 0
log_status: false
increment: true
logging_interval: 10
max_skips: 5
greater_than: 0.0
wandb: false
wandb_name: ''
wandb_notes: ''
wandb_id: ''
wandb_entity: 'jjshoots'
wandb_project: 'my_new_project'
以下是对参数的描述
debug
:是否将模型设置为调试模式save_directory
:Wingman应指向何处保存模型权重model_id
:Wingman 记录此 ID 下的模型,如果留空,Wingman 将自动选择一个数字。ckpt_number
:如果留空,Wingman 将使用此数字检查点模型,如果将increment
参数设置为 true,则发生自动检查点编号。log_status
:是否保存 Wingman 输出的.txt
日志文件。increment
:是否增加检查点编号,如果设置为 false,Wingman 不会保存相同模型的多个变体。logging_interval
:在训练期间,将训练步骤传递给 Wingman,在logging_interval
步骤通过后,Wingman 将记录训练。如果 Wingman 找到一个新的最低点,则将模型权重保存到新文件。max_skips
:在找到新的最低点(使用logging_interval
参数指定)之前,跳过了多少个日志步骤,然后 Wingman 将保存模型的中间检查点。greater_than
:您可以通过此值告诉 Wingman 仅在先前检查点的损失大于当前损失时检查点模型。wandb
:是否将内容记录到 WandB。wandb_name
:在 WandB 中显示的运行名称。如果留空,Wingman 将根据模型版本号自动分配一个。wandb_notes
:一些有用的注释,您可以为将要记录在 WandB 中的运行留下。wandb_id
:此运行的唯一 ID。如果留空,将自动分配一个。wandb_entity
:您的 WandB 用户名/组织名称。wandb_project
:此运行所在的工程。
如果您需要更多参数,可以将它们添加到 config.yaml
文件中,并在以后轻松地参考这些参数。此外,Wingman 还会自动生成一个 device
参数,如果您的系统有 GPU,则此参数将自动设置为 GPU,可以用于以后的张量轻松传输。
您还可以使用 config.yaml
文件定义一组合理的默认值,然后稍后使用命令行参数覆盖它们。这是因为 Wingman 会自动将 config.yaml
文件中的所有参数转换为命令行参数,使用 Python 模块 argparse
。这使得您的 main.py
文件更加简洁,无需在顶部编写 50 多行代码来定义参数。例如,如果您在 config.yaml
中有 hack_level=10.3
,则可以通过命令行参数通过执行 python3 your_program.py --hack_level=69.420
来覆盖其值。
在定义您的 config.yaml
文件后,Wingman 的基本用法如下
from wingman import Wingman
# initialize Wingman and get all the parameters from the `config.yaml` file
wm = Wingman("./config.yaml")
cfg = wm.cfg
# load the model and optimizer, `cfg.device` is automatically generated
model = Model(cfg.YOUR_PARAM, cfg.YOUR_OTHER_PARAM).to(cfg.device)
optim = optimizer.AdamW(model.parameters(), lr=cfg.YOUR_LEARNING_RATE_PARAM, amsgrad=True)
# we can check if we have trained this model before, and if we have, just load it
# this checking is done using the `model_id` param, if `latest=True` is set,
# Wingman automatically searches for the latest model checkpoint,
# otherwise, Wingman uses the checkpoint specified by `ckpt_number`
have_file, weight_file, optim_file = wm.get_weight_files(latest=True)
if have_file:
# Wingman simply returns a string of where the weight files are
# no unnecessary wrapping!
model.load_state_dict(torch.load(model_file))
optim.load_state_dict(torch.load(optim_file))
# let's run some training:
while(training):
...
# training code here
loss = YOUR_LOSS_FUNCTION(model)
...
# when wandb is enabled (via `wandb = true` in the yaml file)
# logging can be done by passing Wingman a dictionary
# the dictionary is logged to wandb every logging interval
wm.log = {"log": 5, "these": 2.34, "values": -5.432}
# ... or you can force wandb logging using
wm.wandb_log()
# let Wingman handle checkpointing for you
update_weights, model_file, optim_file = wm.checkpoint(loss, training_step)
if update_weights:
# if Wingman deems that the weights should be checkpointed, it returns
# a string of where the weight files should go for it to be found later
torch.save(model.state_dict(), model_file)
torch.save(optim.state_dict(), optim_file)
权重目录压缩
如果您训练了大量的模型,权重目录可能会开始占用大量的磁盘空间。在命令行上运行 wingman-compress-weights [可选目录名称]
将删除所有冗余的检查点编号并删除所有空目录。
from wingman import NeuralBlocks
Neural blocks 是一个用于快速原型设计神经网络架构的模块。它提供了定义标准化模块的几种更简单的方法
简单的 3 层 MLP,具有 ReLU 激活
>>> from wingman import NeuralBlocks
>>> features = [4, 16, 64, 3]
>>> activation = ["relu", "tanh", "identity"]
>>> norm = "batch"
>>> bias = True
>>> MLP = NeuralBlocks.generate_linear_stack(features, activation, norm, bias)
>>> print(MLP)
Sequential(
(0): Sequential(
(0): BatchNorm1d(4, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(1): Linear(in_features=4, out_features=16, bias=True)
(2): ReLU()
)
(1): Sequential(
(0): BatchNorm1d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(1): Linear(in_features=16, out_features=64, bias=True)
(2): Tanh()
)
(2): Sequential(
(0): BatchNorm1d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(1): Linear(in_features=64, out_features=3, bias=True)
(2): Identity()
)
)
具有相同填充和最后一个两层 MaxPool2d 的 4 层卷积网络
>>> from wingman import NeuralBlocks
>>> channels = [3, 16, 32, 64, 1]
>>> kernels = [3, 1, 3, 1]
>>> pooling = [0, 0, 2, 2]
>>> activation = ["relu", "relu", "tanh", "tanh"]
>>> padding = None # this is equivalent to same padding
>>> norm = "batch"
>>> CNN = NeuralBlocks.generate_conv_stack(channels, kernels, pooling, activation, padding, norm)
>>> print(CNN)
Sequential(
(0): Sequential(
(0): BatchNorm2d(3, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(1): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(2): ReLU()
)
(1): Sequential(
(0): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(1): Conv2d(16, 32, kernel_size=(1, 1), stride=(1, 1))
(2): ReLU()
)
(2): Sequential(
(0): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(1): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(3): Tanh()
)
(3): Sequential(
(0): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(1): Conv2d(64, 1, kernel_size=(1, 1), stride=(1, 1))
(2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(3): Tanh()
)
)
2 层转置卷积网络
>>> from wingman import NeuralBlocks
>>> channels = [64, 32, 3]
>>> kernels = [4, 4]
>>> padding = [1, 1]
>>> stride = [2, 2]
>>> activation = ["lrelu", "lrelu"]
>>> norm = "non"
>>> TCNN = NeuralBlocks.generate_deconv_stack(channels, kernels, padding, stride, activation, norm)
>>> print(TCNN)
Sequential(
(0): Sequential(
(0): ConvTranspose2d(64, 32, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1))
(1): LeakyReLU(negative_slope=0.01)
)
(1): Sequential(
(0): ConvTranspose2d(32, 3, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1))
(1): LeakyReLU(negative_slope=0.01)
)
)
Neural Blocks 模块还具有生成单个模块的功能,请参阅文件本身以获取更多信息。
from wingman import gpuize, cpuize
这些是提升生活质量的独立函数。
>>> import numpy as np
>>> from wingman import gpuize, cpuize
>>> foo = np.random.random((5, 5))
>>> print(foo)
[[0.28392764 0.50936983 0.55433616 0.45614518 0.82523046]
[0.77437072 0.20900382 0.86220494 0.69071239 0.94863786]
[0.70082865 0.92780018 0.98392965 0.76945165 0.72886401]
[0.47702485 0.54968522 0.22110942 0.72436276 0.42574472]
[0.78330221 0.84888837 0.68529167 0.61878902 0.13556213]]
>>> bar = gpuize(foo, "cuda:0")
>>> print(bar)
tensor([[0.2839, 0.5094, 0.5543, 0.4561, 0.8252],
[0.7744, 0.2090, 0.8622, 0.6907, 0.9486],
[0.7008, 0.9278, 0.9839, 0.7695, 0.7289],
[0.4770, 0.5497, 0.2211, 0.7244, 0.4257],
[0.7833, 0.8489, 0.6853, 0.6188, 0.1356]], device='cuda:0')
>>> baz = cpuize(bar)
>>> print(baz)
[[0.28392764 0.50936983 0.55433616 0.45614518 0.82523046]
[0.77437072 0.20900382 0.86220494 0.69071239 0.94863786]
[0.70082865 0.92780018 0.98392965 0.76945165 0.72886401]
[0.47702485 0.54968522 0.22110942 0.72436276 0.42574472]
[0.78330221 0.84888837 0.68529167 0.61878902 0.13556213]]
如果与 Wingman 一起使用,当 cfg
被定义为之前所示时,可以简单地执行 gpuize(foo, cfg.device)
。
为什么每架飞机都有两个飞行员?实际上,您只需要一个飞行员。让我们去掉第二个飞行员。让这个该死的计算机来飞。
项目详情
下载文件
下载适用于您平台的文件。如果您不确定选择哪个,请了解有关安装包的更多信息。