Skip to main content

Yet Anothor Configuration and Registration System

Project description

YACRS: Yet Anothor Configuration and Registration System

Why YACRS?

There are hundreds of configuration system package for python. YACS (by @rbgirshick) is a great one especially for DeepLearnig projects. Many famous projects' configuration system is based on YACS. Such as Detectron2, fvcore, etc. However, even if yasc is a handy and reliable configuration system, it still has some inconvenience. YASC keep all information in CfgNode which leads to an unsolved issue, how to gracefully map these information to an existing code (funciton or class). For instance

import torch
from yacs.config import CfgNode


class Model(torch.nn.Module):
    def __init__(self, input_channels, output_channels):
        self.net = torch.nn.Linear(input_channels, output_channels)

    @staticmethod
    def from_config(cfg):
        return Model(
            input_channels=cfg.input_channels,
            output_channels=cfg.output_channels
        )

cfg = CfgNode({'input_channels': 3, 'output_channels': 32})

# Option 1, do arguments mapping in main loop
model = Model(
    input_channels=cfg.input_channels,
    output_channels=cfg.output_channels
)

# Option 2, do some extra coding in class defination. Define a staticmethod in class.
model = Model.from_config(cfg)

YACRS is offers a more convenient way

# Option 3, use yacr!
import torch
from yacrs import configurable, _C

# ----------------------------------------------------------------

_C.register('Model1')
_C.Model1.input_channels = 1
_C.Model1.output_channels = 2

# register module with specific scope

@configurable().register  # equal  @configurable(scope='Model1').register
class Model1(torch.nn.Module):
    def __init__(self, input_channels, output_channels):
        super().__init__()
        self.net = torch.nn.Linear(input_channels, output_channels)

model = Model1()

# ----------------------------------------------------------------

_C.register('l1')
_C.register('l2')
_C.l1.input_channels = 1
_C.l1.output_channels = 2
_C.l2.input_channels = 3
_C.l2.output_channels = 4

# register module with unbind scope

@configurable(configurable.UNBIND).register
class Model2(torch.nn.Module):
    def __init__(self, input_channels, output_channels=10):
        super().__init__()
        self.net = torch.nn.Linear(input_channels, output_channels)

# use configurable to bind scope 'l1' and 'l2' to Model2 class separately

model1 = configurable('l1')(Model2)()
model2 = configurable('l2')('Model2')() # both class and class name would work

# you can overwrite augments by passing args or kwargs
# augments priority args/kwargs > bind node > default value
model1 = configurable('l1')(Model2)(3, output_channels=1024)

Example

write a config.yaml for training.

train:
    epoch: 10
    lr: 0.01
    scheduler: 'ExponentialLR'
    optimizer: 'SGD'
    dataset: 'TrainDataset'
    model: 'torchvision.resnet50'

TrainDataset:
    data_files:
        - a.txt
        - b.txt
    mean: [0.5, 0.5, 0.5]
    std: [0.5, 0.5, 0.5]

torchvision:
    resnet50:
        num_classes:
        zero_init_residual: false


ExponentialLR:
    gamma: 0.9

SGD:
    momentum: 0.9

Training script

import torch
from torchvision.models import resnet50
from yacrs import configurable, _C, Node

# register module
configurable('torchvision.resnet50').register(resnet50)
configurable('ExponentialLR').register(torch.optim.lr_scheduler.ExponentialLR)
configurable('SGD').register(torch.optim.SGD)

@configurable().register
class TrainDataset(torch.utils.data.Dataset):
    def __init__(self, data_files, mean, std):
        super().__init__()
        pass


@configurable().register
def train(
    epoch,
    lr,
    scheduler,
    optimizer,
    dataset,
    model,
):
    dataset = configurable()(dataset)()
    model = configurable()(model)(num_classes=dataset.num_classes)
    opt = configurable()(optimizer)(model.parameters(), lr=lr)
    sch = configurable()(scheduler)(optimizer)

    for i in range(epoch):
        ...


if __name__ == '__main__':
    import yaml

    with open("config.yaml") as stream:
        cfg_json = yaml.safe_load(stream)
        cfg = Node(cfg_json)
    _C.update(cfg)

    # print global config
    print(_C.pprint())

    train()

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

yacrs-0.0.1.tar.gz (7.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

yacrs-0.0.1-py3-none-any.whl (4.9 kB view details)

Uploaded Python 3

File details

Details for the file yacrs-0.0.1.tar.gz.

File metadata

  • Download URL: yacrs-0.0.1.tar.gz
  • Upload date:
  • Size: 7.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.0.1 CPython/3.11.5

File hashes

Hashes for yacrs-0.0.1.tar.gz
Algorithm Hash digest
SHA256 fa6a57e203f9067bbe4b49d5aa284c220bce4d3f38455999e9010f7410d22188
MD5 ab6b81e26ad2a24be683b22a448b89a1
BLAKE2b-256 3738b78d81051179d74a5d500b35dbc78a75d32e3504390ca86d31df86b96328

See more details on using hashes here.

File details

Details for the file yacrs-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: yacrs-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 4.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.0.1 CPython/3.11.5

File hashes

Hashes for yacrs-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 ca02204360afb4c4a6f9cc36d1674629e864fb7765ed3ccaaff44e7644f27c7d
MD5 c8b168ecefb79fe1e3f308f94d954cf2
BLAKE2b-256 48fe76e498f2ef76bc31e1cec02d1bb0feb6d6c49ecd0d1cab3de4a3d70c3e82

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page