[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Desktop (please complete the following information):**\n - OS: [e.g. iOS]\n - Browser [e.g. chrome, safari]\n - Version [e.g. 22]\n\n**Smartphone (please complete the following information):**\n - Device: [e.g. iPhone6]\n - OS: [e.g. iOS8.1]\n - Browser [e.g. stock browser, safari]\n - Version [e.g. 22]\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/custom.md",
    "content": "---\nname: Custom issue template\nabout: Describe this issue template's purpose here.\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": "CUB-200-2011.py",
    "content": "'''PyTorch CUB-200-2011 Training with VGG16 (TRAINED FROM SCRATCH).'''\nfrom __future__ import print_function\nimport os\n# import nni\nimport time\nimport torch\nimport logging\nimport argparse\nimport torchvision\nimport random\nimport torch.nn as nn\nimport numpy as np\nimport torch.optim as optim\nimport torch.nn.functional as F\nfrom torch.autograd import Variable\nimport torch.backends.cudnn as cudnn\nimport torchvision\nfrom my_pooling import my_MaxPool2d,my_AvgPool2d\nimport torchvision.transforms as transforms\n\n\nlogger = logging.getLogger('MC_VGG_224')\n\n\nos.environ[\"CUDA_VISIBLE_DEVICES\"] = \"2,3\"\n\nlr = 0.1\nnb_epoch = 300\ncriterion = nn.CrossEntropyLoss()\n\n#Data\nprint('==> Preparing data..')\ntransform_train = transforms.Compose([\n    transforms.Scale((224,224)),\n    transforms.RandomCrop(224, padding=4),\n    transforms.RandomHorizontalFlip(),\n    transforms.ToTensor(),\n    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),\n])\n\ntransform_test = transforms.Compose([\n    transforms.Scale((224,224)),\n    transforms.ToTensor(),\n    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),\n])\n\n\ntrainset    = torchvision.datasets.ImageFolder(root='/home/data/Birds/train', transform=transform_train)\ntrainloader = torch.utils.data.DataLoader(trainset, batch_size=32, shuffle=True, num_workers=16, drop_last = True)\n\ntestset = torchvision.datasets.ImageFolder(root='/home/data/Birds/test', transform=transform_test)\ntestloader = torch.utils.data.DataLoader(testset, batch_size=32, shuffle=True, num_workers=16)\n\n\nprint('==> Building model..')\n\ncfg = {\n    'VGG11': [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],\n    'VGG13': [64, 64, 'M', 128, 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],\n    'VGG16': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 600, 'M', 512, 512, 600],\n    'VGG19': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', 512, 512, 512, 512, 'M', 512, 512, 512, 512, 'M'],\n}\n\n\nclass VGG(nn.Module):\n    def __init__(self, vgg_name):\n        super(VGG, self).__init__()\n        self.features = self._make_layers(cfg[vgg_name])\n        self.classifier = nn.Linear(512, 10)\n\n    def forward(self, x):\n        out = self.features(x)\n        out = out.view(out.size(0), -1)\n        out = self.classifier(out)\n        return out\n\n    def _make_layers(self, cfg):\n        layers = []\n        in_channels = 3\n        for x in cfg:\n            if x == 'M':\n                layers += [nn.MaxPool2d(kernel_size=2, stride=2)]\n            else:\n                layers += [nn.Conv2d(in_channels, x, kernel_size=3, padding=1),\n                           nn.BatchNorm2d(x),\n                           nn.ReLU(inplace=True)]\n                in_channels = x\n        layers += [nn.AvgPool2d(kernel_size=1, stride=1)]\n        return nn.Sequential(*layers)\n\n\n\n\n\n\n\n\ndef Mask(nb_batch, channels):\n\n    foo = [1] * 2 + [0] *  1\n    bar = []\n    for i in range(200):\n        random.shuffle(foo)\n        bar += foo\n    bar = [bar for i in range(nb_batch)]\n    bar = np.array(bar).astype(\"float32\")\n    bar = bar.reshape(nb_batch,200*channels,1,1)\n    bar = torch.from_numpy(bar)\n    bar = bar.cuda()\n    bar = Variable(bar)\n    return bar\n\ndef supervisor(x,targets,height,cnum):\n        mask = Mask(x.size(0), cnum)\n        branch = x\n        branch = branch.reshape(branch.size(0),branch.size(1), branch.size(2) * branch.size(3))\n        branch = F.softmax(branch,2)\n        branch = branch.reshape(branch.size(0),branch.size(1), x.size(2), x.size(2))\n        branch = my_MaxPool2d(kernel_size=(1,cnum), stride=(1,cnum))(branch)  \n        branch = branch.reshape(branch.size(0),branch.size(1), branch.size(2) * branch.size(3))\n        loss_2 = 1.0 - 1.0*torch.mean(torch.sum(branch,2))/cnum # set margin = 3.0\n\n        branch_1 = x * mask \n\n        branch_1 = my_MaxPool2d(kernel_size=(1,cnum), stride=(1,cnum))(branch_1)  \n        branch_1 = nn.AvgPool2d(kernel_size=(height,height))(branch_1)\n        branch_1 = branch_1.view(branch_1.size(0), -1)\n\n        loss_1 = criterion(branch_1, targets)\n        \n        return [loss_1, loss_2] \n\nclass model_bn(nn.Module):\n    def __init__(self, feature_size=512,classes_num=200):\n\n        super(model_bn, self).__init__() \n\n        self.features_1 = nn.Sequential(*list(VGG('VGG16').features.children())[:34])\n        self.features_2 = nn.Sequential(*list(VGG('VGG16').features.children())[34:])\n\n        self.max = nn.MaxPool2d(kernel_size=2, stride=2)\n\n        self.num_ftrs = 600*7*7\n        self.classifier = nn.Sequential(\n            nn.BatchNorm1d(self.num_ftrs),\n            #nn.Dropout(0.5),\n            nn.Linear(self.num_ftrs, feature_size),\n            nn.BatchNorm1d(feature_size),\n            nn.ELU(inplace=True),\n            #nn.Dropout(0.5),\n            nn.Linear(feature_size, classes_num),\n        )\n\n    def forward(self, x, targets):\n\n\n        x = self.features_1(x)\n\n        x = self.features_2(x)\n\n        if self.training:\n            MC_loss = supervisor(x,targets,height=14,cnum=3)\n\n        x = self.max(x)\n        x = x.view(x.size(0), -1)\n        x = self.classifier(x)\n        loss = criterion(x, targets)\n\n        if self.training:\n            return x, loss, MC_loss\n        else:\n            return x, loss\n\n\nuse_cuda = torch.cuda.is_available()\n\n\n\nnet =model_bn(512, 200)\n\nif use_cuda:\n    net.classifier.cuda()\n    net.features_1.cuda()\n    net.features_2.cuda()\n\n    net.classifier = torch.nn.DataParallel(net.classifier)\n    net.features_1 = torch.nn.DataParallel(net.features_1)\n    net.features_2 = torch.nn.DataParallel(net.features_2)\n\n    cudnn.benchmark = True\n\n\ndef train(epoch,net, args, trainloader,optimizer):\n    print('\\nEpoch: %d' % epoch)\n    net.train()\n    train_loss = 0\n    correct = 0\n    total = 0\n    idx = 0\n    \n\n    for batch_idx, (inputs, targets) in enumerate(trainloader):\n        idx = batch_idx\n\n        inputs, targets = inputs.cuda(), targets.cuda()\n        optimizer.zero_grad()\n        inputs, targets = Variable(inputs), Variable(targets)\n        out, ce_loss, MC_loss = net(inputs, targets)\n\n        loss = ce_loss + args[\"alpha_1\"] * MC_loss[0] +   args[\"beta_1\"]  * MC_loss[1] \n\n        loss.backward()\n        optimizer.step()\n\n\n        train_loss += loss.item()\n\n        _, predicted = torch.max(out.data, 1)\n        total += targets.size(0)\n        correct += predicted.eq(targets.data).cpu().sum().item()\n\n\n\n    train_acc = 100.*correct/total\n    train_loss = train_loss/(idx+1)\n    logging.info('Iteration %d, train_acc = %.5f,train_loss = %.6f' % (epoch, train_acc,train_loss))\n    return train_acc, train_loss\n\ndef test(epoch,net,testloader,optimizer):\n\n    net.eval()\n    test_loss = 0\n    correct = 0\n    total = 0\n    idx = 0\n    for batch_idx, (inputs, targets) in enumerate(testloader):\n        with torch.no_grad():\n            idx = batch_idx\n            if use_cuda:\n                inputs, targets = inputs.cuda(), targets.cuda()\n            inputs, targets = Variable(inputs), Variable(targets)\n            out, ce_loss = net(inputs,targets)\n            \n            test_loss += ce_loss.item()\n            _, predicted = torch.max(out.data, 1)\n            total += targets.size(0)\n            correct += predicted.eq(targets.data).cpu().sum().item()\n\n\n    test_acc = 100.*correct/total\n    test_loss = test_loss/(idx+1)\n    logging.info('test, test_acc = %.4f,test_loss = %.4f' % (test_acc,test_loss))\n\n    return test_acc\n \ndef cosine_anneal_schedule(t):\n    cos_inner = np.pi * (t % (nb_epoch  ))  # t - 1 is used when t has 1-based indexing.\n    cos_inner /= (nb_epoch )\n    cos_out = np.cos(cos_inner) + 1\n    return float( 0.1 / 2 * cos_out)\n\n\noptimizer = optim.SGD([\n                        {'params': net.classifier.parameters(), 'lr': 0.1},\n                        {'params': net.features_1.parameters(),   'lr': 0.1},\n                        {'params': net.features_2.parameters(),   'lr': 0.1},\n                        \n                     ], \n                      momentum=0.9, weight_decay=5e-4)\n\n\ndef get_params():\n    # Training settings\n    parser = argparse.ArgumentParser(description='PyTorch MC2_AutoML Example')\n\n    parser.add_argument('--alpha_1', type=float, default=1.5, metavar='ALPHA',\n                        help='alpha_1 value (default: 2.0)')\n    parser.add_argument('--beta_1', type=float, default=20.0, metavar='BETA',\n                        help='beta_1 value (default: 20.0)')\n\n    args, _ = parser.parse_known_args()\n    return args\n\nif __name__ == '__main__':\n    try:\n        args = vars(get_params())\n        print(args)\n        # main(params)\n        max_val_acc = 0\n        for epoch in range(1, nb_epoch+1):\n            if epoch ==150:\n                lr = 0.01\n            if epoch ==225:\n                lr = 0.001\n            optimizer.param_groups[0]['lr'] = lr\n            optimizer.param_groups[1]['lr'] = lr \n            optimizer.param_groups[2]['lr'] = lr \n\n            train(epoch, net, args,trainloader,optimizer)\n            test_acc = test(epoch, net,testloader,optimizer)\n            if test_acc >max_val_acc:\n                max_val_acc = test_acc\n\n            print(\"max_val_acc\", max_val_acc)\n\n\n    except Exception as exception:\n        logger.exception(exception)\n        raise\n\n"
  },
  {
    "path": "CUB-200-2011_ResNet18.py",
    "content": "'''PyTorch CUB-200-2011 Training with ResNet18 (TRAINED FROM SCRATCH).\n   NOTICE: for baseline, the channel of the final features should keep same with the Vanilla ResNet18'''\nfrom __future__ import print_function\nimport os\n# import nni\nimport time\nimport torch\nimport logging\nimport argparse\nimport torchvision\nimport random\nimport torch.nn as nn\nimport numpy as np\nimport torch.optim as optim\nimport torch.nn.functional as F\nfrom torch.autograd import Variable\nimport torch.backends.cudnn as cudnn\nimport torchvision\nfrom my_pooling import my_MaxPool2d,my_AvgPool2d\nimport torchvision.transforms as transforms\n\n\nlogger = logging.getLogger('MC_ResNet18_224')\n\n\nos.environ[\"CUDA_VISIBLE_DEVICES\"] = \"0\"\n\nlr = 0.1\nnb_epoch = 300\ncriterion = nn.CrossEntropyLoss()\n\n#Data\nprint('==> Preparing data..')\ntransform_train = transforms.Compose([\n    transforms.Scale((224,224)),\n    transforms.RandomCrop(224, padding=4),\n    transforms.RandomHorizontalFlip(),\n    transforms.ToTensor(),\n    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),\n])\n\ntransform_test = transforms.Compose([\n    transforms.Scale((224,224)),\n    transforms.ToTensor(),\n    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),\n])\n\n\ntrainset    = torchvision.datasets.ImageFolder(root='/home/data/Birds/train', transform=transform_train)\ntrainloader = torch.utils.data.DataLoader(trainset, batch_size=32, shuffle=True, num_workers=16, drop_last = True)\n\ntestset = torchvision.datasets.ImageFolder(root='/home/data/Birds/test', transform=transform_test)\ntestloader = torch.utils.data.DataLoader(testset, batch_size=32, shuffle=True, num_workers=16)\n\n\n\nprint('==> Building model..')\n\n# Model\n\nimport torch.nn as nn\nimport math\nimport torch.utils.model_zoo as model_zoo\n\n\n__all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101',\n           'resnet152']\n\n\nmodel_urls = {\n    'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth',\n    'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth',\n    'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth',\n    'resnet101': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth',\n    'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth',\n}\n\n\ndef conv3x3(in_planes, out_planes, stride=1):\n    \"3x3 convolution with padding\"\n    return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,\n                     padding=1, bias=False)\n\n\nclass BasicBlock(nn.Module):\n    expansion = 1\n\n    def __init__(self, inplanes, planes, stride=1, downsample=None):\n        super(BasicBlock, self).__init__()\n        self.conv1 = conv3x3(inplanes, planes, stride)\n        self.bn1 = nn.BatchNorm2d(planes)\n        self.relu = nn.ReLU(inplace=True)\n        self.conv2 = conv3x3(planes, planes)\n        self.bn2 = nn.BatchNorm2d(planes)\n        self.downsample = downsample\n        self.stride = stride\n\n    def forward(self, x):\n        residual = x\n\n        out = self.conv1(x)\n        out = self.bn1(out)\n        out = self.relu(out)\n\n        out = self.conv2(out)\n        out = self.bn2(out)\n\n        if self.downsample is not None:\n            residual = self.downsample(x)\n\n        out += residual\n        out = self.relu(out)\n\n        return out\n\n\nclass Bottleneck(nn.Module):\n    expansion = 4\n\n    def __init__(self, inplanes, planes, stride=1, downsample=None):\n        super(Bottleneck, self).__init__()\n        self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False)\n        self.bn1 = nn.BatchNorm2d(planes)\n        self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride,\n                               padding=1, bias=False)\n        self.bn2 = nn.BatchNorm2d(planes)\n        self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False)\n        self.bn3 = nn.BatchNorm2d(planes * 4)\n        self.relu = nn.ReLU(inplace=True)\n        self.downsample = downsample\n        self.stride = stride\n\n    def forward(self, x):\n        residual = x\n\n        out = self.conv1(x)\n        out = self.bn1(out)\n        out = self.relu(out)\n\n        out = self.conv2(out)\n        out = self.bn2(out)\n        out = self.relu(out)\n\n        out = self.conv3(out)\n        out = self.bn3(out)\n\n        if self.downsample is not None:\n            residual = self.downsample(x)\n\n        out += residual\n        out = self.relu(out)\n\n        return out\n\n\nclass ResNet(nn.Module):\n\n    def __init__(self, block, layers, num_classes=1000):\n        self.inplanes = 64\n        super(ResNet, self).__init__()\n        self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3,\n                               bias=False)\n        self.bn1 = nn.BatchNorm2d(64)\n        self.relu = nn.ReLU(inplace=True)\n        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)\n        self.layer1 = self._make_layer(block, 64, layers[0])\n        self.layer2 = self._make_layer(block, 128, layers[1], stride=2)\n        self.layer3 = self._make_layer(block, 256, layers[2], stride=2)\n        self.layer4 = self._make_layer(block, 600, layers[3], stride=1)\n        self.avgpool = nn.AvgPool2d(7, stride=1)\n        self.fc = nn.Linear(512 * block.expansion, num_classes)\n\n        for m in self.modules():\n            if isinstance(m, nn.Conv2d):\n                n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels\n                m.weight.data.normal_(0, math.sqrt(2. / n))\n            elif isinstance(m, nn.BatchNorm2d):\n                m.weight.data.fill_(1)\n                m.bias.data.zero_()\n\n    def _make_layer(self, block, planes, blocks, stride=1):\n        downsample = None\n        if stride != 1 or self.inplanes != planes * block.expansion:\n            downsample = nn.Sequential(\n                nn.Conv2d(self.inplanes, planes * block.expansion,\n                          kernel_size=1, stride=stride, bias=False),\n                nn.BatchNorm2d(planes * block.expansion),\n            )\n\n        layers = []\n        layers.append(block(self.inplanes, planes, stride, downsample))\n        self.inplanes = planes * block.expansion\n        for i in range(1, blocks):\n            layers.append(block(self.inplanes, planes))\n\n        return nn.Sequential(*layers)\n\n\n\ndef resnet18(pretrained=False, **kwargs):\n    \"\"\"Constructs a ResNet-18 model.\n\n    Args:\n        pretrained (bool): If True, returns a model pre-trained on ImageNet\n    \"\"\"\n    model = ResNet(BasicBlock, [2, 2, 2, 2], **kwargs)\n    if pretrained:\n        model.load_state_dict(model_zoo.load_url(model_urls['resnet18']))\n    return model\n\n\nnet = resnet18(pretrained=False)\n\n\n\ndef Mask(nb_batch, channels):\n\n    foo = [1] * 2 + [0] *  1\n    bar = []\n    for i in range(200):\n        random.shuffle(foo)\n        bar += foo\n    bar = [bar for i in range(nb_batch)]\n    bar = np.array(bar).astype(\"float32\")\n    bar = bar.reshape(nb_batch,200*channels,1,1)\n    bar = torch.from_numpy(bar)\n    bar = bar.cuda()\n    bar = Variable(bar)\n    return bar\n\ndef supervisor(x,targets,height,cnum):\n        mask = Mask(x.size(0), cnum)\n        branch = x\n        branch = branch.reshape(branch.size(0),branch.size(1), branch.size(2) * branch.size(3))\n        branch = F.softmax(branch,2)\n        branch = branch.reshape(branch.size(0),branch.size(1), x.size(2), x.size(2))\n        branch = my_MaxPool2d(kernel_size=(1,cnum), stride=(1,cnum))(branch)  \n        branch = branch.reshape(branch.size(0),branch.size(1), branch.size(2) * branch.size(3))\n        loss_2 = 1.0 - 1.0*torch.mean(torch.sum(branch,2))/cnum # set margin = 3.0\n\n        branch_1 = x * mask \n\n        branch_1 = my_MaxPool2d(kernel_size=(1,cnum), stride=(1,cnum))(branch_1)  \n        branch_1 = nn.AvgPool2d(kernel_size=(height,height))(branch_1)\n        branch_1 = branch_1.view(branch_1.size(0), -1)\n\n        loss_1 = criterion(branch_1, targets)\n        \n        return [loss_1, loss_2] \n\nclass model_bn(nn.Module):\n    def __init__(self, feature_size=512,classes_num=200):\n\n        super(model_bn, self).__init__() \n\n        self.features = nn.Sequential(*list(net.children())[:-2]) \n\n        self.max = nn.MaxPool2d(kernel_size=14, stride=14)\n\n        self.num_ftrs = 600*1*1\n        self.classifier = nn.Sequential(\n            nn.BatchNorm1d(self.num_ftrs),\n            #nn.Dropout(0.5),\n            nn.Linear(self.num_ftrs, feature_size),\n            nn.BatchNorm1d(feature_size),\n            nn.ELU(inplace=True),\n            #nn.Dropout(0.5),\n            nn.Linear(feature_size, classes_num),\n        )\n\n    def forward(self, x, targets):\n\n\n\n        x = self.features(x)\n\n        if self.training:\n            MC_loss = supervisor(x,targets,height=14,cnum=3)\n\n        x = self.max(x)\n        x = x.view(x.size(0), -1)\n        x = self.classifier(x)\n        loss = criterion(x, targets)\n\n        if self.training:\n            return x, loss, MC_loss\n        else:\n            return x, loss\n\n\nuse_cuda = torch.cuda.is_available()\n\n\n\nnet =model_bn(512, 200)\n\nif use_cuda:\n    net.classifier.cuda()\n    net.features.cuda()\n\n\n    net.classifier = torch.nn.DataParallel(net.classifier)\n    net.features = torch.nn.DataParallel(net.features)\n\n\n    cudnn.benchmark = True\n\n\ndef train(epoch,net, args, trainloader,optimizer):\n    print('\\nEpoch: %d' % epoch)\n    net.train()\n    train_loss = 0\n    correct = 0\n    total = 0\n    idx = 0\n    \n\n    for batch_idx, (inputs, targets) in enumerate(trainloader):\n        idx = batch_idx\n\n        inputs, targets = inputs.cuda(), targets.cuda()\n        optimizer.zero_grad()\n        inputs, targets = Variable(inputs), Variable(targets)\n        out, ce_loss, MC_loss = net(inputs, targets)\n\n        loss = ce_loss + args[\"alpha_1\"] * MC_loss[0] +   args[\"beta_1\"]  * MC_loss[1] \n\n        loss.backward()\n        optimizer.step()\n\n\n        train_loss += loss.item()\n\n        _, predicted = torch.max(out.data, 1)\n        total += targets.size(0)\n        correct += predicted.eq(targets.data).cpu().sum().item()\n\n\n\n    train_acc = 100.*correct/total\n    train_loss = train_loss/(idx+1)\n    logging.info('Iteration %d, train_acc = %.5f,train_loss = %.6f' % (epoch, train_acc,train_loss))\n    return train_acc, train_loss\n\ndef test(epoch,net,testloader,optimizer):\n\n    net.eval()\n    test_loss = 0\n    correct = 0\n    total = 0\n    idx = 0\n    for batch_idx, (inputs, targets) in enumerate(testloader):\n        with torch.no_grad():\n            idx = batch_idx\n            if use_cuda:\n                inputs, targets = inputs.cuda(), targets.cuda()\n            inputs, targets = Variable(inputs), Variable(targets)\n            out, ce_loss = net(inputs,targets)\n            \n            test_loss += ce_loss.item()\n            _, predicted = torch.max(out.data, 1)\n            total += targets.size(0)\n            correct += predicted.eq(targets.data).cpu().sum().item()\n\n\n    test_acc = 100.*correct/total\n    test_loss = test_loss/(idx+1)\n    logging.info('test, test_acc = %.4f,test_loss = %.4f' % (test_acc,test_loss))\n\n    return test_acc\n \ndef cosine_anneal_schedule(t):\n    cos_inner = np.pi * (t % (nb_epoch  ))  # t - 1 is used when t has 1-based indexing.\n    cos_inner /= (nb_epoch )\n    cos_out = np.cos(cos_inner) + 1\n    return float( 0.1 / 2 * cos_out)\n\n\noptimizer = optim.SGD([\n                        {'params': net.classifier.parameters(), 'lr': 0.1},\n                        {'params': net.features.parameters(),   'lr': 0.1},\n                        \n                     ], \n                      momentum=0.9, weight_decay=5e-4)\n\n\ndef get_params():\n    # Training settings\n    parser = argparse.ArgumentParser(description='PyTorch MC2_AutoML Example')\n\n    parser.add_argument('--alpha_1', type=float, default=1.5, metavar='ALPHA',\n                        help='alpha_1 value (default: 2.0)')\n    parser.add_argument('--beta_1', type=float, default=20.0, metavar='BETA',\n                        help='beta_1 value (default: 20.0)')\n\n    args, _ = parser.parse_known_args()\n    return args\n\nif __name__ == '__main__':\n    try:\n        args = vars(get_params())\n        print(args)\n        # main(params)\n        max_val_acc = 0\n        for epoch in range(1, nb_epoch+1):\n            if epoch ==150:\n                lr = 0.01\n            if epoch ==225:\n                lr = 0.001\n            optimizer.param_groups[0]['lr'] = lr\n            optimizer.param_groups[1]['lr'] = lr \n\n            train(epoch, net, args,trainloader,optimizer)\n            test_acc = test(epoch, net,testloader,optimizer)\n            if test_acc >max_val_acc:\n                max_val_acc = test_acc\n\n            print(\"max_val_acc\", max_val_acc)\n\n\n    except Exception as exception:\n        logger.exception(exception)\n        raise\n\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 Dongliang Chang\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# The Devil is in the Channels: Mutual-Channel Loss for Fine-Grained Image Classification\n\nCode release for The Devil is in the Channels: Mutual-Channel Loss for Fine-Grained Image Classification (TIP 2020)\n[DOI](https://doi.org/10.1109/TIP.2020.2973812 \"DOI\")\n\n\n## Changelog\n- 2020/09/14 update the code: CUB-200-2011_ResNet18.py  Training with ResNet18 (TRAINED FROM SCRATCH).\n- 2020/04/19 add the hyper-parameter fine-tune results. \n- 2020/04/18 clean the code for better understanding.\n\n## Dataset\n### CUB-200-2011\n\n## Requirements\n\n- python 3.6\n- PyTorch 1.2.0\n- torchvision\n\n## Training\n- Download datasets\n- Train: `python CUB-200-2011.py`, the alpha and beta are the hyper-parameters of the  `MC-Loss`\n- Description : PyTorch CUB-200-2011 Training with VGG16 (TRAINED FROM SCRATCH).\n\n## Hyper-parameter\nLoss = ce_loss + alpha_1 * L_dis + beta_1 * L_div  \n![Hyper-parameter_1](https://github.com/dongliangchang/Mutual-Channel-Loss/blob/master/Hyper-parameter_1.jpg)\n![Hyper-parameter_2](https://github.com/dongliangchang/Mutual-Channel-Loss/blob/master/Hyper-parameter_2.jpg)\nThe figure is plot by NNI.\n\n\n\n## Other versions\nOther unofficial implements can be found in the following:\n- Kurumi233: This repo integrate the MC-Loss into a class.  [code](https://github.com/Kurumi233/Mutual-Channel-Loss \"code\") \n- darcula1993: This repo implement the tf version of the MC-Loss. [code](https://github.com/darcula1993/Mutual-Channel-Loss \"code\") \n- Holocron: Implementations of recent Deep Learning tricks in Computer Vision, easily paired up with your favorite framework and model zoo. [code](https://github.com/frgfm/Holocron \"code\") \n\n\n## Citation\nIf you find this paper useful in your research, please consider citing:\n```\n@ARTICLE{9005389, \nauthor={D. {Chang} and Y. {Ding} and J. {Xie} and A. K. {Bhunia} and X. {Li} and Z. {Ma} and M. {Wu} and J. {Guo} and Y. {Song}}, \njournal={IEEE Transactions on Image Processing}, \ntitle={The Devil is in the Channels: Mutual-Channel Loss for Fine-Grained Image Classification}, \nyear={2020}, volume={29}, number={}, pages={4683-4695}, \ndoi={10.1109/TIP.2020.2973812}, \nISSN={1941-0042}, \nmonth={},} \n```\n\n\n## Contact\nThanks for your attention!\nIf you have any suggestion or question, you can leave a message here or contact us directly:\n- changdongliang@bupt.edu.cn\n- mazhanyu@bupt.edu.cn\n"
  },
  {
    "path": "_config.yml",
    "content": "theme: jekyll-theme-modernist"
  },
  {
    "path": "my_pooling.py",
    "content": "import torch\nimport numpy as np\nimport random\nfrom torch.autograd import Variable\nfrom torch.nn.modules.module import Module\nfrom torch.nn.modules.utils import _single, _pair, _triple\nimport torch.nn.functional as F\nfrom torch.nn.parameter import Parameter\n\n\n\nclass my_MaxPool2d(Module):\n\n\n    def __init__(self, kernel_size, stride=None, padding=0, dilation=1,\n                 return_indices=False, ceil_mode=False):\n        super(my_MaxPool2d, self).__init__()\n        self.kernel_size = kernel_size\n        self.stride = stride or kernel_size\n        self.padding = padding\n        self.dilation = dilation\n        self.return_indices = return_indices\n        self.ceil_mode = ceil_mode\n\n    def forward(self, input):\n        input = input.transpose(3,1)\n\n\n        input = F.max_pool2d(input, self.kernel_size, self.stride,\n                            self.padding, self.dilation, self.ceil_mode,\n                            self.return_indices)\n        input = input.transpose(3,1).contiguous()\n\n        return input\n\n    def __repr__(self):\n        kh, kw = _pair(self.kernel_size)\n        dh, dw = _pair(self.stride)\n        padh, padw = _pair(self.padding)\n        dilh, dilw = _pair(self.dilation)\n        padding_str = ', padding=(' + str(padh) + ', ' + str(padw) + ')' \\\n            if padh != 0 or padw != 0 else ''\n        dilation_str = (', dilation=(' + str(dilh) + ', ' + str(dilw) + ')'\n                        if dilh != 0 and dilw != 0 else '')\n        ceil_str = ', ceil_mode=' + str(self.ceil_mode)\n        return self.__class__.__name__ + '(' \\\n            + 'kernel_size=(' + str(kh) + ', ' + str(kw) + ')' \\\n            + ', stride=(' + str(dh) + ', ' + str(dw) + ')' \\\n            + padding_str + dilation_str + ceil_str + ')'\n\n\nclass my_AvgPool2d(Module):\n    def __init__(self, kernel_size, stride=None, padding=0, ceil_mode=False,\n                 count_include_pad=True):\n        super(my_AvgPool2d, self).__init__()\n        self.kernel_size = kernel_size\n        self.stride = stride or kernel_size\n        self.padding = padding\n        self.ceil_mode = ceil_mode\n        self.count_include_pad = count_include_pad\n\n    def forward(self, input):\n        input = input.transpose(3,1)\n        input = F.avg_pool2d(input, self.kernel_size, self.stride,\n                            self.padding, self.ceil_mode, self.count_include_pad)\n        input = input.transpose(3,1).contiguous()\n\n        return input\n\n\n    def __repr__(self):\n        return self.__class__.__name__ + '(' \\\n            + 'kernel_size=' + str(self.kernel_size) \\\n            + ', stride=' + str(self.stride) \\\n            + ', padding=' + str(self.padding) \\\n            + ', ceil_mode=' + str(self.ceil_mode) \\\n            + ', count_include_pad=' + str(self.count_include_pad) + ')'\n\n\nm = my_MaxPool2d((1, 32), stride=(1, 32))\ninput = Variable(torch.randn(3, 2208, 7, 7))\noutput = m(input)\nprint(output.size())\n"
  }
]