""" recur_resnet.py
    Deep thinking model architecture
    November 2020
"""

import torch
import torch.nn as nn
import torch.nn.functional as F

# Ignore statemenst for pylint:
#     Too many branches (R0912), Too many statements (R0915), No member (E1101),
#     Not callable (E1102), Invalid name (C0103), No exception (W0702)
# pylint: disable=R0912, R0915, E1101, E1102, C0103, W0702, R0914


class BasicBlock(nn.Module):
    """Basic residual block class"""
    expansion = 1

    def __init__(self, in_planes, planes, stride=1):
        super(BasicBlock, self).__init__()
        self.conv1 = nn.Conv2d(
            in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)

        self.conv2 = nn.Conv2d(planes, planes, kernel_size=3,
                               stride=1, padding=1, bias=False)

        self.shortcut = nn.Sequential()
        if stride != 1 or in_planes != self.expansion*planes:
            self.shortcut = nn.Sequential(
                nn.Conv2d(in_planes, self.expansion*planes,
                          kernel_size=1, stride=stride, bias=False)
            )

    def forward(self, x):
        out = F.relu(self.conv1(x))
        out = self.conv2(out)
        out += self.shortcut(x)
        out = F.relu(out)
        return out


class RecurResNet(nn.Module):
    """RecurResNet model class"""

    def __init__(self, block, num_blocks, num_classes=10, iters=5, feature_scale=1):
        super(RecurResNet, self).__init__()
        self.iters = iters
        self.in_planes = int(feature_scale*64)
        self.num_classes = num_classes
        self.conv1 = nn.Conv2d(3, int(feature_scale * 64), kernel_size=3,
                               stride=2, padding=1, bias=False)
        self.conv2 = nn.Conv2d(int(feature_scale * 64), int(feature_scale * 64),
                               kernel_size=3, stride=1, padding=1, bias=False)
        layers = []
        for i in range(len(num_blocks)):
            layers.append(self._make_layer(block, int(feature_scale*64), num_blocks[i], stride=1))

        self.recur_block = nn.Sequential(*layers)
        self.conv3 = nn.Conv2d(int(feature_scale*64), 512, kernel_size=3,
                               stride=2, padding=1, bias=False)
        self.linear = nn.Linear(512, num_classes)

    def _make_layer(self, block, planes, num_blocks, stride):
        strides = [stride] + [1]*(num_blocks-1)
        layers = []
        for strd in strides:
            layers.append(block(self.in_planes, planes, strd))
            self.in_planes = planes * block.expansion
        return nn.Sequential(*layers)

    def forward(self, x, penu=False):
        self.thoughts = torch.zeros((self.iters, x.shape[0], self.num_classes)).to(x.device)

        out = F.relu(self.conv1(x))
        for i in range(self.iters):
            out = self.recur_block(out)
        thought = F.relu(self.conv3(out))
        thought = F.avg_pool2d(thought, 8)
        features = thought.view(thought.size(0), -1)
        self.thoughts[i] = self.linear(features)

        if penu:
            return features
        else:
            return self.thoughts[-1]


class RecurResNet_TinyImageNet(nn.Module):
    """RecurResNet model class"""

    def __init__(self, block, num_blocks, num_classes=10, iters=5, feature_scale=1):
        super(RecurResNet_TinyImageNet, self).__init__()
        self.iters = iters
        self.in_planes = int(feature_scale*64)
        self.num_classes = num_classes
        self.conv1 = nn.Conv2d(3, int(feature_scale * 64), kernel_size=3,
                               stride=2, padding=1, bias=False)
        self.conv2 = nn.Conv2d(int(feature_scale * 64), int(feature_scale * 64),
                               kernel_size=3, stride=1, padding=1, bias=False)
        layers = []
        for i in range(len(num_blocks)):
            layers.append(self._make_layer(block, int(feature_scale*64), num_blocks[i], stride=1))

        self.recur_block = nn.Sequential(*layers)
        self.conv3 = nn.Conv2d(int(feature_scale*64), 512, kernel_size=3,
                               stride=2, padding=1, bias=False)
        self.linear = nn.Linear(512, num_classes)

    def _make_layer(self, block, planes, num_blocks, stride):
        strides = [stride] + [1]*(num_blocks-1)
        layers = []
        for strd in strides:
            layers.append(block(self.in_planes, planes, strd))
            self.in_planes = planes * block.expansion
        return nn.Sequential(*layers)

    def forward(self, x):
        thoughts = torch.zeros((self.iters, x.shape[0], self.num_classes)).to(x.device)

        out = F.relu(self.conv1(x))
        for i in range(self.iters):
            out = self.recur_block(out)
            thought = self.conv3(out)
            thought = F.avg_pool2d(thought, 16)
            thought = thought.view(thought.size(0), -1)
            thoughts[i] = self.linear(thought)
        return thoughts[-1]

class RecurResNet_MNIST(nn.Module):
    """RecurResNet_MNIST model class"""

    def __init__(self, block, num_blocks, num_classes=10, iters=5, feature_scale=1):
        super(RecurResNet_MNIST, self).__init__()
        self.iters = iters
        self.in_planes = int(feature_scale*64)
        self.num_classes = num_classes
        self.conv1 = nn.Conv2d(1, int(feature_scale * 64), kernel_size=3,
                               stride=2, padding=1, bias=False)
        layers = []
        for i in range(len(num_blocks)):
            layers.append(self._make_layer(block, int(feature_scale*64), num_blocks[i], stride=1))

        self.recur_block = nn.Sequential(*layers)
        self.conv3 = nn.Conv2d(int(feature_scale*64), 128, kernel_size=3,
                               stride=2, padding=1, bias=False)
        self.linear = nn.Linear(128, num_classes)

    def _make_layer(self, block, planes, num_blocks, stride):
        strides = [stride] + [1]*(num_blocks-1)
        layers = []
        for strd in strides:
            layers.append(block(self.in_planes, planes, strd))
            self.in_planes = planes * block.expansion
        return nn.Sequential(*layers)

    def forward(self, x):
        self.thoughts = torch.zeros((self.iters, x.shape[0], self.num_classes)).to(x.device)

        out = F.relu(self.conv1(x))
        for i in range(self.iters):
            out = self.recur_block(out)
            thought = F.relu(self.conv3(out))
            thought = F.avg_pool2d(thought, 7)
            thought = thought.view(thought.size(0), -1)
            self.thoughts[i] = self.linear(thought)
        return self.thoughts[-1]

class RecurResNet_EMNIST(nn.Module):
    """RecurResNet_EMNIST model class"""

    def __init__(self, block, num_blocks, num_classes=10, iters=5, feature_scale=1):
        super(RecurResNet_EMNIST, self).__init__()
        self.iters = iters
        self.in_planes = int(feature_scale*64)
        self.num_classes = num_classes
        self.conv1 = nn.Conv2d(1, int(feature_scale * 64), kernel_size=3,
                               stride=2, padding=1, bias=False)
        layers = []
        for i in range(len(num_blocks)):
            layers.append(self._make_layer(block, int(feature_scale*64), num_blocks[i], stride=1))

        self.recur_block = nn.Sequential(*layers)
        self.conv3 = nn.Conv2d(int(feature_scale*64), 512, kernel_size=3,
                               stride=2, padding=1, bias=False)
        self.linear = nn.Linear(512, num_classes)

    def _make_layer(self, block, planes, num_blocks, stride):
        strides = [stride] + [1]*(num_blocks-1)
        layers = []
        for strd in strides:
            layers.append(block(self.in_planes, planes, strd))
            self.in_planes = planes * block.expansion
        return nn.Sequential(*layers)

    def forward(self, x):
        self.thoughts = torch.zeros((self.iters, x.shape[0], self.num_classes)).to(x.device)

        out = F.relu(self.conv1(x))
        for i in range(self.iters):
            out = self.recur_block(out)
            thought = F.relu(self.conv3(out))
            thought = F.avg_pool2d(thought, 7)
            thought = thought.view(thought.size(0), -1)
            self.thoughts[i] = self.linear(thought)
        return self.thoughts[-1]

def recur_resnet_7(num_outputs=10):
    return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=1, feature_scale=8)

def recur_resnet_11(num_outputs=10):
    return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=2, feature_scale=8)

def recur_resnet_15(num_outputs=10):
    return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=3, feature_scale=8)

def recur_resnet_19(num_outputs=10):
    return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=4, feature_scale=8)

def recur_resnet_23(num_outputs=10):
    return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=5, feature_scale=8)

def recur_resnet_27(num_outputs=10):
    return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=6, feature_scale=8)

def recur_resnet_7_mnist(num_outputs=10):
    return RecurResNet_MNIST(BasicBlock, [2], num_classes=num_outputs, iters=1, feature_scale=0.1)

def recur_resnet_11_mnist(num_outputs=10):
    return RecurResNet_MNIST(BasicBlock, [2], num_classes=num_outputs, iters=2, feature_scale=0.1)

def recur_resnet_15_mnist(num_outputs=10):
    return RecurResNet_MNIST(BasicBlock, [2], num_classes=num_outputs, iters=3, feature_scale=0.1)

def recur_resnet_19_mnist(num_outputs=10):
    return RecurResNet_MNIST(BasicBlock, [2], num_classes=num_outputs, iters=4, feature_scale=0.1)

def recur_resnet_23_mnist(num_outputs=10):
    return RecurResNet_MNIST(BasicBlock, [2], num_classes=num_outputs, iters=5, feature_scale=0.1)

def recur_resnet_27_mnist(num_outputs=10):
    return RecurResNet_MNIST(BasicBlock, [2], num_classes=num_outputs, iters=6, feature_scale=8)


def recur_resnet_7_emnist(num_outputs=47):
    return RecurResNet_EMNIST(BasicBlock, [2], num_classes=num_outputs, iters=1, feature_scale=4)

def recur_resnet_11_emnist(num_outputs=47):
    return RecurResNet_EMNIST(BasicBlock, [2], num_classes=num_outputs, iters=2, feature_scale=4)

def recur_resnet_15_emnist(num_outputs=47):
    return RecurResNet_EMNIST(BasicBlock, [2], num_classes=num_outputs, iters=3, feature_scale=4)

def recur_resnet_19_emnist(num_outputs=47):
    return RecurResNet_EMNIST(BasicBlock, [2], num_classes=num_outputs, iters=4, feature_scale=4)

def recur_resnet_23_emnist(num_outputs=47):
    return RecurResNet_EMNIST(BasicBlock, [2], num_classes=num_outputs, iters=5, feature_scale=4)

def recur_resnet_27_emnist(num_outputs=47):
    return RecurResNet_EMNIST(BasicBlock, [2], num_classes=num_outputs, iters=6, feature_scale=4)


def recur_resnet_7_deep_thin(num_outputs=10):
    return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=1, feature_scale=4)

def recur_resnet_11_deep_thin(num_outputs=10):
    return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=2, feature_scale=4)

def recur_resnet_15_deep_thin(num_outputs=10):
    return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=3, feature_scale=4)

def recur_resnet_19_deep_thin(num_outputs=10):
    return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=4, feature_scale=4)

def recur_resnet_23_deep_thin(num_outputs=10):
    return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=5, feature_scale=4)

def recur_resnet_27_deep_thin(num_outputs=10):
    return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=6, feature_scale=4)


def recur_resnet_width_depth_2_2_5_cifar10_6(num_outputs=10):
    return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=2, feature_scale=5)

def recur_resnet_width_depth_2_4_5_cifar10_6(num_outputs=10):
    return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=4, feature_scale=5)

def recur_resnet_width_depth_2_2_6_cifar10_9(num_outputs=10):
    return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=2, feature_scale=6)

def recur_resnet_width_depth_2_3_6_cifar10_9(num_outputs=10):
    return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=3, feature_scale=6)

def recur_resnet_width_depth_2_3_7_cifar10_11(num_outputs=10):
    return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=4, feature_scale=7)

def recur_resnet_width_depth_2_4_7_cifar10_11(num_outputs=10):
    return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=4, feature_scale=7)

def recur_resnet_width_depth_2_3_8_cifar10_13(num_outputs=10):
    return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=3, feature_scale=7.8)

def recur_resnet_width_depth_2_5_8_cifar10_13(num_outputs=10):
    return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=5, feature_scale=7.8)

def recur_resnet_width_depth_2_4_8_cifar10_16(num_outputs=10):
    return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=4, feature_scale=8.5)

def recur_resnet_width_depth_2_6_8_cifar10_16(num_outputs=10):
    return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=6, feature_scale=8.5)


def recur_resnet_7_deep_thin_7(num_outputs=10):
    return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=1, feature_scale=7)

def recur_resnet_11_deep_thin_7(num_outputs=10):
    return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=2, feature_scale=7)


def recur_resnet_15_deep_thin_7(num_outputs=10):
    return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=3, feature_scale=7)

def recur_resnet_19_deep_thin_7(num_outputs=10):
    return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=4, feature_scale=7)

def recur_resnet_7_shallow(num_outputs=10):
    return RecurResNet(BasicBlock, [1], num_classes=num_outputs, iters=1, feature_scale=4)


def recur_resnet_11_shallow(num_outputs=10):
    return RecurResNet(BasicBlock, [1], num_classes=num_outputs, iters=2, feature_scale=4)


def recur_resnet_15_shallow(num_outputs=10):
    return RecurResNet(BasicBlock, [1], num_classes=num_outputs, iters=3, feature_scale=4)


def recur_resnet_19_shallow(num_outputs=10):
    return RecurResNet(BasicBlock, [1], num_classes=num_outputs, iters=4, feature_scale=4)

def recur_resnet_7_shallow_wide(num_outputs=10):
    return RecurResNet(BasicBlock, [1], num_classes=num_outputs, iters=1, feature_scale=8)


def recur_resnet_11_shallow_wide(num_outputs=10):
    return RecurResNet(BasicBlock, [1], num_classes=num_outputs, iters=2, feature_scale=8)


def recur_resnet_15_shallow_wide(num_outputs=10):
    return RecurResNet(BasicBlock, [1], num_classes=num_outputs, iters=3, feature_scale=8)


def recur_resnet_19_shallow_wide(num_outputs=10):
    return RecurResNet(BasicBlock, [1], num_classes=num_outputs, iters=4, feature_scale=8)

# """ recur_resnet.py
#     Deep thinking model architecture
#     November 2020
# """
#
# import torch
# import torch.nn as nn
# import torch.nn.functional as F
#
# # Ignore statemenst for pylint:
# #     Too many branches (R0912), Too many statements (R0915), No member (E1101),
# #     Not callable (E1102), Invalid name (C0103), No exception (W0702)
# # pylint: disable=R0912, R0915, E1101, E1102, C0103, W0702, R0914
#
#
# class BasicBlock(nn.Module):
#     """Basic residual block class"""
#     expansion = 1
#
#     def __init__(self, in_planes, planes, stride=1):
#         super(BasicBlock, self).__init__()
#         self.conv1 = nn.Conv2d(
#             in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
#
#         self.conv2 = nn.Conv2d(planes, planes, kernel_size=3,
#                                stride=1, padding=1, bias=False)
#
#         self.shortcut = nn.Sequential()
#         if stride != 1 or in_planes != self.expansion*planes:
#             self.shortcut = nn.Sequential(
#                 nn.Conv2d(in_planes, self.expansion*planes,
#                           kernel_size=1, stride=stride, bias=False)
#             )
#
#     def forward(self, x):
#         out = F.relu(self.conv1(x))
#         out = self.conv2(out)
#         out += self.shortcut(x)
#         out = F.relu(out)
#         return out
#
#
# class RecurResNet(nn.Module):
#     """RecurResNet model class"""
#
#     def __init__(self, block, num_blocks, num_classes=10, iters=5, feature_scale=1):
#         super(RecurResNet, self).__init__()
#         self.iters = iters
#         self.in_planes = int(feature_scale*64)
#         self.num_classes = num_classes
#         self.conv1 = nn.Conv2d(3, int(feature_scale * 64), kernel_size=3,
#                                stride=2, padding=1, bias=False)
#         self.conv2 = nn.Conv2d(int(feature_scale * 64), int(feature_scale * 64),
#                                kernel_size=3, stride=1, padding=1, bias=False)
#         layers = []
#         for i in range(len(num_blocks)):
#             layers.append(self._make_layer(block, int(feature_scale*64), num_blocks[i], stride=1))
#
#         self.recur_block = nn.Sequential(*layers)
#         self.conv3 = nn.Conv2d(int(feature_scale*64), 512, kernel_size=3,
#                                stride=2, padding=1, bias=False)
#         self.linear = nn.Linear(512, num_classes)
#
#     def _make_layer(self, block, planes, num_blocks, stride):
#         strides = [stride] + [1]*(num_blocks-1)
#         layers = []
#         for strd in strides:
#             layers.append(block(self.in_planes, planes, strd))
#             self.in_planes = planes * block.expansion
#         return nn.Sequential(*layers)
#
#     def forward(self, x):
#         thoughts = torch.zeros((self.iters, x.shape[0], self.num_classes)).to(x.device)
#
#         out = F.relu(self.conv1(x))
#         # out = F.relu(self.conv2(out))
#         for i in range(self.iters):
#             out = self.recur_block(out)
#             thought = self.conv3(out)
#             thought = F.avg_pool2d(thought, 8)
#             thought = thought.view(thought.size(0), -1)
#             thoughts[i] = self.linear(thought)
#         return thoughts[-1]
#
#
# class RecurResNetBN(nn.Module):
#     """RecurResNet model class"""
#
#     def __init__(self, block, num_blocks, num_classes=10, iters=5, feature_scale=1, bn=False):
#         super(RecurResNetBN, self).__init__()
#         self.iters = iters
#         self.in_planes = int(feature_scale*64)
#         self.num_classes = num_classes
#         self.bn = bn
#         self.conv1 = nn.Conv2d(3, int(feature_scale*64), kernel_size=3,
#                                stride=2, padding=1, bias=False)
#         self.norm_layer1 = nn.BatchNorm2d(feature_scale*64, affine=False)
#         layers = []
#         for i in range(len(num_blocks)):
#             layers.append(self._make_layer(block, int(feature_scale*64), num_blocks[i], stride=1))
#
#         self.recur_block = nn.Sequential(*layers)
#         self.norm_layer2 = nn.BatchNorm2d(feature_scale * 64)
#         self.conv2 = nn.Conv2d(int(feature_scale*64), 512, kernel_size=3,
#                                stride=2, padding=1, bias=False)
#         self.norm_layer3 = nn.BatchNorm2d(512, affine=False)
#         self.linear = nn.Linear(512*block.expansion, num_classes)
#
#     def _make_layer(self, block, planes, num_blocks, stride):
#         strides = [stride] + [1]*(num_blocks-1)
#         layers = []
#         for strd in strides:
#             layers.append(block(self.in_planes, planes, strd))
#             self.in_planes = planes * block.expansion
#         return nn.Sequential(*layers)
#
#     def forward(self, x):
#         thoughts = torch.zeros((self.iters, x.shape[0], self.num_classes)).to(x.device)
#
#         out = F.relu(self.norm_layer1(self.conv1(x)))
#         for i in range(self.iters):
#             out = F.relu(self.recur_block(out))
#         thought = F.relu(self.norm_layer3(self.conv2(out)))
#         thought = F.avg_pool2d(thought, 8)
#         thought = thought.view(thought.size(0), -1)
#         thought = self.linear(thought)
#         return thought
#
#
# def recur_resnet_6(num_outputs=10):
#     return RecurResNet(BasicBlock, [1], num_classes=num_outputs, iters=1, feature_scale=1)
#
#
# def recur_resnet_10(num_outputs=10):
#     return RecurResNet(BasicBlock, [1], num_classes=num_outputs, iters=3, feature_scale=1)
#
#
# def recur_resnet_6_w4(num_outputs=10):
#     return RecurResNet(BasicBlock, [1], num_classes=num_outputs, iters=1, feature_scale=4)
#
#
# def recur_resnet_8_w4(num_outputs=10):
#     return RecurResNet(BasicBlock, [1], num_classes=num_outputs, iters=2, feature_scale=4)
#
#
# def recur_resnet_10_w4(num_outputs=10):
#     return RecurResNet(BasicBlock, [1], num_classes=num_outputs, iters=3, feature_scale=4)
#
#
# def recur_resnet_14_w4(num_outputs=10):
#     return RecurResNet(BasicBlock, [1], num_classes=num_outputs, iters=5, feature_scale=4)
#
#
# def recur_resnet_18_w4(num_outputs=10):
#     return RecurResNet(BasicBlock, [1], num_classes=num_outputs, iters=7, feature_scale=4)
#
#
# def recur_resnet_6_w2(num_outputs=10):
#     return RecurResNet(BasicBlock, [1], num_classes=num_outputs, iters=1, feature_scale=2)
#
#
# def recur_resnet_8_w2(num_outputs=10):
#     return RecurResNet(BasicBlock, [1], num_classes=num_outputs, iters=2, feature_scale=2)
#
#
# def recur_resnet_10_w2(num_outputs=10):
#     return RecurResNet(BasicBlock, [1], num_classes=num_outputs, iters=3, feature_scale=2)
#
#
# def recur_resnet_14_w2(num_outputs=10):
#     return RecurResNet(BasicBlock, [1], num_classes=num_outputs, iters=5, feature_scale=2)
#
#
# def recur_resnet_18_w2(num_outputs=10):
#     return RecurResNet(BasicBlock, [1], num_classes=num_outputs, iters=7, feature_scale=2)
#
#
# def recur_resnet_8(num_outputs=10):
#     return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=1, feature_scale=1)
#
#
# def recur_resnet_12(num_outputs=10):
#     return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=2, feature_scale=1)
#
#
# def recur_resnet_16(num_outputs=10):
#     return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=3, feature_scale=1)
#
#
# def recur_resnet_20(num_outputs=10):
#     return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=4, feature_scale=1)
#
#
# def recur_resnet_8_wide2(num_outputs=10):
#     return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=1, feature_scale=2)
#
#
# def recur_resnet_12_wide2(num_outputs=10):
#     return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=2, feature_scale=2)
#
#
# def recur_resnet_16_wide2(num_outputs=10):
#     return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=3, feature_scale=2)
#
#
# def recur_resnet_20_wide2(num_outputs=10):
#     return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=4, feature_scale=2)
#
#
# def recur_resnet_8_wide4(num_outputs=10):
#     return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=1, feature_scale=4)
#
#
# def recur_resnet_12_wide4(num_outputs=10):
#     return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=2, feature_scale=4)
#
#
# def recur_resnet_16_wide4(num_outputs=10):
#     return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=3, feature_scale=4)
#
#
# def recur_resnet_20_wide4(num_outputs=10):
#     return RecurResNet(BasicBlock, [2], num_classes=num_outputs, iters=4, feature_scale=4)
#
# #
# #
# # def recur_resnet_5_wide2(num_outputs=10):
# #     return RecurResNet(BasicBlock, [1], num_classes=num_outputs, iters=5, feature_scale=2)
# #
# #
# # def recur_resnet_5_wide4(num_outputs=10):
# #     return RecurResNet(BasicBlock, [1], num_classes=num_outputs, iters=5, feature_scale=4)
# #
# #
# # def recur_resnet_5_wide6(num_outputs=10):
# #     return RecurResNet(BasicBlock, [1], num_classes=num_outputs, iters=5, feature_scale=6)
# #
# #
# # def recur_resnet_5_wide8(num_outputs=10):
# #     return RecurResNet(BasicBlock, [1], num_classes=num_outputs, iters=5, feature_scale=8)
# #
# #
# # def recur_resnet_5_wide10(num_outputs=10):
# #     return RecurResNet(BasicBlock, [1], num_classes=num_outputs, iters=5, feature_scale=10)
# #
# #
# # def recur_resnet_5_wide2_bn(num_outputs=10):
# #     return RecurResNetBN(BasicBlock, [1], num_classes=num_outputs, iters=5, feature_scale=2, bn=True)
# #
# #
# # def recur_resnet_5_wide4_bn(num_outputs=10):
# #     return RecurResNetBN(BasicBlock, [1], num_classes=num_outputs, iters=5, feature_scale=4, bn=True)
# #
# #
# # def recur_resnet_5_wide6_bn(num_outputs=10):
# #     return RecurResNetBN(BasicBlock, [1], num_classes=num_outputs, iters=5, feature_scale=6, bn=True)
# #
# #
# # def recur_resnet_5_wide8_bn(num_outputs=10):
# #     return RecurResNetBN(BasicBlock, [1], num_classes=num_outputs, iters=5, feature_scale=8, bn=True)
# #
# #
# # def recur_resnet_5_wide10_bn(num_outputs=10):
# #     return RecurResNetBN(BasicBlock, [1], num_classes=num_outputs, iters=5, feature_scale=10, bn=True)
# #
