Attribute _children

Might be a simple question but what am I doing wrong here?

class My1Net(gluon.HybridBlock):
    def __init__(self, **kwards):
        super(My1Net, self).__init__(**kwards)

        with self.name_scope():
            self.conv1 = gluon.nn.BatchNorm(center=False, scale=False)
            self.conv2 = gluon.nn.Dense(1)

    def hybrid_forward(self, F, x):
        x1 = self.conv1(x)
        x2 = self.conv2(x1)

        return x1, x2

net = My1Net()
net.initialize()

Gives me

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-5-acc66c8e933d> in <module>()
----> 1 net = My1Net()
      2 net.initialize(mx.init.Xavier())

<ipython-input-3-9fa2d34b74dc> in __init__(self, **kwards)
      1 class My1Net(gluon.HybridBlock):
      2     def __init__(self, **kwards):
----> 3         super(My1Net, self).__init__(**kwards)
      4 
      5         with self.name_scope():

~/anaconda3/envs/mxnet_p36/lib/python3.6/site-packages/mxnet/gluon/block.py in __init__(self, prefix, params)
    715     
    716     def __init__(self, prefix=None, params=None):
--> 717         super(HybridBlock, self).__init__(prefix=prefix, params=params)
    718         self._cached_graph = ()
    719         self._cached_op = None

~/anaconda3/envs/mxnet_p36/lib/python3.6/site-packages/mxnet/gluon/block.py in __init__(self, prefix, params)
    172     def __init__(self, prefix=None, params=None):
    173         self._empty_prefix = prefix == ''
--> 174         self._prefix, self._params = _BlockScope.create(prefix, params, self._alias())
    175         self._name = self._prefix[:-1] if self._prefix.endswith('_') else self._prefix
    176         self._scope = _BlockScope(self)

~/anaconda3/envs/mxnet_p36/lib/python3.6/site-packages/mxnet/gluon/block.py in __setattr__(self, name, value)
    725     def __setattr__(self, name, value):
    726         """Registers parameters."""
--> 727         super(HybridBlock, self).__setattr__(name, value)
    728         if isinstance(value, HybridBlock):
    729             self._clear_cached_op()

~/anaconda3/envs/mxnet_p36/lib/python3.6/site-packages/mxnet/gluon/block.py in __setattr__(self, name, value)
    198 
    199         if isinstance(value, Block):
--> 200             self.register_child(value, name)
    201         elif isinstance(value, Parameter):
    202             assert name not in self._reg_params, \

~/anaconda3/envs/mxnet_p36/lib/python3.6/site-packages/mxnet/gluon/block.py in register_child(self, block, name)
    828                 "please try HybridSequential instead."%(
    829                     str(block), str(type(block))))
--> 830         super(HybridBlock, self).register_child(block, name)
    831         self._clear_cached_op()
    832 

~/anaconda3/envs/mxnet_p36/lib/python3.6/site-packages/mxnet/gluon/block.py in register_child(self, block, name)
    427         if name is None:
    428             name = str(len(self._children))
--> 429         self._children[name] = block
    430 
    431     def register_forward_pre_hook(self, hook):

AttributeError: 'My1Net' object has no attribute '_children'

Try returning only x2

That works! but why would that be? It doesnt seem to be intrinsic to Gluon to only return the final output

I don’t see any specific reasons why code above shouldn’t work. You shouldn’t be limited with returning only 1 output. Check your version of MXNet. Maybe you need to upgrade to 1.4.0.

Here is the code using your block which works fine to me:

import mxnet as mx
from gluoncv.loss import SoftmaxCrossEntropyLoss
from mxnet import gluon, autograd
from mxnet.gluon import Trainer
from mxnet.gluon.data import ArrayDataset, DataLoader


class My1Net(gluon.HybridBlock):
    def __init__(self, **kwargs):
        super(My1Net, self).__init__(**kwargs)

        with self.name_scope():
            self.conv1 = gluon.nn.BatchNorm(center=False, scale=False)
            self.conv2 = gluon.nn.Dense(1)

    def hybrid_forward(self, F, x):
        x1 = self.conv1(x)
        x2 = self.conv2(x1)

        return x1, x2


net = My1Net()
net.initialize()

epochs = 10
batch_size = 100
training_data_size = 500
model_ctx = mx.cpu()

data = mx.nd.uniform(shape=(training_data_size, 2))
labels = mx.nd.array([i % 2 for i in range(training_data_size)])
dataset = ArrayDataset(data, labels)
data_loader_train = DataLoader(dataset, shuffle=True, batch_size=batch_size)

loss_fn = SoftmaxCrossEntropyLoss()
trainer = Trainer(net.collect_params(), 'sgd', {'learning_rate': 0.01, 'wd': 0.999})

for e in range(epochs):
    cumulative_loss = 0
    for i, (data, label) in enumerate(data_loader_train):
        data = data.as_in_context(model_ctx)
        label = label.as_in_context(model_ctx)
        with autograd.record():
            out1, out2 = net(data)
            loss = loss_fn(out2, label)
        loss.backward()
        trainer.step(data.shape[0])
        cumulative_loss += mx.nd.sum(loss).asscalar()

    print('Epoch {}: train loss {}'.format(e, cumulative_loss))

3 Likes

Updating fixed the problem!