Any tutorial for Gluon models?

I want to modify the architecture of a pretrained model (e.g. Densenet121) but I don’t know how to do it. I would like to replace the output to contain 2 parallel fully connected layer like this:

Densenet ----------(FC: 1024) — (FC: 1)–>
|____(FC: 1024) __ (FC: 1) _>

How can I do that? I cannot find an example.

Take a look at this tutorial.

@safrooze Thanks for the reply. This example is exactly what I have been following but I would like to do more advanced stuff like slicing and adding multiple paths of fully-connected layers but I cannot seem to find examples.

Let’s take gluon.model_zoo.vision.Resnet_V2 as an example. You can create your own Block (or HybridBlock) with a dummy feature and whatever type of advanced output you need followed by that. Then after initializing your block’s parameters, simply load the pre-trained network from model-zoo and replace your networks’s feature with the pretrained net’s feature. Just remember that if you want to train end-to-end, parameters that are passed to Trainer must be fetched after pre-trained feature is added to your network:

class MyAdvancedNet(gluon.HybridBlock):
    def __init__(self):
        super(MyAdvancedNet, self).__init__()
        with self.name_scope():
            self.feature = None
            self.output = gluon.nn.Dense(10)

    def hybrid_forward(self, F, x):
        return self.output(self.feature(x))

net = MyAdvancedNet()
net.collect_params().initialize()
pretrained_net = gluon.model_zoo.vision.resnet34_v2(pretrained=True)
net.feature = pretrained_net.features

y = net(nd.random.uniform(shape=(16, 3, 224, 224)))
print(y.shape)
1 Like

@safrooze Thank you for the reply. It is extremely helpful. I have trouble though creating a multi-output on Gluon. Basically what I want to do is something like this:

class MyAdvancedNet(gluon.HybridBlock):
    def __init__(self):
        super(MyAdvancedNet, self).__init__()
        with self.name_scope():
            self.feature = None
            self.output1 = gluon.nn.Dense(10)
            self.output1 = gluon.nn.Dense(1)
            self.output2 = gluon.nn.Dense(10)
            self.output2 = gluon.nn.Dense(1)

    def hybrid_forward(self, F, x):
        return self.output1(self.feature(x)),  self.output2(self.feature(x))

So basically output1 connects to the features as well as output2 connects to the features. I am new to Gluon/MxNet (coming from Keras) and I am trying to learn new stuff.

Thanks a lot!

The only thing I see in this code that’s wrong is that you’re re-assigning self.output1 and self.output2 in __init__ method. Other than that, the hybrid_forward() implementation looks fine. What trouble are you having exactly?

1 Like

What I am trying to do is have 2 outputs:

  • Output 1: self.feature -> gluon.nn.Dense(10) -> gluon.nn.Dense(1)
  • Output 2: self.feature -> gluon.nn.Dense(10) -> gluon.nn.Dense(1)

How about:

class MyAdvancedNet(gluon.HybridBlock):
    def __init__(self):
        super(MyAdvancedNet, self).__init__()
        with self.name_scope():

            self.feature = None

            self.output11 = gluon.nn.Dense(10)
            self.output12 = gluon.nn.Dense(1)

            self.output21 = gluon.nn.Dense(10)
            self.output22 = gluon.nn.Dense(1)

    def hybrid_forward(self, F, x):

        featureX = self.feature(x)

        out1 = self.output11(featureX)
        out1 = self.output12(out1)

        out2 = self.output21(featureX)
        out2 = self.output22(out2)


        return out1, out2
1 Like

Hi @feevos Thanks for the input. I will try to give it a spin and let you know if I have any issues. That is what I was going after.

1 Like

A quick comparison with Keras philosophy: in gluon models, you define the layers you are going to use in the __init__ function. Then you combine these layers in the architecture you are after in the hybrid_forward function. Without being an expert in keras, I recall that the definition and usage of the layers (Functional API) was happening at the same point of the code (at least in the examples). However, this is not necessary (e.g. shared layers with the shared_lstm layer where it is first defined, and then used). I am writing this because I noticed in your initial example

class MyAdvancedNet(gluon.HybridBlock):
    def __init__(self):
        super(MyAdvancedNet, self).__init__()
        with self.name_scope():
            self.feature = None
            self.output1 = gluon.nn.Dense(10)
            # This overwrites previous definition of self.output1
            self.output1 = gluon.nn.Dense(1) 
            self.output2 = gluon.nn.Dense(10)
            # This overwrites previous definition of self.output2
            self.output2 = gluon.nn.Dense(1)

    def hybrid_forward(self, F, x):
        return self.output1(self.feature(x)),  self.output2(self.feature(x))

that you tried to define and use the layers (architecture) in the __init__ function.

Also, there are great similarities (lucky us!) between gluon and pytorch. I’ve found great help when I was starting with gluon in looking at examples from pytorch where they use the nn.Module for defining abstract models. The syntax is quite similar. Take a look here.

Hope this helps,
Cheers

Hi @safrooze,

Thanks for this answer, and just trying to riff on this reply.
Here we load a model with 1 class, and the backbone is pretrained
model = gluoncv.model_zoo.DeepLabV3(nclass=1,backbone=‘resnet152’, pretrained_base=True)

Here we load the same model, but it has 21 classes instead, and the backbone, and onwards are all pretrained
p_model = gluoncv.model_zoo.get_deeplab(dataset=‘coco’, backbone=‘resnet152’, pretrained=True)

model.features = p_model.features

Throws the following error

AttributeError: ‘DeepLabV3’ object has no attribute ‘features’

Do you know what would be going wrong here?

Edit: The reason I want to do this, is I want everything after the backbone to be pretrained also, up to but not including the last layer, of course.