""" $lic$
Copyright (C) 2016-2020 by Tsinghua University and The Board of Trustees of
Stanford University

This program is free software: you can redistribute it and/or modify it under
the terms of the Modified BSD-3 License as published by the Open Source
Initiative.

This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the BSD-3 License for more details.

You should have received a copy of the Modified BSD-3 License along with this
program. If not, see <https://opensource.org/licenses/BSD-3-Clause>.
"""

import unittest

from nn_dataflow.core import Network
from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, \
        PoolingLayer, EltwiseLayer

class TestNetwork(unittest.TestCase):
    ''' Tests for Network. '''
    # pylint: disable=too-many-public-methods

    def setUp(self):
        ''' Set up. '''
        self.network = Network('test_net')
        self.network.set_input_layer(InputLayer(3, 224))
        self.network.add('c1', ConvLayer(3, 64, 224, 3))
        self.network.add('p1', PoolingLayer(64, 7, 32))
        self.network.add('f1', FCLayer(64, 1000, 7))

    def test_set_input_layer(self):
        ''' Modifier set_input_layer. '''
        network = Network('test_net')
        network.set_input_layer(InputLayer(3, 24))
        self.assertIsInstance(network.input_layer(), InputLayer)
        self.assertEqual(network.input_layer().nofm, 3)
        self.assertEqual(network.input_layer().hofm, 24)
        self.assertEqual(network.input_layer().wofm, 24)
        self.assertEqual(len(network), 0)

    def test_set_input_layer_type(self):
        ''' Modifier set_input_layer type. '''
        network = Network('test_net')
        with self.assertRaisesRegex(TypeError, 'Network: .*input_layer.*'):
            network.set_input_layer(Layer(3, 24))
        with self.assertRaisesRegex(TypeError, 'Network: .*input_layer.*'):
            network.set_input_layer(ConvLayer(3, 8, 24, 3))

    def test_set_input_layer_duplicate(self):
        ''' Modifier set_input_layer duplicate. '''
        network = Network('test_net')
        network.set_input_layer(InputLayer(3, 24))
        with self.assertRaisesRegex(KeyError, 'Network: .*input.*'):
            network.set_input_layer(InputLayer(3, 24))

    def test_add(self):
        ''' Modifier add. '''
        self.assertEqual(len(self.network), 3)

        self.network.add('f2', FCLayer(64, 2000, 7), prevs='p1')
        self.network.add('f3', FCLayer(3000, 1000), prevs=('f1', 'f2'))
        self.network.add('e4', EltwiseLayer(1000, 1, 2), prevs=('f1', 'f3'))
        self.network.add('f4', FCLayer(1000, 1000), prevs='e4')
        self.assertEqual(len(self.network), 7)

    def test_add_same_key(self):
        ''' Modifier add same key. '''
        network = Network('test_net')
        network.set_input_layer(InputLayer(3, 224))

        network.add('c1', ConvLayer(3, 64, 224, 3))
        with self.assertRaisesRegex(KeyError, 'Network: .*c1.*'):
            network.add('c1', ConvLayer(64, 128, 224, 3))

    def test_add_no_input(self):
        ''' Modifier add no input. '''
        network = Network('test_net')

        with self.assertRaisesRegex(RuntimeError, 'Network: .*input.*'):
            network.add('c1', ConvLayer(3, 64, 224, 3))

    def test_add_no_prev(self):
        ''' Modifier add no prevs. '''
        network = Network('test_net')
        network.set_input_layer(InputLayer(3, 224))

        network.add('c1', ConvLayer(3, 64, 224, 3))
        with self.assertRaisesRegex(KeyError, 'Network: .*prev.*p1.*'):
            network.add('p1', PoolingLayer(64, 7, 32), prevs='p1')

    def test_add_invalid_type(self):
        ''' Modifier add invalid type. '''
        network = Network('test_net')
        network.set_input_layer(InputLayer(3, 224))

        with self.assertRaisesRegex(TypeError, 'Network: .*Layer.*'):
            network.add('c1', (3, 64, 224, 3))

    def test_add_unmatch_prev(self):
        ''' Modifier add unmatch prevs. '''
        network = Network('test_net')
        network.set_input_layer(InputLayer(3, 224))
        network.add('c1', ConvLayer(3, 64, 224, 3))

        with self.assertRaisesRegex(ValueError,
                                    'Network: .*c1.*p1.*mismatch fmap.*'):
            network.add('p1', PoolingLayer(64, 7, 2))
        self.assertEqual(len(network), 1)
        with self.assertRaisesRegex(ValueError,
                                    'Network: .*c1.*c2.*mismatch fmap.*'):
            network.add('c2', ConvLayer(64, 128, 220, 3))
        self.assertEqual(len(network), 1)

        with self.assertRaisesRegex(ValueError, 'Network: .*c1.*prev.*p1.*'):
            network.add('p1', PoolingLayer(32, 7, 32))
        self.assertEqual(len(network), 1)
        with self.assertRaisesRegex(ValueError, 'Network: .*c1.*prev.*c2.*'):
            network.add('c2', ConvLayer(32, 128, 224, 3))
        self.assertEqual(len(network), 1)

        network.add('c2', ConvLayer(64, 128, 224, 3))

        with self.assertRaisesRegex(ValueError,
                                    r'Network: .*c1 | c2.*prev.*p1.*'):
            network.add('p1', PoolingLayer(128, 7, 32), prevs=('c1', 'c2'))
        self.assertEqual(len(network), 2)

    def test_add_ext(self):
        ''' Modifier add_ext. '''
        self.assertEqual(len(self.network), 3)

        self.network.add_ext('e0', InputLayer(3, 24))
        self.assertIsInstance(self.network['e0'], InputLayer)
        self.assertEqual(self.network['e0'].nofm, 3)
        self.assertEqual(self.network['e0'].hofm, 24)
        self.assertEqual(self.network['e0'].wofm, 24)

        self.network.add_ext('e1', InputLayer(5, (16, 20)))
        self.assertIsInstance(self.network['e1'], InputLayer)
        self.assertEqual(self.network['e1'].nofm, 5)
        self.assertEqual(self.network['e1'].hofm, 16)
        self.assertEqual(self.network['e1'].wofm, 20)

        self.assertEqual(len(self.network), 3)

    def test_add_ext_same_key(self):
        ''' Modifier add_ext same key. '''
        network = Network('test_net')

        network.add_ext('e0', InputLayer(3, 24))
        with self.assertRaisesRegex(KeyError, 'Network: .*ext.*'):
            network.add_ext('e0', InputLayer(3, 24))

    def test_add_ext_invalid_type(self):
        ''' Modifier add_ext invalid type. '''
        network = Network('test_net')

        with self.assertRaisesRegex(TypeError, 'Network: .*external layer.*'):
            network.add_ext('e0', Layer(3, 24))
        with self.assertRaisesRegex(TypeError, 'Network: .*external layer.*'):
            network.add_ext('e0', ConvLayer(3, 8, 24, 3))

    def test_prevs(self):
        ''' Get prevs. '''
        self.network.add('f2', FCLayer(64, 2000, 7), prevs='p1')
        self.network.add('f3', FCLayer(3000, 1000), prevs=('f1', 'f2'))

        prevs = self.network.prevs('f1')
        self.assertTupleEqual(prevs, ('p1',))

        prevs = self.network.prevs('f2')
        self.assertTupleEqual(prevs, ('p1',))
        prevs = self.network.prevs('f3')
        self.assertTupleEqual(prevs, ('f1', 'f2'))

    def test_prevs_first(self):
        ''' Get prevs first layer. '''
        self.network.add('c2', ConvLayer(3, 3, 224, 1),
                         prevs=self.network.INPUT_LAYER_KEY)

        prevs = self.network.prevs('c1')
        self.assertTupleEqual(prevs, (None,))

        prevs = self.network.prevs('c2')
        self.assertTupleEqual(prevs, (None,))

    def test_prevs_input(self):
        ''' Get prevs input layer. '''
        with self.assertRaisesRegex(ValueError, 'Network: .*input.*'):
            _ = self.network.prevs(self.network.INPUT_LAYER_KEY)

    def test_prevs_ext_next(self):
        ''' Get prevs next layer of an external layer. '''
        self.network.add_ext('e0', InputLayer(3, 224))

        self.network.add('n', ConvLayer(6, 3, 224, 1),
                         prevs=(self.network.INPUT_LAYER_KEY, 'e0'))

        prevs = self.network.prevs('n')
        self.assertTupleEqual(prevs, (None, 'e0'))

    def test_prevs_ext(self):
        ''' Get prevs external layer. '''
        self.network.add_ext('e0', InputLayer(3, 3))
        with self.assertRaisesRegex(ValueError, 'Network: .*ext.*'):
            _ = self.network.prevs('e0')

    def test_nexts(self):
        ''' Get nexts. '''
        self.network.add('f2', FCLayer(64, 2000, 7), prevs='p1')
        self.network.add('f3', FCLayer(3000, 1000), prevs=('f1', 'f2'))
        self.network.add('e4', EltwiseLayer(1000, 1, 2), prevs=('f1', 'f3'))
        self.network.add('f4', FCLayer(1000, 1000), prevs='e4')

        nexts = self.network.nexts('p1')
        self.assertTupleEqual(nexts, ('f1', 'f2'))

        nexts = self.network.nexts('f1')
        self.assertTupleEqual(nexts, ('f3', 'e4'))

        nexts = self.network.nexts('f2')
        self.assertTupleEqual(nexts, ('f3',))

        nexts = self.network.nexts('f3')
        self.assertTupleEqual(nexts, ('e4',))

    def test_nexts_last(self):
        ''' Get nexts first layer. '''
        nexts = self.network.nexts('f1')
        self.assertTupleEqual(nexts, (None,))

        self.network.add('f2', FCLayer(64, 2000, 7), prevs='p1')

        nexts = self.network.nexts('f1')
        self.assertTupleEqual(nexts, (None,))
        nexts = self.network.nexts('f2')
        self.assertTupleEqual(nexts, (None,))

    def test_nexts_input(self):
        ''' Get nexts input layer. '''
        nexts = self.network.nexts(self.network.INPUT_LAYER_KEY)
        self.assertTupleEqual(nexts, ('c1',))

        self.network.add('c2', ConvLayer(3, 3, 224, 1),
                         prevs=self.network.INPUT_LAYER_KEY)
        self.network.add('c3', ConvLayer(6, 4, 224, 1),
                         prevs=(self.network.INPUT_LAYER_KEY, 'c2'))
        nexts = self.network.nexts(self.network.INPUT_LAYER_KEY)
        self.assertTupleEqual(nexts, ('c1', 'c2', 'c3'))

    def test_firsts(self):
        ''' Get firsts. '''
        firsts = self.network.firsts()
        self.assertTupleEqual(firsts, ('c1',))

        self.network.add('c2', ConvLayer(3, 3, 224, 1),
                         prevs=self.network.INPUT_LAYER_KEY)
        self.network.add('c3', ConvLayer(6, 4, 224, 1),
                         prevs=(self.network.INPUT_LAYER_KEY, 'c2'))

        firsts = self.network.firsts()
        self.assertTupleEqual(firsts, ('c1', 'c2'))
        self.assertIn('c1', firsts)
        self.assertNotIn('c3', firsts)

    def test_firsts_ext(self):
        ''' Get firsts with external layers. '''
        self.network.add_ext('e0', InputLayer(3, 224))

        self.network.add('c2', ConvLayer(3, 3, 224, 1), prevs=('e0',))
        self.network.add('c3', ConvLayer(67, 3, 224, 1), prevs=('e0', 'c1'))
        self.network.add('c4', ConvLayer(6, 3, 224, 1),
                         prevs=(self.network.INPUT_LAYER_KEY, 'e0',))

        firsts = self.network.firsts()
        self.assertIn('c2', firsts)
        self.assertNotIn('c3', firsts)
        self.assertIn('c4', firsts)

    def test_lasts(self):
        ''' Get lasts. '''
        lasts = self.network.lasts()
        self.assertTupleEqual(lasts, ('f1',))

        self.network.add('f2', FCLayer(64, 2000, 7), prevs='p1')

        lasts = self.network.lasts()
        self.assertTupleEqual(lasts, ('f1', 'f2'))

    def test_ext_layers(self):
        ''' Get external layers. '''
        self.assertTupleEqual(self.network.ext_layers(), tuple())

        self.network.add_ext('e0', InputLayer(3, 224))
        self.assertTupleEqual(self.network.ext_layers(), ('e0',))

        self.network.add_ext('e1', InputLayer(3, 224))
        self.assertTupleEqual(self.network.ext_layers(), ('e0', 'e1'))

    def test_contains(self):
        ''' Whether contains. '''
        self.assertIn('c1', self.network)
        self.assertIn('p1', self.network)
        self.assertIn('f1', self.network)
        self.assertNotIn('f2', self.network)

        self.network.add('f2', FCLayer(64, 2000, 7), prevs='p1')
        self.assertIn('f2', self.network)

    def test_len(self):
        ''' Accessor len. '''
        self.assertEqual(len(self.network), 3)

        network = Network('test_net')
        self.assertEqual(len(network), 0)
        network.set_input_layer(InputLayer(3, 224))
        self.assertEqual(len(network), 0)
        network.add('c1', ConvLayer(3, 4, 224, 1))
        self.assertEqual(len(network), 1)

        self.network.add('f2', FCLayer(64, 2000, 7), prevs='p1')
        self.assertEqual(len(self.network), 4)
        self.network.add('f3', FCLayer(3000, 1000), prevs=('f1', 'f2'))
        self.assertEqual(len(self.network), 5)
        self.network.add('e4', EltwiseLayer(1000, 1, 2), prevs=('f1', 'f3'))
        self.assertEqual(len(self.network), 6)
        self.network.add('f4', FCLayer(1000, 1000), prevs='e4')
        self.assertEqual(len(self.network), 7)

    def test_iter(self):
        ''' Accessor iter. '''
        num = 0
        for layer in self.network:
            self.assertIn(layer, self.network)
            self.assertIsInstance(self.network[layer], Layer)
            num += 1
        self.assertEqual(len(self.network), num)

        network = Network('test_net')
        network.set_input_layer(InputLayer(3, 224))
        with self.assertRaises(StopIteration):
            _ = next(iter(network))

    def test_contains_ext(self):
        ''' Whether contains external layer. '''
        self.assertNotIn('e0', self.network)
        self.network.add_ext('e0', InputLayer(3, 224))
        self.assertIn('e0', self.network)

    def test_len_ext(self):
        ''' Accessor len external layer. '''
        self.assertEqual(len(self.network), 3)
        self.network.add_ext('e0', InputLayer(3, 224))
        self.assertEqual(len(self.network), 3)

    def test_iter_ext(self):
        ''' Accessor iter external layer. '''
        self.network.add_ext('e0', InputLayer(3, 224))
        for layer in self.network:
            self.assertNotEqual(layer, 'e0')

    def test_getitem(self):
        ''' Accessor getitem. '''
        self.assertIsInstance(self.network['c1'], ConvLayer)
        self.assertIsInstance(self.network['p1'], PoolingLayer)
        self.assertIsInstance(self.network['f1'], FCLayer)

    def test_getitem_error(self):
        ''' Accessor getitem. '''
        with self.assertRaisesRegex(KeyError, 'Network: .*c2.*'):
            _ = self.network['c2']

    def test_str(self):
        ''' Accessor str. '''
        string = str(self.network)
        for layer in self.network:
            self.assertIn(layer, string)


[((29, 23, 29, 42), 'nn_dataflow.core.Network', 'Network', ({(29, 31, 29, 41): '"""test_net"""'}, {}), "('test_net')", False, 'from nn_dataflow.core import Network\n'), ((37, 18, 37, 37), 'nn_dataflow.core.Network', 'Network', ({(37, 26, 37, 36): '"""test_net"""'}, {}), "('test_net')", False, 'from nn_dataflow.core import Network\n'), ((47, 18, 47, 37), 'nn_dataflow.core.Network', 'Network', ({(47, 26, 47, 36): '"""test_net"""'}, {}), "('test_net')", False, 'from nn_dataflow.core import Network\n'), ((55, 18, 55, 37), 'nn_dataflow.core.Network', 'Network', ({(55, 26, 55, 36): '"""test_net"""'}, {}), "('test_net')", False, 'from nn_dataflow.core import Network\n'), ((72, 18, 72, 37), 'nn_dataflow.core.Network', 'Network', ({(72, 26, 72, 36): '"""test_net"""'}, {}), "('test_net')", False, 'from nn_dataflow.core import Network\n'), ((81, 18, 81, 37), 'nn_dataflow.core.Network', 'Network', ({(81, 26, 81, 36): '"""test_net"""'}, {}), "('test_net')", False, 'from nn_dataflow.core import Network\n'), ((88, 18, 88, 37), 'nn_dataflow.core.Network', 'Network', ({(88, 26, 88, 36): '"""test_net"""'}, {}), "('test_net')", False, 'from nn_dataflow.core import Network\n'), ((97, 18, 97, 37), 'nn_dataflow.core.Network', 'Network', ({(97, 26, 97, 36): '"""test_net"""'}, {}), "('test_net')", False, 'from nn_dataflow.core import Network\n'), ((105, 18, 105, 37), 'nn_dataflow.core.Network', 'Network', ({(105, 26, 105, 36): '"""test_net"""'}, {}), "('test_net')", False, 'from nn_dataflow.core import Network\n'), ((152, 18, 152, 37), 'nn_dataflow.core.Network', 'Network', ({(152, 26, 152, 36): '"""test_net"""'}, {}), "('test_net')", False, 'from nn_dataflow.core import Network\n'), ((160, 18, 160, 37), 'nn_dataflow.core.Network', 'Network', ({(160, 26, 160, 36): '"""test_net"""'}, {}), "('test_net')", False, 'from nn_dataflow.core import Network\n'), ((318, 18, 318, 37), 'nn_dataflow.core.Network', 'Network', ({(318, 26, 318, 36): '"""test_net"""'}, {}), "('test_net')", False, 'from nn_dataflow.core import Network\n'), ((343, 18, 343, 37), 'nn_dataflow.core.Network', 'Network', ({(343, 26, 343, 36): '"""test_net"""'}, {}), "('test_net')", False, 'from nn_dataflow.core import Network\n'), ((30, 37, 30, 55), 'nn_dataflow.core.InputLayer', 'InputLayer', ({(30, 48, 30, 49): '(3)', (30, 51, 30, 54): '(224)'}, {}), '(3, 224)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((31, 31, 31, 55), 'nn_dataflow.core.ConvLayer', 'ConvLayer', ({(31, 41, 31, 42): '(3)', (31, 44, 31, 46): '(64)', (31, 48, 31, 51): '(224)', (31, 53, 31, 54): '(3)'}, {}), '(3, 64, 224, 3)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((32, 31, 32, 54), 'nn_dataflow.core.PoolingLayer', 'PoolingLayer', ({(32, 44, 32, 46): '(64)', (32, 48, 32, 49): '(7)', (32, 51, 32, 53): '(32)'}, {}), '(64, 7, 32)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((33, 31, 33, 51), 'nn_dataflow.core.FCLayer', 'FCLayer', ({(33, 39, 33, 41): '(64)', (33, 43, 33, 47): '(1000)', (33, 49, 33, 50): '(7)'}, {}), '(64, 1000, 7)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((38, 32, 38, 49), 'nn_dataflow.core.InputLayer', 'InputLayer', ({(38, 43, 38, 44): '(3)', (38, 46, 38, 48): '(24)'}, {}), '(3, 24)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((56, 32, 56, 49), 'nn_dataflow.core.InputLayer', 'InputLayer', ({(56, 43, 56, 44): '(3)', (56, 46, 56, 48): '(24)'}, {}), '(3, 24)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((64, 31, 64, 51), 'nn_dataflow.core.FCLayer', 'FCLayer', ({(64, 39, 64, 41): '(64)', (64, 43, 64, 47): '(2000)', (64, 49, 64, 50): '(7)'}, {}), '(64, 2000, 7)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((65, 31, 65, 50), 'nn_dataflow.core.FCLayer', 'FCLayer', ({(65, 39, 65, 43): '(3000)', (65, 45, 65, 49): '(1000)'}, {}), '(3000, 1000)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((66, 31, 66, 55), 'nn_dataflow.core.EltwiseLayer', 'EltwiseLayer', ({(66, 44, 66, 48): '(1000)', (66, 50, 66, 51): '(1)', (66, 53, 66, 54): '(2)'}, {}), '(1000, 1, 2)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((67, 31, 67, 50), 'nn_dataflow.core.FCLayer', 'FCLayer', ({(67, 39, 67, 43): '(1000)', (67, 45, 67, 49): '(1000)'}, {}), '(1000, 1000)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((73, 32, 73, 50), 'nn_dataflow.core.InputLayer', 'InputLayer', ({(73, 43, 73, 44): '(3)', (73, 46, 73, 49): '(224)'}, {}), '(3, 224)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((75, 26, 75, 50), 'nn_dataflow.core.ConvLayer', 'ConvLayer', ({(75, 36, 75, 37): '(3)', (75, 39, 75, 41): '(64)', (75, 43, 75, 46): '(224)', (75, 48, 75, 49): '(3)'}, {}), '(3, 64, 224, 3)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((89, 32, 89, 50), 'nn_dataflow.core.InputLayer', 'InputLayer', ({(89, 43, 89, 44): '(3)', (89, 46, 89, 49): '(224)'}, {}), '(3, 224)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((91, 26, 91, 50), 'nn_dataflow.core.ConvLayer', 'ConvLayer', ({(91, 36, 91, 37): '(3)', (91, 39, 91, 41): '(64)', (91, 43, 91, 46): '(224)', (91, 48, 91, 49): '(3)'}, {}), '(3, 64, 224, 3)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((98, 32, 98, 50), 'nn_dataflow.core.InputLayer', 'InputLayer', ({(98, 43, 98, 44): '(3)', (98, 46, 98, 49): '(224)'}, {}), '(3, 224)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((106, 32, 106, 50), 'nn_dataflow.core.InputLayer', 'InputLayer', ({(106, 43, 106, 44): '(3)', (106, 46, 106, 49): '(224)'}, {}), '(3, 224)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((107, 26, 107, 50), 'nn_dataflow.core.ConvLayer', 'ConvLayer', ({(107, 36, 107, 37): '(3)', (107, 39, 107, 41): '(64)', (107, 43, 107, 46): '(224)', (107, 48, 107, 49): '(3)'}, {}), '(3, 64, 224, 3)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((125, 26, 125, 52), 'nn_dataflow.core.ConvLayer', 'ConvLayer', ({(125, 36, 125, 38): '(64)', (125, 40, 125, 43): '(128)', (125, 45, 125, 48): '(224)', (125, 50, 125, 51): '(3)'}, {}), '(64, 128, 224, 3)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((136, 35, 136, 52), 'nn_dataflow.core.InputLayer', 'InputLayer', ({(136, 46, 136, 47): '(3)', (136, 49, 136, 51): '(24)'}, {}), '(3, 24)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((142, 35, 142, 58), 'nn_dataflow.core.InputLayer', 'InputLayer', ({(142, 46, 142, 47): '(5)', (142, 49, 142, 57): '(16, 20)'}, {}), '(5, (16, 20))', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((154, 30, 154, 47), 'nn_dataflow.core.InputLayer', 'InputLayer', ({(154, 41, 154, 42): '(3)', (154, 44, 154, 46): '(24)'}, {}), '(3, 24)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((169, 31, 169, 51), 'nn_dataflow.core.FCLayer', 'FCLayer', ({(169, 39, 169, 41): '(64)', (169, 43, 169, 47): '(2000)', (169, 49, 169, 50): '(7)'}, {}), '(64, 2000, 7)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((170, 31, 170, 50), 'nn_dataflow.core.FCLayer', 'FCLayer', ({(170, 39, 170, 43): '(3000)', (170, 45, 170, 49): '(1000)'}, {}), '(3000, 1000)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((182, 31, 182, 54), 'nn_dataflow.core.ConvLayer', 'ConvLayer', ({(182, 41, 182, 42): '(3)', (182, 44, 182, 45): '(3)', (182, 47, 182, 50): '(224)', (182, 52, 182, 53): '(1)'}, {}), '(3, 3, 224, 1)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((198, 35, 198, 53), 'nn_dataflow.core.InputLayer', 'InputLayer', ({(198, 46, 198, 47): '(3)', (198, 49, 198, 52): '(224)'}, {}), '(3, 224)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((200, 30, 200, 53), 'nn_dataflow.core.ConvLayer', 'ConvLayer', ({(200, 40, 200, 41): '(6)', (200, 43, 200, 44): '(3)', (200, 46, 200, 49): '(224)', (200, 51, 200, 52): '(1)'}, {}), '(6, 3, 224, 1)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((208, 35, 208, 51), 'nn_dataflow.core.InputLayer', 'InputLayer', ({(208, 46, 208, 47): '(3)', (208, 49, 208, 50): '(3)'}, {}), '(3, 3)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((214, 31, 214, 51), 'nn_dataflow.core.FCLayer', 'FCLayer', ({(214, 39, 214, 41): '(64)', (214, 43, 214, 47): '(2000)', (214, 49, 214, 50): '(7)'}, {}), '(64, 2000, 7)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((215, 31, 215, 50), 'nn_dataflow.core.FCLayer', 'FCLayer', ({(215, 39, 215, 43): '(3000)', (215, 45, 215, 49): '(1000)'}, {}), '(3000, 1000)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((216, 31, 216, 55), 'nn_dataflow.core.EltwiseLayer', 'EltwiseLayer', ({(216, 44, 216, 48): '(1000)', (216, 50, 216, 51): '(1)', (216, 53, 216, 54): '(2)'}, {}), '(1000, 1, 2)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((217, 31, 217, 50), 'nn_dataflow.core.FCLayer', 'FCLayer', ({(217, 39, 217, 43): '(1000)', (217, 45, 217, 49): '(1000)'}, {}), '(1000, 1000)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((236, 31, 236, 51), 'nn_dataflow.core.FCLayer', 'FCLayer', ({(236, 39, 236, 41): '(64)', (236, 43, 236, 47): '(2000)', (236, 49, 236, 50): '(7)'}, {}), '(64, 2000, 7)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((248, 31, 248, 54), 'nn_dataflow.core.ConvLayer', 'ConvLayer', ({(248, 41, 248, 42): '(3)', (248, 44, 248, 45): '(3)', (248, 47, 248, 50): '(224)', (248, 52, 248, 53): '(1)'}, {}), '(3, 3, 224, 1)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((250, 31, 250, 54), 'nn_dataflow.core.ConvLayer', 'ConvLayer', ({(250, 41, 250, 42): '(6)', (250, 44, 250, 45): '(4)', (250, 47, 250, 50): '(224)', (250, 52, 250, 53): '(1)'}, {}), '(6, 4, 224, 1)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((260, 31, 260, 54), 'nn_dataflow.core.ConvLayer', 'ConvLayer', ({(260, 41, 260, 42): '(3)', (260, 44, 260, 45): '(3)', (260, 47, 260, 50): '(224)', (260, 52, 260, 53): '(1)'}, {}), '(3, 3, 224, 1)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((262, 31, 262, 54), 'nn_dataflow.core.ConvLayer', 'ConvLayer', ({(262, 41, 262, 42): '(6)', (262, 44, 262, 45): '(4)', (262, 47, 262, 50): '(224)', (262, 52, 262, 53): '(1)'}, {}), '(6, 4, 224, 1)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((272, 35, 272, 53), 'nn_dataflow.core.InputLayer', 'InputLayer', ({(272, 46, 272, 47): '(3)', (272, 49, 272, 52): '(224)'}, {}), '(3, 224)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((274, 31, 274, 54), 'nn_dataflow.core.ConvLayer', 'ConvLayer', ({(274, 41, 274, 42): '(3)', (274, 44, 274, 45): '(3)', (274, 47, 274, 50): '(224)', (274, 52, 274, 53): '(1)'}, {}), '(3, 3, 224, 1)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((275, 31, 275, 55), 'nn_dataflow.core.ConvLayer', 'ConvLayer', ({(275, 41, 275, 43): '(67)', (275, 45, 275, 46): '(3)', (275, 48, 275, 51): '(224)', (275, 53, 275, 54): '(1)'}, {}), '(67, 3, 224, 1)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((276, 31, 276, 54), 'nn_dataflow.core.ConvLayer', 'ConvLayer', ({(276, 41, 276, 42): '(6)', (276, 44, 276, 45): '(3)', (276, 47, 276, 50): '(224)', (276, 52, 276, 53): '(1)'}, {}), '(6, 3, 224, 1)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((289, 31, 289, 51), 'nn_dataflow.core.FCLayer', 'FCLayer', ({(289, 39, 289, 41): '(64)', (289, 43, 289, 47): '(2000)', (289, 49, 289, 50): '(7)'}, {}), '(64, 2000, 7)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((298, 35, 298, 53), 'nn_dataflow.core.InputLayer', 'InputLayer', ({(298, 46, 298, 47): '(3)', (298, 49, 298, 52): '(224)'}, {}), '(3, 224)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((301, 35, 301, 53), 'nn_dataflow.core.InputLayer', 'InputLayer', ({(301, 46, 301, 47): '(3)', (301, 49, 301, 52): '(224)'}, {}), '(3, 224)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((311, 31, 311, 51), 'nn_dataflow.core.FCLayer', 'FCLayer', ({(311, 39, 311, 41): '(64)', (311, 43, 311, 47): '(2000)', (311, 49, 311, 50): '(7)'}, {}), '(64, 2000, 7)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((320, 32, 320, 50), 'nn_dataflow.core.InputLayer', 'InputLayer', ({(320, 43, 320, 44): '(3)', (320, 46, 320, 49): '(224)'}, {}), '(3, 224)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((322, 26, 322, 49), 'nn_dataflow.core.ConvLayer', 'ConvLayer', ({(322, 36, 322, 37): '(3)', (322, 39, 322, 40): '(4)', (322, 42, 322, 45): '(224)', (322, 47, 322, 48): '(1)'}, {}), '(3, 4, 224, 1)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((325, 31, 325, 51), 'nn_dataflow.core.FCLayer', 'FCLayer', ({(325, 39, 325, 41): '(64)', (325, 43, 325, 47): '(2000)', (325, 49, 325, 50): '(7)'}, {}), '(64, 2000, 7)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((327, 31, 327, 50), 'nn_dataflow.core.FCLayer', 'FCLayer', ({(327, 39, 327, 43): '(3000)', (327, 45, 327, 49): '(1000)'}, {}), '(3000, 1000)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((329, 31, 329, 55), 'nn_dataflow.core.EltwiseLayer', 'EltwiseLayer', ({(329, 44, 329, 48): '(1000)', (329, 50, 329, 51): '(1)', (329, 53, 329, 54): '(2)'}, {}), '(1000, 1, 2)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((331, 31, 331, 50), 'nn_dataflow.core.FCLayer', 'FCLayer', ({(331, 39, 331, 43): '(1000)', (331, 45, 331, 49): '(1000)'}, {}), '(1000, 1000)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((344, 32, 344, 50), 'nn_dataflow.core.InputLayer', 'InputLayer', ({(344, 43, 344, 44): '(3)', (344, 46, 344, 49): '(224)'}, {}), '(3, 224)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((351, 35, 351, 53), 'nn_dataflow.core.InputLayer', 'InputLayer', ({(351, 46, 351, 47): '(3)', (351, 49, 351, 52): '(224)'}, {}), '(3, 224)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((357, 35, 357, 53), 'nn_dataflow.core.InputLayer', 'InputLayer', ({(357, 46, 357, 47): '(3)', (357, 49, 357, 52): '(224)'}, {}), '(3, 224)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((362, 35, 362, 53), 'nn_dataflow.core.InputLayer', 'InputLayer', ({(362, 46, 362, 47): '(3)', (362, 49, 362, 52): '(224)'}, {}), '(3, 224)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((49, 36, 49, 48), 'nn_dataflow.core.Layer', 'Layer', ({(49, 42, 49, 43): '(3)', (49, 45, 49, 47): '(24)'}, {}), '(3, 24)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((51, 36, 51, 58), 'nn_dataflow.core.ConvLayer', 'ConvLayer', ({(51, 46, 51, 47): '(3)', (51, 49, 51, 50): '(8)', (51, 52, 51, 54): '(24)', (51, 56, 51, 57): '(3)'}, {}), '(3, 8, 24, 3)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((58, 36, 58, 53), 'nn_dataflow.core.InputLayer', 'InputLayer', ({(58, 47, 58, 48): '(3)', (58, 50, 58, 52): '(24)'}, {}), '(3, 24)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((77, 30, 77, 56), 'nn_dataflow.core.ConvLayer', 'ConvLayer', ({(77, 40, 77, 42): '(64)', (77, 44, 77, 47): '(128)', (77, 49, 77, 52): '(224)', (77, 54, 77, 55): '(3)'}, {}), '(64, 128, 224, 3)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((84, 30, 84, 54), 'nn_dataflow.core.ConvLayer', 'ConvLayer', ({(84, 40, 84, 41): '(3)', (84, 43, 84, 45): '(64)', (84, 47, 84, 50): '(224)', (84, 52, 84, 53): '(3)'}, {}), '(3, 64, 224, 3)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((93, 30, 93, 53), 'nn_dataflow.core.PoolingLayer', 'PoolingLayer', ({(93, 43, 93, 45): '(64)', (93, 47, 93, 48): '(7)', (93, 50, 93, 52): '(32)'}, {}), '(64, 7, 32)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((111, 30, 111, 52), 'nn_dataflow.core.PoolingLayer', 'PoolingLayer', ({(111, 43, 111, 45): '(64)', (111, 47, 111, 48): '(7)', (111, 50, 111, 51): '(2)'}, {}), '(64, 7, 2)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((115, 30, 115, 56), 'nn_dataflow.core.ConvLayer', 'ConvLayer', ({(115, 40, 115, 42): '(64)', (115, 44, 115, 47): '(128)', (115, 49, 115, 52): '(220)', (115, 54, 115, 55): '(3)'}, {}), '(64, 128, 220, 3)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((119, 30, 119, 53), 'nn_dataflow.core.PoolingLayer', 'PoolingLayer', ({(119, 43, 119, 45): '(32)', (119, 47, 119, 48): '(7)', (119, 50, 119, 52): '(32)'}, {}), '(32, 7, 32)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((122, 30, 122, 56), 'nn_dataflow.core.ConvLayer', 'ConvLayer', ({(122, 40, 122, 42): '(32)', (122, 44, 122, 47): '(128)', (122, 49, 122, 52): '(224)', (122, 54, 122, 55): '(3)'}, {}), '(32, 128, 224, 3)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((129, 30, 129, 54), 'nn_dataflow.core.PoolingLayer', 'PoolingLayer', ({(129, 43, 129, 46): '(128)', (129, 48, 129, 49): '(7)', (129, 51, 129, 53): '(32)'}, {}), '(128, 7, 32)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((156, 34, 156, 51), 'nn_dataflow.core.InputLayer', 'InputLayer', ({(156, 45, 156, 46): '(3)', (156, 48, 156, 50): '(24)'}, {}), '(3, 24)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((163, 34, 163, 46), 'nn_dataflow.core.Layer', 'Layer', ({(163, 40, 163, 41): '(3)', (163, 43, 163, 45): '(24)'}, {}), '(3, 24)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n'), ((165, 34, 165, 56), 'nn_dataflow.core.ConvLayer', 'ConvLayer', ({(165, 44, 165, 45): '(3)', (165, 47, 165, 48): '(8)', (165, 50, 165, 52): '(24)', (165, 54, 165, 55): '(3)'}, {}), '(3, 8, 24, 3)', False, 'from nn_dataflow.core import Layer, InputLayer, ConvLayer, FCLayer, PoolingLayer, EltwiseLayer\n')]