[
  {
    "path": "A2S2KResNet/A2S2KResNet.py",
    "content": "#!/usr/bin/env python\n# coding: utf-8\n\n# # Imports\n\nimport argparse\nimport collections\nimport math\nimport time\n\nimport numpy as np\nimport scipy.io as sio\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.optim as optim\nfrom sklearn import metrics, preprocessing\nfrom sklearn.decomposition import PCA\nfrom sklearn.metrics import confusion_matrix\n\nimport geniter\nimport record\nimport torch_optimizer as optim2\nimport Utils\nfrom torchsummary import summary\n\n# # Setting Params\n\nparser = argparse.ArgumentParser(description='Training for HSI')\nparser.add_argument(\n    '-d', '--dataset', dest='dataset', default='IN', help=\"Name of dataset.\")\nparser.add_argument(\n    '-o',\n    '--optimizer',\n    dest='optimizer',\n    default='adam',\n    help=\"Name of optimizer.\")\nparser.add_argument(\n    '-e', '--epoch', type=int, dest='epoch', default=200, help=\"No of epoch\")\nparser.add_argument(\n    '-i', '--iter', type=int, dest='iter', default=3, help=\"No of iter\")\nparser.add_argument(\n    '-p', '--patch', type=int, dest='patch', default=4, help=\"Length of patch\")\nparser.add_argument(\n    '-k',\n    '--kernel',\n    type=int,\n    dest='kernel',\n    default=24,\n    help=\"Length of kernel\")\nparser.add_argument(\n    '-vs',\n    '--valid_split',\n    type=float,\n    dest='valid_split',\n    default=0.9,\n    help=\"Percentage of validation split.\")\nargs = parser.parse_args()\n\nPARAM_DATASET = args.dataset  # UP,IN,SV, KSC\nPARAM_EPOCH = args.epoch\nPARAM_ITER = args.iter\nPATCH_SIZE = args.patch\nPARAM_VAL = args.valid_split\nPARAM_OPTIM = args.optimizer\nPARAM_KERNEL_SIZE = args.kernel\n\n# # Data Loading\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n\n# for Monte Carlo runs\nseeds = [1331, 1332, 1333, 1334, 1335, 1336, 1337, 1338, 1339, 1340, 1341]\nensemble = 1\n\nglobal Dataset  # UP,IN,SV, KSC\ndataset = PARAM_DATASET  # input('Please input the name of Dataset(IN, UP, SV, KSC):')\nDataset = dataset.upper()\n\n\ndef load_dataset(Dataset, split=0.9):\n    data_path = '../dataset/'\n    if Dataset == 'IN':\n        mat_data = sio.loadmat(data_path + 'Indian_pines_corrected.mat')\n        mat_gt = sio.loadmat(data_path + 'Indian_pines_gt.mat')\n        data_hsi = mat_data['indian_pines_corrected']\n        gt_hsi = mat_gt['indian_pines_gt']\n        K = 200\n        TOTAL_SIZE = 10249\n        VALIDATION_SPLIT = split\n        TRAIN_SIZE = math.ceil(TOTAL_SIZE * VALIDATION_SPLIT)\n\n    if Dataset == 'UP':\n        uPavia = sio.loadmat(data_path + 'PaviaU.mat')\n        gt_uPavia = sio.loadmat(data_path + 'PaviaU_gt.mat')\n        data_hsi = uPavia['paviaU']\n        gt_hsi = gt_uPavia['paviaU_gt']\n        K = 103\n        TOTAL_SIZE = 42776\n        VALIDATION_SPLIT = split\n        TRAIN_SIZE = math.ceil(TOTAL_SIZE * VALIDATION_SPLIT)\n\n    if Dataset == 'SV':\n        SV = sio.loadmat(data_path + 'Salinas_corrected.mat')\n        gt_SV = sio.loadmat(data_path + 'Salinas_gt.mat')\n        data_hsi = SV['salinas_corrected']\n        gt_hsi = gt_SV['salinas_gt']\n        K = 15\n        TOTAL_SIZE = 54129\n        VALIDATION_SPLIT = split\n        TRAIN_SIZE = math.ceil(TOTAL_SIZE * VALIDATION_SPLIT)\n\n    if Dataset == 'KSC':\n        SV = sio.loadmat(data_path + 'KSC.mat')\n        gt_SV = sio.loadmat(data_path + 'KSC_gt.mat')\n        data_hsi = SV['KSC']\n        gt_hsi = gt_SV['KSC_gt']\n        K = data_hsi.shape[2]\n        TOTAL_SIZE = 5211\n        VALIDATION_SPLIT = split\n        TRAIN_SIZE = math.ceil(TOTAL_SIZE * VALIDATION_SPLIT)\n\n    shapeor = data_hsi.shape\n    data_hsi = data_hsi.reshape(-1, data_hsi.shape[-1])\n    data_hsi = PCA(n_components=K).fit_transform(data_hsi)\n    shapeor = np.array(shapeor)\n    shapeor[-1] = K\n    data_hsi = data_hsi.reshape(shapeor)\n\n    return data_hsi, gt_hsi, TOTAL_SIZE, TRAIN_SIZE, VALIDATION_SPLIT\n\n\n# # Pytorch Data Loader Creation\n\ndata_hsi, gt_hsi, TOTAL_SIZE, TRAIN_SIZE, VALIDATION_SPLIT = load_dataset(\n    Dataset, PARAM_VAL)\nprint(data_hsi.shape)\nimage_x, image_y, BAND = data_hsi.shape\ndata = data_hsi.reshape(\n    np.prod(data_hsi.shape[:2]), np.prod(data_hsi.shape[2:]))\ngt = gt_hsi.reshape(np.prod(gt_hsi.shape[:2]), )\nCLASSES_NUM = max(gt)\nprint('The class numbers of the HSI data is:', CLASSES_NUM)\n\nprint('-----Importing Setting Parameters-----')\nITER = PARAM_ITER\nPATCH_LENGTH = PATCH_SIZE\nlr, num_epochs, batch_size = 0.001, 200, 32\nloss = torch.nn.CrossEntropyLoss()\n\nimg_rows = 2 * PATCH_LENGTH + 1\nimg_cols = 2 * PATCH_LENGTH + 1\nimg_channels = data_hsi.shape[2]\nINPUT_DIMENSION = data_hsi.shape[2]\nALL_SIZE = data_hsi.shape[0] * data_hsi.shape[1]\nVAL_SIZE = int(TRAIN_SIZE)\nTEST_SIZE = TOTAL_SIZE - TRAIN_SIZE\n\nKAPPA = []\nOA = []\nAA = []\nTRAINING_TIME = []\nTESTING_TIME = []\nELEMENT_ACC = np.zeros((ITER, CLASSES_NUM))\n\ndata = preprocessing.scale(data)\ndata_ = data.reshape(data_hsi.shape[0], data_hsi.shape[1], data_hsi.shape[2])\nwhole_data = data_\npadded_data = np.lib.pad(\n    whole_data, ((PATCH_LENGTH, PATCH_LENGTH), (PATCH_LENGTH, PATCH_LENGTH),\n                 (0, 0)),\n    'constant',\n    constant_values=0)\n\n# # Model\n\n\nclass ChannelSELayer3D(nn.Module):\n    \"\"\"\n    3D extension of Squeeze-and-Excitation (SE) block described in:\n        *Hu et al., Squeeze-and-Excitation Networks, arXiv:1709.01507*\n        *Zhu et al., AnatomyNet, arXiv:arXiv:1808.05238*\n    \"\"\"\n\n    def __init__(self, num_channels, reduction_ratio=2):\n        \"\"\"\n        :param num_channels: No of input channels\n        :param reduction_ratio: By how much should the num_channels should be reduced\n        \"\"\"\n        super(ChannelSELayer3D, self).__init__()\n        self.avg_pool = nn.AdaptiveAvgPool3d(1)\n        num_channels_reduced = num_channels // reduction_ratio\n        self.reduction_ratio = reduction_ratio\n        self.fc1 = nn.Linear(num_channels, num_channels_reduced, bias=True)\n        self.fc2 = nn.Linear(num_channels_reduced, num_channels, bias=True)\n        self.relu = nn.ReLU()\n        self.sigmoid = nn.Sigmoid()\n\n    def forward(self, input_tensor):\n        \"\"\"\n        :param input_tensor: X, shape = (batch_size, num_channels, D, H, W)\n        :return: output tensor\n        \"\"\"\n        batch_size, num_channels, D, H, W = input_tensor.size()\n        # Average along each channel\n        squeeze_tensor = self.avg_pool(input_tensor)\n\n        # channel excitation\n        fc_out_1 = self.relu(\n            self.fc1(squeeze_tensor.view(batch_size, num_channels)))\n        fc_out_2 = self.sigmoid(self.fc2(fc_out_1))\n\n        output_tensor = torch.mul(\n            input_tensor, fc_out_2.view(batch_size, num_channels, 1, 1, 1))\n\n        return output_tensor\n\n\nclass SpatialSELayer3D(nn.Module):\n    \"\"\"\n    3D extension of SE block -- squeezing spatially and exciting channel-wise described in:\n        *Roy et al., Concurrent Spatial and Channel Squeeze & Excitation in Fully Convolutional Networks, MICCAI 2018*\n    \"\"\"\n\n    def __init__(self, num_channels):\n        \"\"\"\n        :param num_channels: No of input channels\n        \"\"\"\n        super(SpatialSELayer3D, self).__init__()\n        self.conv = nn.Conv3d(num_channels, 1, 1)\n        self.sigmoid = nn.Sigmoid()\n\n    def forward(self, input_tensor, weights=None):\n        \"\"\"\n        :param weights: weights for few shot learning\n        :param input_tensor: X, shape = (batch_size, num_channels, D, H, W)\n        :return: output_tensor\n        \"\"\"\n        # channel squeeze\n        batch_size, channel, D, H, W = input_tensor.size()\n\n        if weights:\n            weights = weights.view(1, channel, 1, 1)\n            out = F.conv2d(input_tensor, weights)\n        else:\n            out = self.conv(input_tensor)\n\n        squeeze_tensor = self.sigmoid(out)\n\n        # spatial excitation\n        output_tensor = torch.mul(input_tensor,\n                                  squeeze_tensor.view(batch_size, 1, D, H, W))\n\n        return output_tensor\n\n\nclass ChannelSpatialSELayer3D(nn.Module):\n    \"\"\"\n       3D extension of concurrent spatial and channel squeeze & excitation:\n           *Roy et al., Concurrent Spatial and Channel Squeeze & Excitation in Fully Convolutional Networks, arXiv:1803.02579*\n       \"\"\"\n\n    def __init__(self, num_channels, reduction_ratio=2):\n        \"\"\"\n        :param num_channels: No of input channels\n        :param reduction_ratio: By how much should the num_channels should be reduced\n        \"\"\"\n        super(ChannelSpatialSELayer3D, self).__init__()\n        self.cSE = ChannelSELayer3D(num_channels, reduction_ratio)\n        self.sSE = SpatialSELayer3D(num_channels)\n\n    def forward(self, input_tensor):\n        \"\"\"\n        :param input_tensor: X, shape = (batch_size, num_channels, D, H, W)\n        :return: output_tensor\n        \"\"\"\n        output_tensor = torch.max(\n            self.cSE(input_tensor), self.sSE(input_tensor))\n        return output_tensor\n\n\nclass ProjectExciteLayer(nn.Module):\n    \"\"\"\n        Project & Excite Module, specifically designed for 3D inputs\n        *quote*\n    \"\"\"\n\n    def __init__(self, num_channels, reduction_ratio=2):\n        \"\"\"\n        :param num_channels: No of input channels\n        :param reduction_ratio: By how much should the num_channels should be reduced\n        \"\"\"\n        super(ProjectExciteLayer, self).__init__()\n        num_channels_reduced = num_channels // reduction_ratio\n        self.reduction_ratio = reduction_ratio\n        self.relu = nn.ReLU()\n        self.conv_c = nn.Conv3d(\n            in_channels=num_channels,\n            out_channels=num_channels_reduced,\n            kernel_size=1,\n            stride=1)\n        self.conv_cT = nn.Conv3d(\n            in_channels=num_channels_reduced,\n            out_channels=num_channels,\n            kernel_size=1,\n            stride=1)\n        self.sigmoid = nn.Sigmoid()\n\n    def forward(self, input_tensor):\n        \"\"\"\n        :param input_tensor: X, shape = (batch_size, num_channels, D, H, W)\n        :return: output tensor\n        \"\"\"\n        batch_size, num_channels, D, H, W = input_tensor.size()\n\n        # Average along channels and different axes\n        squeeze_tensor_w = F.adaptive_avg_pool3d(input_tensor, (1, 1, W))\n\n        squeeze_tensor_h = F.adaptive_avg_pool3d(input_tensor, (1, H, 1))\n\n        squeeze_tensor_d = F.adaptive_avg_pool3d(input_tensor, (D, 1, 1))\n\n        # tile tensors to original size and add:\n        final_squeeze_tensor = sum([\n            squeeze_tensor_w.view(batch_size, num_channels, 1, 1, W),\n            squeeze_tensor_h.view(batch_size, num_channels, 1, H, 1),\n            squeeze_tensor_d.view(batch_size, num_channels, D, 1, 1)\n        ])\n\n        # Excitation:\n        final_squeeze_tensor = self.sigmoid(\n            self.conv_cT(self.relu(self.conv_c(final_squeeze_tensor))))\n        output_tensor = torch.mul(input_tensor, final_squeeze_tensor)\n\n        return output_tensor\n\n\nclass eca_layer(nn.Module):\n    \"\"\"Constructs a ECA module.\n    Args:\n        channel: Number of channels of the input feature map\n        k_size: Adaptive selection of kernel size\n    \"\"\"\n\n    def __init__(self, channel, k_size=3):\n        super(eca_layer, self).__init__()\n        self.avg_pool = nn.AdaptiveAvgPool3d(1)\n        self.conv = nn.Conv2d(\n            1, 1, kernel_size=k_size, padding=(k_size - 1) // 2, bias=False)\n        self.sigmoid = nn.Sigmoid()\n\n    def forward(self, x):\n        # x: input features with shape [b, c, h, w]\n        b, c, h, w, t = x.size()\n\n        # feature descriptor on the global spatial information\n        # 24, 1, 1, 1\n        y = self.avg_pool(x)\n\n        # Two different branches of ECA module\n        y = self.conv(y.squeeze(-1).transpose(-1, -3)).transpose(\n            -1, -3).unsqueeze(-1)\n\n        # Multi-scale information fusion\n        y = self.sigmoid(y)\n\n        return x * y.expand_as(x)\n\n\nclass Residual(nn.Module):  # pytorch\n    def __init__(\n            self,\n            in_channels,\n            out_channels,\n            kernel_size,\n            padding,\n            use_1x1conv=False,\n            stride=1,\n            start_block=False,\n            end_block=False,\n    ):\n        super(Residual, self).__init__()\n        self.conv1 = nn.Sequential(\n            nn.Conv3d(\n                in_channels,\n                out_channels,\n                kernel_size=kernel_size,\n                padding=padding,\n                stride=stride), nn.ReLU())\n        self.conv2 = nn.Conv3d(\n            out_channels,\n            out_channels,\n            kernel_size=kernel_size,\n            padding=padding,\n            stride=stride)\n        if use_1x1conv:\n            self.conv3 = nn.Conv3d(\n                in_channels, out_channels, kernel_size=1, stride=stride)\n        else:\n            self.conv3 = None\n\n        if not start_block:\n            self.bn0 = nn.BatchNorm3d(in_channels)\n\n        self.bn1 = nn.BatchNorm3d(out_channels)\n        self.bn2 = nn.BatchNorm3d(out_channels)\n\n        if start_block:\n            self.bn2 = nn.BatchNorm3d(out_channels)\n\n        if end_block:\n            self.bn2 = nn.BatchNorm3d(out_channels)\n\n        # ECA Attention Layer\n        self.ecalayer = eca_layer(out_channels)\n\n        # start and end block initialization\n        self.start_block = start_block\n        self.end_block = end_block\n\n    def forward(self, X):\n        identity = X\n\n        if self.start_block:\n            out = self.conv1(X)\n        else:\n            out = self.bn0(X)\n            out = F.relu(out)\n            out = self.conv1(out)\n\n        out = self.bn1(out)\n        out = F.relu(out)\n\n        out = self.conv2(out)\n\n        if self.start_block:\n            out = self.bn2(out)\n\n        out = self.ecalayer(out)\n\n        out += identity\n\n        if self.end_block:\n            out = self.bn2(out)\n            out = F.relu(out)\n\n        return out\n\n\nclass S3KAIResNet(nn.Module):\n    def __init__(self, band, classes, reduction):\n        super(S3KAIResNet, self).__init__()\n        self.name = 'SSRN'\n        self.conv1x1 = nn.Conv3d(\n            in_channels=1,\n            out_channels=PARAM_KERNEL_SIZE,\n            kernel_size=(1, 1, 7),\n            stride=(1, 1, 2),\n            padding=0)\n        self.conv3x3 = nn.Conv3d(\n            in_channels=1,\n            out_channels=PARAM_KERNEL_SIZE,\n            kernel_size=(3, 3, 7),\n            stride=(1, 1, 2),\n            padding=(1, 1, 0))\n\n        self.batch_norm1x1 = nn.Sequential(\n            nn.BatchNorm3d(\n                PARAM_KERNEL_SIZE, eps=0.001, momentum=0.1,\n                affine=True),  # 0.1\n            nn.ReLU(inplace=True))\n        self.batch_norm3x3 = nn.Sequential(\n            nn.BatchNorm3d(\n                PARAM_KERNEL_SIZE, eps=0.001, momentum=0.1,\n                affine=True),  # 0.1\n            nn.ReLU(inplace=True))\n\n        self.pool = nn.AdaptiveAvgPool3d(1)\n        self.conv_se = nn.Sequential(\n            nn.Conv3d(\n                PARAM_KERNEL_SIZE, band // reduction, 1, padding=0, bias=True),\n            nn.ReLU(inplace=True))\n        self.conv_ex = nn.Conv3d(\n            band // reduction, PARAM_KERNEL_SIZE, 1, padding=0, bias=True)\n        self.softmax = nn.Softmax(dim=1)\n\n        self.res_net1 = Residual(\n            PARAM_KERNEL_SIZE,\n            PARAM_KERNEL_SIZE, (1, 1, 7), (0, 0, 3),\n            start_block=True)\n        self.res_net2 = Residual(PARAM_KERNEL_SIZE, PARAM_KERNEL_SIZE,\n                                 (1, 1, 7), (0, 0, 3))\n        self.res_net3 = Residual(PARAM_KERNEL_SIZE, PARAM_KERNEL_SIZE,\n                                 (3, 3, 1), (1, 1, 0))\n        self.res_net4 = Residual(\n            PARAM_KERNEL_SIZE,\n            PARAM_KERNEL_SIZE, (3, 3, 1), (1, 1, 0),\n            end_block=True)\n\n        kernel_3d = math.ceil((band - 6) / 2)\n        # print(kernel_3d)\n\n        self.conv2 = nn.Conv3d(\n            in_channels=PARAM_KERNEL_SIZE,\n            out_channels=128,\n            padding=(0, 0, 0),\n            kernel_size=(1, 1, kernel_3d),\n            stride=(1, 1, 1))\n        self.batch_norm2 = nn.Sequential(\n            nn.BatchNorm3d(128, eps=0.001, momentum=0.1, affine=True),  # 0.1\n            nn.ReLU(inplace=True))\n        self.conv3 = nn.Conv3d(\n            in_channels=1,\n            out_channels=PARAM_KERNEL_SIZE,\n            padding=(0, 0, 0),\n            kernel_size=(3, 3, 128),\n            stride=(1, 1, 1))\n        self.batch_norm3 = nn.Sequential(\n            nn.BatchNorm3d(\n                PARAM_KERNEL_SIZE, eps=0.001, momentum=0.1,\n                affine=True),  # 0.1\n            nn.ReLU(inplace=True))\n\n        self.avg_pooling = nn.AvgPool3d(kernel_size=(5, 5, 1))\n        self.full_connection = nn.Sequential(\n            nn.Linear(PARAM_KERNEL_SIZE, classes)\n            # nn.Softmax()\n        )\n\n    def forward(self, X):\n        x_1x1 = self.conv1x1(X)\n        x_1x1 = self.batch_norm1x1(x_1x1).unsqueeze(dim=1)\n        x_3x3 = self.conv3x3(X)\n        x_3x3 = self.batch_norm3x3(x_3x3).unsqueeze(dim=1)\n\n        x1 = torch.cat([x_3x3, x_1x1], dim=1)\n        U = torch.sum(x1, dim=1)\n        S = self.pool(U)\n        Z = self.conv_se(S)\n        attention_vector = torch.cat(\n            [\n                self.conv_ex(Z).unsqueeze(dim=1),\n                self.conv_ex(Z).unsqueeze(dim=1)\n            ],\n            dim=1)\n        attention_vector = self.softmax(attention_vector)\n        V = (x1 * attention_vector).sum(dim=1)\n\n        x2 = self.res_net1(V)\n        x2 = self.res_net2(x2)\n        x2 = self.batch_norm2(self.conv2(x2))\n        x2 = x2.permute(0, 4, 2, 3, 1)\n        x2 = self.batch_norm3(self.conv3(x2))\n\n        x3 = self.res_net3(x2)\n        x3 = self.res_net4(x3)\n        x4 = self.avg_pooling(x3)\n        x4 = x4.view(x4.size(0), -1)\n        return self.full_connection(x4)\n\n\nmodel = S3KAIResNet(BAND, CLASSES_NUM, 2).cuda()\n\nsummary(model, input_data=(1, img_rows, img_cols, BAND), verbose=1)\n\n\ndef train(net,\n          train_iter,\n          valida_iter,\n          loss,\n          optimizer,\n          device,\n          epochs,\n          early_stopping=True,\n          early_num=20):\n    loss_list = [100]\n    early_epoch = 0\n\n    net = net.to(device)\n    print(\"training on \", device)\n    start = time.time()\n    train_loss_list = []\n    valida_loss_list = []\n    train_acc_list = []\n    valida_acc_list = []\n    for epoch in range(epochs):\n        train_acc_sum, n = 0.0, 0\n        time_epoch = time.time()\n        lr_adjust = torch.optim.lr_scheduler.CosineAnnealingLR(\n            optimizer, 15, eta_min=0.0, last_epoch=-1)\n        for X, y in train_iter:\n\n            batch_count, train_l_sum = 0, 0\n            X = X.to(device)\n            y = y.to(device)\n            y_hat = net(X)\n            l = loss(y_hat, y.long())\n\n            optimizer.zero_grad()\n            l.backward()\n            optimizer.step()\n            train_l_sum += l.cpu().item()\n            train_acc_sum += (y_hat.argmax(dim=1) == y).sum().cpu().item()\n            n += y.shape[0]\n            batch_count += 1\n        lr_adjust.step()\n        valida_acc, valida_loss = record.evaluate_accuracy(\n            valida_iter, net, loss, device)\n        loss_list.append(valida_loss)\n\n        train_loss_list.append(train_l_sum)  # / batch_count)\n        train_acc_list.append(train_acc_sum / n)\n        valida_loss_list.append(valida_loss)\n        valida_acc_list.append(valida_acc)\n\n        print(\n            'epoch %d, train loss %.6f, train acc %.3f, valida loss %.6f, valida acc %.3f, time %.1f sec'\n            % (epoch + 1, train_l_sum / batch_count, train_acc_sum / n,\n               valida_loss, valida_acc, time.time() - time_epoch))\n\n        PATH = \"./net_DBA.pt\"\n\n        if early_stopping and loss_list[-2] < loss_list[-1]:\n            if early_epoch == 0:\n                torch.save(net.state_dict(), PATH)\n            early_epoch += 1\n            loss_list[-1] = loss_list[-2]\n            if early_epoch == early_num:\n                net.load_state_dict(torch.load(PATH))\n                break\n        else:\n            early_epoch = 0\n\n    print('epoch %d, loss %.4f, train acc %.3f, time %.1f sec'\n          % (epoch + 1, train_l_sum / batch_count, train_acc_sum / n,\n             time.time() - start))\n\n\ndef sampling(proportion, ground_truth):\n    train = {}\n    test = {}\n    labels_loc = {}\n    m = max(ground_truth)\n    for i in range(m):\n        indexes = [\n            j for j, x in enumerate(ground_truth.ravel().tolist())\n            if x == i + 1\n        ]\n        np.random.shuffle(indexes)\n        labels_loc[i] = indexes\n        if proportion != 1:\n            nb_val = max(int((1 - proportion) * len(indexes)), 3)\n        else:\n            nb_val = 0\n        train[i] = indexes[:nb_val]\n        test[i] = indexes[nb_val:]\n    train_indexes = []\n    test_indexes = []\n    for i in range(m):\n        train_indexes += train[i]\n        test_indexes += test[i]\n    np.random.shuffle(train_indexes)\n    np.random.shuffle(test_indexes)\n    return train_indexes, test_indexes\n\n\ndef select(groundTruth):  #divide dataset into train and test datasets\n    labels_loc = {}\n    train = {}\n    test = {}\n    m = max(groundTruth)\n    #amount = [3, 41, 29, 7, 14, 20, 2, 15, 3, 36, 64, 22, 4, 28, 10, 2]\n    #amount = [43, 1387, 801, 230, 469, 710, 26, 463, 17, 936, 2391, 571, 201, 1237, 376, 91]\n    if Dataset == 'IN':\n        amount = [\n            35, 1011, 581, 167, 344, 515, 19, 327, 12, 683, 1700, 418, 138,\n            876, 274, 69\n        ]  #IP 20%\n    #amount = [6, 144, 84, 24, 50, 75, 3, 49, 2, 97, 247, 62, 22, 130, 38, 10]   #IP 20%\n    if Dataset == 'UP':\n        amount = [5297, 14974, 1648, 2424, 1076, 4026, 1046, 2950, 755]  #UP\n    if Dataset == 'KSC':\n        amount = [\n            530, 165, 176, 170, 110, 161, 80, 299, 377, 283, 296, 341, 654\n        ]  #KSC\n    for i in range(m):\n        indices = [\n            j for j, x in enumerate(groundTruth.ravel().tolist()) if x == i + 1\n        ]\n        np.random.shuffle(indices)\n        labels_loc[i] = indices\n        nb_val = int(amount[i])\n        train[i] = indices[:-nb_val]\n        test[i] = indices[-nb_val:]\n#    whole_indices = []\n    train_indices = []\n    test_indices = []\n    for i in range(m):\n        #        whole_indices += labels_loc[i]\n        train_indices += train[i]\n        test_indices += test[i]\n    np.random.shuffle(train_indices)\n    np.random.shuffle(test_indices)\n    return train_indices, test_indices\n\n\n# # Training\n\nfor index_iter in range(ITER):\n    print('iter:', index_iter)\n    #define the model\n    net = S3KAIResNet(BAND, CLASSES_NUM, 2)\n\n    if PARAM_OPTIM == 'diffgrad':\n        optimizer = optim2.DiffGrad(\n            net.parameters(),\n            lr=lr,\n            betas=(0.9, 0.999),\n            eps=1e-8,\n            weight_decay=0)  # weight_decay=0.0001)\n    if PARAM_OPTIM == 'adam':\n        optimizer = optim.Adam(\n            net.parameters(),\n            lr=1e-3,\n            betas=(0.9, 0.999),\n            eps=1e-8,\n            weight_decay=0)\n    time_1 = int(time.time())\n    np.random.seed(seeds[index_iter])\n    # train_indices, test_indices = select(gt)\n    train_indices, test_indices = sampling(VALIDATION_SPLIT, gt)\n    _, total_indices = sampling(1, gt)\n\n    TRAIN_SIZE = len(train_indices)\n    print('Train size: ', TRAIN_SIZE)\n    TEST_SIZE = TOTAL_SIZE - TRAIN_SIZE\n    print('Test size: ', TEST_SIZE)\n    VAL_SIZE = int(TRAIN_SIZE)\n    print('Validation size: ', VAL_SIZE)\n\n    print('-----Selecting Small Pieces from the Original Cube Data-----')\n    train_iter, valida_iter, test_iter, all_iter = geniter.generate_iter(\n        TRAIN_SIZE, train_indices, TEST_SIZE, test_indices, TOTAL_SIZE,\n        total_indices, VAL_SIZE, whole_data, PATCH_LENGTH, padded_data,\n        INPUT_DIMENSION, 16, gt)  #batchsize in 1\n\n    tic1 = time.time()\n    train(\n        net,\n        train_iter,\n        valida_iter,\n        loss,\n        optimizer,\n        device,\n        epochs=PARAM_EPOCH)\n    toc1 = time.time()\n\n    pred_test = []\n    tic2 = time.time()\n    with torch.no_grad():\n        for X, y in test_iter:\n            # print('Shape of X', X.shape, 'Shape of y', y.shape)\n            # X = X.permute(0, 3, 1, 2)\n            X = X.to(device)\n            net.eval()\n            y_hat = net(X)\n            pred_test.extend(np.array(net(X).cpu().argmax(axis=1)))\n    toc2 = time.time()\n    collections.Counter(pred_test)\n    gt_test = gt[test_indices] - 1\n\n    overall_acc = metrics.accuracy_score(pred_test, gt_test[:-VAL_SIZE])\n    confusion_matrix = metrics.confusion_matrix(pred_test, gt_test[:-VAL_SIZE])\n    each_acc, average_acc = record.aa_and_each_accuracy(confusion_matrix)\n    kappa = metrics.cohen_kappa_score(pred_test, gt_test[:-VAL_SIZE])\n\n    torch.save(\n        net.state_dict(), \"./models/S3KAIResNetpatch_\" + str(img_rows) + '_' +\n        Dataset + '_split_' + str(VALIDATION_SPLIT) + '_lr_' + str(lr) +\n        PARAM_OPTIM + '_kernel_' + str(PARAM_KERNEL_SIZE) + str(\n            round(overall_acc, 3)) + '.pt')\n    KAPPA.append(kappa)\n    OA.append(overall_acc)\n    AA.append(average_acc)\n    TRAINING_TIME.append(toc1 - tic1)\n    TESTING_TIME.append(toc2 - tic2)\n    ELEMENT_ACC[index_iter, :] = each_acc\n\n# # Map, Records\nprint(\"--------\" + \" Training Finished-----------\")\nrecord.record_output(\n    OA, AA, KAPPA, ELEMENT_ACC, TRAINING_TIME, TESTING_TIME,\n    './report/' + 'S3KAIResNetpatch:' + str(img_rows) + '_' + Dataset + 'split'\n    + str(VALIDATION_SPLIT) + 'lr' + str(lr) + PARAM_OPTIM + '_kernel_' +\n    str(PARAM_KERNEL_SIZE) + '.txt')\n\nUtils.generate_png(\n    all_iter, net, gt_hsi, Dataset, device, total_indices,\n    './classification_maps/' + 'S3KAIResNetpatch:' + str(img_rows) + '_' +\n    Dataset + 'split' + str(VALIDATION_SPLIT) + 'lr' + str(lr) + PARAM_OPTIM +\n    '_kernel_' + str(PARAM_KERNEL_SIZE))\n"
  },
  {
    "path": "A2S2KResNet/Utils.py",
    "content": "import numpy as np\nfrom sklearn import metrics, preprocessing\nfrom sklearn.preprocessing import MinMaxScaler\nfrom sklearn.decomposition import PCA\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import confusion_matrix, accuracy_score, classification_report, cohen_kappa_score\nfrom operator import truediv\nimport matplotlib.pyplot as plt\nimport scipy.io as sio\nimport os\nimport spectral\nimport torch\nimport cv2\nfrom operator import truediv\n\n\ndef sampling(proportion, ground_truth):\n    train = {}\n    test = {}\n    labels_loc = {}\n    m = max(ground_truth)\n    for i in range(m):\n        indexes = [\n            j for j, x in enumerate(ground_truth.ravel().tolist())\n            if x == i + 1\n        ]\n        np.random.shuffle(indexes)\n        labels_loc[i] = indexes\n        if proportion != 1:\n            nb_val = max(int((1 - proportion) * len(indexes)), 3)\n        else:\n            nb_val = 0\n        train[i] = indexes[:nb_val]\n        test[i] = indexes[nb_val:]\n    train_indexes = []\n    test_indexes = []\n    for i in range(m):\n        train_indexes += train[i]\n        test_indexes += test[i]\n    np.random.shuffle(train_indexes)\n    np.random.shuffle(test_indexes)\n    return train_indexes, test_indexes\n\n\ndef set_figsize(figsize=(3.5, 2.5)):\n    display.set_matplotlib_formats('svg')\n    plt.rcParams['figure.figsize'] = figsize\n\n\ndef classification_map(map, ground_truth, dpi, save_path):\n    fig = plt.figure(frameon=False)\n    fig.set_size_inches(ground_truth.shape[1] * 2.0 / dpi,\n                        ground_truth.shape[0] * 2.0 / dpi)\n    ax = plt.Axes(fig, [0., 0., 1., 1.])\n    ax.set_axis_off()\n    ax.xaxis.set_visible(False)\n    ax.yaxis.set_visible(False)\n    fig.add_axes(ax)\n    ax.imshow(map)\n    fig.savefig(save_path, dpi=dpi)\n    return 0\n\n\ndef list_to_colormap(x_list):\n    y = np.zeros((x_list.shape[0], 3))\n    for index, item in enumerate(x_list):\n        if item == 0:\n            y[index] = np.array([255, 0, 0]) / 255.\n        if item == 1:\n            y[index] = np.array([0, 255, 0]) / 255.\n        if item == 2:\n            y[index] = np.array([0, 0, 255]) / 255.\n        if item == 3:\n            y[index] = np.array([255, 255, 0]) / 255.\n        if item == 4:\n            y[index] = np.array([0, 255, 255]) / 255.\n        if item == 5:\n            y[index] = np.array([255, 0, 255]) / 255.\n        if item == 6:\n            y[index] = np.array([192, 192, 192]) / 255.\n        if item == 7:\n            y[index] = np.array([128, 128, 128]) / 255.\n        if item == 8:\n            y[index] = np.array([128, 0, 0]) / 255.\n        if item == 9:\n            y[index] = np.array([128, 128, 0]) / 255.\n        if item == 10:\n            y[index] = np.array([0, 128, 0]) / 255.\n        if item == 11:\n            y[index] = np.array([128, 0, 128]) / 255.\n        if item == 12:\n            y[index] = np.array([0, 128, 128]) / 255.\n        if item == 13:\n            y[index] = np.array([0, 0, 128]) / 255.\n        if item == 14:\n            y[index] = np.array([255, 165, 0]) / 255.\n        if item == 15:\n            y[index] = np.array([255, 215, 0]) / 255.\n        if item == 16:\n            y[index] = np.array([0, 0, 0]) / 255.\n        if item == 17:\n            y[index] = np.array([215, 255, 0]) / 255.\n        if item == 18:\n            y[index] = np.array([0, 255, 215]) / 255.\n        if item == -1:\n            y[index] = np.array([0, 0, 0]) / 255.\n    return y\n\n\ndef generate_png(all_iter, net, gt_hsi, Dataset, device, total_indices, path):\n    pred_test = []\n    for X, y in all_iter:\n        #X = X.permute(0, 3, 1, 2)\n        X = X.to(device)\n        net.eval()\n        pred_test.extend(net(X).cpu().argmax(axis=1).detach().numpy())\n    gt = gt_hsi.flatten()\n    x_label = np.zeros(gt.shape)\n    for i in range(len(gt)):\n        if gt[i] == 0:\n            gt[i] = 17\n            x_label[i] = 16\n    gt = gt[:] - 1\n    x_label[total_indices] = pred_test\n    x = np.ravel(x_label)\n    y_list = list_to_colormap(x)\n    y_gt = list_to_colormap(gt)\n    y_re = np.reshape(y_list, (gt_hsi.shape[0], gt_hsi.shape[1], 3))\n    gt_re = np.reshape(y_gt, (gt_hsi.shape[0], gt_hsi.shape[1], 3))\n    classification_map(y_re, gt_hsi, 300,\n                       path + '.png')\n    classification_map(gt_re, gt_hsi, 300,\n                       path + '_gt.png')\n    print('------Get classification maps successful-------')\n"
  },
  {
    "path": "A2S2KResNet/geniter.py",
    "content": "import torch\nimport numpy as np\nimport torch.utils.data as Data\n\ndef index_assignment(index, row, col, pad_length):\n    new_assign = {}\n    for counter, value in enumerate(index):\n        assign_0 = value // col + pad_length\n        assign_1 = value % col + pad_length\n        new_assign[counter] = [assign_0, assign_1]\n    return new_assign\n\ndef select_patch(matrix, pos_row, pos_col, ex_len):\n    selected_rows = matrix[range(pos_row-ex_len, pos_row+ex_len+1)]\n    selected_patch = selected_rows[:, range(pos_col-ex_len, pos_col+ex_len+1)]\n    return selected_patch\n\n\ndef select_small_cubic(data_size, data_indices, whole_data, patch_length, padded_data, dimension):\n    small_cubic_data = np.zeros((data_size, 2 * patch_length + 1, 2 * patch_length + 1, dimension))\n    data_assign = index_assignment(data_indices, whole_data.shape[0], whole_data.shape[1], patch_length)\n    for i in range(len(data_assign)):\n        small_cubic_data[i] = select_patch(padded_data, data_assign[i][0], data_assign[i][1], patch_length)\n    return small_cubic_data\n\n\ndef generate_iter(TRAIN_SIZE, train_indices, TEST_SIZE, test_indices, TOTAL_SIZE, total_indices, VAL_SIZE,\n                  whole_data, PATCH_LENGTH, padded_data, INPUT_DIMENSION, batch_size, gt):\n    gt_all = gt[total_indices] - 1\n    y_train = gt[train_indices] - 1\n    y_test = gt[test_indices] - 1\n\n    all_data =  select_small_cubic(TOTAL_SIZE, total_indices, whole_data,\n                                                      PATCH_LENGTH, padded_data, INPUT_DIMENSION)\n\n    train_data = select_small_cubic(TRAIN_SIZE, train_indices, whole_data,\n                                                        PATCH_LENGTH, padded_data, INPUT_DIMENSION)\n    print(train_data.shape)\n    test_data =  select_small_cubic(TEST_SIZE, test_indices, whole_data,\n                                                       PATCH_LENGTH, padded_data, INPUT_DIMENSION)\n    x_train = train_data.reshape(train_data.shape[0], train_data.shape[1], train_data.shape[2], INPUT_DIMENSION)\n    x_test_all = test_data.reshape(test_data.shape[0], test_data.shape[1], test_data.shape[2], INPUT_DIMENSION)\n\n    x_val = x_test_all[-VAL_SIZE:]\n    y_val = y_test[-VAL_SIZE:]\n\n    x_test = x_test_all[:-VAL_SIZE]\n    y_test = y_test[:-VAL_SIZE]\n    \n    x1_tensor_train = torch.from_numpy(x_train).type(torch.FloatTensor).unsqueeze(1)\n    y1_tensor_train = torch.from_numpy(y_train).type(torch.FloatTensor)\n    torch_dataset_train = Data.TensorDataset(x1_tensor_train, y1_tensor_train)\n\n    x1_tensor_valida = torch.from_numpy(x_val).type(torch.FloatTensor).unsqueeze(1)\n    y1_tensor_valida = torch.from_numpy(y_val).type(torch.FloatTensor)\n    torch_dataset_valida = Data.TensorDataset(x1_tensor_valida, y1_tensor_valida)\n\n    x1_tensor_test = torch.from_numpy(x_test).type(torch.FloatTensor).unsqueeze(1)\n    y1_tensor_test = torch.from_numpy(y_test).type(torch.FloatTensor)\n    torch_dataset_test = Data.TensorDataset(x1_tensor_test,y1_tensor_test)\n\n    all_data.reshape(all_data.shape[0], all_data.shape[1], all_data.shape[2], INPUT_DIMENSION)\n    all_tensor_data = torch.from_numpy(all_data).type(torch.FloatTensor).unsqueeze(1)\n    all_tensor_data_label = torch.from_numpy(gt_all).type(torch.FloatTensor)\n    torch_dataset_all = Data.TensorDataset(all_tensor_data, all_tensor_data_label)\n\n\n    train_iter = Data.DataLoader(\n        dataset=torch_dataset_train,  # torch TensorDataset format\n        batch_size=batch_size,  # mini batch size\n        shuffle=True,  \n        num_workers=0, \n    )\n    valiada_iter = Data.DataLoader(\n        dataset=torch_dataset_valida,  # torch TensorDataset format\n        batch_size=batch_size,  # mini batch size\n        shuffle=True,  \n        num_workers=0, \n    )\n    test_iter = Data.DataLoader(\n        dataset=torch_dataset_test,  # torch TensorDataset format\n        batch_size=batch_size,  # mini batch size\n        shuffle=False, \n        num_workers=0, \n    )\n    all_iter = Data.DataLoader(\n        dataset=torch_dataset_all,  # torch TensorDataset format\n        batch_size=batch_size,  # mini batch size\n        shuffle=False, \n        num_workers=0, \n    )\n    return train_iter, valiada_iter, test_iter, all_iter #, y_test\n"
  },
  {
    "path": "A2S2KResNet/record.py",
    "content": "import numpy as np\nimport torch\nfrom operator import truediv\n\ndef evaluate_accuracy(data_iter, net, loss, device):\n    acc_sum, n = 0.0, 0\n    with torch.no_grad():\n        for X, y in data_iter:\n            test_l_sum, test_num = 0, 0\n            #X = X.permute(0, 3, 1, 2)\n            X = X.to(device)\n            y = y.to(device)\n            net.eval() \n            y_hat = net(X)\n            l = loss(y_hat, y.long())\n            acc_sum += (y_hat.argmax(dim=1) == y.to(device)).float().sum().cpu().item()\n            test_l_sum += l\n            test_num += 1\n            net.train() \n            n += y.shape[0]\n    return [acc_sum / n, test_l_sum] # / test_num]\n\n\ndef aa_and_each_accuracy(confusion_matrix):\n    list_diag = np.diag(confusion_matrix)\n    list_raw_sum = np.sum(confusion_matrix, axis=1)\n    each_acc = np.nan_to_num(truediv(list_diag, list_raw_sum))\n    average_acc = np.mean(each_acc)\n    return each_acc, average_acc\n\n\n\ndef record_output(oa_ae, aa_ae, kappa_ae, element_acc_ae, training_time_ae, testing_time_ae, path):\n    f = open(path, 'a')\n    sentence0 = 'OAs for each iteration are:' + str(oa_ae) + '\\n'\n    f.write(sentence0)\n    sentence1 = 'AAs for each iteration are:' + str(aa_ae) + '\\n'\n    f.write(sentence1)\n    sentence2 = 'KAPPAs for each iteration are:' + str(kappa_ae) + '\\n' + '\\n'\n    f.write(sentence2)\n    sentence3 = 'mean_OA ± std_OA is: ' + str(np.mean(oa_ae)) + ' ± ' + str(np.std(oa_ae)) + '\\n'\n    f.write(sentence3)\n    sentence4 = 'mean_AA ± std_AA is: ' + str(np.mean(aa_ae)) + ' ± ' + str(np.std(aa_ae)) + '\\n'\n    f.write(sentence4)\n    sentence5 = 'mean_KAPPA ± std_KAPPA is: ' + str(np.mean(kappa_ae)) + ' ± ' + str(np.std(kappa_ae)) + '\\n' + '\\n'\n    f.write(sentence5)\n    sentence6 = 'Total average Training time is: ' + str(np.sum(training_time_ae)) + '\\n'\n    f.write(sentence6)\n    sentence7 = 'Total average Testing time is: ' + str(np.sum(testing_time_ae)) + '\\n' + '\\n'\n    f.write(sentence7)\n    element_mean = np.mean(element_acc_ae, axis=0)\n    element_std = np.std(element_acc_ae, axis=0)\n    sentence8 = \"Mean of all elements in confusion matrix: \" + str(element_mean) + '\\n'\n    f.write(sentence8)\n    sentence9 = \"Standard deviation of all elements in confusion matrix: \" + str(element_std) + '\\n'\n    f.write(sentence9)\n    f.close()\n\n"
  },
  {
    "path": "ContextualNet/ContextualNet.py",
    "content": "#!/usr/bin/env python\n# coding: utf-8\n\n# # Imports\n\nimport argparse\nimport collections\nimport math\nimport time\n\nimport numpy as np\nimport scipy.io as sio\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.optim as optim\nfrom sklearn import metrics, preprocessing\nfrom sklearn.decomposition import PCA\nfrom sklearn.metrics import confusion_matrix\n\nimport geniter\nimport record\nimport torch_optimizer as optim2\nimport Utils\nfrom torchsummary import summary\n\n# # Setting Params\n\nparser = argparse.ArgumentParser(description='Training for HSI')\nparser.add_argument(\n    '-d', '--dataset', dest='dataset', default='IN', help=\"Name of dataset.\")\nparser.add_argument(\n    '-o',\n    '--optimizer',\n    dest='optimizer',\n    default='adam',\n    help=\"Name of optimizer.\")\nparser.add_argument(\n    '-e', '--epoch', type=int, dest='epoch', default=200, help=\"No of epoch\")\nparser.add_argument(\n    '-i', '--iter', type=int, dest='iter', default=3, help=\"No of iter\")\nparser.add_argument(\n    '-p', '--patch', type=int, dest='patch', default=4, help=\"Length of patch\")\nparser.add_argument(\n    '-vs',\n    '--valid_split',\n    type=float,\n    dest='valid_split',\n    default=0.9,\n    help=\"Percentage of validation split.\")\nargs = parser.parse_args()\n\nPARAM_DATASET = args.dataset  # UP,IN,SV, KSC\nPARAM_EPOCH = args.epoch\nPARAM_ITER = args.iter\nPATCH_SIZE = args.patch\nPARAM_VAL = args.valid_split\nPARAM_OPTIM = args.optimizer\n\n# # Data Loading\n\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n\n# for Monte Carlo runs\nseeds = [1331, 1332, 1333, 1334, 1335, 1336, 1337, 1338, 1339, 1340, 1341]\nensemble = 1\n\nglobal Dataset  # UP,IN,SV, KSC\ndataset = PARAM_DATASET  #input('Please input the name of Dataset(IN, UP, SV, KSC):')\nDataset = dataset.upper()\n\n\ndef load_dataset(Dataset, split=0.9):\n    data_path = '../dataset/'\n    if Dataset == 'IN':\n        mat_data = sio.loadmat(data_path + 'Indian_pines_corrected.mat')\n        mat_gt = sio.loadmat(data_path + 'Indian_pines_gt.mat')\n        data_hsi = mat_data['indian_pines_corrected']\n        gt_hsi = mat_gt['indian_pines_gt']\n        K = data_hsi.shape[2]\n        TOTAL_SIZE = 10249\n        VALIDATION_SPLIT = split\n        TRAIN_SIZE = math.ceil(TOTAL_SIZE * VALIDATION_SPLIT)\n\n    if Dataset == 'UP':\n        uPavia = sio.loadmat(data_path + 'PaviaU.mat')\n        gt_uPavia = sio.loadmat(data_path + 'PaviaU_gt.mat')\n        data_hsi = uPavia['paviaU']\n        gt_hsi = gt_uPavia['paviaU_gt']\n        K = data_hsi.shape[2]\n        TOTAL_SIZE = 42776\n        VALIDATION_SPLIT = split\n        TRAIN_SIZE = math.ceil(TOTAL_SIZE * VALIDATION_SPLIT)\n\n    if Dataset == 'SV':\n        SV = sio.loadmat(data_path + 'Salinas_corrected.mat')\n        gt_SV = sio.loadmat(data_path + 'Salinas_gt.mat')\n        data_hsi = SV['salinas_corrected']\n        gt_hsi = gt_SV['salinas_gt']\n        K = data_hsi.shape[2]\n        TOTAL_SIZE = 54129\n        VALIDATION_SPLIT = split\n        TRAIN_SIZE = math.ceil(TOTAL_SIZE * VALIDATION_SPLIT)\n\n    if Dataset == 'KSC':\n        SV = sio.loadmat(data_path + 'KSC.mat')\n        gt_SV = sio.loadmat(data_path + 'KSC_gt.mat')\n        data_hsi = SV['KSC']\n        gt_hsi = gt_SV['KSC_gt']\n        K = data_hsi.shape[2]\n        TOTAL_SIZE = 5211\n        VALIDATION_SPLIT = split\n        TRAIN_SIZE = math.ceil(TOTAL_SIZE * VALIDATION_SPLIT)\n\n    shapeor = data_hsi.shape\n    data_hsi = data_hsi.reshape(-1, data_hsi.shape[-1])\n    data_hsi = PCA(n_components=K).fit_transform(data_hsi)\n    shapeor = np.array(shapeor)\n    shapeor[-1] = K\n    data_hsi = data_hsi.reshape(shapeor)\n\n    return data_hsi, gt_hsi, TOTAL_SIZE, TRAIN_SIZE, VALIDATION_SPLIT\n\n\n# # Pytorch Data Loader Creation\n\ndata_hsi, gt_hsi, TOTAL_SIZE, TRAIN_SIZE, VALIDATION_SPLIT = load_dataset(\n    Dataset, PARAM_VAL)\nprint(data_hsi.shape)\nimage_x, image_y, BAND = data_hsi.shape\ndata = data_hsi.reshape(\n    np.prod(data_hsi.shape[:2]), np.prod(data_hsi.shape[2:]))\ngt = gt_hsi.reshape(np.prod(gt_hsi.shape[:2]), )\nCLASSES_NUM = max(gt)\nprint('The class numbers of the HSI data is:', CLASSES_NUM)\n\nprint('-----Importing Setting Parameters-----')\nITER = PARAM_ITER\nPATCH_LENGTH = PATCH_SIZE\nlr, num_epochs, batch_size = 0.001, 200, 32\nloss = torch.nn.CrossEntropyLoss()\n\nimg_rows = 2 * PATCH_LENGTH + 1\nimg_cols = 2 * PATCH_LENGTH + 1\nimg_channels = data_hsi.shape[2]\nINPUT_DIMENSION = data_hsi.shape[2]\nALL_SIZE = data_hsi.shape[0] * data_hsi.shape[1]\nVAL_SIZE = int(TRAIN_SIZE)\nTEST_SIZE = TOTAL_SIZE - TRAIN_SIZE\n\nKAPPA = []\nOA = []\nAA = []\nTRAINING_TIME = []\nTESTING_TIME = []\nELEMENT_ACC = np.zeros((ITER, CLASSES_NUM))\n\ndata = preprocessing.scale(data)\ndata_ = data.reshape(data_hsi.shape[0], data_hsi.shape[1], data_hsi.shape[2])\nwhole_data = data_\npadded_data = np.lib.pad(\n    whole_data, ((PATCH_LENGTH, PATCH_LENGTH), (PATCH_LENGTH, PATCH_LENGTH),\n                 (0, 0)),\n    'constant',\n    constant_values=0)\n\n# # Model\n\n\nclass LeeEtAl(nn.Module):\n    \"\"\"\n    CONTEXTUAL DEEP CNN BASED HYPERSPECTRAL CLASSIFICATION\n    Hyungtae Lee and Heesung Kwon\n    IGARSS 2016\n    \"\"\"\n\n    @staticmethod\n    def weight_init(m):\n        if isinstance(m, nn.Linear) or isinstance(m, nn.Conv3d):\n            init.kaiming_uniform_(m.weight)\n            init.zeros_(m.bias)\n\n    def __init__(self, in_channels, n_classes):\n        super(LeeEtAl, self).__init__()\n        # The first convolutional layer applied to the input hyperspectral\n        # image uses an inception module that locally convolves the input\n        # image with two convolutional filters with different sizes\n        # (1x1xB and 3x3xB where B is the number of spectral bands)\n        self.conv_3x3 = nn.Conv3d(\n            1, 128, (3, 3, in_channels), stride=(1, 1, 2), padding=(1, 1, 0))\n        self.conv_1x1 = nn.Conv3d(\n            1, 128, (1, 1, in_channels), stride=(1, 1, 1), padding=0)\n        self.name = 'LeeEtAl'\n\n        # We use two modules from the residual learning approach\n        # Residual block 1\n        self.conv1 = nn.Conv2d(256, 128, (1, 1))\n        self.conv2 = nn.Conv2d(128, 128, (1, 1))\n        self.conv3 = nn.Conv2d(128, 128, (1, 1))\n\n        # Residual block 2\n        self.conv4 = nn.Conv2d(128, 128, (1, 1))\n        self.conv5 = nn.Conv2d(128, 128, (1, 1))\n\n        # The layer combination in the last three convolutional layers\n        # is the same as the fully connected layers of Alexnet\n        self.conv6 = nn.Conv2d(128, 128, (1, 1))\n        self.conv7 = nn.Conv2d(128, 128, (1, 1))\n        self.conv8 = nn.Conv2d(128, n_classes, (9, 9))\n\n        self.lrn1 = nn.LocalResponseNorm(256)\n        self.lrn2 = nn.LocalResponseNorm(128)\n\n        # The 7 th and 8 th convolutional layers have dropout in training\n        self.dropout = nn.Dropout(p=0.5)\n\n        self.apply(self.weight_init)\n\n    def forward(self, x):\n        # Inception module\n        x_3x3 = self.conv_3x3(x)\n        x_1x1 = self.conv_1x1(x)\n        x = torch.cat([x_3x3, x_1x1], dim=1)\n        # Remove the third dimension of the tensor\n        x = torch.squeeze(x)\n\n        # Local Response Normalization\n        x = F.relu(self.lrn1(x))\n\n        # First convolution\n        x = self.conv1(x)\n\n        # Local Response Normalization\n        x = F.relu(self.lrn2(x))\n\n        # First residual block\n        x_res = F.relu(self.conv2(x))\n        x_res = self.conv3(x_res)\n        x = F.relu(x + x_res)\n\n        # Second residual block\n        x_res = F.relu(self.conv4(x))\n        x_res = self.conv5(x_res)\n        x = F.relu(x + x_res)\n\n        x = F.relu(self.conv6(x))\n        x = self.dropout(x)\n        x = F.relu(self.conv7(x))\n        x = self.dropout(x)\n        x = self.conv8(x)\n        x = x.squeeze(2).squeeze(2)\n        return x\n\n\nmodel = LeeEtAl(BAND, CLASSES_NUM).cuda()\n\nsummary(model, input_data=(1, img_rows, img_cols, BAND), verbose=1)\n\n# # Plotting\n\n\ndef train(net,\n          train_iter,\n          valida_iter,\n          loss,\n          optimizer,\n          device,\n          epochs,\n          early_stopping=True,\n          early_num=20):\n    loss_list = [100]\n    early_epoch = 0\n\n    net = net.to(device)\n    print(\"training on \", device)\n    start = time.time()\n    train_loss_list = []\n    valida_loss_list = []\n    train_acc_list = []\n    valida_acc_list = []\n    for epoch in range(epochs):\n        train_acc_sum, n = 0.0, 0\n        time_epoch = time.time()\n        lr_adjust = torch.optim.lr_scheduler.CosineAnnealingLR(\n            optimizer, 15, eta_min=0.0, last_epoch=-1)\n        for X, y in train_iter:\n\n            batch_count, train_l_sum = 0, 0\n            #X = X.permute(0, 3, 1, 2)\n            X = X.to(device)\n            y = y.to(device)\n            y_hat = net(X)\n            # print('y_hat', y_hat)\n            # print('y', y)\n            l = loss(y_hat, y.long())\n\n            optimizer.zero_grad()\n            l.backward()\n            optimizer.step()\n            train_l_sum += l.cpu().item()\n            train_acc_sum += (y_hat.argmax(dim=1) == y).sum().cpu().item()\n            n += y.shape[0]\n            batch_count += 1\n        lr_adjust.step()\n        valida_acc, valida_loss = record.evaluate_accuracy(\n            valida_iter, net, loss, device)\n        loss_list.append(valida_loss)\n\n        train_loss_list.append(train_l_sum)  # / batch_count)\n        train_acc_list.append(train_acc_sum / n)\n        valida_loss_list.append(valida_loss)\n        valida_acc_list.append(valida_acc)\n\n        print(\n            'epoch %d, train loss %.6f, train acc %.3f, valida loss %.6f, valida acc %.3f, time %.1f sec'\n            % (epoch + 1, train_l_sum / batch_count, train_acc_sum / n,\n               valida_loss, valida_acc, time.time() - time_epoch))\n\n        PATH = \"./net_DBA.pt\"\n        # if loss_list[-1] <= 0.01 and valida_acc >= 0.95:\n        #     torch.save(net.state_dict(), PATH)\n        #     break\n\n        if early_stopping and loss_list[-2] < loss_list[-1]:\n            if early_epoch == 0:  # and valida_acc > 0.9:\n                torch.save(net.state_dict(), PATH)\n            early_epoch += 1\n            loss_list[-1] = loss_list[-2]\n            if early_epoch == early_num:\n                net.load_state_dict(torch.load(PATH))\n                break\n        else:\n            early_epoch = 0\n\n    print('epoch %d, loss %.4f, train acc %.3f, time %.1f sec'\n          % (epoch + 1, train_l_sum / batch_count, train_acc_sum / n,\n             time.time() - start))\n\n\ndef sampling(proportion, ground_truth):\n    train = {}\n    test = {}\n    labels_loc = {}\n    m = max(ground_truth)\n    for i in range(m):\n        indexes = [\n            j for j, x in enumerate(ground_truth.ravel().tolist())\n            if x == i + 1\n        ]\n        np.random.shuffle(indexes)\n        labels_loc[i] = indexes\n        if proportion != 1:\n            nb_val = max(int((1 - proportion) * len(indexes)), 3)\n        else:\n            nb_val = 0\n        train[i] = indexes[:nb_val]\n        test[i] = indexes[nb_val:]\n    train_indexes = []\n    test_indexes = []\n    for i in range(m):\n        train_indexes += train[i]\n        test_indexes += test[i]\n    np.random.shuffle(train_indexes)\n    np.random.shuffle(test_indexes)\n    return train_indexes, test_indexes\n\n\ndef select(groundTruth):  #divide dataset into train and test datasets\n    labels_loc = {}\n    train = {}\n    test = {}\n    m = max(groundTruth)\n    #amount = [3, 41, 29, 7, 14, 20, 2, 15, 3, 36, 64, 22, 4, 28, 10, 2]\n    #amount = [43, 1387, 801, 230, 469, 710, 26, 463, 17, 936, 2391, 571, 201, 1237, 376, 91]\n    if Dataset == 'IN':\n        amount = [\n            35, 1011, 581, 167, 344, 515, 19, 327, 12, 683, 1700, 418, 138,\n            876, 274, 69\n        ]  #IP 20%\n    #amount = [6, 144, 84, 24, 50, 75, 3, 49, 2, 97, 247, 62, 22, 130, 38, 10]   #IP 20%\n    if Dataset == 'UP':\n        amount = [5297, 14974, 1648, 2424, 1076, 4026, 1046, 2950, 755]  #UP\n    if Dataset == 'KSC':\n        amount = [\n            530, 165, 176, 170, 110, 161, 80, 299, 377, 283, 296, 341, 654\n        ]  #KSC\n    for i in range(m):\n        indices = [\n            j for j, x in enumerate(groundTruth.ravel().tolist()) if x == i + 1\n        ]\n        np.random.shuffle(indices)\n        labels_loc[i] = indices\n        nb_val = int(amount[i])\n        train[i] = indices[:-nb_val]\n        test[i] = indices[-nb_val:]\n#    whole_indices = []\n    train_indices = []\n    test_indices = []\n    for i in range(m):\n        #        whole_indices += labels_loc[i]\n        train_indices += train[i]\n        test_indices += test[i]\n    np.random.shuffle(train_indices)\n    np.random.shuffle(test_indices)\n    return train_indices, test_indices\n\n\n# # Training\n\nfor index_iter in range(ITER):\n    print('iter:', index_iter)\n    #define the model\n    #net = pResNet(32, 48, CLASSES_NUM, BAND, 2, 16, bottleneck=True)\n    #net = resnet20(num_classes=CLASSES_NUM)\n    net = LeeEtAl(BAND, CLASSES_NUM)\n\n    if PARAM_OPTIM == 'diffgrad':\n        optimizer = optim2.DiffGrad(\n            net.parameters(),\n            lr=lr,\n            betas=(0.9, 0.999),\n            eps=1e-8,\n            weight_decay=0)  # weight_decay=0.0001)\n    if PARAM_OPTIM == 'adam':\n        optimizer = optim.Adam(\n            net.parameters(),\n            lr=1e-3,\n            betas=(0.9, 0.999),\n            eps=1e-8,\n            weight_decay=0)\n    time_1 = int(time.time())\n    np.random.seed(seeds[index_iter])\n    # train_indices, test_indices = select(gt)\n    train_indices, test_indices = sampling(VALIDATION_SPLIT, gt)\n    _, total_indices = sampling(1, gt)\n\n    TRAIN_SIZE = len(train_indices)\n    print('Train size: ', TRAIN_SIZE)\n    TEST_SIZE = TOTAL_SIZE - TRAIN_SIZE\n    print('Test size: ', TEST_SIZE)\n    VAL_SIZE = int(TRAIN_SIZE)\n    print('Validation size: ', VAL_SIZE)\n\n    print('-----Selecting Small Pieces from the Original Cube Data-----')\n    train_iter, valida_iter, test_iter, all_iter = geniter.generate_iter(\n        TRAIN_SIZE, train_indices, TEST_SIZE, test_indices, TOTAL_SIZE,\n        total_indices, VAL_SIZE, whole_data, PATCH_LENGTH, padded_data,\n        INPUT_DIMENSION, 16, gt)  #batchsize in 1\n\n    tic1 = time.time()\n    train(\n        net,\n        train_iter,\n        valida_iter,\n        loss,\n        optimizer,\n        device,\n        epochs=PARAM_EPOCH)\n    toc1 = time.time()\n\n    pred_test = []\n    tic2 = time.time()\n    with torch.no_grad():\n        for X, y in test_iter:\n            #print('Shape of X',X.shape)\n            #X = X.permute(0, 3, 1, 2)\n            X = X.to(device)\n            net.eval()\n            y_hat = net(X)\n            pred_test.extend(np.array(net(X).cpu().argmax(axis=1)))\n    toc2 = time.time()\n    collections.Counter(pred_test)\n    gt_test = gt[test_indices] - 1\n\n    overall_acc = metrics.accuracy_score(pred_test, gt_test[:-VAL_SIZE])\n    confusion_matrix = metrics.confusion_matrix(pred_test, gt_test[:-VAL_SIZE])\n    each_acc, average_acc = record.aa_and_each_accuracy(confusion_matrix)\n    kappa = metrics.cohen_kappa_score(pred_test, gt_test[:-VAL_SIZE])\n\n    torch.save(\n        net.state_dict(),\n        \"./models/\" + 'ContextualNet' + str(round(overall_acc, 3)) + '.pt')\n    KAPPA.append(kappa)\n    OA.append(overall_acc)\n    AA.append(average_acc)\n    TRAINING_TIME.append(toc1 - tic1)\n    TESTING_TIME.append(toc2 - tic2)\n    ELEMENT_ACC[index_iter, :] = each_acc\n\n# # Map, Records\nprint(\"--------\" + \" Training Finished-----------\")\nrecord.record_output(\n    OA, AA, KAPPA, ELEMENT_ACC, TRAINING_TIME, TESTING_TIME,\n    './report/' + 'ContextualNetpatch:' + str(img_rows) + '_' + Dataset +\n    'split' + str(VALIDATION_SPLIT) + 'lr' + str(lr) + PARAM_OPTIM + '.txt')\n\nUtils.generate_png(\n    all_iter, net, gt_hsi, Dataset, device, total_indices,\n    './classification_maps/' + 'ContextualNetpatch:' + str(img_rows) + '_' +\n    Dataset + 'split' + str(VALIDATION_SPLIT) + 'lr' + str(lr) + PARAM_OPTIM)\n"
  },
  {
    "path": "ContextualNet/Utils.py",
    "content": "import numpy as np\nfrom sklearn import metrics, preprocessing\nfrom sklearn.preprocessing import MinMaxScaler\nfrom sklearn.decomposition import PCA\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import confusion_matrix, accuracy_score, classification_report, cohen_kappa_score\nfrom operator import truediv\nimport matplotlib.pyplot as plt\nimport scipy.io as sio\nimport os\nimport spectral\nimport torch\nimport cv2\nfrom operator import truediv\n\n\ndef sampling(proportion, ground_truth):\n    train = {}\n    test = {}\n    labels_loc = {}\n    m = max(ground_truth)\n    for i in range(m):\n        indexes = [\n            j for j, x in enumerate(ground_truth.ravel().tolist())\n            if x == i + 1\n        ]\n        np.random.shuffle(indexes)\n        labels_loc[i] = indexes\n        if proportion != 1:\n            nb_val = max(int((1 - proportion) * len(indexes)), 3)\n        else:\n            nb_val = 0\n        train[i] = indexes[:nb_val]\n        test[i] = indexes[nb_val:]\n    train_indexes = []\n    test_indexes = []\n    for i in range(m):\n        train_indexes += train[i]\n        test_indexes += test[i]\n    np.random.shuffle(train_indexes)\n    np.random.shuffle(test_indexes)\n    return train_indexes, test_indexes\n\n\ndef set_figsize(figsize=(3.5, 2.5)):\n    display.set_matplotlib_formats('svg')\n    plt.rcParams['figure.figsize'] = figsize\n\n\ndef classification_map(map, ground_truth, dpi, save_path):\n    fig = plt.figure(frameon=False)\n    fig.set_size_inches(ground_truth.shape[1] * 2.0 / dpi,\n                        ground_truth.shape[0] * 2.0 / dpi)\n    ax = plt.Axes(fig, [0., 0., 1., 1.])\n    ax.set_axis_off()\n    ax.xaxis.set_visible(False)\n    ax.yaxis.set_visible(False)\n    fig.add_axes(ax)\n    ax.imshow(map)\n    fig.savefig(save_path, dpi=dpi)\n    return 0\n\n\ndef list_to_colormap(x_list):\n    y = np.zeros((x_list.shape[0], 3))\n    for index, item in enumerate(x_list):\n        if item == 0:\n            y[index] = np.array([255, 0, 0]) / 255.\n        if item == 1:\n            y[index] = np.array([0, 255, 0]) / 255.\n        if item == 2:\n            y[index] = np.array([0, 0, 255]) / 255.\n        if item == 3:\n            y[index] = np.array([255, 255, 0]) / 255.\n        if item == 4:\n            y[index] = np.array([0, 255, 255]) / 255.\n        if item == 5:\n            y[index] = np.array([255, 0, 255]) / 255.\n        if item == 6:\n            y[index] = np.array([192, 192, 192]) / 255.\n        if item == 7:\n            y[index] = np.array([128, 128, 128]) / 255.\n        if item == 8:\n            y[index] = np.array([128, 0, 0]) / 255.\n        if item == 9:\n            y[index] = np.array([128, 128, 0]) / 255.\n        if item == 10:\n            y[index] = np.array([0, 128, 0]) / 255.\n        if item == 11:\n            y[index] = np.array([128, 0, 128]) / 255.\n        if item == 12:\n            y[index] = np.array([0, 128, 128]) / 255.\n        if item == 13:\n            y[index] = np.array([0, 0, 128]) / 255.\n        if item == 14:\n            y[index] = np.array([255, 165, 0]) / 255.\n        if item == 15:\n            y[index] = np.array([255, 215, 0]) / 255.\n        if item == 16:\n            y[index] = np.array([0, 0, 0]) / 255.\n        if item == 17:\n            y[index] = np.array([215, 255, 0]) / 255.\n        if item == 18:\n            y[index] = np.array([0, 255, 215]) / 255.\n        if item == -1:\n            y[index] = np.array([0, 0, 0]) / 255.\n    return y\n\n\ndef generate_png(all_iter, net, gt_hsi, Dataset, device, total_indices, path):\n    pred_test = []\n    for X, y in all_iter:\n        # X = X.permute(0, 3, 1, 2)\n        X = X.to(device)\n        net.eval()\n        pred_test.extend(net(X).cpu().argmax(axis=1).detach().numpy())\n    gt = gt_hsi.flatten()\n    x_label = np.zeros(gt.shape)\n    for i in range(len(gt)):\n        if gt[i] == 0:\n            gt[i] = 17\n            x_label[i] = 16\n    gt = gt[:] - 1\n    x_label[total_indices] = pred_test\n    x = np.ravel(x_label)\n    y_list = list_to_colormap(x)\n    y_gt = list_to_colormap(gt)\n    y_re = np.reshape(y_list, (gt_hsi.shape[0], gt_hsi.shape[1], 3))\n    gt_re = np.reshape(y_gt, (gt_hsi.shape[0], gt_hsi.shape[1], 3))\n    classification_map(y_re, gt_hsi, 300,\n                       path + '.png')\n    classification_map(gt_re, gt_hsi, 300,\n                       path + '_gt.png')\n    print('------Get classification maps successful-------')\n"
  },
  {
    "path": "ContextualNet/geniter.py",
    "content": "import torch\nimport numpy as np\nimport torch.utils.data as Data\n\ndef index_assignment(index, row, col, pad_length):\n    new_assign = {}\n    for counter, value in enumerate(index):\n        assign_0 = value // col + pad_length\n        assign_1 = value % col + pad_length\n        new_assign[counter] = [assign_0, assign_1]\n    return new_assign\n\ndef select_patch(matrix, pos_row, pos_col, ex_len):\n    selected_rows = matrix[range(pos_row-ex_len, pos_row+ex_len+1)]\n    selected_patch = selected_rows[:, range(pos_col-ex_len, pos_col+ex_len+1)]\n    return selected_patch\n\n\ndef select_small_cubic(data_size, data_indices, whole_data, patch_length, padded_data, dimension):\n    small_cubic_data = np.zeros((data_size, 2 * patch_length + 1, 2 * patch_length + 1, dimension))\n    data_assign = index_assignment(data_indices, whole_data.shape[0], whole_data.shape[1], patch_length)\n    for i in range(len(data_assign)):\n        small_cubic_data[i] = select_patch(padded_data, data_assign[i][0], data_assign[i][1], patch_length)\n    return small_cubic_data\n\n\ndef generate_iter(TRAIN_SIZE, train_indices, TEST_SIZE, test_indices, TOTAL_SIZE, total_indices, VAL_SIZE,\n                  whole_data, PATCH_LENGTH, padded_data, INPUT_DIMENSION, batch_size, gt):\n    gt_all = gt[total_indices] - 1\n    y_train = gt[train_indices] - 1\n    y_test = gt[test_indices] - 1\n\n    all_data =  select_small_cubic(TOTAL_SIZE, total_indices, whole_data,\n                                                      PATCH_LENGTH, padded_data, INPUT_DIMENSION)\n\n    train_data = select_small_cubic(TRAIN_SIZE, train_indices, whole_data,\n                                                        PATCH_LENGTH, padded_data, INPUT_DIMENSION)\n    print(train_data.shape)\n    test_data =  select_small_cubic(TEST_SIZE, test_indices, whole_data,\n                                                       PATCH_LENGTH, padded_data, INPUT_DIMENSION)\n    x_train = train_data.reshape(train_data.shape[0], train_data.shape[1], train_data.shape[2], INPUT_DIMENSION)\n    x_test_all = test_data.reshape(test_data.shape[0], test_data.shape[1], test_data.shape[2], INPUT_DIMENSION)\n\n    x_val = x_test_all[-VAL_SIZE:]\n    y_val = y_test[-VAL_SIZE:]\n\n    x_test = x_test_all[:-VAL_SIZE]\n    y_test = y_test[:-VAL_SIZE]\n    \n    x1_tensor_train = torch.from_numpy(x_train).type(torch.FloatTensor).unsqueeze(1)\n    y1_tensor_train = torch.from_numpy(y_train).type(torch.FloatTensor)\n    torch_dataset_train = Data.TensorDataset(x1_tensor_train, y1_tensor_train)\n\n    x1_tensor_valida = torch.from_numpy(x_val).type(torch.FloatTensor).unsqueeze(1)\n    y1_tensor_valida = torch.from_numpy(y_val).type(torch.FloatTensor)\n    torch_dataset_valida = Data.TensorDataset(x1_tensor_valida, y1_tensor_valida)\n\n    x1_tensor_test = torch.from_numpy(x_test).type(torch.FloatTensor).unsqueeze(1)\n    y1_tensor_test = torch.from_numpy(y_test).type(torch.FloatTensor)\n    torch_dataset_test = Data.TensorDataset(x1_tensor_test,y1_tensor_test)\n\n    all_data.reshape(all_data.shape[0], all_data.shape[1], all_data.shape[2], INPUT_DIMENSION)\n    all_tensor_data = torch.from_numpy(all_data).type(torch.FloatTensor).unsqueeze(1)\n    all_tensor_data_label = torch.from_numpy(gt_all).type(torch.FloatTensor)\n    torch_dataset_all = Data.TensorDataset(all_tensor_data, all_tensor_data_label)\n\n\n    train_iter = Data.DataLoader(\n        dataset=torch_dataset_train,  # torch TensorDataset format\n        batch_size=batch_size,  # mini batch size\n        shuffle=True,  \n        num_workers=0, \n    )\n    valiada_iter = Data.DataLoader(\n        dataset=torch_dataset_valida,  # torch TensorDataset format\n        batch_size=batch_size,  # mini batch size\n        shuffle=True,  \n        num_workers=0, \n    )\n    test_iter = Data.DataLoader(\n        dataset=torch_dataset_test,  # torch TensorDataset format\n        batch_size=batch_size,  # mini batch size\n        shuffle=False, \n        num_workers=0, \n    )\n    all_iter = Data.DataLoader(\n        dataset=torch_dataset_all,  # torch TensorDataset format\n        batch_size=batch_size,  # mini batch size\n        shuffle=False, \n        num_workers=0, \n    )\n    return train_iter, valiada_iter, test_iter, all_iter #, y_test\n"
  },
  {
    "path": "ContextualNet/record.py",
    "content": "import numpy as np\nimport torch\nfrom operator import truediv\n\ndef evaluate_accuracy(data_iter, net, loss, device):\n    acc_sum, n = 0.0, 0\n    with torch.no_grad():\n        for X, y in data_iter:\n            test_l_sum, test_num = 0, 0\n            #X = X.permute(0, 3, 1, 2)\n            X = X.to(device)\n            y = y.to(device)\n            net.eval() \n            y_hat = net(X)\n            l = loss(y_hat, y.long())\n            acc_sum += (y_hat.argmax(dim=1) == y.to(device)).float().sum().cpu().item()\n            test_l_sum += l\n            test_num += 1\n            net.train() \n            n += y.shape[0]\n    return [acc_sum / n, test_l_sum] # / test_num]\n\n\ndef aa_and_each_accuracy(confusion_matrix):\n    list_diag = np.diag(confusion_matrix)\n    list_raw_sum = np.sum(confusion_matrix, axis=1)\n    each_acc = np.nan_to_num(truediv(list_diag, list_raw_sum))\n    average_acc = np.mean(each_acc)\n    return each_acc, average_acc\n\n\n\ndef record_output(oa_ae, aa_ae, kappa_ae, element_acc_ae, training_time_ae, testing_time_ae, path):\n    f = open(path, 'a')\n    sentence0 = 'OAs for each iteration are:' + str(oa_ae) + '\\n'\n    f.write(sentence0)\n    sentence1 = 'AAs for each iteration are:' + str(aa_ae) + '\\n'\n    f.write(sentence1)\n    sentence2 = 'KAPPAs for each iteration are:' + str(kappa_ae) + '\\n' + '\\n'\n    f.write(sentence2)\n    sentence3 = 'mean_OA ± std_OA is: ' + str(np.mean(oa_ae)) + ' ± ' + str(np.std(oa_ae)) + '\\n'\n    f.write(sentence3)\n    sentence4 = 'mean_AA ± std_AA is: ' + str(np.mean(aa_ae)) + ' ± ' + str(np.std(aa_ae)) + '\\n'\n    f.write(sentence4)\n    sentence5 = 'mean_KAPPA ± std_KAPPA is: ' + str(np.mean(kappa_ae)) + ' ± ' + str(np.std(kappa_ae)) + '\\n' + '\\n'\n    f.write(sentence5)\n    sentence6 = 'Total average Training time is: ' + str(np.sum(training_time_ae)) + '\\n'\n    f.write(sentence6)\n    sentence7 = 'Total average Testing time is: ' + str(np.sum(testing_time_ae)) + '\\n' + '\\n'\n    f.write(sentence7)\n    element_mean = np.mean(element_acc_ae, axis=0)\n    element_std = np.std(element_acc_ae, axis=0)\n    sentence8 = \"Mean of all elements in confusion matrix: \" + str(element_mean) + '\\n'\n    f.write(sentence8)\n    sentence9 = \"Standard deviation of all elements in confusion matrix: \" + str(element_std) + '\\n'\n    f.write(sentence9)\n    f.close()\n"
  },
  {
    "path": "PyResNet/PyResNet.py",
    "content": "#!/usr/bin/env python\n# coding: utf-8\n\n# # Imports\n\nimport argparse\nimport collections\nimport math\nimport time\n\nimport numpy as np\nimport scipy.io as sio\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.optim as optim\nfrom sklearn import metrics, preprocessing\nfrom sklearn.decomposition import PCA\nfrom sklearn.metrics import confusion_matrix\n\nimport geniter\nimport record\nimport torch_optimizer as optim2\nimport Utils\nfrom torchsummary import summary\n\n# # Setting Params\n\nparser = argparse.ArgumentParser(description='Training for HSI')\nparser.add_argument(\n    '-d', '--dataset', dest='dataset', default='IN', help=\"Name of dataset.\")\nparser.add_argument(\n    '-o',\n    '--optimizer',\n    dest='optimizer',\n    default='adam',\n    help=\"Name of optimizer.\")\nparser.add_argument(\n    '-e', '--epoch', type=int, dest='epoch', default=200, help=\"No of epoch\")\nparser.add_argument(\n    '-i', '--iter', type=int, dest='iter', default=3, help=\"No of iter\")\nparser.add_argument(\n    '-p', '--patch', type=int, dest='patch', default=4, help=\"Length of patch\")\nparser.add_argument(\n    '-vs',\n    '--valid_split',\n    type=float,\n    dest='valid_split',\n    default=0.9,\n    help=\"Percentage of validation split.\")\nargs = parser.parse_args()\n\nPARAM_DATASET = args.dataset  # UP,IN,SV, KSC\nPARAM_EPOCH = args.epoch\nPARAM_ITER = args.iter\nPATCH_SIZE = args.patch\nPARAM_VAL = args.valid_split\nPARAM_OPTIM = args.optimizer\n\n# # Data Loading\n\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n\n# for Monte Carlo runs\nseeds = [1331, 1332, 1333, 1334, 1335, 1336, 1337, 1338, 1339, 1340, 1341]\nensemble = 1\n\nglobal Dataset  # UP,IN,SV, KSC\ndataset = PARAM_DATASET  #input('Please input the name of Dataset(IN, UP, SV, KSC):')\nDataset = dataset.upper()\n\n\ndef load_dataset(Dataset, split=0.9):\n    data_path = '../dataset/'\n    if Dataset == 'IN':\n        mat_data = sio.loadmat(data_path + 'Indian_pines_corrected.mat')\n        mat_gt = sio.loadmat(data_path + 'Indian_pines_gt.mat')\n        data_hsi = mat_data['indian_pines_corrected']\n        gt_hsi = mat_gt['indian_pines_gt']\n        K = 200\n        TOTAL_SIZE = 10249\n        VALIDATION_SPLIT = split\n        TRAIN_SIZE = math.ceil(TOTAL_SIZE * VALIDATION_SPLIT)\n\n    if Dataset == 'UP':\n        uPavia = sio.loadmat(data_path + 'PaviaU.mat')\n        gt_uPavia = sio.loadmat(data_path + 'PaviaU_gt.mat')\n        data_hsi = uPavia['paviaU']\n        gt_hsi = gt_uPavia['paviaU_gt']\n        K = 103\n        TOTAL_SIZE = 42776\n        VALIDATION_SPLIT = split\n        TRAIN_SIZE = math.ceil(TOTAL_SIZE * VALIDATION_SPLIT)\n\n    if Dataset == 'SV':\n        SV = sio.loadmat(data_path + 'Salinas_corrected.mat')\n        gt_SV = sio.loadmat(data_path + 'Salinas_gt.mat')\n        data_hsi = SV['salinas_corrected']\n        gt_hsi = gt_SV['salinas_gt']\n        K = 15\n        TOTAL_SIZE = 54129\n        VALIDATION_SPLIT = split\n        TRAIN_SIZE = math.ceil(TOTAL_SIZE * VALIDATION_SPLIT)\n\n    if Dataset == 'KSC':\n        SV = sio.loadmat(data_path + 'KSC.mat')\n        gt_SV = sio.loadmat(data_path + 'KSC_gt.mat')\n        data_hsi = SV['KSC']\n        gt_hsi = gt_SV['KSC_gt']\n        K = data_hsi.shape[2]\n        TOTAL_SIZE = 5211\n        VALIDATION_SPLIT = split\n        TRAIN_SIZE = math.ceil(TOTAL_SIZE * VALIDATION_SPLIT)\n\n    shapeor = data_hsi.shape\n    data_hsi = data_hsi.reshape(-1, data_hsi.shape[-1])\n    data_hsi = PCA(n_components=K).fit_transform(data_hsi)\n    shapeor = np.array(shapeor)\n    shapeor[-1] = K\n    data_hsi = data_hsi.reshape(shapeor)\n\n    return data_hsi, gt_hsi, TOTAL_SIZE, TRAIN_SIZE, VALIDATION_SPLIT\n\n\n# # Pytorch Data Loader Creation\n\ndata_hsi, gt_hsi, TOTAL_SIZE, TRAIN_SIZE, VALIDATION_SPLIT = load_dataset(\n    Dataset, PARAM_VAL)\nprint(data_hsi.shape)\nimage_x, image_y, BAND = data_hsi.shape\ndata = data_hsi.reshape(\n    np.prod(data_hsi.shape[:2]), np.prod(data_hsi.shape[2:]))\ngt = gt_hsi.reshape(np.prod(gt_hsi.shape[:2]), )\nCLASSES_NUM = max(gt)\nprint('The class numbers of the HSI data is:', CLASSES_NUM)\n\nprint('-----Importing Setting Parameters-----')\nITER = PARAM_ITER\nPATCH_LENGTH = PATCH_SIZE\nlr, num_epochs, batch_size = 0.001, 200, 32\nloss = torch.nn.CrossEntropyLoss()\n\nimg_rows = 2 * PATCH_LENGTH + 1\nimg_cols = 2 * PATCH_LENGTH + 1\nimg_channels = data_hsi.shape[2]\nINPUT_DIMENSION = data_hsi.shape[2]\nALL_SIZE = data_hsi.shape[0] * data_hsi.shape[1]\nVAL_SIZE = int(TRAIN_SIZE)\nTEST_SIZE = TOTAL_SIZE - TRAIN_SIZE\n\nKAPPA = []\nOA = []\nAA = []\nTRAINING_TIME = []\nTESTING_TIME = []\nELEMENT_ACC = np.zeros((ITER, CLASSES_NUM))\n\ndata = preprocessing.scale(data)\ndata_ = data.reshape(data_hsi.shape[0], data_hsi.shape[1], data_hsi.shape[2])\nwhole_data = data_\npadded_data = np.lib.pad(\n    whole_data, ((PATCH_LENGTH, PATCH_LENGTH), (PATCH_LENGTH, PATCH_LENGTH),\n                 (0, 0)),\n    'constant',\n    constant_values=0)\n\n# # Model\n\n\ndef make_conv_bn_relu(in_channels,\n                      out_channels,\n                      kernel_size=3,\n                      stride=1,\n                      padding=1,\n                      groups=1):\n    return [\n        nn.Conv2d(\n            in_channels,\n            out_channels,\n            kernel_size=kernel_size,\n            stride=stride,\n            padding=padding,\n            groups=groups,\n            bias=False),\n        nn.BatchNorm2d(out_channels),\n        nn.ReLU(inplace=True),\n    ]\n\n\ndef make_linear_bn_relu(in_channels, out_channels):\n    return [\n        nn.Linear(in_channels, out_channels, bias=False),\n        nn.BatchNorm1d(out_channels),\n        nn.ReLU(inplace=True),\n    ]\n\n\ndef make_max_flat(out):\n    flat = F.adaptive_max_pool2d(\n        out, output_size=1)\n    flat = flat.view(flat.size(0), -1)\n    return flat\n\n\ndef make_avg_flat(out):\n    flat = F.adaptive_avg_pool2d(out, output_size=1)\n    flat = flat.view(flat.size(0), -1)\n    return flat\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 = nn.Conv2d(\n            inplanes,\n            planes,\n            kernel_size=3,\n            stride=stride,\n            padding=1,\n            bias=False)\n        self.bn1 = nn.BatchNorm2d(planes)\n        self.relu = nn.ReLU(inplace=True)\n        self.conv2 = nn.Conv2d(\n            planes, planes, kernel_size=3, stride=1, padding=1, bias=False)\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 PyResNet(nn.Module):\n    def __init__(self, block, layers, in_shape=(3, 256, 256), num_classes=17):\n        self.inplanes = 64\n\n        super(PyResNet, self).__init__()\n        in_channels, height, width = in_shape\n\n        self.conv1 = nn.Conv2d(\n            in_channels, 64, kernel_size=7, stride=2, padding=3, bias=False)\n        self.bn1 = nn.BatchNorm2d(64)\n        self.relu = nn.ReLU(inplace=True)\n\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, 512, layers[3], stride=2)\n\n        self.fc2 = nn.Sequential(\n            *make_linear_bn_relu(128 * block.expansion, 512),\n            nn.Linear(512, num_classes),\n        )\n        self.fc3 = nn.Sequential(\n            *make_linear_bn_relu(256 * block.expansion, 512),\n            nn.Linear(512, num_classes),\n        )\n        self.fc4 = nn.Sequential(\n            *make_linear_bn_relu(512 * block.expansion, 512),\n            nn.Linear(512, num_classes),\n        )\n\n        # self.fc = nn.Sequential(\n        #     *make_linear_bn_relu((128+256+512) * block.expansion, 1024),\n        #     nn.Linear(1024, num_classes)\n        # )\n        #\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(\n                    self.inplanes,\n                    planes * block.expansion,\n                    kernel_size=1,\n                    stride=stride,\n                    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    def forward(self, x):\n        x = self.conv1(x)\n        x = self.bn1(x)\n        x = self.relu(x)\n        x = F.max_pool2d(x, kernel_size=3, stride=2, padding=1)\n\n        x = self.layer1(x)  # 64, 64x64\n\n        x = self.layer2(x)  #128, 32x32\n        flat2 = make_max_flat(x)  ##make_avg_flat\n\n        x = self.layer3(x)  #256, 16x16\n        flat3 = make_max_flat(x)\n\n        x = self.layer4(x)  #512,  8x8\n        flat4 = make_max_flat(x)\n\n        x = self.fc2(flat2) + self.fc3(flat3) + self.fc4(flat4)\n\n        logit = x\n        return logit\n\n\ndef PyResNet34(pretrained=None, **kwargs):\n    \"\"\"Not Pretrained\"\"\"\n    if pretrained:\n        raise NotImplementedError()\n    model = PyResNet(BasicBlock, [3, 4, 6, 3], **kwargs)\n    return model\n\n\nmodel = PyResNet34(\n    in_shape=(BAND, img_rows, img_cols), num_classes=CLASSES_NUM).cuda()\n\nsummary(model, input_data=(BAND, img_rows, img_cols), verbose=1)\n\n# # Plotting\n\n\ndef train(net,\n          train_iter,\n          valida_iter,\n          loss,\n          optimizer,\n          device,\n          epochs,\n          early_stopping=True,\n          early_num=20):\n    loss_list = [100]\n    early_epoch = 0\n\n    net = net.to(device)\n    print(\"training on \", device)\n    start = time.time()\n    train_loss_list = []\n    valida_loss_list = []\n    train_acc_list = []\n    valida_acc_list = []\n    for epoch in range(epochs):\n        train_acc_sum, n = 0.0, 0\n        time_epoch = time.time()\n        lr_adjust = torch.optim.lr_scheduler.CosineAnnealingLR(\n            optimizer, 15, eta_min=0.0, last_epoch=-1)\n        for X, y in train_iter:\n\n            batch_count, train_l_sum = 0, 0\n            X = X.permute(0, 3, 1, 2)\n            X = X.to(device)\n            y = y.to(device)\n            y_hat = net(X)\n            l = loss(y_hat, y.long())\n\n            optimizer.zero_grad()\n            l.backward()\n            optimizer.step()\n            train_l_sum += l.cpu().item()\n            train_acc_sum += (y_hat.argmax(dim=1) == y).sum().cpu().item()\n            n += y.shape[0]\n            batch_count += 1\n        lr_adjust.step()\n        valida_acc, valida_loss = record.evaluate_accuracy(\n            valida_iter, net, loss, device)\n        loss_list.append(valida_loss)\n\n        train_loss_list.append(train_l_sum)  # / batch_count)\n        train_acc_list.append(train_acc_sum / n)\n        valida_loss_list.append(valida_loss)\n        valida_acc_list.append(valida_acc)\n\n        print(\n            'epoch %d, train loss %.6f, train acc %.3f, valida loss %.6f, valida acc %.3f, time %.1f sec'\n            % (epoch + 1, train_l_sum / batch_count, train_acc_sum / n,\n               valida_loss, valida_acc, time.time() - time_epoch))\n\n        PATH = \"./net_DBA.pt\"\n\n        if early_stopping and loss_list[-2] < loss_list[-1]:\n            if early_epoch == 0:\n                torch.save(net.state_dict(), PATH)\n            early_epoch += 1\n            loss_list[-1] = loss_list[-2]\n            if early_epoch == early_num:\n                net.load_state_dict(torch.load(PATH))\n                break\n        else:\n            early_epoch = 0\n\n    print('epoch %d, loss %.4f, train acc %.3f, time %.1f sec'\n          % (epoch + 1, train_l_sum / batch_count, train_acc_sum / n,\n             time.time() - start))\n\n\ndef sampling(proportion, ground_truth):\n    train = {}\n    test = {}\n    labels_loc = {}\n    m = max(ground_truth)\n    for i in range(m):\n        indexes = [\n            j for j, x in enumerate(ground_truth.ravel().tolist())\n            if x == i + 1\n        ]\n        np.random.shuffle(indexes)\n        labels_loc[i] = indexes\n        if proportion != 1:\n            nb_val = max(int((1 - proportion) * len(indexes)), 3)\n        else:\n            nb_val = 0\n        train[i] = indexes[:nb_val]\n        test[i] = indexes[nb_val:]\n    train_indexes = []\n    test_indexes = []\n    for i in range(m):\n        train_indexes += train[i]\n        test_indexes += test[i]\n    np.random.shuffle(train_indexes)\n    np.random.shuffle(test_indexes)\n    return train_indexes, test_indexes\n\n\ndef select(groundTruth):  #divide dataset into train and test datasets\n    labels_loc = {}\n    train = {}\n    test = {}\n    m = max(groundTruth)\n    #amount = [3, 41, 29, 7, 14, 20, 2, 15, 3, 36, 64, 22, 4, 28, 10, 2]\n    #amount = [43, 1387, 801, 230, 469, 710, 26, 463, 17, 936, 2391, 571, 201, 1237, 376, 91]\n    if Dataset == 'IN':\n        amount = [\n            35, 1011, 581, 167, 344, 515, 19, 327, 12, 683, 1700, 418, 138,\n            876, 274, 69\n        ]  #IP 20%\n    #amount = [6, 144, 84, 24, 50, 75, 3, 49, 2, 97, 247, 62, 22, 130, 38, 10]   #IP 20%\n    if Dataset == 'UP':\n        amount = [5297, 14974, 1648, 2424, 1076, 4026, 1046, 2950, 755]  #UP\n    if Dataset == 'KSC':\n        amount = [\n            530, 165, 176, 170, 110, 161, 80, 299, 377, 283, 296, 341, 654\n        ]  #KSC\n    for i in range(m):\n        indices = [\n            j for j, x in enumerate(groundTruth.ravel().tolist()) if x == i + 1\n        ]\n        np.random.shuffle(indices)\n        labels_loc[i] = indices\n        nb_val = int(amount[i])\n        train[i] = indices[:-nb_val]\n        test[i] = indices[-nb_val:]\n    train_indices = []\n    test_indices = []\n    for i in range(m):\n        train_indices += train[i]\n        test_indices += test[i]\n    np.random.shuffle(train_indices)\n    np.random.shuffle(test_indices)\n    return train_indices, test_indices\n\n\n# # Training\n\nfor index_iter in range(ITER):\n    print('iter:', index_iter)\n    net = PyResNet34(\n        in_shape=(BAND, img_rows, img_cols), num_classes=CLASSES_NUM)\n\n    if PARAM_OPTIM == 'diffgrad':\n        optimizer = optim2.DiffGrad(\n            net.parameters(),\n            lr=lr,\n            betas=(0.9, 0.999),\n            eps=1e-8,\n            weight_decay=0)  # weight_decay=0.0001)\n    if PARAM_OPTIM == 'adam':\n        optimizer = optim.Adam(\n            net.parameters(),\n            lr=1e-3,\n            betas=(0.9, 0.999),\n            eps=1e-8,\n            weight_decay=0)\n    time_1 = int(time.time())\n    np.random.seed(seeds[index_iter])\n    # train_indices, test_indices = select(gt)\n    train_indices, test_indices = sampling(VALIDATION_SPLIT, gt)\n    _, total_indices = sampling(1, gt)\n\n    TRAIN_SIZE = len(train_indices)\n    print('Train size: ', TRAIN_SIZE)\n    TEST_SIZE = TOTAL_SIZE - TRAIN_SIZE\n    print('Test size: ', TEST_SIZE)\n    VAL_SIZE = int(TRAIN_SIZE)\n    print('Validation size: ', VAL_SIZE)\n\n    print('-----Selecting Small Pieces from the Original Cube Data-----')\n    train_iter, valida_iter, test_iter, all_iter = geniter.generate_iter(\n        TRAIN_SIZE, train_indices, TEST_SIZE, test_indices, TOTAL_SIZE,\n        total_indices, VAL_SIZE, whole_data, PATCH_LENGTH, padded_data,\n        INPUT_DIMENSION, 16, gt)  #batchsize in 1\n\n    tic1 = time.time()\n    train(\n        net,\n        train_iter,\n        valida_iter,\n        loss,\n        optimizer,\n        device,\n        epochs=PARAM_EPOCH)\n    toc1 = time.time()\n\n    pred_test = []\n    tic2 = time.time()\n    with torch.no_grad():\n        for X, y in test_iter:\n            # print('Shape of X',X.shape)\n            X = X.permute(0, 3, 1, 2)\n            X = X.to(device)\n            net.eval()\n            y_hat = net(X)\n            pred_test.extend(np.array(net(X).cpu().argmax(axis=1)))\n    toc2 = time.time()\n    collections.Counter(pred_test)\n    gt_test = gt[test_indices] - 1\n\n    overall_acc = metrics.accuracy_score(pred_test, gt_test[:-VAL_SIZE])\n    confusion_matrix = metrics.confusion_matrix(pred_test, gt_test[:-VAL_SIZE])\n    each_acc, average_acc = record.aa_and_each_accuracy(confusion_matrix)\n    kappa = metrics.cohen_kappa_score(pred_test, gt_test[:-VAL_SIZE])\n\n    torch.save(net.state_dict(),\n               \"./models/\" + 'PyResnet34' + str(round(overall_acc, 3)) + '.pt')\n    KAPPA.append(kappa)\n    OA.append(overall_acc)\n    AA.append(average_acc)\n    TRAINING_TIME.append(toc1 - tic1)\n    TESTING_TIME.append(toc2 - tic2)\n    ELEMENT_ACC[index_iter, :] = each_acc\n\n# # Map, Records\nprint(\"--------\" + \" Training Finished-----------\")\nrecord.record_output(\n    OA, AA, KAPPA, ELEMENT_ACC, TRAINING_TIME, TESTING_TIME,\n    './report/' + 'PyResnet34patch:' + str(img_rows) + '_' + Dataset + 'split'\n    + str(VALIDATION_SPLIT) + 'lr' + str(lr) + PARAM_OPTIM + '.txt')\n\nUtils.generate_png(\n    all_iter, net, gt_hsi, Dataset, device, total_indices,\n    './classification_maps/' + 'PyResnet34patch:' + str(img_rows) + '_' +\n    Dataset + 'split' + str(VALIDATION_SPLIT) + 'lr' + str(lr) + PARAM_OPTIM)\n"
  },
  {
    "path": "PyResNet/Utils.py",
    "content": "import numpy as np\nfrom sklearn import metrics, preprocessing\nfrom sklearn.preprocessing import MinMaxScaler\nfrom sklearn.decomposition import PCA\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import confusion_matrix, accuracy_score, classification_report, cohen_kappa_score\nfrom operator import truediv\nimport matplotlib.pyplot as plt\nimport scipy.io as sio\nimport os\nimport spectral\nimport torch\nimport cv2\nfrom operator import truediv\n\n\ndef sampling(proportion, ground_truth):\n    train = {}\n    test = {}\n    labels_loc = {}\n    m = max(ground_truth)\n    for i in range(m):\n        indexes = [\n            j for j, x in enumerate(ground_truth.ravel().tolist())\n            if x == i + 1\n        ]\n        np.random.shuffle(indexes)\n        labels_loc[i] = indexes\n        if proportion != 1:\n            nb_val = max(int((1 - proportion) * len(indexes)), 3)\n        else:\n            nb_val = 0\n        train[i] = indexes[:nb_val]\n        test[i] = indexes[nb_val:]\n    train_indexes = []\n    test_indexes = []\n    for i in range(m):\n        train_indexes += train[i]\n        test_indexes += test[i]\n    np.random.shuffle(train_indexes)\n    np.random.shuffle(test_indexes)\n    return train_indexes, test_indexes\n\n\ndef set_figsize(figsize=(3.5, 2.5)):\n    display.set_matplotlib_formats('svg')\n    plt.rcParams['figure.figsize'] = figsize\n\n\ndef classification_map(map, ground_truth, dpi, save_path):\n    fig = plt.figure(frameon=False)\n    fig.set_size_inches(ground_truth.shape[1] * 2.0 / dpi,\n                        ground_truth.shape[0] * 2.0 / dpi)\n    ax = plt.Axes(fig, [0., 0., 1., 1.])\n    ax.set_axis_off()\n    ax.xaxis.set_visible(False)\n    ax.yaxis.set_visible(False)\n    fig.add_axes(ax)\n    ax.imshow(map)\n    fig.savefig(save_path, dpi=dpi)\n    return 0\n\n\ndef list_to_colormap(x_list):\n    y = np.zeros((x_list.shape[0], 3))\n    for index, item in enumerate(x_list):\n        if item == 0:\n            y[index] = np.array([255, 0, 0]) / 255.\n        if item == 1:\n            y[index] = np.array([0, 255, 0]) / 255.\n        if item == 2:\n            y[index] = np.array([0, 0, 255]) / 255.\n        if item == 3:\n            y[index] = np.array([255, 255, 0]) / 255.\n        if item == 4:\n            y[index] = np.array([0, 255, 255]) / 255.\n        if item == 5:\n            y[index] = np.array([255, 0, 255]) / 255.\n        if item == 6:\n            y[index] = np.array([192, 192, 192]) / 255.\n        if item == 7:\n            y[index] = np.array([128, 128, 128]) / 255.\n        if item == 8:\n            y[index] = np.array([128, 0, 0]) / 255.\n        if item == 9:\n            y[index] = np.array([128, 128, 0]) / 255.\n        if item == 10:\n            y[index] = np.array([0, 128, 0]) / 255.\n        if item == 11:\n            y[index] = np.array([128, 0, 128]) / 255.\n        if item == 12:\n            y[index] = np.array([0, 128, 128]) / 255.\n        if item == 13:\n            y[index] = np.array([0, 0, 128]) / 255.\n        if item == 14:\n            y[index] = np.array([255, 165, 0]) / 255.\n        if item == 15:\n            y[index] = np.array([255, 215, 0]) / 255.\n        if item == 16:\n            y[index] = np.array([0, 0, 0]) / 255.\n        if item == 17:\n            y[index] = np.array([215, 255, 0]) / 255.\n        if item == 18:\n            y[index] = np.array([0, 255, 215]) / 255.\n        if item == -1:\n            y[index] = np.array([0, 0, 0]) / 255.\n    return y\n\n\ndef generate_png(all_iter, net, gt_hsi, Dataset, device, total_indices, path):\n    pred_test = []\n    for X, y in all_iter:\n        X = X.permute(0, 3, 1, 2)\n        X = X.to(device)\n        net.eval()\n        pred_test.extend(net(X).cpu().argmax(axis=1).detach().numpy())\n    gt = gt_hsi.flatten()\n    x_label = np.zeros(gt.shape)\n    for i in range(len(gt)):\n        if gt[i] == 0:\n            gt[i] = 17\n            x_label[i] = 16\n    gt = gt[:] - 1\n    x_label[total_indices] = pred_test\n    x = np.ravel(x_label)\n    y_list = list_to_colormap(x)\n    y_gt = list_to_colormap(gt)\n    y_re = np.reshape(y_list, (gt_hsi.shape[0], gt_hsi.shape[1], 3))\n    gt_re = np.reshape(y_gt, (gt_hsi.shape[0], gt_hsi.shape[1], 3))\n    classification_map(y_re, gt_hsi, 300,\n                       path + '.png')\n    classification_map(gt_re, gt_hsi, 300,\n                       path + '_gt.png')\n    print('------Get classification maps successful-------')\n"
  },
  {
    "path": "PyResNet/geniter.py",
    "content": "import torch\nimport numpy as np\nimport torch.utils.data as Data\n\ndef index_assignment(index, row, col, pad_length):\n    new_assign = {}\n    for counter, value in enumerate(index):\n        assign_0 = value // col + pad_length\n        assign_1 = value % col + pad_length\n        new_assign[counter] = [assign_0, assign_1]\n    return new_assign\n\ndef select_patch(matrix, pos_row, pos_col, ex_len):\n    selected_rows = matrix[range(pos_row-ex_len, pos_row+ex_len+1)]\n    selected_patch = selected_rows[:, range(pos_col-ex_len, pos_col+ex_len+1)]\n    return selected_patch\n\n\ndef select_small_cubic(data_size, data_indices, whole_data, patch_length, padded_data, dimension):\n    small_cubic_data = np.zeros((data_size, 2 * patch_length + 1, 2 * patch_length + 1, dimension))\n    data_assign = index_assignment(data_indices, whole_data.shape[0], whole_data.shape[1], patch_length)\n    for i in range(len(data_assign)):\n        small_cubic_data[i] = select_patch(padded_data, data_assign[i][0], data_assign[i][1], patch_length)\n    return small_cubic_data\n\n\ndef generate_iter(TRAIN_SIZE, train_indices, TEST_SIZE, test_indices, TOTAL_SIZE, total_indices, VAL_SIZE,\n                  whole_data, PATCH_LENGTH, padded_data, INPUT_DIMENSION, batch_size, gt):\n    gt_all = gt[total_indices] - 1\n    y_train = gt[train_indices] - 1\n    y_test = gt[test_indices] - 1\n\n    all_data =  select_small_cubic(TOTAL_SIZE, total_indices, whole_data,\n                                                      PATCH_LENGTH, padded_data, INPUT_DIMENSION)\n\n    train_data = select_small_cubic(TRAIN_SIZE, train_indices, whole_data,\n                                                        PATCH_LENGTH, padded_data, INPUT_DIMENSION)\n    print(train_data.shape)\n    test_data =  select_small_cubic(TEST_SIZE, test_indices, whole_data,\n                                                       PATCH_LENGTH, padded_data, INPUT_DIMENSION)\n    x_train = train_data.reshape(train_data.shape[0], train_data.shape[1], train_data.shape[2], INPUT_DIMENSION)\n    x_test_all = test_data.reshape(test_data.shape[0], test_data.shape[1], test_data.shape[2], INPUT_DIMENSION)\n\n    x_val = x_test_all[-VAL_SIZE:]\n    y_val = y_test[-VAL_SIZE:]\n\n    x_test = x_test_all[:-VAL_SIZE]\n    y_test = y_test[:-VAL_SIZE]\n    \n    x1_tensor_train = torch.from_numpy(x_train).type(torch.FloatTensor)#.unsqueeze(1)\n    y1_tensor_train = torch.from_numpy(y_train).type(torch.FloatTensor)\n    torch_dataset_train = Data.TensorDataset(x1_tensor_train, y1_tensor_train)\n\n    x1_tensor_valida = torch.from_numpy(x_val).type(torch.FloatTensor)#.unsqueeze(1)\n    y1_tensor_valida = torch.from_numpy(y_val).type(torch.FloatTensor)\n    torch_dataset_valida = Data.TensorDataset(x1_tensor_valida, y1_tensor_valida)\n\n    x1_tensor_test = torch.from_numpy(x_test).type(torch.FloatTensor)#.unsqueeze(1)\n    y1_tensor_test = torch.from_numpy(y_test).type(torch.FloatTensor)\n    torch_dataset_test = Data.TensorDataset(x1_tensor_test,y1_tensor_test)\n\n    all_data.reshape(all_data.shape[0], all_data.shape[1], all_data.shape[2], INPUT_DIMENSION)\n    all_tensor_data = torch.from_numpy(all_data).type(torch.FloatTensor)#.unsqueeze(1)\n    all_tensor_data_label = torch.from_numpy(gt_all).type(torch.FloatTensor)\n    torch_dataset_all = Data.TensorDataset(all_tensor_data, all_tensor_data_label)\n\n\n    train_iter = Data.DataLoader(\n        dataset=torch_dataset_train,  # torch TensorDataset format\n        batch_size=batch_size,  # mini batch size\n        shuffle=True,  \n        num_workers=0, \n    )\n    valiada_iter = Data.DataLoader(\n        dataset=torch_dataset_valida,  # torch TensorDataset format\n        batch_size=batch_size,  # mini batch size\n        shuffle=True,  \n        num_workers=0, \n    )\n    test_iter = Data.DataLoader(\n        dataset=torch_dataset_test,  # torch TensorDataset format\n        batch_size=batch_size,  # mini batch size\n        shuffle=False, \n        num_workers=0, \n    )\n    all_iter = Data.DataLoader(\n        dataset=torch_dataset_all,  # torch TensorDataset format\n        batch_size=batch_size,  # mini batch size\n        shuffle=False, \n        num_workers=0, \n    )\n    return train_iter, valiada_iter, test_iter, all_iter #, y_test\n"
  },
  {
    "path": "PyResNet/record.py",
    "content": "import numpy as np\nimport torch\nfrom operator import truediv\n\ndef evaluate_accuracy(data_iter, net, loss, device):\n    acc_sum, n = 0.0, 0\n    with torch.no_grad():\n        for X, y in data_iter:\n            test_l_sum, test_num = 0, 0\n            X = X.permute(0, 3, 1, 2)\n            X = X.to(device)\n            y = y.to(device)\n            net.eval() \n            y_hat = net(X)\n            l = loss(y_hat, y.long())\n            acc_sum += (y_hat.argmax(dim=1) == y.to(device)).float().sum().cpu().item()\n            test_l_sum += l\n            test_num += 1\n            net.train() \n            n += y.shape[0]\n    return [acc_sum / n, test_l_sum] # / test_num]\n\n\ndef aa_and_each_accuracy(confusion_matrix):\n    list_diag = np.diag(confusion_matrix)\n    list_raw_sum = np.sum(confusion_matrix, axis=1)\n    each_acc = np.nan_to_num(truediv(list_diag, list_raw_sum))\n    average_acc = np.mean(each_acc)\n    return each_acc, average_acc\n\n\n\ndef record_output(oa_ae, aa_ae, kappa_ae, element_acc_ae, training_time_ae, testing_time_ae, path):\n    f = open(path, 'a')\n    sentence0 = 'OAs for each iteration are:' + str(oa_ae) + '\\n'\n    f.write(sentence0)\n    sentence1 = 'AAs for each iteration are:' + str(aa_ae) + '\\n'\n    f.write(sentence1)\n    sentence2 = 'KAPPAs for each iteration are:' + str(kappa_ae) + '\\n' + '\\n'\n    f.write(sentence2)\n    sentence3 = 'mean_OA ± std_OA is: ' + str(np.mean(oa_ae)) + ' ± ' + str(np.std(oa_ae)) + '\\n'\n    f.write(sentence3)\n    sentence4 = 'mean_AA ± std_AA is: ' + str(np.mean(aa_ae)) + ' ± ' + str(np.std(aa_ae)) + '\\n'\n    f.write(sentence4)\n    sentence5 = 'mean_KAPPA ± std_KAPPA is: ' + str(np.mean(kappa_ae)) + ' ± ' + str(np.std(kappa_ae)) + '\\n' + '\\n'\n    f.write(sentence5)\n    sentence6 = 'Total average Training time is: ' + str(np.sum(training_time_ae)) + '\\n'\n    f.write(sentence6)\n    sentence7 = 'Total average Testing time is: ' + str(np.sum(testing_time_ae)) + '\\n' + '\\n'\n    f.write(sentence7)\n    element_mean = np.mean(element_acc_ae, axis=0)\n    element_std = np.std(element_acc_ae, axis=0)\n    sentence8 = \"Mean of all elements in confusion matrix: \" + str(element_mean) + '\\n'\n    f.write(sentence8)\n    sentence9 = \"Standard deviation of all elements in confusion matrix: \" + str(element_std) + '\\n'\n    f.write(sentence9)\n    f.close()\n\n"
  },
  {
    "path": "README.md",
    "content": "[![PWC](https://img.shields.io/endpoint.svg?url=https://paperswithcode.com/badge/attention-based-adaptive-spectral-spatial/hyperspectral-image-classification-on-kennedy)](https://paperswithcode.com/sota/hyperspectral-image-classification-on-kennedy?p=attention-based-adaptive-spectral-spatial)\n\t\n[![PWC](https://img.shields.io/endpoint.svg?url=https://paperswithcode.com/badge/attention-based-adaptive-spectral-spatial/hyperspectral-image-classification-on-pavia)](https://paperswithcode.com/sota/hyperspectral-image-classification-on-pavia?p=attention-based-adaptive-spectral-spatial)\n\t\n[![PWC](https://img.shields.io/endpoint.svg?url=https://paperswithcode.com/badge/attention-based-adaptive-spectral-spatial/hyperspectral-image-classification-on-indian)](https://paperswithcode.com/sota/hyperspectral-image-classification-on-indian?p=attention-based-adaptive-spectral-spatial)\n\n\n# Attention-Based Adaptive Spectral-Spatial Kernel ResNet for Hyperspectral Image Classification\n\nThis repository is the official implementation of [Attention-Based Adaptive Spectral-Spatial Kernel ResNet for Hyperspectral Image Classification](https://ieeexplore.ieee.org/document/9306920). \n[![Open A2S2K-ResNet in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1x2CYfaUXNjX4yDMLCvoVFqAMZXZwwVgS)\n\n\n>📋  Abstract:\nHyperspectral images (HSIs) provide rich spectral-spatial information with stacked hundreds of contiguous narrowbands. Due to the existence of noise and band correlation, the selection of informative spectral-spatial kernel features poses a challenge. This is often addressed by using convolutional neural networks (CNNs) with receptive field (RF) having fixed sizes. However, these solutions cannot enable neurons to effectively adjust RF sizes and cross-channel dependencies when forward and backward propagations are used to optimize the network. In this article, we present an attention-based adaptive spectral-spatial kernel improved residual network (A²S²K-ResNet) with spectral attention to capture discriminative spectral-spatial features for HSI classification in an end-to-end training fashion. In particular, the proposed network learns selective 3-D convolutional kernels to jointly extract spectral-spatial features using improved 3-D ResBlocks and adopts an efficient feature recalibration (EFR) mechanism to boost the classification performance. Extensive experiments are performed on three well-known hyperspectral data sets, i.e., IP, KSC, and UP, and the proposed A²S²K-ResNet can provide better classification results in terms of overall accuracy (OA), average accuracy (AA), and Kappa compared with the existing methods investigated.\n\n\n<img src=\"figs/model.png\"/>\n\n## Requirements\n\nTo install requirements:\n\n```setup\nconda env create -f environment.yml\n```\n\nTo download the dataset and setup the folders, run:\n\n```\nbash setup_script.sh\n```\n\n## Training\n\nTo train the model(s) in the paper, run this command in the A2S2KResNet folder:\n\n```train\npython A2S2KResNet.py -d <IN|UP|KSC> -e 200 -i 3 -p 3 -vs 0.9 -o adam\n```\n\n## Results\n\nOur model achieves the following performance on 10% of datasets:\n\n### [India Pines](http://www.ehu.eus/ccwintco/uploads/6/67/Indian_pines_corrected.mat) dataset\n\n| Model name         | OA  |\n| ------------------ |---------------- |\n| A2S2K-ResNet   | 98.66 ± 0.004 % |\n\n### [Kennedy Space Center](http://www.ehu.es/ccwintco/uploads/2/26/KSC.mat) dataset\n\n| Model name         | OA  |\n| ------------------ |---------------- |\n| A2S2K-ResNet   | 99.34 ± 0.001 % |\n\n### [University of Pavia](http://www.ehu.eus/ccwintco/uploads/e/ee/PaviaU.mat) dataset\n\n| Model name         | OA  |\n| ------------------ |---------------- |\n| A2S2K-ResNet   | 99.85 ± 0.001 % |\n\nFor deatiled results refer to Table IV-VII of our paper. \n\n\n## Citation\n\nIf you use A2S2K-ResNet code in your research, we would appreciate a citation to the original paper:\n```\n@article{roy2020attention,\n\ttitle={Attention-based adaptive spectral-spatial kernel resnet for hyperspectral image classification},\n\tauthor={Swalpa Kumar Roy, and Suvojit Manna, and Tiecheng Song, and Lorenzo Bruzzone},\n\tjournal={IEEE Transactions on Geoscience and Remote Sensing},\n\tvolume={59},\n\tno.={9},\n\tpp.={7831-7843},\n\tyear={2021},\n\tpublisher={IEEE}\n\t}\t\n```\n"
  },
  {
    "path": "ResNet/ResNet.py",
    "content": "#!/usr/bin/env python\n# coding: utf-8\n\n# # Imports\n\nimport argparse\nimport collections\nimport math\nimport time\n\nimport numpy as np\nimport scipy.io as sio\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.optim as optim\nfrom sklearn import metrics, preprocessing\nfrom sklearn.decomposition import PCA\nfrom sklearn.metrics import confusion_matrix\n\nimport geniter\nimport record\nimport torch_optimizer as optim2\nimport Utils\nfrom torchsummary import summary\n\n# # Setting Params\n\nparser = argparse.ArgumentParser(description='Training for HSI')\nparser.add_argument(\n    '-d', '--dataset', dest='dataset', default='IN', help=\"Name of dataset.\")\nparser.add_argument(\n    '-o',\n    '--optimizer',\n    dest='optimizer',\n    default='adam',\n    help=\"Name of optimizer.\")\nparser.add_argument(\n    '-e', '--epoch', type=int, dest='epoch', default=200, help=\"No of epoch\")\nparser.add_argument(\n    '-i', '--iter', type=int, dest='iter', default=3, help=\"No of iter\")\nparser.add_argument(\n    '-p', '--patch', type=int, dest='patch', default=4, help=\"Length of patch\")\nparser.add_argument(\n    '-vs',\n    '--valid_split',\n    type=float,\n    dest='valid_split',\n    default=0.9,\n    help=\"Percentage of validation split.\")\nargs = parser.parse_args()\n\nPARAM_DATASET = args.dataset  # UP,IN,SV, KSC\nPARAM_EPOCH = args.epoch\nPARAM_ITER = args.iter\nPATCH_SIZE = args.patch\nPARAM_VAL = args.valid_split\nPARAM_OPTIM = args.optimizer\n\n# # Data Loading\n\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n\n# for Monte Carlo runs\nseeds = [1331, 1332, 1333, 1334, 1335, 1336, 1337, 1338, 1339, 1340, 1341]\nensemble = 1\n\nglobal Dataset  # UP,IN,SV, KSC\ndataset = PARAM_DATASET  #input('Please input the name of Dataset(IN, UP, SV, KSC):')\nDataset = dataset.upper()\n\n\ndef load_dataset(Dataset, split=0.9):\n    data_path = '../dataset/'\n    if Dataset == 'IN':\n        mat_data = sio.loadmat(data_path + 'Indian_pines_corrected.mat')\n        mat_gt = sio.loadmat(data_path + 'Indian_pines_gt.mat')\n        data_hsi = mat_data['indian_pines_corrected']\n        gt_hsi = mat_gt['indian_pines_gt']\n        K = 200\n        TOTAL_SIZE = 10249\n        VALIDATION_SPLIT = split\n        TRAIN_SIZE = math.ceil(TOTAL_SIZE * VALIDATION_SPLIT)\n\n    if Dataset == 'UP':\n        uPavia = sio.loadmat(data_path + 'PaviaU.mat')\n        gt_uPavia = sio.loadmat(data_path + 'PaviaU_gt.mat')\n        data_hsi = uPavia['paviaU']\n        gt_hsi = gt_uPavia['paviaU_gt']\n        K = 103\n        TOTAL_SIZE = 42776\n        VALIDATION_SPLIT = split\n        TRAIN_SIZE = math.ceil(TOTAL_SIZE * VALIDATION_SPLIT)\n\n    if Dataset == 'SV':\n        SV = sio.loadmat(data_path + 'Salinas_corrected.mat')\n        gt_SV = sio.loadmat(data_path + 'Salinas_gt.mat')\n        data_hsi = SV['salinas_corrected']\n        gt_hsi = gt_SV['salinas_gt']\n        K = 15\n        TOTAL_SIZE = 54129\n        VALIDATION_SPLIT = split\n        TRAIN_SIZE = math.ceil(TOTAL_SIZE * VALIDATION_SPLIT)\n\n    if Dataset == 'KSC':\n        SV = sio.loadmat(data_path + 'KSC.mat')\n        gt_SV = sio.loadmat(data_path + 'KSC_gt.mat')\n        data_hsi = SV['KSC']\n        gt_hsi = gt_SV['KSC_gt']\n        K = data_hsi.shape[2]\n        TOTAL_SIZE = 5211\n        VALIDATION_SPLIT = split\n        TRAIN_SIZE = math.ceil(TOTAL_SIZE * VALIDATION_SPLIT)\n\n    shapeor = data_hsi.shape\n    data_hsi = data_hsi.reshape(-1, data_hsi.shape[-1])\n    data_hsi = PCA(n_components=K).fit_transform(data_hsi)\n    shapeor = np.array(shapeor)\n    shapeor[-1] = K\n    data_hsi = data_hsi.reshape(shapeor)\n\n    return data_hsi, gt_hsi, TOTAL_SIZE, TRAIN_SIZE, VALIDATION_SPLIT\n\n\n# # Pytorch Data Loader Creation\n\ndata_hsi, gt_hsi, TOTAL_SIZE, TRAIN_SIZE, VALIDATION_SPLIT = load_dataset(\n    Dataset, PARAM_VAL)\nprint(data_hsi.shape)\nimage_x, image_y, BAND = data_hsi.shape\ndata = data_hsi.reshape(\n    np.prod(data_hsi.shape[:2]), np.prod(data_hsi.shape[2:]))\ngt = gt_hsi.reshape(np.prod(gt_hsi.shape[:2]), )\nCLASSES_NUM = max(gt)\nprint('The class numbers of the HSI data is:', CLASSES_NUM)\n\nprint('-----Importing Setting Parameters-----')\nITER = PARAM_ITER\nPATCH_LENGTH = PATCH_SIZE\nlr, num_epochs, batch_size = 0.001, 200, 32\nloss = torch.nn.CrossEntropyLoss()\n\nimg_rows = 2 * PATCH_LENGTH + 1\nimg_cols = 2 * PATCH_LENGTH + 1\nimg_channels = data_hsi.shape[2]\nINPUT_DIMENSION = data_hsi.shape[2]\nALL_SIZE = data_hsi.shape[0] * data_hsi.shape[1]\nVAL_SIZE = int(TRAIN_SIZE)\nTEST_SIZE = TOTAL_SIZE - TRAIN_SIZE\n\nKAPPA = []\nOA = []\nAA = []\nTRAINING_TIME = []\nTESTING_TIME = []\nELEMENT_ACC = np.zeros((ITER, CLASSES_NUM))\n\ndata = preprocessing.scale(data)\ndata_ = data.reshape(data_hsi.shape[0], data_hsi.shape[1], data_hsi.shape[2])\nwhole_data = data_\npadded_data = np.lib.pad(\n    whole_data, ((PATCH_LENGTH, PATCH_LENGTH), (PATCH_LENGTH, PATCH_LENGTH),\n                 (0, 0)),\n    'constant',\n    constant_values=0)\n\n# # Model\n\n\ndef conv3x3(in_planes, out_planes, stride=1, groups=1, dilation=1):\n    \"\"\"3x3 convolution with padding\"\"\"\n    return nn.Conv2d(\n        in_planes,\n        out_planes,\n        kernel_size=3,\n        stride=stride,\n        padding=dilation,\n        groups=groups,\n        bias=False,\n        dilation=dilation)\n\n\ndef conv1x1(in_planes, out_planes, stride=1):\n    \"\"\"1x1 convolution\"\"\"\n    return nn.Conv2d(\n        in_planes, out_planes, kernel_size=1, stride=stride, bias=False)\n\n\nclass BasicBlock(nn.Module):\n    expansion = 1\n\n    def __init__(self,\n                 inplanes,\n                 planes,\n                 stride=1,\n                 downsample=None,\n                 groups=1,\n                 base_width=64,\n                 dilation=1,\n                 norm_layer=None):\n        super(BasicBlock, self).__init__()\n        if norm_layer is None:\n            norm_layer = nn.BatchNorm2d\n        if groups != 1 or base_width != 64:\n            raise ValueError(\n                'BasicBlock only supports groups=1 and base_width=64')\n        if dilation > 1:\n            raise NotImplementedError(\n                \"Dilation > 1 not supported in BasicBlock\")\n        # Both self.conv1 and self.downsample layers downsample the input when stride != 1\n        self.conv1 = conv3x3(inplanes, planes, stride)\n        self.bn1 = norm_layer(planes)\n        self.relu = nn.ReLU(inplace=True)\n        self.conv2 = conv3x3(planes, planes)\n        self.bn2 = norm_layer(planes)\n        self.downsample = downsample\n        self.stride = stride\n\n    def forward(self, x):\n        identity = 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            identity = self.downsample(x)\n\n        out += identity\n        out = self.relu(out)\n\n        return out\n\n\nclass Bottleneck(nn.Module):\n    # Bottleneck in torchvision places the stride for downsampling at 3x3 convolution(self.conv2)\n    # while original implementation places the stride at the first 1x1 convolution(self.conv1)\n    # according to \"Deep residual learning for image recognition\"https://arxiv.org/abs/1512.03385.\n    # This variant is also known as ResNet V1.5 and improves accuracy according to\n    # https://ngc.nvidia.com/catalog/model-scripts/nvidia:resnet_50_v1_5_for_pytorch.\n\n    expansion = 4\n\n    def __init__(self,\n                 inplanes,\n                 planes,\n                 stride=1,\n                 downsample=None,\n                 groups=1,\n                 base_width=64,\n                 dilation=1,\n                 norm_layer=None):\n        super(Bottleneck, self).__init__()\n        if norm_layer is None:\n            norm_layer = nn.BatchNorm2d\n        width = int(planes * (base_width / 64.)) * groups\n        # Both self.conv2 and self.downsample layers downsample the input when stride != 1\n        self.conv1 = conv1x1(inplanes, width)\n        self.bn1 = norm_layer(width)\n        self.conv2 = conv3x3(width, width, stride, groups, dilation)\n        self.bn2 = norm_layer(width)\n        self.conv3 = conv1x1(width, planes * self.expansion)\n        self.bn3 = norm_layer(planes * self.expansion)\n        self.relu = nn.ReLU(inplace=True)\n        self.downsample = downsample\n        self.stride = stride\n\n    def forward(self, x):\n        identity = 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            identity = self.downsample(x)\n\n        out += identity\n        out = self.relu(out)\n\n        return out\n\n\nclass ResNet(nn.Module):\n    def __init__(self,\n                 block,\n                 layers,\n                 num_classes=1000,\n                 in_shape=3,\n                 zero_init_residual=False,\n                 groups=1,\n                 width_per_group=64,\n                 replace_stride_with_dilation=None,\n                 norm_layer=None):\n        super(ResNet, self).__init__()\n        if norm_layer is None:\n            norm_layer = nn.BatchNorm2d\n        self._norm_layer = norm_layer\n\n        self.inplanes = 64\n        self.dilation = 1\n        if replace_stride_with_dilation is None:\n            # each element in the tuple indicates if we should replace\n            # the 2x2 stride with a dilated convolution instead\n            replace_stride_with_dilation = [False, False, False]\n        if len(replace_stride_with_dilation) != 3:\n            raise ValueError(\"replace_stride_with_dilation should be None \"\n                             \"or a 3-element tuple, got {}\".format(\n                                 replace_stride_with_dilation))\n        self.groups = groups\n        self.base_width = width_per_group\n        self.conv1 = nn.Conv2d(\n            in_shape,\n            self.inplanes,\n            kernel_size=7,\n            stride=2,\n            padding=3,\n            bias=False)\n        self.bn1 = norm_layer(self.inplanes)\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(\n            block,\n            128,\n            layers[1],\n            stride=2,\n            dilate=replace_stride_with_dilation[0])\n        self.layer3 = self._make_layer(\n            block,\n            256,\n            layers[2],\n            stride=2,\n            dilate=replace_stride_with_dilation[1])\n        self.layer4 = self._make_layer(\n            block,\n            512,\n            layers[3],\n            stride=2,\n            dilate=replace_stride_with_dilation[2])\n        self.avgpool = nn.AdaptiveAvgPool2d((1, 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                nn.init.kaiming_normal_(\n                    m.weight, mode='fan_out', nonlinearity='relu')\n            elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):\n                nn.init.constant_(m.weight, 1)\n                nn.init.constant_(m.bias, 0)\n\n        # Zero-initialize the last BN in each residual branch,\n        # so that the residual branch starts with zeros, and each residual block behaves like an identity.\n        # This improves the model by 0.2~0.3% according to https://arxiv.org/abs/1706.02677\n        if zero_init_residual:\n            for m in self.modules():\n                if isinstance(m, Bottleneck):\n                    nn.init.constant_(m.bn3.weight, 0)\n                elif isinstance(m, BasicBlock):\n                    nn.init.constant_(m.bn2.weight, 0)\n\n    def _make_layer(self, block, planes, blocks, stride=1, dilate=False):\n        norm_layer = self._norm_layer\n        downsample = None\n        previous_dilation = self.dilation\n        if dilate:\n            self.dilation *= stride\n            stride = 1\n        if stride != 1 or self.inplanes != planes * block.expansion:\n            downsample = nn.Sequential(\n                conv1x1(self.inplanes, planes * block.expansion, stride),\n                norm_layer(planes * block.expansion),\n            )\n\n        layers = []\n        layers.append(\n            block(self.inplanes, planes, stride, downsample, self.groups,\n                  self.base_width, previous_dilation, norm_layer))\n        self.inplanes = planes * block.expansion\n        for _ in range(1, blocks):\n            layers.append(\n                block(\n                    self.inplanes,\n                    planes,\n                    groups=self.groups,\n                    base_width=self.base_width,\n                    dilation=self.dilation,\n                    norm_layer=norm_layer))\n\n        return nn.Sequential(*layers)\n\n    def _forward_impl(self, x):\n        # See note [TorchScript super()]\n        x = self.conv1(x)\n        x = self.bn1(x)\n        x = self.relu(x)\n        x = self.maxpool(x)\n\n        x = self.layer1(x)\n        x = self.layer2(x)\n        x = self.layer3(x)\n        x = self.layer4(x)\n\n        x = self.avgpool(x)\n        x = torch.flatten(x, 1)\n        x = self.fc(x)\n\n        return x\n\n    def forward(self, x):\n        return self._forward_impl(x)\n\n\ndef ResNet34(in_shape, num_classes):\n    r\"\"\"ResNet-34 model from\n    `\"Deep Residual Learning for Image Recognition\" <https://arxiv.org/pdf/1512.03385.pdf>`_\n\n    Args:\n        in_shape (tuple): Shape of input\n        num_classes (tuple): No of classes\n    \"\"\"\n    model = ResNet(\n        BasicBlock, [3, 4, 6, 3],\n        in_shape=in_shape[0],\n        num_classes=num_classes)\n    return model\n\n\nmodel = ResNet34(\n    in_shape=(BAND, img_rows, img_cols), num_classes=CLASSES_NUM).cuda()\n\nsummary(model, input_data=(BAND, img_rows, img_cols), verbose=1)\n\n# # Plotting\n\n\ndef train(net,\n          train_iter,\n          valida_iter,\n          loss,\n          optimizer,\n          device,\n          epochs,\n          early_stopping=True,\n          early_num=20):\n    loss_list = [100]\n    early_epoch = 0\n\n    net = net.to(device)\n    print(\"training on \", device)\n    start = time.time()\n    train_loss_list = []\n    valida_loss_list = []\n    train_acc_list = []\n    valida_acc_list = []\n    for epoch in range(epochs):\n        train_acc_sum, n = 0.0, 0\n        time_epoch = time.time()\n        lr_adjust = torch.optim.lr_scheduler.CosineAnnealingLR(\n            optimizer, 15, eta_min=0.0, last_epoch=-1)\n        for X, y in train_iter:\n\n            batch_count, train_l_sum = 0, 0\n            X = X.permute(0, 3, 1, 2)\n            X = X.to(device)\n            y = y.to(device)\n            y_hat = net(X)\n            # print('y_hat', y_hat)\n            # print('y', y)\n            l = loss(y_hat, y.long())\n\n            optimizer.zero_grad()\n            l.backward()\n            optimizer.step()\n            train_l_sum += l.cpu().item()\n            train_acc_sum += (y_hat.argmax(dim=1) == y).sum().cpu().item()\n            n += y.shape[0]\n            batch_count += 1\n        lr_adjust.step()\n        valida_acc, valida_loss = record.evaluate_accuracy(\n            valida_iter, net, loss, device)\n        loss_list.append(valida_loss)\n\n        train_loss_list.append(train_l_sum)  # / batch_count)\n        train_acc_list.append(train_acc_sum / n)\n        valida_loss_list.append(valida_loss)\n        valida_acc_list.append(valida_acc)\n\n        print(\n            'epoch %d, train loss %.6f, train acc %.3f, valida loss %.6f, valida acc %.3f, time %.1f sec'\n            % (epoch + 1, train_l_sum / batch_count, train_acc_sum / n,\n               valida_loss, valida_acc, time.time() - time_epoch))\n\n        PATH = \"./net_DBA.pt\"\n\n        if early_stopping and loss_list[-2] < loss_list[-1]:\n            if early_epoch == 0:  # and valida_acc > 0.9:\n                torch.save(net.state_dict(), PATH)\n            early_epoch += 1\n            loss_list[-1] = loss_list[-2]\n            if early_epoch == early_num:\n                net.load_state_dict(torch.load(PATH))\n                break\n        else:\n            early_epoch = 0\n\n    print('epoch %d, loss %.4f, train acc %.3f, time %.1f sec'\n          % (epoch + 1, train_l_sum / batch_count, train_acc_sum / n,\n             time.time() - start))\n\n\ndef sampling(proportion, ground_truth):\n    train = {}\n    test = {}\n    labels_loc = {}\n    m = max(ground_truth)\n    for i in range(m):\n        indexes = [\n            j for j, x in enumerate(ground_truth.ravel().tolist())\n            if x == i + 1\n        ]\n        np.random.shuffle(indexes)\n        labels_loc[i] = indexes\n        if proportion != 1:\n            nb_val = max(int((1 - proportion) * len(indexes)), 3)\n        else:\n            nb_val = 0\n        train[i] = indexes[:nb_val]\n        test[i] = indexes[nb_val:]\n    train_indexes = []\n    test_indexes = []\n    for i in range(m):\n        train_indexes += train[i]\n        test_indexes += test[i]\n    np.random.shuffle(train_indexes)\n    np.random.shuffle(test_indexes)\n    return train_indexes, test_indexes\n\n\ndef select(groundTruth):  #divide dataset into train and test datasets\n    labels_loc = {}\n    train = {}\n    test = {}\n    m = max(groundTruth)\n    #amount = [3, 41, 29, 7, 14, 20, 2, 15, 3, 36, 64, 22, 4, 28, 10, 2]\n    #amount = [43, 1387, 801, 230, 469, 710, 26, 463, 17, 936, 2391, 571, 201, 1237, 376, 91]\n    if Dataset == 'IN':\n        amount = [\n            35, 1011, 581, 167, 344, 515, 19, 327, 12, 683, 1700, 418, 138,\n            876, 274, 69\n        ]  #IP 20%\n    #amount = [6, 144, 84, 24, 50, 75, 3, 49, 2, 97, 247, 62, 22, 130, 38, 10]   #IP 20%\n    if Dataset == 'UP':\n        amount = [5297, 14974, 1648, 2424, 1076, 4026, 1046, 2950, 755]  #UP\n    if Dataset == 'KSC':\n        amount = [\n            530, 165, 176, 170, 110, 161, 80, 299, 377, 283, 296, 341, 654\n        ]  #KSC\n    for i in range(m):\n        indices = [\n            j for j, x in enumerate(groundTruth.ravel().tolist()) if x == i + 1\n        ]\n        np.random.shuffle(indices)\n        labels_loc[i] = indices\n        nb_val = int(amount[i])\n        train[i] = indices[:-nb_val]\n        test[i] = indices[-nb_val:]\n#    whole_indices = []\n    train_indices = []\n    test_indices = []\n    for i in range(m):\n        #        whole_indices += labels_loc[i]\n        train_indices += train[i]\n        test_indices += test[i]\n    np.random.shuffle(train_indices)\n    np.random.shuffle(test_indices)\n    return train_indices, test_indices\n\n\n# # Training\n\nfor index_iter in range(ITER):\n    print('iter:', index_iter)\n    #define the model\n    #net = pResNet(32, 48, CLASSES_NUM, BAND, 2, 16, bottleneck=True)\n    #net = resnet20(num_classes=CLASSES_NUM)\n    net = ResNet34(\n        in_shape=(BAND, img_rows, img_cols), num_classes=CLASSES_NUM)\n\n    if PARAM_OPTIM == 'diffgrad':\n        optimizer = optim2.DiffGrad(\n            net.parameters(),\n            lr=lr,\n            betas=(0.9, 0.999),\n            eps=1e-8,\n            weight_decay=0)  # weight_decay=0.0001)\n    if PARAM_OPTIM == 'adam':\n        optimizer = optim.Adam(\n            net.parameters(),\n            lr=1e-3,\n            betas=(0.9, 0.999),\n            eps=1e-8,\n            weight_decay=0)\n    time_1 = int(time.time())\n    np.random.seed(seeds[index_iter])\n    # train_indices, test_indices = select(gt)\n    train_indices, test_indices = sampling(VALIDATION_SPLIT, gt)\n    _, total_indices = sampling(1, gt)\n\n    TRAIN_SIZE = len(train_indices)\n    print('Train size: ', TRAIN_SIZE)\n    TEST_SIZE = TOTAL_SIZE - TRAIN_SIZE\n    print('Test size: ', TEST_SIZE)\n    VAL_SIZE = int(TRAIN_SIZE)\n    print('Validation size: ', VAL_SIZE)\n\n    print('-----Selecting Small Pieces from the Original Cube Data-----')\n    train_iter, valida_iter, test_iter, all_iter = geniter.generate_iter(\n        TRAIN_SIZE, train_indices, TEST_SIZE, test_indices, TOTAL_SIZE,\n        total_indices, VAL_SIZE, whole_data, PATCH_LENGTH, padded_data,\n        INPUT_DIMENSION, 16, gt)  #batchsize in 1\n\n    tic1 = time.time()\n    train(\n        net,\n        train_iter,\n        valida_iter,\n        loss,\n        optimizer,\n        device,\n        epochs=PARAM_EPOCH)\n    toc1 = time.time()\n\n    pred_test = []\n    tic2 = time.time()\n    with torch.no_grad():\n        for X, y in test_iter:\n            # print('Shape of X',X.shape)\n            X = X.permute(0, 3, 1, 2)\n            X = X.to(device)\n            net.eval()\n            y_hat = net(X)\n            pred_test.extend(np.array(net(X).cpu().argmax(axis=1)))\n    toc2 = time.time()\n    collections.Counter(pred_test)\n    gt_test = gt[test_indices] - 1\n\n    overall_acc = metrics.accuracy_score(pred_test, gt_test[:-VAL_SIZE])\n    confusion_matrix = metrics.confusion_matrix(pred_test, gt_test[:-VAL_SIZE])\n    each_acc, average_acc = record.aa_and_each_accuracy(confusion_matrix)\n    kappa = metrics.cohen_kappa_score(pred_test, gt_test[:-VAL_SIZE])\n\n    torch.save(net.state_dict(),\n               \"./models/\" + 'Resnet34' + str(round(overall_acc, 3)) + '.pt')\n    KAPPA.append(kappa)\n    OA.append(overall_acc)\n    AA.append(average_acc)\n    TRAINING_TIME.append(toc1 - tic1)\n    TESTING_TIME.append(toc2 - tic2)\n    ELEMENT_ACC[index_iter, :] = each_acc\n\n# # Map, Records\nprint(\"--------\" + \" Training Finished-----------\")\nrecord.record_output(\n    OA, AA, KAPPA, ELEMENT_ACC, TRAINING_TIME, TESTING_TIME,\n    './report/' + 'Resnet34patch:' + str(img_rows) + '_' + Dataset + 'split' +\n    str(VALIDATION_SPLIT) + 'lr' + str(lr) + PARAM_OPTIM + '.txt')\n\nUtils.generate_png(\n    all_iter, net, gt_hsi, Dataset, device, total_indices,\n    './classification_maps/' + 'Resnet34patch:' + str(img_rows) + '_' + Dataset\n    + 'split' + str(VALIDATION_SPLIT) + 'lr' + str(lr) + PARAM_OPTIM)\n"
  },
  {
    "path": "ResNet/Utils.py",
    "content": "import numpy as np\nfrom sklearn import metrics, preprocessing\nfrom sklearn.preprocessing import MinMaxScaler\nfrom sklearn.decomposition import PCA\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import confusion_matrix, accuracy_score, classification_report, cohen_kappa_score\nfrom operator import truediv\nimport matplotlib.pyplot as plt\nimport scipy.io as sio\nimport os\nimport spectral\nimport torch\nimport cv2\nfrom operator import truediv\n\n\ndef sampling(proportion, ground_truth):\n    train = {}\n    test = {}\n    labels_loc = {}\n    m = max(ground_truth)\n    for i in range(m):\n        indexes = [\n            j for j, x in enumerate(ground_truth.ravel().tolist())\n            if x == i + 1\n        ]\n        np.random.shuffle(indexes)\n        labels_loc[i] = indexes\n        if proportion != 1:\n            nb_val = max(int((1 - proportion) * len(indexes)), 3)\n        else:\n            nb_val = 0\n        train[i] = indexes[:nb_val]\n        test[i] = indexes[nb_val:]\n    train_indexes = []\n    test_indexes = []\n    for i in range(m):\n        train_indexes += train[i]\n        test_indexes += test[i]\n    np.random.shuffle(train_indexes)\n    np.random.shuffle(test_indexes)\n    return train_indexes, test_indexes\n\n\ndef set_figsize(figsize=(3.5, 2.5)):\n    display.set_matplotlib_formats('svg')\n    plt.rcParams['figure.figsize'] = figsize\n\n\ndef classification_map(map, ground_truth, dpi, save_path):\n    fig = plt.figure(frameon=False)\n    fig.set_size_inches(ground_truth.shape[1] * 2.0 / dpi,\n                        ground_truth.shape[0] * 2.0 / dpi)\n    ax = plt.Axes(fig, [0., 0., 1., 1.])\n    ax.set_axis_off()\n    ax.xaxis.set_visible(False)\n    ax.yaxis.set_visible(False)\n    fig.add_axes(ax)\n    ax.imshow(map)\n    fig.savefig(save_path, dpi=dpi)\n    return 0\n\n\ndef list_to_colormap(x_list):\n    y = np.zeros((x_list.shape[0], 3))\n    for index, item in enumerate(x_list):\n        if item == 0:\n            y[index] = np.array([255, 0, 0]) / 255.\n        if item == 1:\n            y[index] = np.array([0, 255, 0]) / 255.\n        if item == 2:\n            y[index] = np.array([0, 0, 255]) / 255.\n        if item == 3:\n            y[index] = np.array([255, 255, 0]) / 255.\n        if item == 4:\n            y[index] = np.array([0, 255, 255]) / 255.\n        if item == 5:\n            y[index] = np.array([255, 0, 255]) / 255.\n        if item == 6:\n            y[index] = np.array([192, 192, 192]) / 255.\n        if item == 7:\n            y[index] = np.array([128, 128, 128]) / 255.\n        if item == 8:\n            y[index] = np.array([128, 0, 0]) / 255.\n        if item == 9:\n            y[index] = np.array([128, 128, 0]) / 255.\n        if item == 10:\n            y[index] = np.array([0, 128, 0]) / 255.\n        if item == 11:\n            y[index] = np.array([128, 0, 128]) / 255.\n        if item == 12:\n            y[index] = np.array([0, 128, 128]) / 255.\n        if item == 13:\n            y[index] = np.array([0, 0, 128]) / 255.\n        if item == 14:\n            y[index] = np.array([255, 165, 0]) / 255.\n        if item == 15:\n            y[index] = np.array([255, 215, 0]) / 255.\n        if item == 16:\n            y[index] = np.array([0, 0, 0]) / 255.\n        if item == 17:\n            y[index] = np.array([215, 255, 0]) / 255.\n        if item == 18:\n            y[index] = np.array([0, 255, 215]) / 255.\n        if item == -1:\n            y[index] = np.array([0, 0, 0]) / 255.\n    return y\n\n\ndef generate_png(all_iter, net, gt_hsi, Dataset, device, total_indices, path):\n    pred_test = []\n    for X, y in all_iter:\n        X = X.permute(0, 3, 1, 2)\n        X = X.to(device)\n        net.eval()\n        pred_test.extend(net(X).cpu().argmax(axis=1).detach().numpy())\n    gt = gt_hsi.flatten()\n    x_label = np.zeros(gt.shape)\n    for i in range(len(gt)):\n        if gt[i] == 0:\n            gt[i] = 17\n            x_label[i] = 16\n    gt = gt[:] - 1\n    x_label[total_indices] = pred_test\n    x = np.ravel(x_label)\n    y_list = list_to_colormap(x)\n    y_gt = list_to_colormap(gt)\n    y_re = np.reshape(y_list, (gt_hsi.shape[0], gt_hsi.shape[1], 3))\n    gt_re = np.reshape(y_gt, (gt_hsi.shape[0], gt_hsi.shape[1], 3))\n    classification_map(y_re, gt_hsi, 300,\n                       path + '.png')\n    classification_map(gt_re, gt_hsi, 300,\n                       path + '_gt.png')\n    print('------Get classification maps successful-------')\n"
  },
  {
    "path": "ResNet/geniter.py",
    "content": "import torch\nimport numpy as np\nimport torch.utils.data as Data\n\ndef index_assignment(index, row, col, pad_length):\n    new_assign = {}\n    for counter, value in enumerate(index):\n        assign_0 = value // col + pad_length\n        assign_1 = value % col + pad_length\n        new_assign[counter] = [assign_0, assign_1]\n    return new_assign\n\ndef select_patch(matrix, pos_row, pos_col, ex_len):\n    selected_rows = matrix[range(pos_row-ex_len, pos_row+ex_len+1)]\n    selected_patch = selected_rows[:, range(pos_col-ex_len, pos_col+ex_len+1)]\n    return selected_patch\n\n\ndef select_small_cubic(data_size, data_indices, whole_data, patch_length, padded_data, dimension):\n    small_cubic_data = np.zeros((data_size, 2 * patch_length + 1, 2 * patch_length + 1, dimension))\n    data_assign = index_assignment(data_indices, whole_data.shape[0], whole_data.shape[1], patch_length)\n    for i in range(len(data_assign)):\n        small_cubic_data[i] = select_patch(padded_data, data_assign[i][0], data_assign[i][1], patch_length)\n    return small_cubic_data\n\n\ndef generate_iter(TRAIN_SIZE, train_indices, TEST_SIZE, test_indices, TOTAL_SIZE, total_indices, VAL_SIZE,\n                  whole_data, PATCH_LENGTH, padded_data, INPUT_DIMENSION, batch_size, gt):\n    gt_all = gt[total_indices] - 1\n    y_train = gt[train_indices] - 1\n    y_test = gt[test_indices] - 1\n\n    all_data =  select_small_cubic(TOTAL_SIZE, total_indices, whole_data,\n                                                      PATCH_LENGTH, padded_data, INPUT_DIMENSION)\n\n    train_data = select_small_cubic(TRAIN_SIZE, train_indices, whole_data,\n                                                        PATCH_LENGTH, padded_data, INPUT_DIMENSION)\n    print(train_data.shape)\n    test_data =  select_small_cubic(TEST_SIZE, test_indices, whole_data,\n                                                       PATCH_LENGTH, padded_data, INPUT_DIMENSION)\n    x_train = train_data.reshape(train_data.shape[0], train_data.shape[1], train_data.shape[2], INPUT_DIMENSION)\n    x_test_all = test_data.reshape(test_data.shape[0], test_data.shape[1], test_data.shape[2], INPUT_DIMENSION)\n\n    x_val = x_test_all[-VAL_SIZE:]\n    y_val = y_test[-VAL_SIZE:]\n\n    x_test = x_test_all[:-VAL_SIZE]\n    y_test = y_test[:-VAL_SIZE]\n    \n    x1_tensor_train = torch.from_numpy(x_train).type(torch.FloatTensor)#.unsqueeze(1)\n    y1_tensor_train = torch.from_numpy(y_train).type(torch.FloatTensor)\n    torch_dataset_train = Data.TensorDataset(x1_tensor_train, y1_tensor_train)\n\n    x1_tensor_valida = torch.from_numpy(x_val).type(torch.FloatTensor)#.unsqueeze(1)\n    y1_tensor_valida = torch.from_numpy(y_val).type(torch.FloatTensor)\n    torch_dataset_valida = Data.TensorDataset(x1_tensor_valida, y1_tensor_valida)\n\n    x1_tensor_test = torch.from_numpy(x_test).type(torch.FloatTensor)#.unsqueeze(1)\n    y1_tensor_test = torch.from_numpy(y_test).type(torch.FloatTensor)\n    torch_dataset_test = Data.TensorDataset(x1_tensor_test,y1_tensor_test)\n\n    all_data.reshape(all_data.shape[0], all_data.shape[1], all_data.shape[2], INPUT_DIMENSION)\n    all_tensor_data = torch.from_numpy(all_data).type(torch.FloatTensor)#.unsqueeze(1)\n    all_tensor_data_label = torch.from_numpy(gt_all).type(torch.FloatTensor)\n    torch_dataset_all = Data.TensorDataset(all_tensor_data, all_tensor_data_label)\n\n\n    train_iter = Data.DataLoader(\n        dataset=torch_dataset_train,  # torch TensorDataset format\n        batch_size=batch_size,  # mini batch size\n        shuffle=True,  \n        num_workers=0, \n    )\n    valiada_iter = Data.DataLoader(\n        dataset=torch_dataset_valida,  # torch TensorDataset format\n        batch_size=batch_size,  # mini batch size\n        shuffle=True,  \n        num_workers=0, \n    )\n    test_iter = Data.DataLoader(\n        dataset=torch_dataset_test,  # torch TensorDataset format\n        batch_size=batch_size,  # mini batch size\n        shuffle=False, \n        num_workers=0, \n    )\n    all_iter = Data.DataLoader(\n        dataset=torch_dataset_all,  # torch TensorDataset format\n        batch_size=batch_size,  # mini batch size\n        shuffle=False, \n        num_workers=0, \n    )\n    return train_iter, valiada_iter, test_iter, all_iter #, y_test\n"
  },
  {
    "path": "ResNet/record.py",
    "content": "import numpy as np\nimport torch\nfrom operator import truediv\n\ndef evaluate_accuracy(data_iter, net, loss, device):\n    acc_sum, n = 0.0, 0\n    with torch.no_grad():\n        for X, y in data_iter:\n            test_l_sum, test_num = 0, 0\n            X = X.permute(0, 3, 1, 2)\n            X = X.to(device)\n            y = y.to(device)\n            net.eval() \n            y_hat = net(X)\n            l = loss(y_hat, y.long())\n            acc_sum += (y_hat.argmax(dim=1) == y.to(device)).float().sum().cpu().item()\n            test_l_sum += l\n            test_num += 1\n            net.train() \n            n += y.shape[0]\n    return [acc_sum / n, test_l_sum] # / test_num]\n\n\ndef aa_and_each_accuracy(confusion_matrix):\n    list_diag = np.diag(confusion_matrix)\n    list_raw_sum = np.sum(confusion_matrix, axis=1)\n    each_acc = np.nan_to_num(truediv(list_diag, list_raw_sum))\n    average_acc = np.mean(each_acc)\n    return each_acc, average_acc\n\n\n\ndef record_output(oa_ae, aa_ae, kappa_ae, element_acc_ae, training_time_ae, testing_time_ae, path):\n    f = open(path, 'a')\n    sentence0 = 'OAs for each iteration are:' + str(oa_ae) + '\\n'\n    f.write(sentence0)\n    sentence1 = 'AAs for each iteration are:' + str(aa_ae) + '\\n'\n    f.write(sentence1)\n    sentence2 = 'KAPPAs for each iteration are:' + str(kappa_ae) + '\\n' + '\\n'\n    f.write(sentence2)\n    sentence3 = 'mean_OA ± std_OA is: ' + str(np.mean(oa_ae)) + ' ± ' + str(np.std(oa_ae)) + '\\n'\n    f.write(sentence3)\n    sentence4 = 'mean_AA ± std_AA is: ' + str(np.mean(aa_ae)) + ' ± ' + str(np.std(aa_ae)) + '\\n'\n    f.write(sentence4)\n    sentence5 = 'mean_KAPPA ± std_KAPPA is: ' + str(np.mean(kappa_ae)) + ' ± ' + str(np.std(kappa_ae)) + '\\n' + '\\n'\n    f.write(sentence5)\n    sentence6 = 'Total average Training time is: ' + str(np.sum(training_time_ae)) + '\\n'\n    f.write(sentence6)\n    sentence7 = 'Total average Testing time is: ' + str(np.sum(testing_time_ae)) + '\\n' + '\\n'\n    f.write(sentence7)\n    element_mean = np.mean(element_acc_ae, axis=0)\n    element_std = np.std(element_acc_ae, axis=0)\n    sentence8 = \"Mean of all elements in confusion matrix: \" + str(element_mean) + '\\n'\n    f.write(sentence8)\n    sentence9 = \"Standard deviation of all elements in confusion matrix: \" + str(element_std) + '\\n'\n    f.write(sentence9)\n    f.close()\n\n"
  },
  {
    "path": "SSRN/SSRN.py",
    "content": "#!/usr/bin/env python\n# coding: utf-8\n\n# # Imports\n\nimport argparse\nimport collections\nimport math\nimport time\n\nimport numpy as np\nimport scipy.io as sio\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.optim as optim\nfrom sklearn import metrics, preprocessing\nfrom sklearn.decomposition import PCA\nfrom sklearn.metrics import confusion_matrix\n\nimport geniter\nimport record\nimport torch_optimizer as optim2\nimport Utils\nfrom torchsummary import summary\n\n# # Setting Params\n\nparser = argparse.ArgumentParser(description='Training for HSI')\nparser.add_argument(\n    '-d', '--dataset', dest='dataset', default='IN', help=\"Name of dataset.\")\nparser.add_argument(\n    '-o',\n    '--optimizer',\n    dest='optimizer',\n    default='adam',\n    help=\"Name of optimizer.\")\nparser.add_argument(\n    '-e', '--epoch', type=int, dest='epoch', default=200, help=\"No of epoch\")\nparser.add_argument(\n    '-i', '--iter', type=int, dest='iter', default=3, help=\"No of iter\")\nparser.add_argument(\n    '-p', '--patch', type=int, dest='patch', default=4, help=\"Length of patch\")\nparser.add_argument(\n    '-vs',\n    '--valid_split',\n    type=float,\n    dest='valid_split',\n    default=0.9,\n    help=\"Percentage of validation split.\")\nargs = parser.parse_args()\n\nPARAM_DATASET = args.dataset  # UP,IN,SV, KSC\nPARAM_EPOCH = args.epoch\nPARAM_ITER = args.iter\nPATCH_SIZE = args.patch\nPARAM_VAL = args.valid_split\nPARAM_OPTIM = args.optimizer\n\n# # Data Loading\n\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n\n# for Monte Carlo runs\nseeds = [1331, 1332, 1333, 1334, 1335, 1336, 1337, 1338, 1339, 1340, 1341]\nensemble = 1\n\nglobal Dataset  # UP,IN,SV, KSC\ndataset = PARAM_DATASET  #input('Please input the name of Dataset(IN, UP, SV, KSC):')\nDataset = dataset.upper()\n\n\ndef load_dataset(Dataset, split=0.9):\n    data_path = '../dataset/'\n    if Dataset == 'IN':\n        mat_data = sio.loadmat(data_path + 'Indian_pines_corrected.mat')\n        mat_gt = sio.loadmat(data_path + 'Indian_pines_gt.mat')\n        data_hsi = mat_data['indian_pines_corrected']\n        gt_hsi = mat_gt['indian_pines_gt']\n        K = data_hsi.shape[2]\n        TOTAL_SIZE = 10249\n        VALIDATION_SPLIT = split\n        TRAIN_SIZE = math.ceil(TOTAL_SIZE * VALIDATION_SPLIT)\n\n    if Dataset == 'UP':\n        uPavia = sio.loadmat(data_path + 'PaviaU.mat')\n        gt_uPavia = sio.loadmat(data_path + 'PaviaU_gt.mat')\n        data_hsi = uPavia['paviaU']\n        gt_hsi = gt_uPavia['paviaU_gt']\n        K = data_hsi.shape[2]\n        TOTAL_SIZE = 42776\n        VALIDATION_SPLIT = split\n        TRAIN_SIZE = math.ceil(TOTAL_SIZE * VALIDATION_SPLIT)\n\n    if Dataset == 'SV':\n        SV = sio.loadmat(data_path + 'Salinas_corrected.mat')\n        gt_SV = sio.loadmat(data_path + 'Salinas_gt.mat')\n        data_hsi = SV['salinas_corrected']\n        gt_hsi = gt_SV['salinas_gt']\n        K = data_hsi.shape[2]\n        TOTAL_SIZE = 54129\n        VALIDATION_SPLIT = split\n        TRAIN_SIZE = math.ceil(TOTAL_SIZE * VALIDATION_SPLIT)\n\n    if Dataset == 'KSC':\n        SV = sio.loadmat(data_path + 'KSC.mat')\n        gt_SV = sio.loadmat(data_path + 'KSC_gt.mat')\n        data_hsi = SV['KSC']\n        gt_hsi = gt_SV['KSC_gt']\n        K = data_hsi.shape[2]\n        TOTAL_SIZE = 5211\n        VALIDATION_SPLIT = split\n        TRAIN_SIZE = math.ceil(TOTAL_SIZE * VALIDATION_SPLIT)\n\n    shapeor = data_hsi.shape\n    data_hsi = data_hsi.reshape(-1, data_hsi.shape[-1])\n    data_hsi = PCA(n_components=K).fit_transform(data_hsi)\n    shapeor = np.array(shapeor)\n    shapeor[-1] = K\n    data_hsi = data_hsi.reshape(shapeor)\n\n    return data_hsi, gt_hsi, TOTAL_SIZE, TRAIN_SIZE, VALIDATION_SPLIT\n\n\n# # Pytorch Data Loader Creation\n\ndata_hsi, gt_hsi, TOTAL_SIZE, TRAIN_SIZE, VALIDATION_SPLIT = load_dataset(\n    Dataset, PARAM_VAL)\nprint(data_hsi.shape)\nimage_x, image_y, BAND = data_hsi.shape\ndata = data_hsi.reshape(\n    np.prod(data_hsi.shape[:2]), np.prod(data_hsi.shape[2:]))\ngt = gt_hsi.reshape(np.prod(gt_hsi.shape[:2]), )\nCLASSES_NUM = max(gt)\nprint('The class numbers of the HSI data is:', CLASSES_NUM)\n\nprint('-----Importing Setting Parameters-----')\nITER = PARAM_ITER\nPATCH_LENGTH = PATCH_SIZE\nlr, num_epochs, batch_size = 0.001, 200, 32\nloss = torch.nn.CrossEntropyLoss()\n\nimg_rows = 2 * PATCH_LENGTH + 1\nimg_cols = 2 * PATCH_LENGTH + 1\nimg_channels = data_hsi.shape[2]\nINPUT_DIMENSION = data_hsi.shape[2]\nALL_SIZE = data_hsi.shape[0] * data_hsi.shape[1]\nVAL_SIZE = int(TRAIN_SIZE)\nTEST_SIZE = TOTAL_SIZE - TRAIN_SIZE\n\nKAPPA = []\nOA = []\nAA = []\nTRAINING_TIME = []\nTESTING_TIME = []\nELEMENT_ACC = np.zeros((ITER, CLASSES_NUM))\n\ndata = preprocessing.scale(data)\ndata_ = data.reshape(data_hsi.shape[0], data_hsi.shape[1], data_hsi.shape[2])\nwhole_data = data_\npadded_data = np.lib.pad(\n    whole_data, ((PATCH_LENGTH, PATCH_LENGTH), (PATCH_LENGTH, PATCH_LENGTH),\n                 (0, 0)),\n    'constant',\n    constant_values=0)\n\n# # Model\n\n\nclass Residual(nn.Module):  # pytorch\n    def __init__(self,\n                 in_channels,\n                 out_channels,\n                 kernel_size,\n                 padding,\n                 use_1x1conv=False,\n                 stride=1):\n        super(Residual, self).__init__()\n        self.conv1 = nn.Sequential(\n            nn.Conv3d(\n                in_channels,\n                out_channels,\n                kernel_size=kernel_size,\n                padding=padding,\n                stride=stride), nn.ReLU())\n        self.conv2 = nn.Conv3d(\n            out_channels,\n            out_channels,\n            kernel_size=kernel_size,\n            padding=padding,\n            stride=stride)\n        if use_1x1conv:\n            self.conv3 = nn.Conv3d(\n                in_channels, out_channels, kernel_size=1, stride=stride)\n        else:\n            self.conv3 = None\n        self.bn1 = nn.BatchNorm3d(out_channels)\n        self.bn2 = nn.BatchNorm3d(out_channels)\n\n    def forward(self, X):\n        Y = F.relu(self.bn1(self.conv1(X)))\n        Y = self.bn2(self.conv2(Y))\n        if self.conv3:\n            X = self.conv3(X)\n        return F.relu(Y + X)\n\n\nclass SSRN_network(nn.Module):\n    def __init__(self, band, classes):\n        super(SSRN_network, self).__init__()\n        self.name = 'SSRN'\n        self.conv1 = nn.Conv3d(\n            in_channels=1,\n            out_channels=24,\n            kernel_size=(1, 1, 7),\n            stride=(1, 1, 2))\n        self.batch_norm1 = nn.Sequential(\n            nn.BatchNorm3d(24, eps=0.001, momentum=0.1, affine=True),  # 0.1\n            nn.ReLU(inplace=True))\n\n        self.res_net1 = Residual(24, 24, (1, 1, 7), (0, 0, 3))\n        self.res_net2 = Residual(24, 24, (1, 1, 7), (0, 0, 3))\n        self.res_net3 = Residual(24, 24, (3, 3, 1), (1, 1, 0))\n        self.res_net4 = Residual(24, 24, (3, 3, 1), (1, 1, 0))\n\n        kernel_3d = math.ceil((band - 6) / 2)\n\n        self.conv2 = nn.Conv3d(\n            in_channels=24,\n            out_channels=128,\n            padding=(0, 0, 0),\n            kernel_size=(1, 1, kernel_3d),\n            stride=(1, 1, 1))\n        self.batch_norm2 = nn.Sequential(\n            nn.BatchNorm3d(128, eps=0.001, momentum=0.1, affine=True),  # 0.1\n            nn.ReLU(inplace=True))\n        self.conv3 = nn.Conv3d(\n            in_channels=1,\n            out_channels=24,\n            padding=(0, 0, 0),\n            kernel_size=(3, 3, 128),\n            stride=(1, 1, 1))\n        self.batch_norm3 = nn.Sequential(\n            nn.BatchNorm3d(24, eps=0.001, momentum=0.1, affine=True),  # 0.1\n            nn.ReLU(inplace=True))\n\n        self.avg_pooling = nn.AvgPool3d(kernel_size=(5, 5, 1))\n        self.full_connection = nn.Sequential(\n            nn.Dropout(p=0.5),\n            nn.Linear(24, classes)  # ,\n            # nn.Softmax()\n        )\n\n    def forward(self, X):\n        x1 = self.batch_norm1(self.conv1(X))\n        # print('x1', x1.shape)\n\n        x2 = self.res_net1(x1)\n        x2 = self.res_net2(x2)\n        x2 = self.batch_norm2(self.conv2(x2))\n        x2 = x2.permute(0, 4, 2, 3, 1)\n        x2 = self.batch_norm3(self.conv3(x2))\n\n        x3 = self.res_net3(x2)\n        x3 = self.res_net4(x3)\n        x4 = self.avg_pooling(x3)\n        x4 = x4.view(x4.size(0), -1)\n        return self.full_connection(x4)\n\n\nmodel = SSRN_network(BAND, CLASSES_NUM).cuda()\n\nsummary(model, input_data=(1, img_rows, img_cols, BAND), verbose=1)\n\n# # Plotting\n\n\ndef train(net,\n          train_iter,\n          valida_iter,\n          loss,\n          optimizer,\n          device,\n          epochs,\n          early_stopping=True,\n          early_num=20):\n    loss_list = [100]\n    early_epoch = 0\n\n    net = net.to(device)\n    print(\"training on \", device)\n    start = time.time()\n    train_loss_list = []\n    valida_loss_list = []\n    train_acc_list = []\n    valida_acc_list = []\n    for epoch in range(epochs):\n        train_acc_sum, n = 0.0, 0\n        time_epoch = time.time()\n        lr_adjust = torch.optim.lr_scheduler.CosineAnnealingLR(\n            optimizer, 15, eta_min=0.0, last_epoch=-1)\n        for X, y in train_iter:\n\n            batch_count, train_l_sum = 0, 0\n            #X = X.permute(0, 3, 1, 2)\n            X = X.to(device)\n            y = y.to(device)\n            y_hat = net(X)\n            # print('y_hat', y_hat)\n            # print('y', y)\n            l = loss(y_hat, y.long())\n\n            optimizer.zero_grad()\n            l.backward()\n            optimizer.step()\n            train_l_sum += l.cpu().item()\n            train_acc_sum += (y_hat.argmax(dim=1) == y).sum().cpu().item()\n            n += y.shape[0]\n            batch_count += 1\n        lr_adjust.step()\n        valida_acc, valida_loss = record.evaluate_accuracy(\n            valida_iter, net, loss, device)\n        loss_list.append(valida_loss)\n\n        train_loss_list.append(train_l_sum)  # / batch_count)\n        train_acc_list.append(train_acc_sum / n)\n        valida_loss_list.append(valida_loss)\n        valida_acc_list.append(valida_acc)\n\n        print(\n            'epoch %d, train loss %.6f, train acc %.3f, valida loss %.6f, valida acc %.3f, time %.1f sec'\n            % (epoch + 1, train_l_sum / batch_count, train_acc_sum / n,\n               valida_loss, valida_acc, time.time() - time_epoch))\n\n        PATH = \"./net_DBA.pt\"\n        # if loss_list[-1] <= 0.01 and valida_acc >= 0.95:\n        #     torch.save(net.state_dict(), PATH)\n        #     break\n\n        if early_stopping and loss_list[-2] < loss_list[-1]:\n            if early_epoch == 0:  # and valida_acc > 0.9:\n                torch.save(net.state_dict(), PATH)\n            early_epoch += 1\n            loss_list[-1] = loss_list[-2]\n            if early_epoch == early_num:\n                net.load_state_dict(torch.load(PATH))\n                break\n        else:\n            early_epoch = 0\n\n    print('epoch %d, loss %.4f, train acc %.3f, time %.1f sec'\n          % (epoch + 1, train_l_sum / batch_count, train_acc_sum / n,\n             time.time() - start))\n\n\ndef sampling(proportion, ground_truth):\n    train = {}\n    test = {}\n    labels_loc = {}\n    m = max(ground_truth)\n    for i in range(m):\n        indexes = [\n            j for j, x in enumerate(ground_truth.ravel().tolist())\n            if x == i + 1\n        ]\n        np.random.shuffle(indexes)\n        labels_loc[i] = indexes\n        if proportion != 1:\n            nb_val = max(int((1 - proportion) * len(indexes)), 3)\n        else:\n            nb_val = 0\n        train[i] = indexes[:nb_val]\n        test[i] = indexes[nb_val:]\n    train_indexes = []\n    test_indexes = []\n    for i in range(m):\n        train_indexes += train[i]\n        test_indexes += test[i]\n    np.random.shuffle(train_indexes)\n    np.random.shuffle(test_indexes)\n    return train_indexes, test_indexes\n\n\ndef select(groundTruth):  #divide dataset into train and test datasets\n    labels_loc = {}\n    train = {}\n    test = {}\n    m = max(groundTruth)\n    #amount = [3, 41, 29, 7, 14, 20, 2, 15, 3, 36, 64, 22, 4, 28, 10, 2]\n    #amount = [43, 1387, 801, 230, 469, 710, 26, 463, 17, 936, 2391, 571, 201, 1237, 376, 91]\n    if Dataset == 'IN':\n        amount = [\n            35, 1011, 581, 167, 344, 515, 19, 327, 12, 683, 1700, 418, 138,\n            876, 274, 69\n        ]  #IP 20%\n    #amount = [6, 144, 84, 24, 50, 75, 3, 49, 2, 97, 247, 62, 22, 130, 38, 10]   #IP 20%\n    if Dataset == 'UP':\n        amount = [5297, 14974, 1648, 2424, 1076, 4026, 1046, 2950, 755]  #UP\n    if Dataset == 'KSC':\n        amount = [\n            530, 165, 176, 170, 110, 161, 80, 299, 377, 283, 296, 341, 654\n        ]  #KSC\n    for i in range(m):\n        indices = [\n            j for j, x in enumerate(groundTruth.ravel().tolist()) if x == i + 1\n        ]\n        np.random.shuffle(indices)\n        labels_loc[i] = indices\n        nb_val = int(amount[i])\n        train[i] = indices[:-nb_val]\n        test[i] = indices[-nb_val:]\n#    whole_indices = []\n    train_indices = []\n    test_indices = []\n    for i in range(m):\n        #        whole_indices += labels_loc[i]\n        train_indices += train[i]\n        test_indices += test[i]\n    np.random.shuffle(train_indices)\n    np.random.shuffle(test_indices)\n    return train_indices, test_indices\n\n\n# # Training\n\nfor index_iter in range(ITER):\n    print('iter:', index_iter)\n    # define the model\n    net = SSRN_network(BAND, CLASSES_NUM)\n\n    if PARAM_OPTIM == 'diffgrad':\n        optimizer = optim2.DiffGrad(\n            net.parameters(),\n            lr=lr,\n            betas=(0.9, 0.999),\n            eps=1e-8,\n            weight_decay=0)  # weight_decay=0.0001)\n    if PARAM_OPTIM == 'adam':\n        optimizer = optim.Adam(\n            net.parameters(),\n            lr=1e-3,\n            betas=(0.9, 0.999),\n            eps=1e-8,\n            weight_decay=0)\n    time_1 = int(time.time())\n    np.random.seed(seeds[index_iter])\n    # train_indices, test_indices = select(gt)\n    train_indices, test_indices = sampling(VALIDATION_SPLIT, gt)\n    _, total_indices = sampling(1, gt)\n\n    TRAIN_SIZE = len(train_indices)\n    print('Train size: ', TRAIN_SIZE)\n    TEST_SIZE = TOTAL_SIZE - TRAIN_SIZE\n    print('Test size: ', TEST_SIZE)\n    VAL_SIZE = int(TRAIN_SIZE)\n    print('Validation size: ', VAL_SIZE)\n\n    print('-----Selecting Small Pieces from the Original Cube Data-----')\n    train_iter, valida_iter, test_iter, all_iter = geniter.generate_iter(\n        TRAIN_SIZE, train_indices, TEST_SIZE, test_indices, TOTAL_SIZE,\n        total_indices, VAL_SIZE, whole_data, PATCH_LENGTH, padded_data,\n        INPUT_DIMENSION, 16, gt)  #batchsize in 1\n\n    tic1 = time.time()\n    train(\n        net,\n        train_iter,\n        valida_iter,\n        loss,\n        optimizer,\n        device,\n        epochs=PARAM_EPOCH)\n    toc1 = time.time()\n\n    pred_test = []\n    tic2 = time.time()\n    with torch.no_grad():\n        for X, y in test_iter:\n            X = X.to(device)\n            net.eval()\n            y_hat = net(X)\n            pred_test.extend(np.array(net(X).cpu().argmax(axis=1)))\n    toc2 = time.time()\n    collections.Counter(pred_test)\n    gt_test = gt[test_indices] - 1\n\n    overall_acc = metrics.accuracy_score(pred_test, gt_test[:-VAL_SIZE])\n    confusion_matrix = metrics.confusion_matrix(pred_test, gt_test[:-VAL_SIZE])\n    each_acc, average_acc = record.aa_and_each_accuracy(confusion_matrix)\n    kappa = metrics.cohen_kappa_score(pred_test, gt_test[:-VAL_SIZE])\n\n    torch.save(net.state_dict(),\n               \"./models/\" + 'SSRN' + str(round(overall_acc, 3)) + '.pt')\n    KAPPA.append(kappa)\n    OA.append(overall_acc)\n    AA.append(average_acc)\n    TRAINING_TIME.append(toc1 - tic1)\n    TESTING_TIME.append(toc2 - tic2)\n    ELEMENT_ACC[index_iter, :] = each_acc\n\n# # Map, Records\nprint(\"--------\" + \" Training Finished-----------\")\nrecord.record_output(\n    OA, AA, KAPPA, ELEMENT_ACC, TRAINING_TIME, TESTING_TIME,\n    './report/' + 'SSRNpatch:' + str(img_rows) + '_' + Dataset + 'split' +\n    str(VALIDATION_SPLIT) + 'lr' + str(lr) + PARAM_OPTIM + '.txt')\n\nUtils.generate_png(\n    all_iter, net, gt_hsi, Dataset, device, total_indices,\n    './classification_maps/' + 'SSRNpatch:' + str(img_rows) + '_' + Dataset +\n    'split' + str(VALIDATION_SPLIT) + 'lr' + str(lr) + PARAM_OPTIM)\n"
  },
  {
    "path": "SSRN/Utils.py",
    "content": "import numpy as np\nfrom sklearn import metrics, preprocessing\nfrom sklearn.preprocessing import MinMaxScaler\nfrom sklearn.decomposition import PCA\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import confusion_matrix, accuracy_score, classification_report, cohen_kappa_score\nfrom operator import truediv\nimport matplotlib.pyplot as plt\nimport scipy.io as sio\nimport os\nimport spectral\nimport torch\nimport cv2\nfrom operator import truediv\n\n\ndef sampling(proportion, ground_truth):\n    train = {}\n    test = {}\n    labels_loc = {}\n    m = max(ground_truth)\n    for i in range(m):\n        indexes = [\n            j for j, x in enumerate(ground_truth.ravel().tolist())\n            if x == i + 1\n        ]\n        np.random.shuffle(indexes)\n        labels_loc[i] = indexes\n        if proportion != 1:\n            nb_val = max(int((1 - proportion) * len(indexes)), 3)\n        else:\n            nb_val = 0\n        train[i] = indexes[:nb_val]\n        test[i] = indexes[nb_val:]\n    train_indexes = []\n    test_indexes = []\n    for i in range(m):\n        train_indexes += train[i]\n        test_indexes += test[i]\n    np.random.shuffle(train_indexes)\n    np.random.shuffle(test_indexes)\n    return train_indexes, test_indexes\n\n\ndef set_figsize(figsize=(3.5, 2.5)):\n    display.set_matplotlib_formats('svg')\n    plt.rcParams['figure.figsize'] = figsize\n\n\ndef classification_map(map, ground_truth, dpi, save_path):\n    fig = plt.figure(frameon=False)\n    fig.set_size_inches(ground_truth.shape[1] * 2.0 / dpi,\n                        ground_truth.shape[0] * 2.0 / dpi)\n    ax = plt.Axes(fig, [0., 0., 1., 1.])\n    ax.set_axis_off()\n    ax.xaxis.set_visible(False)\n    ax.yaxis.set_visible(False)\n    fig.add_axes(ax)\n    ax.imshow(map)\n    fig.savefig(save_path, dpi=dpi)\n    return 0\n\n\ndef list_to_colormap(x_list):\n    y = np.zeros((x_list.shape[0], 3))\n    for index, item in enumerate(x_list):\n        if item == 0:\n            y[index] = np.array([255, 0, 0]) / 255.\n        if item == 1:\n            y[index] = np.array([0, 255, 0]) / 255.\n        if item == 2:\n            y[index] = np.array([0, 0, 255]) / 255.\n        if item == 3:\n            y[index] = np.array([255, 255, 0]) / 255.\n        if item == 4:\n            y[index] = np.array([0, 255, 255]) / 255.\n        if item == 5:\n            y[index] = np.array([255, 0, 255]) / 255.\n        if item == 6:\n            y[index] = np.array([192, 192, 192]) / 255.\n        if item == 7:\n            y[index] = np.array([128, 128, 128]) / 255.\n        if item == 8:\n            y[index] = np.array([128, 0, 0]) / 255.\n        if item == 9:\n            y[index] = np.array([128, 128, 0]) / 255.\n        if item == 10:\n            y[index] = np.array([0, 128, 0]) / 255.\n        if item == 11:\n            y[index] = np.array([128, 0, 128]) / 255.\n        if item == 12:\n            y[index] = np.array([0, 128, 128]) / 255.\n        if item == 13:\n            y[index] = np.array([0, 0, 128]) / 255.\n        if item == 14:\n            y[index] = np.array([255, 165, 0]) / 255.\n        if item == 15:\n            y[index] = np.array([255, 215, 0]) / 255.\n        if item == 16:\n            y[index] = np.array([0, 0, 0]) / 255.\n        if item == 17:\n            y[index] = np.array([215, 255, 0]) / 255.\n        if item == 18:\n            y[index] = np.array([0, 255, 215]) / 255.\n        if item == -1:\n            y[index] = np.array([0, 0, 0]) / 255.\n    return y\n\n\ndef generate_png(all_iter, net, gt_hsi, Dataset, device, total_indices, path):\n    pred_test = []\n    for X, y in all_iter:\n        # X = X.permute(0, 3, 1, 2)\n        X = X.to(device)\n        net.eval()\n        pred_test.extend(net(X).cpu().argmax(axis=1).detach().numpy())\n    gt = gt_hsi.flatten()\n    x_label = np.zeros(gt.shape)\n    for i in range(len(gt)):\n        if gt[i] == 0:\n            gt[i] = 17\n            x_label[i] = 16\n    gt = gt[:] - 1\n    x_label[total_indices] = pred_test\n    x = np.ravel(x_label)\n    y_list = list_to_colormap(x)\n    y_gt = list_to_colormap(gt)\n    y_re = np.reshape(y_list, (gt_hsi.shape[0], gt_hsi.shape[1], 3))\n    gt_re = np.reshape(y_gt, (gt_hsi.shape[0], gt_hsi.shape[1], 3))\n    classification_map(y_re, gt_hsi, 300,\n                       path + '.png')\n    classification_map(gt_re, gt_hsi, 300,\n                       path + '_gt.png')\n    print('------Get classification maps successful-------')\n"
  },
  {
    "path": "SSRN/geniter.py",
    "content": "import torch\nimport numpy as np\nimport torch.utils.data as Data\n\ndef index_assignment(index, row, col, pad_length):\n    new_assign = {}\n    for counter, value in enumerate(index):\n        assign_0 = value // col + pad_length\n        assign_1 = value % col + pad_length\n        new_assign[counter] = [assign_0, assign_1]\n    return new_assign\n\ndef select_patch(matrix, pos_row, pos_col, ex_len):\n    selected_rows = matrix[range(pos_row-ex_len, pos_row+ex_len+1)]\n    selected_patch = selected_rows[:, range(pos_col-ex_len, pos_col+ex_len+1)]\n    return selected_patch\n\n\ndef select_small_cubic(data_size, data_indices, whole_data, patch_length, padded_data, dimension):\n    small_cubic_data = np.zeros((data_size, 2 * patch_length + 1, 2 * patch_length + 1, dimension))\n    data_assign = index_assignment(data_indices, whole_data.shape[0], whole_data.shape[1], patch_length)\n    for i in range(len(data_assign)):\n        small_cubic_data[i] = select_patch(padded_data, data_assign[i][0], data_assign[i][1], patch_length)\n    return small_cubic_data\n\n\ndef generate_iter(TRAIN_SIZE, train_indices, TEST_SIZE, test_indices, TOTAL_SIZE, total_indices, VAL_SIZE,\n                  whole_data, PATCH_LENGTH, padded_data, INPUT_DIMENSION, batch_size, gt):\n    gt_all = gt[total_indices] - 1\n    y_train = gt[train_indices] - 1\n    y_test = gt[test_indices] - 1\n\n    all_data =  select_small_cubic(TOTAL_SIZE, total_indices, whole_data,\n                                                      PATCH_LENGTH, padded_data, INPUT_DIMENSION)\n\n    train_data = select_small_cubic(TRAIN_SIZE, train_indices, whole_data,\n                                                        PATCH_LENGTH, padded_data, INPUT_DIMENSION)\n    print(train_data.shape)\n    test_data =  select_small_cubic(TEST_SIZE, test_indices, whole_data,\n                                                       PATCH_LENGTH, padded_data, INPUT_DIMENSION)\n    x_train = train_data.reshape(train_data.shape[0], train_data.shape[1], train_data.shape[2], INPUT_DIMENSION)\n    x_test_all = test_data.reshape(test_data.shape[0], test_data.shape[1], test_data.shape[2], INPUT_DIMENSION)\n\n    x_val = x_test_all[-VAL_SIZE:]\n    y_val = y_test[-VAL_SIZE:]\n\n    x_test = x_test_all[:-VAL_SIZE]\n    y_test = y_test[:-VAL_SIZE]\n    \n    x1_tensor_train = torch.from_numpy(x_train).type(torch.FloatTensor).unsqueeze(1)\n    y1_tensor_train = torch.from_numpy(y_train).type(torch.FloatTensor)\n    torch_dataset_train = Data.TensorDataset(x1_tensor_train, y1_tensor_train)\n\n    x1_tensor_valida = torch.from_numpy(x_val).type(torch.FloatTensor).unsqueeze(1)\n    y1_tensor_valida = torch.from_numpy(y_val).type(torch.FloatTensor)\n    torch_dataset_valida = Data.TensorDataset(x1_tensor_valida, y1_tensor_valida)\n\n    x1_tensor_test = torch.from_numpy(x_test).type(torch.FloatTensor).unsqueeze(1)\n    y1_tensor_test = torch.from_numpy(y_test).type(torch.FloatTensor)\n    torch_dataset_test = Data.TensorDataset(x1_tensor_test,y1_tensor_test)\n\n    all_data.reshape(all_data.shape[0], all_data.shape[1], all_data.shape[2], INPUT_DIMENSION)\n    all_tensor_data = torch.from_numpy(all_data).type(torch.FloatTensor).unsqueeze(1)\n    all_tensor_data_label = torch.from_numpy(gt_all).type(torch.FloatTensor)\n    torch_dataset_all = Data.TensorDataset(all_tensor_data, all_tensor_data_label)\n\n\n    train_iter = Data.DataLoader(\n        dataset=torch_dataset_train,  # torch TensorDataset format\n        batch_size=batch_size,  # mini batch size\n        shuffle=True,  \n        num_workers=0, \n    )\n    valiada_iter = Data.DataLoader(\n        dataset=torch_dataset_valida,  # torch TensorDataset format\n        batch_size=batch_size,  # mini batch size\n        shuffle=True,  \n        num_workers=0, \n    )\n    test_iter = Data.DataLoader(\n        dataset=torch_dataset_test,  # torch TensorDataset format\n        batch_size=batch_size,  # mini batch size\n        shuffle=False, \n        num_workers=0, \n    )\n    all_iter = Data.DataLoader(\n        dataset=torch_dataset_all,  # torch TensorDataset format\n        batch_size=batch_size,  # mini batch size\n        shuffle=False, \n        num_workers=0, \n    )\n    return train_iter, valiada_iter, test_iter, all_iter #, y_test\n"
  },
  {
    "path": "SSRN/record.py",
    "content": "import numpy as np\nimport torch\nfrom operator import truediv\n\ndef evaluate_accuracy(data_iter, net, loss, device):\n    acc_sum, n = 0.0, 0\n    with torch.no_grad():\n        for X, y in data_iter:\n            test_l_sum, test_num = 0, 0\n            #X = X.permute(0, 3, 1, 2)\n            X = X.to(device)\n            y = y.to(device)\n            net.eval() \n            y_hat = net(X)\n            l = loss(y_hat, y.long())\n            acc_sum += (y_hat.argmax(dim=1) == y.to(device)).float().sum().cpu().item()\n            test_l_sum += l\n            test_num += 1\n            net.train() \n            n += y.shape[0]\n    return [acc_sum / n, test_l_sum] # / test_num]\n\n\ndef aa_and_each_accuracy(confusion_matrix):\n    list_diag = np.diag(confusion_matrix)\n    list_raw_sum = np.sum(confusion_matrix, axis=1)\n    each_acc = np.nan_to_num(truediv(list_diag, list_raw_sum))\n    average_acc = np.mean(each_acc)\n    return each_acc, average_acc\n\n\n\ndef record_output(oa_ae, aa_ae, kappa_ae, element_acc_ae, training_time_ae, testing_time_ae, path):\n    f = open(path, 'a')\n    sentence0 = 'OAs for each iteration are:' + str(oa_ae) + '\\n'\n    f.write(sentence0)\n    sentence1 = 'AAs for each iteration are:' + str(aa_ae) + '\\n'\n    f.write(sentence1)\n    sentence2 = 'KAPPAs for each iteration are:' + str(kappa_ae) + '\\n' + '\\n'\n    f.write(sentence2)\n    sentence3 = 'mean_OA ± std_OA is: ' + str(np.mean(oa_ae)) + ' ± ' + str(np.std(oa_ae)) + '\\n'\n    f.write(sentence3)\n    sentence4 = 'mean_AA ± std_AA is: ' + str(np.mean(aa_ae)) + ' ± ' + str(np.std(aa_ae)) + '\\n'\n    f.write(sentence4)\n    sentence5 = 'mean_KAPPA ± std_KAPPA is: ' + str(np.mean(kappa_ae)) + ' ± ' + str(np.std(kappa_ae)) + '\\n' + '\\n'\n    f.write(sentence5)\n    sentence6 = 'Total average Training time is: ' + str(np.sum(training_time_ae)) + '\\n'\n    f.write(sentence6)\n    sentence7 = 'Total average Testing time is: ' + str(np.sum(testing_time_ae)) + '\\n' + '\\n'\n    f.write(sentence7)\n    element_mean = np.mean(element_acc_ae, axis=0)\n    element_std = np.std(element_acc_ae, axis=0)\n    sentence8 = \"Mean of all elements in confusion matrix: \" + str(element_mean) + '\\n'\n    f.write(sentence8)\n    sentence9 = \"Standard deviation of all elements in confusion matrix: \" + str(element_std) + '\\n'\n    f.write(sentence9)\n    f.close()\n"
  },
  {
    "path": "convert_report_to_csv.py",
    "content": "import pandas as pd\nimport re\nfrom glob import glob\nimport argparse\nimport os\n\n\ndef get_data(report):\n    class_wise_acc_regex = r'\\[[\\d.\\se\\-\\+(\\\\n)]*\\]'\n    oa_aa_kappa_regex = r'([-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?\\s±\\s[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?)'\n\n    result = {}\n\n    x = re.findall(oa_aa_kappa_regex, report)\n    result['oa'] = x[0][0]\n    result['aa'] = x[1][0]\n    result['kappa'] = x[2][0]\n\n    result['oa'] = \"{:.2f}\".format(\n        float(result['oa'].split(' ± ')[0]) * 100) + ' ± ' + \"{:.3f}\".format(\n            float(result['oa'].split(' ± ')[1]))\n    result['aa'] = \"{:.2f}\".format(\n        float(result['aa'].split(' ± ')[0]) * 100) + ' ± ' + \"{:.3f}\".format(\n            float(result['aa'].split(' ± ')[1]))\n    result['kappa'] = \"{:.4f}\".format(float(\n        result['kappa'].split(' ± ')[0])) + ' ± ' + \"{:.3f}\".format(\n            float(result['kappa'].split(' ± ')[1]))\n\n    x = re.findall(class_wise_acc_regex, report)\n    result['class_mean'] = x[0][1:-1].split()\n    result['class_std'] = x[1][1:-1].split()\n    result['class_wise'] = [\n        \"{:.2f}\".format(float(m) * 100) + ' ± ' + \"{:.3f}\".format(float(n))\n        for m, n in zip(result['class_mean'], result['class_std'])\n    ]\n\n    return result\n\n\ndef main(dataset, search_path, output_file):\n    all_reports = glob(search_path + '/*' + dataset + '*.txt')\n    no_of_labels = 0\n    dataframe_dict = {}\n\n    for report in all_reports:\n        print('Processing...', report)\n        column_name = os.path.basename(report)[:-4]\n        with open(report) as f:\n            report_content = f.read()\n\n        result = get_data(report_content)\n\n        dataframe_dict[column_name] = result['class_wise'] + [result['oa']] + [\n            result['aa']\n        ] + [result['kappa']]\n        no_of_labels = len(result['class_wise'])\n\n    label_list = [str(i)\n                  for i in range(1, no_of_labels + 1)] + ['oa', 'aa', 'kappa']\n    df = pd.DataFrame(dataframe_dict)\n    df = df.reindex(sorted(df.columns), axis=1)\n    df.insert(0, 'label', label_list)\n\n    print('Saving...', dataset, 'report.')\n    if output_file is not None:\n        df.to_csv(output_file, index=False)\n    else:\n        if not os.path.exists('csv_reports'):\n            os.makedirs('csv_reports')\n        df.to_csv(\n            os.path.join('csv_reports', dataset + '_report.csv'), index=False)\n\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser(\n        description='Convert Code Generated Report to CSV.')\n    parser.add_argument(\n        '-d',\n        '--dataset_name',\n        dest='dataset',\n        required=True,\n        help=\"Name of dataset to search.\")\n    parser.add_argument(\n        '-r',\n        '--root_dir',\n        dest='root_dir',\n        default='./*/report',\n        help=\"Directories to search for the report files.\")\n    parser.add_argument(\n        '-o',\n        '--output',\n        dest='output',\n        default=None,\n        help=\"Output name to save csv.\")\n    args = parser.parse_args()\n    main(args.dataset, args.root_dir, args.output)\n"
  },
  {
    "path": "environment.yml",
    "content": "name: ms2kiresnet_env\nchannels:\n  - pytorch\n  - anaconda\n  - conda-forge\n  - defaults\ndependencies:\n  - cudatoolkit=10.1.243\n  - matplotlib=3.1.3\n  - numpy=1.18.1\n  - opencv=3.4.2\n  - pip=20.0.2\n  - python=3.7.7\n  - pytorch=1.4.0\n  - scikit-learn=0.22.1\n  - scipy=1.4.1\n  - pip:\n    - pytorch-ranger==0.1.1\n    - spectral==0.20\n    - torch-optimizer==0.0.1a12\n    - torch-summary==1.2.0\n\n"
  },
  {
    "path": "setup_script.sh",
    "content": "DATASET_PATH=\"./dataset\"\nCLASS_MAP_PATH=\"classification_maps\"\nMODEL_PATH=\"models\"\nREPORT_PATH=\"report\"\n\ndeclare -a NETWORKS=(\"PyResNet\"\n                    \"SSRN\"\n                    \"A2S2KResNet\"\n                    \"ResNet\"\n                    \"ContextualNet\")\n\ndeclare -a DATAFILES=(\"Indian_pines_corrected.mat\"\n                    \"Indian_pines_gt.mat\"\n                    \"PaviaU.mat\"\n                    \"PaviaU_gt.mat\"\n                    \"KSC.mat\"\n                    \"KSC_gt.mat\"\n                    \"Salinas_corrected.mat\"\n                    \"Salinas_gt.mat\")\ndeclare -a DATAURL=(\"http://www.ehu.eus/ccwintco/uploads/6/67/Indian_pines_corrected.mat\"\n                    \"http://www.ehu.eus/ccwintco/uploads/c/c4/Indian_pines_gt.mat\"\n                    \"http://www.ehu.eus/ccwintco/uploads/e/ee/PaviaU.mat\"\n                    \"http://www.ehu.eus/ccwintco/uploads/5/50/PaviaU_gt.mat\"\n                    \"http://www.ehu.es/ccwintco/uploads/2/26/KSC.mat\"\n                    \"http://www.ehu.es/ccwintco/uploads/a/a6/KSC_gt.mat\"\n                    \"https://github.com/gokriznastic/HybridSN/raw/master/data/Salinas_corrected.mat\"\n                    \"https://github.com/gokriznastic/HybridSN/raw/master/data/Salinas_gt.mat\")\n\nif [ ! -d \"$DATASET_PATH\" ]; then\n  # Take action if $DIR exists. #\n  echo \"Creaating ${DATASET_PATH}...\"\n  mkdir \"$DATASET_PATH\"\nfi\nlength=${#DATAFILES[@]}\nfor (( i = 0; i < length; i++ )); \ndo\n    if [ -f \"$DATASET_PATH/${DATAFILES[i]}\" ]; then\n        ### Take action if $DIR exists ###\n        echo \"${DATAFILES[i]} File exists...\"\n    else\n        ###  Control will jump here if $DIR does NOT exists ###\n        echo \"${DATAFILES[i]} file doesn't exists...\"\n        wget \"${DATAURL[i]}\" -P \"$DATASET_PATH\"\n    fi\ndone\n\n\nfor net in \"${NETWORKS[@]}\"\ndo\n  if [ ! -d \"$net/$CLASS_MAP_PATH\" ]; then\n    # Take action if $DIR exists. #\n    echo \"Creaating $net/$CLASS_MAP_PATH...\"\n    mkdir \"$net/$CLASS_MAP_PATH\"\n  fi\n  if [ ! -d \"$net/$MODEL_PATH\" ]; then\n    # Take action if $DIR exists. #\n    echo \"Creaating $net/$MODEL_PATH...\"\n    mkdir \"$net/$MODEL_PATH\"\n  fi\n  if [ ! -d \"$net/$REPORT_PATH\" ]; then\n    # Take action if $DIR exists. #\n    echo \"Creaating $net/$REPORT_PATH...\"\n    mkdir \"$net/$REPORT_PATH\"\n  fi\ndone\n"
  }
]