or explicitly specify ``PrimaryFields
[Transforms.RandomPaddingCrop]
crop_size = [1024, 512]
It can even be undefined when there are no arguments
[Normalize]
</details>
<details>
<summary> :sparkles:Auto-complement, type-hinting, docstring and code navigation for config files </summary>
The old-style design of plain text configs has been criticized for being difficult to write (without auto-completion) and not allowing navigation to the corresponding class. However, Language Server Protocol can be leveraged to support various code editing features, such as auto-completion, type-hinting, and code navigation. By utilizing lsp and json schema, it's able to provide the ability of auto-completion, some weak type-hinting (If code is well annotated, such as standard type hint in python, it will acheive more) and docstring of corresponding class.
![](https://user-images.githubusercontent.com/72954905/267884541-56e75031-48a2-4768-8a6c-fc7b83ed977e.gif)
![config](https://github.com/Asthestarsfalll/ExCore/assets/72954905/2b0e151c-5c2b-4082-9796-d171e211c7c8)
`ExCore` dump the mappings of class name and it file location to support code navigation. Currently only support for neovim, see [excore.nvim](https://github.com/Asthestarsfalll/excore.nvim).
![to_class](https://github.com/Asthestarsfalll/ExCore/assets/72954905/9677c204-eb46-4cf3-a8bf-03f9bee8d6fb)
</details>
<details>
<summary>Config inheritance</summary>
Use `__base__` to inherit from a toml file. Only dict can be updated locally, other types are overwritten directly.
toml
__base__ = ["xxx.toml", "xxxx.toml"]
</details>
<details>
<summary>``Reused module</summary>
`ExCore` use `` to mark the reused module, which is shared between different modules.
toml
FCN and SegNet will use the same ResNet object
[Model.FCN]
backbone = "ResNet"
[Model.SegNet]
backbone = "ResNet"
[ResNet]
layers = 50
in_channel = 3
equls to
python
resnet = ResNet(layers=50, in_channel=3)
FCN(backbone=resnet)
SegNet(backbone=resnet)
If use `!`, it equls to
FCN(backbone=ResNet(layers=50, in_channel=3))
SegNet(backbone=ResNet(layers=50, in_channel=3))
</details>
<details>
<summary>`$`Refer Class and cross file</summary>
`ExCore` use `$` to represents class itself, which will not be instantiated.
toml
[Model.ResNet]
$block = "BasicBlock"
layers = 50
in_channel = 3
equls to
python
from xxx import ResNet, BasicBlock
ResNet(block=BasicBlock, layers=50, in_channel=3)
In order to refer module accross files, `$` can be used before `PrimaryFields`. For example:
File A:
toml
[Block.BasicBlock]
File B:
toml
[Block.BottleneckBlock]
File C:
toml
[Model.ResNet]
!block="$Block"
So we can combine file A and C or file B and C with a toml file
toml
__base__ = ["A.toml", "C.toml"]
or
__base__ = ["B.toml", "C.toml"]
</details>
<details>
<summary>`&`Variable reference</summary>
`ExCore` use `&` to refer a variable from the top-level of config.
**Note: The value may be overwritten when inheriting, so the call it variable.**
toml
size = 224
[TrainData.ImageNet]
&train_size = "size"
!transforms = ['RandomResize', 'Pad']
data_path = 'xxx'
[Transform.Pad]
&pad_size = "size"
[TestData.ImageNet]
!transforms = ['Normalize']
&test_size = "size"
data_path = 'xxx'
</details>
<details>
<summary>:sparkles:Using python module in config file</summary>
The `Registry` in `ExCore` is able to register a module:
python
from excore import Registry
import torch
MODULE = Registry("module")
MODULE.register_module(torch)
Then you can use torch in config file:
toml
[Model.ResNet]
$activation = "torch.nn.ReLU"
or
!activation = "torch.nn.ReLU"
python
import torch
from xxx import ResNet
ResNet(torch.nn.ReLU)
or
ResNet(torch.nn.ReLU())
**Note: You shouldn't define arguments of a module.**
</details>
<details>
<summary>:sparkles:Argument-level hook</summary>
`ExCore` provide a simple way to call argument-level hooks without arguments.
toml
[Optimizer.AdamW]
params = "$Model.parameters()"