コード例 #1
0
    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))
コード例 #2
0
    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))
コード例 #3
0
class TestNNDataflowScheme(unittest.TestCase):
    ''' Tests for NNDataflowScheme. '''

    # pylint: disable=too-many-public-methods

    # pylint: disable=too-many-public-methods

    def setUp(self):
        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), prevs='c1')
        self.network.add('p2', PoolingLayer(64, 7, 32), prevs='c1')
        self.network.add('f1', FCLayer(128, 1000, 7), prevs=['p1', 'p2'])

        self.batch_size = 4

        input_layer = self.network.input_layer()
        self.input_layout = DataLayout(
            frngs=(FmapRange((0, 0, 0, 0),
                             FmapPosition(b=self.batch_size,
                                          n=input_layer.nofm,
                                          h=input_layer.hofm,
                                          w=input_layer.wofm)), ),
            regions=(NodeRegion(origin=PhyDim2(0, 0),
                                dim=PhyDim2(2, 1),
                                type=NodeRegion.DRAM), ),
            parts=(PartitionScheme(order=range(pe.NUM),
                                   pdims=[(1, 1)] * pe.NUM), ))

        c1_layer = self.network['c1']
        self.c1res = SchedulingResult(
            scheme=OrderedDict([
                ('cost', 1.5),
                ('time', 200.),
                ('ops', 4.),
                ('num_nodes', 4),
                ('cost_op', 0.5),
                ('cost_access', 1.),
                ('cost_noc', 0),
                ('cost_static', 0),
                ('proc_time', 200),
                ('bus_time', 0),
                ('dram_time', 0),
                ('access', [[7, 8, 9]] * me.NUM),
                ('remote_gbuf_access', [0] * 3),
                ('total_nhops', [4, 5, 6]),
                ('fetch', [[1, 1, 1], [2, 2, 2]]),
                ('ti', [2, 2, 3]),
                ('to', [1, 2, 3]),
                ('tb', [1, 2, 3]),
                ('tvals', [[2, 1, 1], [2, 2, 2], [3, 3, 3]]),
                ('orders', [range(3)] * 2),
            ]),
            ofmap_layout=DataLayout(
                frngs=(FmapRange(
                    (0, 0, 0, 0),
                    FmapPosition(b=self.batch_size,
                                 n=c1_layer.nofm,
                                 h=c1_layer.hofm,
                                 w=c1_layer.wofm)), ),
                regions=(NodeRegion(origin=PhyDim2(0, 0),
                                    dim=PhyDim2(1, 2),
                                    type=NodeRegion.DRAM), ),
                parts=(PartitionScheme(order=range(pe.NUM),
                                       pdims=[(1, 1)] * pe.NUM), )),
            sched_seq=(0, 0, 0))

        p1_layer = self.network['p1']
        self.p1res = SchedulingResult(
            scheme=OrderedDict([
                ('cost', 0.6),
                ('time', 5),
                ('ops', 0.1),
                ('num_nodes', 2),
                ('cost_op', 0.1),
                ('cost_access', 0.5),
                ('cost_noc', 0),
                ('cost_static', 0),
                ('proc_time', 5),
                ('bus_time', 0),
                ('dram_time', 0),
                ('access', [[.7, .8, .9]] * me.NUM),
                ('remote_gbuf_access', [0] * 3),
                ('total_nhops', [.4, .5, .6]),
                ('fetch', [[1, 1, 1], [2, 2, 2]]),
                ('ti', [2, 2, 3]),
                ('to', [1, 2, 3]),
                ('tb', [1, 2, 3]),
                ('tvals', [[2, 1, 1], [2, 2, 2], [3, 3, 3]]),
                ('orders', [range(3)] * 2),
            ]),
            ofmap_layout=DataLayout(
                frngs=(FmapRange(
                    (0, 0, 0, 0),
                    FmapPosition(b=self.batch_size,
                                 n=p1_layer.nofm,
                                 h=p1_layer.hofm,
                                 w=p1_layer.wofm)), ),
                regions=(NodeRegion(origin=PhyDim2(0, 0),
                                    dim=PhyDim2(1, 2),
                                    type=NodeRegion.DRAM), ),
                parts=(PartitionScheme(order=range(pe.NUM),
                                       pdims=[(1, 1)] * pe.NUM), )),
            sched_seq=(0, 1, 0))

        self.p2res = SchedulingResult(scheme=self.p1res.scheme,
                                      ofmap_layout=self.p1res.ofmap_layout,
                                      sched_seq=(0, 2, 0))

        self.dtfl = NNDataflowScheme(self.network, self.input_layout)
        self.dtfl['c1'] = self.c1res
        self.dtfl['p1'] = self.p1res
        self.dtfl['p2'] = self.p2res

    def test_init(self):
        ''' Initial. '''
        df = NNDataflowScheme(self.network, self.input_layout)

        self.assertEqual(df.network, self.network)
        self.assertEqual(df.input_layout, self.input_layout)
        self.assertDictEqual(df.ext_layout_dict, {})

        self.assertEqual(df.total_cost, 0)
        self.assertEqual(df.total_time, 0)
        self.assertFalse(df.res_dict)

        self.assertFalse(df)
        self.assertEqual(df.total_ops, 0)
        self.assertSequenceEqual(df.total_accesses, [0] * me.NUM)
        self.assertEqual(df.total_noc_hops, 0)

    def test_init_ext(self):
        ''' Initial with external layers. '''
        self.network.add_ext('e0', InputLayer(3, 224))
        self.network.add_ext('e1', InputLayer(6, 224))

        e0_layout = DataLayout(frngs=(FmapRange(
            (0, 0, 0, 0),
            FmapPosition(b=self.batch_size,
                         n=self.network['e0'].nofm,
                         h=self.network['e0'].hofm,
                         w=self.network['e0'].wofm)), ),
                               regions=self.input_layout.regions,
                               parts=self.input_layout.parts)
        e1_layout = DataLayout(frngs=(FmapRange(
            (0, 0, 0, 0),
            FmapPosition(b=self.batch_size,
                         n=self.network['e1'].nofm,
                         h=self.network['e1'].hofm,
                         w=self.network['e1'].wofm)), ),
                               regions=self.input_layout.regions,
                               parts=self.input_layout.parts)

        ext_layout_dict = {'e0': e0_layout, 'e1': e1_layout}

        df = NNDataflowScheme(self.network, self.input_layout, ext_layout_dict)

        self.assertIn('e0', df.ext_layout_dict)
        self.assertIn('e1', df.ext_layout_dict)
        self.assertEqual(df.ext_layout_dict['e0'], e0_layout)
        self.assertEqual(df.ext_layout_dict['e1'], e1_layout)

    def test_init_invalid_network(self):
        ''' Invalid network. '''
        with self.assertRaisesRegexp(TypeError,
                                     'NNDataflowScheme: .*network*'):
            _ = NNDataflowScheme(self.network['c1'], self.input_layout)

    def test_init_invalid_input_layout(self):
        ''' Invalid input_layout. '''
        with self.assertRaisesRegexp(TypeError,
                                     'NNDataflowScheme: .*input_layout*'):
            _ = NNDataflowScheme(self.network, self.input_layout.frngs)

    def test_init_invalid_eld_keys(self):
        ''' Invalid ext_layout_dict keys. '''
        with self.assertRaisesRegexp(ValueError,
                                     'NNDataflowScheme: .*ext_layout_dict*'):
            _ = NNDataflowScheme(self.network, self.input_layout,
                                 {'e0': self.input_layout})

        self.network.add_ext('e0', InputLayer(3, 224))
        with self.assertRaisesRegexp(ValueError,
                                     'NNDataflowScheme: .*ext_layout_dict*'):
            _ = NNDataflowScheme(self.network, self.input_layout)

    def test_init_invalid_eld_type(self):
        ''' Invalid ext_layout_dict value type. '''
        self.network.add_ext('e0', InputLayer(3, 224))
        self.network.add_ext('e1', InputLayer(3, 224))

        with self.assertRaisesRegexp(TypeError,
                                     'NNDataflowScheme: .*ext_layout*'):
            _ = NNDataflowScheme(self.network, self.input_layout, {
                'e0': self.input_layout,
                'e1': self.input_layout.frngs
            })

    def test_setgetitem(self):
        ''' __set/getitem__. '''
        df = NNDataflowScheme(self.network, self.input_layout)

        df['c1'] = self.c1res
        self.assertEqual(df['c1'], self.c1res)

    def test_getitem_not_in(self):
        ''' __getitem__ not in. '''
        df = NNDataflowScheme(self.network, self.input_layout)

        with self.assertRaises(KeyError):
            _ = df['c1']

    def test_setitem_not_in_network(self):
        ''' __setitem__ not in network. '''
        df = NNDataflowScheme(self.network, self.input_layout)

        with self.assertRaisesRegexp(KeyError, 'NNDataflowScheme: .*cc.*'):
            df['cc'] = self.c1res

    def test_setitem_invalid_value(self):
        ''' __setitem__ invalid value. '''
        df = NNDataflowScheme(self.network, self.input_layout)

        with self.assertRaisesRegexp(TypeError,
                                     'NNDataflowScheme: .*SchedulingResult*'):
            df['c1'] = self.c1res.scheme

    def test_setitem_already_exists(self):
        ''' __setitem__ already exists. '''
        df = NNDataflowScheme(self.network, self.input_layout)
        df['c1'] = self.c1res

        with self.assertRaisesRegexp(KeyError, 'NNDataflowScheme: .*c1*'):
            df['c1'] = self.c1res._replace(sched_seq=(1, 0, 0))

    def test_setitem_prev_not_in(self):
        ''' __setitem__ previous not existing. '''
        df = NNDataflowScheme(self.network, self.input_layout)

        with self.assertRaisesRegexp(KeyError, 'NNDataflowScheme: .*p1*'):
            df['p1'] = self.p1res

    def test_setitem_prev_input_ext(self):
        ''' __setitem__ previous is input or external. '''
        df = NNDataflowScheme(self.network, self.input_layout)
        df['c1'] = self.c1res
        self.assertAlmostEqual(df.total_cost, self.c1res.total_cost)

        self.network.add_ext('e0', InputLayer(3, 224))
        self.network.add('c2', self.network['c1'], prevs=('e0', ))
        df = NNDataflowScheme(self.network, self.input_layout,
                              {'e0': self.input_layout})
        df['c2'] = self.c1res
        self.assertAlmostEqual(df.total_cost, self.c1res.total_cost)

    def test_setitem_invalid_seg_idx(self):
        ''' __setitem__ invalid segment index. '''
        df = NNDataflowScheme(self.network, self.input_layout)

        with self.assertRaisesRegexp(ValueError,
                                     'NNDataflowScheme: .*segment index*'):
            df['c1'] = self.c1res._replace(sched_seq=(1, 0, 0))

        df = NNDataflowScheme(self.network, self.input_layout)
        df['c1'] = self.c1res
        df['p1'] = self.p1res._replace(sched_seq=(1, 0, 0))

        with self.assertRaisesRegexp(ValueError,
                                     'NNDataflowScheme: .*segment index*'):
            df['p2'] = self.p2res._replace(sched_seq=(0, 0, 0))

    def test_delitem(self):
        ''' __delitem__. '''
        df = NNDataflowScheme(self.network, self.input_layout)
        df['c1'] = self.c1res

        with self.assertRaisesRegexp(KeyError, 'NNDataflowScheme: .*'):
            del df['c1']

    def test_iter_len(self):
        ''' __iter__ and __len__. '''
        self.assertEqual(len(self.dtfl), 3)

        lst = [l for l in self.dtfl]
        self.assertIn('c1', lst)
        self.assertIn('p1', lst)
        self.assertIn('p2', lst)
        self.assertNotIn('f1', lst)

    def test_copy(self):
        ''' copy. '''
        df = self.dtfl
        df2 = df.copy()

        self.assertAlmostEqual(df.total_cost, df2.total_cost)
        self.assertAlmostEqual(df.total_time, df2.total_time)
        self.assertDictEqual(df.res_dict, df2.res_dict)

        # Shallow copy.
        for layer_name in df:
            self.assertEqual(id(df[layer_name]), id(df2[layer_name]))

    def test_copy_ext(self):
        ''' copy external layers. '''
        self.network.add_ext('e0', self.network.input_layer())
        self.network.add_ext('e1', self.network.input_layer())

        df1 = NNDataflowScheme(self.network, self.input_layout, {
            'e0': self.input_layout,
            'e1': self.input_layout
        })
        df1['c1'] = self.c1res
        df1['p1'] = self.p1res
        df1['p2'] = self.p2res

        df2 = df1.copy()

        self.assertAlmostEqual(df1.total_cost, df2.total_cost)
        self.assertAlmostEqual(df1.total_time, df2.total_time)
        self.assertDictEqual(df1.res_dict, df2.res_dict)
        self.assertDictEqual(df1.ext_layout_dict, df2.ext_layout_dict)

    def test_fmap_layout(self):
        ''' fmap_layout. '''
        flayout = self.dtfl.fmap_layout(('c1', ))
        frng = flayout.complete_fmap_range()
        self.assertTrue(flayout.is_in(self.c1res.ofmap_layout.regions[0]))
        self.assertEqual(frng, self.c1res.ofmap_layout.frngs[0])

        flayout = self.dtfl.fmap_layout((None, ))
        frng = flayout.complete_fmap_range()
        self.assertTrue(flayout.is_in(self.input_layout.regions[0]))
        self.assertEqual(frng, self.input_layout.frngs[0])

        flayout = self.dtfl.fmap_layout(('p1', 'p2'))
        frng = flayout.complete_fmap_range()
        self.assertEqual(frng.size('n'),
                         self.network['p1'].nofm + self.network['p2'].nofm)

        flayout = self.dtfl.fmap_layout((None, 'c1'))
        frng = flayout.complete_fmap_range()
        self.assertEqual(
            frng.size('n'),
            self.network.input_layer().nofm + self.network['c1'].nofm)

    def test_fmap_layout_ext(self):
        ''' fmap_layout external layers. '''
        self.network.add_ext('e0', self.network.input_layer())
        self.network.add_ext('e1', self.network.input_layer())

        df = NNDataflowScheme(self.network, self.input_layout, {
            'e0': self.input_layout,
            'e1': self.input_layout
        })
        df['c1'] = self.c1res
        df['p1'] = self.p1res
        df['p2'] = self.p2res

        flayout = df.fmap_layout(('e0', ))
        self.assertEqual(flayout, self.input_layout)

        flayout = df.fmap_layout(('e1', None))
        self.assertTrue(flayout.is_in(self.input_layout.regions[0]))
        frng = flayout.complete_fmap_range()
        self.assertEqual(
            frng.size('n'),
            self.network['e1'].nofm + self.network.input_layer().nofm)

    def test_properties(self):
        ''' Property accessors. '''
        self.assertAlmostEqual(self.dtfl.total_cost, 1.5 + 0.6 * 2)
        self.assertAlmostEqual(self.dtfl.total_time, 200 + 5)

        self.assertAlmostEqual(self.dtfl.total_ops, 4 + 0.1 * 2)
        for a in self.dtfl.total_accesses:
            self.assertAlmostEqual(a, (7 + 8 + 9) + (.7 + .8 + .9) * 2)
        self.assertAlmostEqual(self.dtfl.total_noc_hops,
                               (4 + 5 + 6) + (.4 + .5 + .6) * 2)

    def test_time_full_net_single_seg(self):
        ''' time() when full network fits in a single segment. '''
        dtfl = NNDataflowScheme(self.network, self.input_layout)
        dtfl['c1'] = self.c1res
        dtfl['p1'] = self.p1res._replace(sched_seq=(0, 1, 0))
        dtfl['p2'] = self.p2res._replace(sched_seq=(0, 2, 0))
        dtfl['f1'] = self.c1res._replace(sched_seq=(0, 3, 0))
        self.assertEqual(dtfl.total_time, 200)

    def test_static_cost_adjust(self):
        ''' Adjust static cost portion. '''

        # Add static cost.
        idl_unit_cost = 1e-3

        c1scheme = self.c1res.scheme
        c1static = c1scheme['time'] * idl_unit_cost
        c1scheme['cost_static'] += c1static
        c1scheme['cost_access'] -= c1static

        p1scheme = self.p1res.scheme
        p1static = p1scheme['time'] * idl_unit_cost
        p1scheme['cost_static'] += p1static
        p1scheme['cost_access'] -= p1static

        # No adjust.
        dtfl = NNDataflowScheme(self.network, self.input_layout)
        dtfl['c1'] = self.c1res._replace(scheme=c1scheme)
        dtfl['p1'] = self.p1res._replace(scheme=p1scheme, sched_seq=(1, 0, 0))
        dtfl['p2'] = self.p2res._replace(scheme=p1scheme, sched_seq=(2, 0, 0))
        dtfl['f1'] = self.c1res._replace(scheme=c1scheme, sched_seq=(3, 0, 0))

        sum_cost = 1.5 + 0.6 + 0.6 + 1.5
        sum_time = 200 + 5 + 5 + 200

        self.assertAlmostEqual(dtfl.total_cost, sum_cost)
        self.assertAlmostEqual(dtfl.total_time, sum_time)

        # With adjust.
        dtfl = NNDataflowScheme(self.network, self.input_layout)
        dtfl['c1'] = self.c1res._replace(scheme=c1scheme)
        dtfl['p1'] = self.p1res._replace(scheme=p1scheme, sched_seq=(0, 1, 0))
        dtfl['p2'] = self.p2res._replace(scheme=p1scheme, sched_seq=(0, 2, 0))
        dtfl['f1'] = self.c1res._replace(scheme=c1scheme, sched_seq=(1, 0, 0))

        diff = (sum_time - dtfl.total_time) * idl_unit_cost
        self.assertGreater(diff, 0)
        self.assertAlmostEqual(dtfl.total_cost, sum_cost - diff)

        # All in one segment.
        dtfl = NNDataflowScheme(self.network, self.input_layout)
        dtfl['c1'] = self.c1res._replace(scheme=c1scheme)
        dtfl['p1'] = self.p1res._replace(scheme=p1scheme, sched_seq=(0, 1, 0))
        dtfl['p2'] = self.p2res._replace(scheme=p1scheme, sched_seq=(0, 2, 0))
        dtfl['f1'] = self.c1res._replace(scheme=c1scheme, sched_seq=(0, 3, 0))

        diff = (sum_time - dtfl.total_time) * idl_unit_cost
        self.assertGreater(diff, 0)
        self.assertAlmostEqual(dtfl.total_cost, sum_cost - diff)

    def test_segment_time_list(self):
        ''' segment_time_list(). '''
        dtfl = NNDataflowScheme(self.network, self.input_layout)
        dtfl['c1'] = self.c1res
        dtfl['p1'] = self.p1res
        dtfl['p2'] = self.p2res._replace(sched_seq=(1, 0, 0))
        self.assertListEqual(dtfl.segment_time_list(), [205, 5])

    def test_segment_dram_time_list(self):
        ''' segment_dram_time_list(). '''
        c1_scheme = self.c1res.scheme.copy()
        c1_scheme['dram_time'] = 180
        p1_scheme = self.p1res.scheme.copy()
        p1_scheme['dram_time'] = 5
        p2_scheme = self.p2res.scheme.copy()
        p2_scheme['dram_time'] = 10
        dtfl = NNDataflowScheme(self.network, self.input_layout)
        dtfl['c1'] = self.c1res._replace(scheme=c1_scheme)
        dtfl['p1'] = self.p1res._replace(scheme=p1_scheme)
        dtfl['p2'] = self.p2res._replace(sched_seq=(1, 0, 0), scheme=p2_scheme)
        self.assertListEqual(dtfl.segment_dram_time_list(), [185, 10])
        self.assertListEqual(dtfl.segment_time_list(), [205, 10])

    def test_stats_active_node_pes(self):
        ''' Per-layer stats: active node PEs. '''
        stats = self.dtfl.perlayer_stats('active_node_pes')
        self.assertEqual(len(stats), len(self.dtfl))
        self.assertAlmostEqual(stats['c1'], 0.005)
        self.assertAlmostEqual(stats['p1'], 0.01)
        self.assertAlmostEqual(stats['p2'], 0.01)

    def test_stats_dram_bandwidth(self):
        ''' Per-layer stats: DRAM bandwidth. '''
        stats = self.dtfl.perlayer_stats('dram_bandwidth')
        self.assertEqual(len(stats), len(self.dtfl))
        self.assertAlmostEqual(stats['c1'], (7. + 8. + 9.) / 200)
        self.assertAlmostEqual(stats['p1'], (.7 + .8 + .9) / 5)
        self.assertAlmostEqual(stats['p2'], (.7 + .8 + .9) / 5)

    def test_stats_not_supported(self):
        ''' Per-layer stats: not supported. '''
        with self.assertRaisesRegexp(AttributeError,
                                     'NNDataflowScheme: .*not_supported.*'):
            _ = self.dtfl.perlayer_stats('not_supported')
コード例 #4
0
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)