in Darknet Computer Vision PyTorch ~ read.

cvgear, inauguration

cvgear 0.1.0 was released on 20 May, 2020.

CVGear means Computer Vision Gear. It is under MIT License and contains computer vision gears for good uses.

TorchNestedLoader

TorchNestedLoader allows you to save/load between different modules with actually the same logic structure.

Suppose we have a SimpleNet:

import torch.nn as nn

class SimpleNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(
            in_channels=3,
            out_channels=32,
            kernel_size=3,
            stride=1,
            padding=1,
            bias=False
        )
        self.bn1 = nn.BatchNorm2d(32)
        self.conv2 = nn.Conv2d(
            in_channels=32,
            out_channels=32,
            kernel_size=3,
            stride=1,
            padding=1,
            bias=False
        )
        self.bn2 = nn.BatchNorm2d(32)
        
    def forward(self, x):
        x = self.conv1(x)
        x = self.bn1(x)
        x = self.conv2(x)
        x = self.bn2(x)
        return x

simplenet = SimpleNet()

The structure of SimpleNet is:

SimpleNet(
  (conv1): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
  (bn1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (conv2): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
  (bn2): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)

And we have a more "wrapped" version WrappedSimpleNet:

import torch.nn as nn

class Conv2d(torch.nn.Conv2d):
    def __init__(self, *args, **kwargs):
        norm = kwargs.pop("norm", None)
        super().__init__(*args, **kwargs)
        self.norm = norm
	
    def forward(self, x):
        x = super().forward(x)
        if self.norm is not None:
            x = self.norm(x)
        return x

class WrappedSimpleNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.stem = Conv2d(
            in_channels=3,
            out_channels=32,
            kernel_size=3,
            stride=1,
            padding=1,
            bias=False,
            norm=nn.BatchNorm2d(32)
        )
        self.conv1 = Conv2d(
            in_channels=32,
            out_channels=32,
            kernel_size=3,
            stride=1,
            padding=1,
            bias=False,
            norm=nn.BatchNorm2d(32)
        )
	
    def forward(self, x):
        x = self.stem(x)
        x = self.conv1(x)
        return x
    
wrappedsimplenet = WrappedSimpleNet()

The structure of WrappedSimpleNet is:

WrappedSimpleNet(
  (stem): Conv2d(
    3, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False
    (norm): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  )
  (conv1): Conv2d(
    32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False
    (norm): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  )
)

The logic structure of SimpleNet and WrappedSimpleNet is exactly the same. But they differ from submodule names and tree structure. So you cannot save/load state_dict between these two modules using .state_dict() and .load_state_dict() methods easily.

But with TorchNestedLoader, you can save/load nested_dict between these two modules easily:

from cvgear.framework.torch import TorchNestedLoader

simplenetloader = TorchNestedLoader(simplenet)
wrappedsimplenetloader = TorchNestedLoader(wrappedsimplenet)

# save as nested_dict
nested_dict = simplenetloader.nested_dict()
# load nested_dict
wrappedsimplenetloader.load_nested_dict(nested_dict)

Imagine you just implement one state-of-the-art model in torch and want to test it. Train your model from scratch will be time-consuming. After downloading pre-trained model from the Internet then found it painful to load it to your model manually?

Use TorchNestedLoader as your gear!

DarknetParser

Everyone loves darknet. It is very fast and in public domain.

The configuration file of the darknet network is often long and tedious(due to its sequential structure), hard to read through. With darknet installed, the network configuration file can be parsed easily and you can get a clear sense of what the network structure is from the information it displayed.

Without darknet installed:

from cvgear.framework.darknet import DarknetParser, build_darknet_parser

# create a DarknetParser instance, then load network configuration
darknet53 = DarknetParser("darknet53")
darknet53.load_darknet_cfg("path/to/darknet53.cfg")
# or build a DarknetParser from network configuration file directly
darknet53 = build_darknet_parser("path/to/darknet53.cfg")

print(darknet53)

Crystal clear!

cvgear_inauguration_darknet53-2
parse darknet network with DarknetParser 

DarknetNestedLoader

Save/load torch module...

Parse darknet network...

What about... Save/load darknet network?

Even more! Save/load between darknet network and torch.nn.Module ! DarknetNestedLoader is made for save/load darknet network(DarknetParser) as binary weights(.weights file) or as nested_dict.

from cvgear.framework.darknet import DarknetNestedLoader, build_darknet_nested_loader

# create a DarknetNestedLoader instance with DarknetParser, then load from binary weights file
darknet53loader = DarknetNestedLoader(darknet53)
darknet53loader.load_darknet_weights("path/to/darknet53.weights")
# or build a DarknetNestedLoader from network configuration file and binary weights file
darknet53loader = build_darknet_nested_loader("path/to/darknet53.cfg", "path/to/darknet53.weights")

# save weights to nested_dict
nested_dict = darknet53loader.nested_dict()

# load nested_dict to a torch.nn.Module with TorchNestedLoader
# ...

Recap

save/load between darknet and torch models as nested_dict
  1. DarknetParser describes a darknet network(as torch.nn.Module describes a torch module)
  2. DarknetNestedLoader can save/load a darknet network as nested_dict or binary file
  3. TorchNestedLoader can save/load a torch module as nested_dict
  4. So with DarknetNestedLoader and TorchNestedLoader, you can convert between darknet weights and torch weights easily.

That is little cvgear 0.1.0
More gears are coming up...
Happy inauguration!🎉🎉🎉