<commit_before>""" <NAME>. et al. "`Large Kernel Matters -
Improve Semantic Segmentation by Global Convolutional Network
<https://arxiv.org/abs/1703.02719>`_"
"""
import tensorflow as tf

from .layers import conv_block
from . import TFModel
from .resnet import ResNet, ResNet101


class GlobalConvolutionNetwork(TFModel):
    """ Global Convolution Network

    **Configuration**

    inputs : dict
        dict with 'images' and 'masks' (see :meth:`._make_inputs`)

    body : dict
        encoder : dict
            base_class : TFModel
                encoder model class (should implement ``make_encoder``)
            filters : list of int
                number of filters in encoder convolutions
        block : dict
            parameters for Global Convolution Network conv block
        br : dict
            parameters for boundary refinement conv block
        upsample : dict
            parameters for upsampling in decoders

    head : dict
        num_classes : int
            number of semantic classes
        upsample : dict
            parameters for upsampling
    """
    @classmethod
    def default_config(cls):
        config = TFModel.default_config()

        config['input_block'].update(dict(layout='cna', filters=64, kernel_size=7, strides=2))
        config['body']['encoder'] = dict(base_class=ResNet101, filters=[256, 512, 1024, 2048])
        config['body']['block'] = dict(layout='cn cn', filters=21, kernel_size=11)
        config['body']['br'] = dict(layout='cn', bottleneck=False, downsample=False)
        config['body']['upsample'] = dict(layout='tna', factor=2, kernel_size=4)
        config['head']['upsample'] = dict(layout='tna', factor=2, kernel_size=4)
        config['body']['res_block'] = False

        config['loss'] = 'ce'
        config['optimizer'] = dict(name='Momentum', learning_rate=.0005, momentum=.99)
        return config

    def build_config(self, names=None):
        config = super().build_config(names)
        config['head']['num_classes'] = self.num_classes('targets')
        config['head']['targets'] = self.targets
        return config

    @classmethod
    def body(cls, inputs, name='body', **kwargs):
        """ GCN body

        Parameters
        ----------
        inputs : tf.Tensor
            input tensor
        name : str
            scope name

        Returns
        -------
        tf.Tensor
        """
        kwargs = cls.fill_params('body', **kwargs)
        block, br_block, encoder, upsample = cls.pop(['block', 'br', 'encoder', 'upsample'], kwargs)

        with tf.variable_scope(name):
            encoder_outputs = cls.encoder(inputs, block=block, br=br_block, encoder=encoder, **kwargs)

            encoder_outputs = [inputs] + encoder_outputs
            x = encoder_outputs[-1]
            for i, tensor in enumerate(encoder_outputs[-2::-1]):
                with tf.variable_scope('decoder-%d' % i):
                    x = cls.decoder_block(x, tensor, **upsample, **kwargs)
                    if i < len(encoder_outputs) - 2:
                        x = tf.add(x, tensor)
                    x = cls.boundary_refinement(x, name='BR', **br_block, **kwargs)
        return x

    @classmethod
    def encoder(cls, inputs, name='encoder', **kwargs):
        """ Create encoder from a base_class model

        Parameters
        ----------
        inputs : tf.Tensor
            input tensor
        name : str
            scope name
        kwargs : dict
            parameters

        Returns
        -------
        tf.Tensor
        """
        encoder = cls.fill_params('body/encoder', **kwargs.pop('encoder', {}))
        base_class = cls.pop('base_class', encoder)
        block, br_block, res_block = cls.pop(['block', 'br', 'res_block'], kwargs)

        with tf.variable_scope(name):
            base_tensors = base_class.make_encoder(inputs, name='base', **{**kwargs, **encoder})
            encoder_tensors = []
            for i, tensor in enumerate(base_tensors):
                with tf.variable_scope('encoder-%d' % i):
                    if res_block:
                        x = cls.res_block(tensor, name='GCN', **block, **kwargs)
                    else:
                        x = cls.block(tensor, name='GCN', **block, **kwargs)
                    x = cls.boundary_refinement(x, name='BR', **br_block, **kwargs)
                encoder_tensors.append(x)
        return encoder_tensors

    @classmethod
    def block(cls, inputs, name, **kwargs):
        """ Two branches with two convolutions with large kernels (k,1)(1,k) and (1,k)(k,1)

        Parameters
        ----------
        inputs : tf.Tensor
            input tensor
        filters : int
            number of output filters
        kernel_size : int
            convolution kernel size
        name : str
            scope name

        Returns
        -------
        tf.Tensor
        """
        kwargs = cls.fill_params('body/block', **kwargs)
        kernel_size = cls.pop('kernel_size', kwargs)
        i = inputs
        with tf.variable_scope(name):
            kernel_size = [(1, kernel_size), (kernel_size, 1)]
            x = conv_block(i, kernel_size=kernel_size, name='left', **kwargs)
            y = conv_block(i, kernel_size=kernel_size[::-1], name='right', **kwargs)
            x = x + y
        return x

    @classmethod
    def res_block(cls, inputs, name, **kwargs):
        """ The ResNn GCN block, shown in Figure 5, using a 1x1 conv layer in skipconnection
        for the correct operation of the network.

        Parameters
        ----------
        inputs : tf.Tensor
            input tensor
        filters : int
            number of output filters
        kernel_size : int
            convolution kernel size
        name : str
            scope name

        Returns
        -------
        tf.Tensor
        """
        with tf.variable_scope('res_' + name):
            x = cls.block(inputs, name, **kwargs)
            x = conv_block(x, name='norm', **{**kwargs, 'layout':'cn', 'kernel_size':1})
            y = conv_block(inputs, name='skip', **{**kwargs, 'layout':'cn', 'kernel_size':1})
            x = x + y
        return x

    @classmethod
    def boundary_refinement(cls, inputs, name, **kwargs):
        """ An ordinary ResNet block
<commit_msg>The scope name of res_block was changed<commit_after>""" <NAME>. et al. "`Large Kernel Matters -
Improve Semantic Segmentation by Global Convolutional Network
<https://arxiv.org/abs/1703.02719>`_"
"""
import tensorflow as tf

from .layers import conv_block
from . import TFModel
from .resnet import ResNet, ResNet101


class GlobalConvolutionNetwork(TFModel):
    """ Global Convolution Network

    **Configuration**

    inputs : dict
        dict with 'images' and 'masks' (see :meth:`._make_inputs`)

    body : dict
        encoder : dict
            base_class : TFModel
                encoder model class (should implement ``make_encoder``)
            filters : list of int
                number of filters in encoder convolutions
        block : dict
            parameters for Global Convolution Network conv block
        br : dict
            parameters for boundary refinement conv block
        upsample : dict
            parameters for upsampling in decoders

    head : dict
        num_classes : int
            number of semantic classes
        upsample : dict
            parameters for upsampling
    """
    @classmethod
    def default_config(cls):
        config = TFModel.default_config()

        config['input_block'].update(dict(layout='cna', filters=64, kernel_size=7, strides=2))
        config['body']['encoder'] = dict(base_class=ResNet101, filters=[256, 512, 1024, 2048])
        config['body']['block'] = dict(layout='cn cn', filters=21, kernel_size=11)
        config['body']['br'] = dict(layout='cn', bottleneck=False, downsample=False)
        config['body']['upsample'] = dict(layout='tna', factor=2, kernel_size=4)
        config['head']['upsample'] = dict(layout='tna', factor=2, kernel_size=4)
        config['body']['res_block'] = False

        config['loss'] = 'ce'
        config['optimizer'] = dict(name='Momentum', learning_rate=.0005, momentum=.99)
        return config

    def build_config(self, names=None):
        config = super().build_config(names)
        config['head']['num_classes'] = self.num_classes('targets')
        config['head']['targets'] = self.targets
        return config

    @classmethod
    def body(cls, inputs, name='body', **kwargs):
        """ GCN body

        Parameters
        ----------
        inputs : tf.Tensor
            input tensor
        name : str
            scope name

        Returns
        -------
        tf.Tensor
        """
        kwargs = cls.fill_params('body', **kwargs)
        block, br_block, encoder, upsample = cls.pop(['block', 'br', 'encoder', 'upsample'], kwargs)

        with tf.variable_scope(name):
            encoder_outputs = cls.encoder(inputs, block=block, br=br_block, encoder=encoder, **kwargs)

            encoder_outputs = [inputs] + encoder_outputs
            x = encoder_outputs[-1]
            for i, tensor in enumerate(encoder_outputs[-2::-1]):
                with tf.variable_scope('decoder-%d' % i):
                    x = cls.decoder_block(x, tensor, **upsample, **kwargs)
                    if i < len(encoder_outputs) - 2:
                        x = tf.add(x, tensor)
                    x = cls.boundary_refinement(x, name='BR', **br_block, **kwargs)
        return x

    @classmethod
    def encoder(cls, inputs, name='encoder', **kwargs):
        """ Create encoder from a base_class model

        Parameters
        ----------
        inputs : tf.Tensor
            input tensor
        name : str
            scope name
        kwargs : dict
            parameters

        Returns
        -------
        tf.Tensor
        """
        encoder = cls.fill_params('body/encoder', **kwargs.pop('encoder', {}))
        base_class = cls.pop('base_class', encoder)
        block, br_block, res_block = cls.pop(['block', 'br', 'res_block'], kwargs)

        with tf.variable_scope(name):
            base_tensors = base_class.make_encoder(inputs, name='base', **{**kwargs, **encoder})
            encoder_tensors = []
            for i, tensor in enumerate(base_tensors):
                with tf.variable_scope('encoder-%d' % i):
                    if res_block:
                        x = cls.res_block(tensor, name='GCN', **block, **kwargs)
                    else:
                        x = cls.block(tensor, name='res_GCN', **block, **kwargs)
                    x = cls.boundary_refinement(x, name='BR', **br_block, **kwargs)
                encoder_tensors.append(x)
        return encoder_tensors

    @classmethod
    def block(cls, inputs, name, **kwargs):
        """ Two branches with two convolutions with large kernels (k,1)(1,k) and (1,k)(k,1)

        Parameters
        ----------
        inputs : tf.Tensor
            input tensor
        filters : int
            number of output filters
        kernel_size : int
            convolution kernel size
        name : str
            scope name

        Returns
        -------
        tf.Tensor
        """
        kwargs = cls.fill_params('body/block', **kwargs)
        kernel_size = cls.pop('kernel_size', kwargs)
        i = inputs
        with tf.variable_scope(name):
            kernel_size = [(1, kernel_size), (kernel_size, 1)]
            x = conv_block(i, kernel_size=kernel_size, name='left', **kwargs)
            y = conv_block(i, kernel_size=kernel_size[::-1], name='right', **kwargs)
            x = x + y
        return x

    @classmethod
    def res_block(cls, inputs, name, **kwargs):
        """ The ResNet GCN block, shown in Figure 5, using a 1x1 conv layer in skipconnection
        for the correct operation of the network.

        Parameters
        ----------
        inputs : tf.Tensor
            input tensor
        filters : int
            number of output filters
        kernel_size : int
            convolution kernel size
        name : str
            scope name

        Returns
        -------
        tf.Tensor
        """
        with tf.variable_scope(name):
            x = cls.block(inputs, name, **kwargs)
            x = conv_block(x, name='norm', **{**kwargs, 'layout':'cn', 'kernel_size':1})
            y = conv_block(inputs, name='skip', **{**kwargs, 'layout':'cn', 'kernel_size':1})
            x = x + y
        return x

    @classmethod
    def boundary_refinement(cls, inputs, name, **kwargs):
        """ An ordinary ResNet block

{'fraction_non_alphanumeric': 0.12706349206349207, 'fraction_numerical': 0.01, 'mean_word_length': 1.9614571092831963, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 7, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2609233', 'n_tokens_mistral': 3598, 'n_tokens_neox': 3395, 'n_words': 921}