{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"'''ResNet-18 Image classfication for cifar-10 with PyTorch \n\nAuthor 'Sun-qian'.\n\n'''\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\n\nclass ResidualBlock(nn.Module):\n    def __init__(self, inchannel, outchannel, stride=1):\n        super(ResidualBlock, self).__init__()\n        self.left = nn.Sequential(\n            nn.Conv2d(inchannel, outchannel, kernel_size=3, stride=stride, padding=1, bias=False),\n            nn.BatchNorm2d(outchannel),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(outchannel, outchannel, kernel_size=3, stride=1, padding=1, bias=False),\n            nn.BatchNorm2d(outchannel)\n        )\n        self.shortcut = nn.Sequential()\n        if stride != 1 or inchannel != outchannel:\n            self.shortcut = nn.Sequential(\n                nn.Conv2d(inchannel, outchannel, kernel_size=1, stride=stride, bias=False),\n                nn.BatchNorm2d(outchannel)\n            )\n\n    def forward(self, x):\n        out = self.left(x)\n        out += self.shortcut(x)\n        out = F.relu(out)\n        return out\n\nclass ResNet(nn.Module):\n    def __init__(self, ResidualBlock, num_classes=10):\n        super(ResNet, self).__init__()\n        self.inchannel = 64\n        self.conv1 = nn.Sequential(\n            nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False),\n            nn.BatchNorm2d(64),\n            nn.ReLU(),\n        )\n        self.layer1 = self.make_layer(ResidualBlock, 64,  2, stride=1)\n        self.layer2 = self.make_layer(ResidualBlock, 128, 2, stride=2)\n        self.layer3 = self.make_layer(ResidualBlock, 256, 2, stride=2)\n        self.layer4 = self.make_layer(ResidualBlock, 512, 2, stride=2)\n        self.fc = nn.Linear(512, num_classes)\n\n    def make_layer(self, block, channels, num_blocks, stride):\n        strides = [stride] + [1] * (num_blocks - 1)   #strides=[1,1]\n        layers = []\n        for stride in strides:\n            layers.append(block(self.inchannel, channels, stride))\n            self.inchannel = channels\n        return nn.Sequential(*layers)\n\n    def forward(self, x):\n        out = self.conv1(x)\n        out = self.layer1(out)\n        out = self.layer2(out)\n        out = self.layer3(out)\n        out = self.layer4(out)\n        out = F.avg_pool2d(out, 4)\n        out = out.view(out.size(0), -1)\n        out = self.fc(out)\n        return out\n\n\ndef ResNet18():\n\n    return ResNet(ResidualBlock)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-12-31T05:44:36.757982Z","iopub.execute_input":"2021-12-31T05:44:36.758224Z","iopub.status.idle":"2021-12-31T05:44:36.779678Z","shell.execute_reply.started":"2021-12-31T05:44:36.758194Z","shell.execute_reply":"2021-12-31T05:44:36.778701Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport torchvision\nimport torchvision.transforms as transforms\nimport argparse\n\n# 定义是否使用GPU\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n# device = torch.device('cpu')\n# 参数设置,使得我们能够手动输入命令行参数，就是让风格变得和Linux命令行差不多\n# parser = argparse.ArgumentParser(description='PyTorch CIFAR10 Training')\n# parser.add_argument('--outf', default='./', help='folder to output images and model checkpoints') #输出结果保存路径\n# parser.add_argument('--net', default='./Resnet18.pth', help=\"path to net (to continue training)\")  #恢复训练时的模型路径\n# args = parser.parse_args()\n\noutf = \"./\"\n# 超参数设置\nEPOCH = 135   #遍历数据集次数\npre_epoch = 0  # 定义已经遍历数据集的次数\nBATCH_SIZE = 128      #批处理尺寸(batch_size)\nLR = 0.1        #学习率\n\n# 准备数据集并预处理\ntransform_train = transforms.Compose([\n    transforms.RandomCrop(32, padding=4),  #先四周填充0，在吧图像随机裁剪成32*32\n    transforms.RandomHorizontalFlip(),  #图像一半的概率翻转，一半的概率不翻转\n    transforms.ToTensor(),\n    transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), #R,G,B每层的归一化用到的均值和方差\n])\n\ntransform_test = transforms.Compose([\n    transforms.ToTensor(),\n    transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)),\n])\n\ntrainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform_train) #训练数据集\ntrainloader = torch.utils.data.DataLoader(trainset, batch_size=BATCH_SIZE, shuffle=True, num_workers=2)   #生成一个个batch进行批训练，组成batch的时候顺序打乱取\n\ntestset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform_test)\ntestloader = torch.utils.data.DataLoader(testset, batch_size=100, shuffle=False, num_workers=2)\n# Cifar-10的标签\nclasses = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')\n\n# 模型定义-ResNet\nnet = ResNet18().to(device)\n\n# 定义损失函数和优化方式\ncriterion = nn.CrossEntropyLoss()  #损失函数为交叉熵，多用于多分类问题\noptimizer = optim.SGD(net.parameters(), lr=LR, momentum=0.9, weight_decay=5e-4) #优化方式为mini-batch momentum-SGD，并采用L2正则化（权重衰减）\n\n# 训练\nif __name__ == \"__main__\":\n    best_acc = 85  #2 初始化best test accuracy\n    print(\"Start Training, Resnet-18!\")  # 定义遍历数据集的次数\n    with open(\"acc.txt\", \"w\") as f:\n        with open(\"log.txt\", \"w\")as f2:\n            for epoch in range(pre_epoch, EPOCH):\n                print('\\nEpoch: %d' % (epoch + 1))\n                net.train()\n                sum_loss = 0.0\n                correct = 0.0\n                total = 0.0\n                for i, data in enumerate(trainloader, 0):\n                    # 准备数据\n                    length = len(trainloader)\n                    inputs, labels = data\n                    inputs, labels = inputs.to(device), labels.to(device)\n                    optimizer.zero_grad()\n\n                    # forward + backward\n                    outputs = net(inputs)\n                    loss = criterion(outputs, labels)\n                    loss.backward()\n                    optimizer.step()\n\n                    # 每训练1个batch打印一次loss和准确率\n                    sum_loss += loss.item()\n                    _, predicted = torch.max(outputs.data, 1)\n                    total += labels.size(0)\n                    correct += predicted.eq(labels.data).cpu().sum()\n                    print('[epoch:%d, iter:%d] Loss: %.03f | Acc: %.3f%% '\n                          % (epoch + 1, (i + 1 + epoch * length), sum_loss / (i + 1), 100. * correct / total))\n                    f2.write('%03d  %05d |Loss: %.03f | Acc: %.3f%% '\n                          % (epoch + 1, (i + 1 + epoch * length), sum_loss / (i + 1), 100. * correct / total))\n                    f2.write('\\n')\n                    f2.flush()\n\n                # 每训练完一个epoch测试一下准确率\n                print(\"Waiting Test!\")\n                with torch.no_grad():\n                    correct = 0\n                    total = 0\n                    for data in testloader:\n                        net.eval()\n                        images, labels = data\n                        images, labels = images.to(device), labels.to(device)\n                        outputs = net(images)\n                        # 取得分最高的那个类 (outputs.data的索引号)\n                        _, predicted = torch.max(outputs.data, 1)\n                        total += labels.size(0)\n                        correct += (predicted == labels).sum()\n                    print('测试分类准确率为：%.3f%%' % (100 * correct / total))\n                    acc = 100. * correct / total\n                    # 将每次测试结果实时写入acc.txt文件中\n                    print('Saving model......')\n                    torch.save(net.state_dict(), '%s/net_%03d.pth' % (outf, epoch + 1))\n                    f.write(\"EPOCH=%03d,Accuracy= %.3f%%\" % (epoch + 1, acc))\n                    f.write('\\n')\n                    f.flush()\n                    # 记录最佳测试分类准确率并写入best_acc.txt文件中\n                    if acc > best_acc:\n                        f3 = open(\"best_acc.txt\", \"w\")\n                        f3.write(\"EPOCH=%d,best_acc= %.3f%%\" % (epoch + 1, acc))\n                        f3.close()\n                        best_acc = acc\n            print(\"Training Finished, TotalEPOCH=%d\" % EPOCH)\n\n","metadata":{"execution":{"iopub.status.busy":"2021-12-31T05:44:40.072291Z","iopub.execute_input":"2021-12-31T05:44:40.072757Z"},"trusted":true},"execution_count":null,"outputs":[]}]}