├── .gitignore ├── AlexNet ├── AlexNet.py ├── main.py └── test.py ├── DenseNet ├── DenseNet.py └── main.py ├── GoogLeNet ├── GoogLeNet.py └── main.py ├── LeNet ├── LeNet.py ├── main.py └── test.py ├── MobileNet ├── main.py ├── model_v2.py └── model_v3.py ├── README.md ├── ResNet ├── ResNet.py └── main.py ├── SENet └── senet.py ├── VGGNet ├── VGGNet.py └── main.py └── functions.py /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | Datasets/ 3 | */data/log/* 4 | */data/saved_module/* 5 | */__pycache__/ 6 | __pycache__/ 7 | -------------------------------------------------------------------------------- /AlexNet/AlexNet.py: -------------------------------------------------------------------------------- 1 | import torch.nn as nn 2 | 3 | 4 | class AlexNet(nn.Module): 5 | """AlexNet""" 6 | def __init__(self, num_classes): 7 | super(AlexNet, self).__init__() 8 | self.conv1 = nn.Sequential(nn.Conv2d(3, 96, 3, 1), 9 | nn.BatchNorm2d(96), 10 | nn.ReLU(inplace=True), 11 | nn.MaxPool2d(3, 2)) 12 | self.conv2 = nn.Sequential(nn.Conv2d(96, 256, 3, 1), 13 | nn.BatchNorm2d(256), 14 | nn.ReLU(inplace=True), 15 | nn.MaxPool2d(3, 2)) 16 | self.conv3 = nn.Sequential(nn.Conv2d(256, 384, 3, 1, 1), 17 | nn.ReLU(inplace=True), 18 | nn.Conv2d(384, 384, 3, 1, 1), 19 | nn.ReLU(inplace=True), 20 | nn.Conv2d(384, 256, 3, 1, 1), 21 | nn.ReLU(inplace=True), 22 | nn.MaxPool2d(3, 2)) 23 | self.fc = nn.Sequential(nn.Flatten(), 24 | nn.Linear(256 * 2 * 2, 2048), 25 | nn.ReLU(inplace=True), 26 | nn.Dropout(0.5), 27 | nn.Linear(2048, 2048), 28 | nn.ReLU(inplace=True), 29 | nn.Dropout(0.5), 30 | nn.Linear(2048, num_classes)) 31 | 32 | # self.apply(self.init_weights) 33 | 34 | def init_weights(self, m): 35 | if isinstance(m, (nn.Linear, nn.Conv2d)): 36 | nn.init.kaiming_normal_(m.weight, 37 | a=0, 38 | mode='fan_out', 39 | nonlinearity='relu') 40 | 41 | def forward(self, img): 42 | img = self.conv1(img) 43 | img = self.conv2(img) 44 | img = self.conv3(img) 45 | img = self.fc(img) 46 | return img 47 | -------------------------------------------------------------------------------- /AlexNet/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | sys.path.append("..") 5 | from functions import Test 6 | import torch 7 | import torch.nn as nn 8 | import torch.optim as optim 9 | import torch.utils.data as Data 10 | import torchvision.datasets as datasets 11 | import torchvision.transforms as transforms 12 | from tensorboardX import SummaryWriter 13 | from AlexNet import AlexNet 14 | from tqdm import tqdm 15 | 16 | 17 | def main(): 18 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 19 | print("Using {} device.".format(device)) 20 | 21 | transform_train = transforms.Compose([ 22 | transforms.RandomHorizontalFlip(), 23 | transforms.ToTensor(), 24 | transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)) 25 | ]) 26 | 27 | transform_test = transforms.Compose([ 28 | transforms.ToTensor(), 29 | transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)) 30 | ]) 31 | 32 | # CIFAR10 33 | train_dataset = datasets.CIFAR10(root="../Datasets/CIFAR10/train", 34 | train=True, 35 | transform=transform_train, 36 | download=False) 37 | val_dataset = datasets.CIFAR10(root="../Datasets/CIFAR10/test", 38 | train=False, 39 | transform=transform_test, 40 | download=False) 41 | 42 | train_num = len(train_dataset) 43 | val_num = len(val_dataset) 44 | 45 | batch_size = 64 46 | nw = min(os.cpu_count(), batch_size if batch_size > 1 else 0) 47 | print('Using {} dataloader workers every process'.format(nw)) 48 | 49 | train_dataloader = Data.DataLoader(dataset=train_dataset, 50 | batch_size=batch_size, 51 | shuffle=True, 52 | num_workers=4) 53 | val_dataloader = Data.DataLoader(dataset=val_dataset, 54 | batch_size=batch_size, 55 | shuffle=True, 56 | num_workers=4) 57 | 58 | print("using {} images for training, {} images for validation.".format( 59 | train_num, val_num)) 60 | 61 | # 定义网络 62 | torch.manual_seed(12) 63 | model = AlexNet(10).to(device) 64 | 65 | learning_rate = 1e-3 66 | optimizer = optim.Adam(model.parameters(), lr=learning_rate) 67 | loss_func = nn.CrossEntropyLoss() 68 | 69 | train_steps = len(train_dataloader) 70 | print_step = 100 71 | epoch = 30 72 | best_acc = 0.0 73 | save_path = 'data/saved_module/AlexNet.pth' 74 | 75 | # writer = SummaryWriter(log_dir="data/log") 76 | for e in range(epoch): 77 | # Train 78 | model.train() 79 | running_loss = 0.0 80 | train_bar = tqdm(train_dataloader, file=sys.stdout) 81 | for step, (b_x, b_y) in enumerate(train_bar): 82 | if torch.cuda.is_available(): 83 | b_x = b_x.to(device) 84 | b_y = b_y.to(device) 85 | optimizer.zero_grad() 86 | output = model(b_x) 87 | loss = loss_func(output, b_y) 88 | loss.backward() 89 | optimizer.step() 90 | 91 | running_loss += loss.item() 92 | 93 | train_bar.desc = "Train epoch[{}/{}] loss:{:.3f}".format( 94 | e + 1, epoch, loss) 95 | # train_steps += 1 96 | 97 | # # 迭代输出日志 98 | # if train_steps % print_step == 0: 99 | # # 控制台输出 100 | # print("Train: {}, Loss: {}".format(train_steps, 101 | # round(loss.item(), 3))) 102 | # # 记录损失 103 | # writer.add_scalar("train loss", 104 | # scalar_value=loss.item(), 105 | # global_step=train_steps) 106 | # 107 | # # 绘制参数分布 108 | # for name, param in model.named_parameters(): 109 | # writer.add_histogram(name, 110 | # param.data.cpu().numpy(), 111 | # train_steps) 112 | 113 | # Validate 114 | model.eval() 115 | acc = 0.0 116 | with torch.no_grad(): 117 | val_bar = tqdm(val_dataloader, file=sys.stdout) 118 | for val_images, val_labels in val_bar: 119 | if torch.cuda.is_available(): 120 | val_images, val_labels = val_images.to( 121 | device), val_labels.to(device) 122 | outputs = model(val_images) 123 | # loss = loss_function(outputs, test_labels) 124 | predict_y = torch.max(outputs, dim=1)[1] 125 | acc += torch.eq(predict_y, val_labels).sum().item() 126 | 127 | val_bar.desc = "Valid epoch[{}/{}]".format(e + 1, epoch) 128 | 129 | val_accurate = acc / val_num 130 | print('[Epoch %d] train_loss: %.3f val_accuracy: %.3f' % 131 | (e + 1, running_loss / train_steps, val_accurate)) 132 | 133 | if val_accurate > best_acc: 134 | best_acc = val_accurate 135 | torch.save(model.state_dict(), save_path) 136 | 137 | print("FINISHED TRAINING, THE BEST ACCURACY IS: {}".format(best_acc)) 138 | # acc = Test(model, test_dataloader, device) 139 | # writer.add_scalar("test_acc", acc, total_test_step) 140 | # total_test_step += 1 141 | # 142 | # # 保存模型 143 | # torch.save(model.state_dict(), 144 | # "data/saved_module/resnet_{}.pkl".format(e)) 145 | 146 | 147 | if __name__ == "__main__": 148 | main() 149 | -------------------------------------------------------------------------------- /AlexNet/test.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | import torchvision.transforms as transforms 4 | from torchvision.datasets import CIFAR10 5 | import torch.utils.data as Data 6 | from Net import AlexNet 7 | 8 | test_data = CIFAR10("../Datasets/CIFAR10/test", 9 | train=False, 10 | transform=transforms.ToTensor(), 11 | download=False) 12 | 13 | test_dataloader = Data.DataLoader(dataset=test_data, 14 | batch_size=100, 15 | shuffle=True, 16 | num_workers=4) 17 | 18 | network = AlexNet(10) 19 | model = torch.load("data/save_module/alexnet_param.pkl") # 加载模型 20 | network.load_state_dict(model) # 将参数放入模型当中 21 | 22 | acc_list = [] 23 | for data in test_dataloader: 24 | imgs, targets = data 25 | output = network(imgs) # 输出预测 26 | _, pre_lab = torch.max(output, 1) # 提取预测序列 27 | acc = np.array(pre_lab == targets).sum() / 100 # 计算正确率 28 | 29 | print("accuracy: ", acc) # 输出正确率 30 | acc_list.append(acc) 31 | 32 | sum = 0 33 | for a in acc_list: 34 | sum += a 35 | 36 | acc = sum / 100 37 | print(acc) 38 | -------------------------------------------------------------------------------- /DenseNet/DenseNet.py: -------------------------------------------------------------------------------- 1 | import torch.nn as nn 2 | import torch.nn.functional as F 3 | import torch 4 | 5 | 6 | class BN_Conv2d(nn.Module): 7 | """ 8 | BN_CONV_RELU 9 | """ 10 | def __init__(self, 11 | in_channels: object, 12 | out_channels: object, 13 | kernel_size: object, 14 | stride: object, 15 | padding: object, 16 | dilation=1, 17 | groups=1, 18 | bias=False) -> object: 19 | super(BN_Conv2d, self).__init__() 20 | self.seq = nn.Sequential( 21 | nn.Conv2d(in_channels, 22 | out_channels, 23 | kernel_size=kernel_size, 24 | stride=stride, 25 | padding=padding, 26 | dilation=dilation, 27 | groups=groups, 28 | bias=bias), nn.BatchNorm2d(out_channels)) 29 | 30 | def forward(self, x): 31 | return F.relu(self.seq(x)) 32 | 33 | 34 | class DenseBlock(nn.Module): 35 | def __init__(self, input_channels, num_layers, growth_rate): 36 | super(DenseBlock, self).__init__() 37 | self.num_layers = num_layers 38 | self.k0 = input_channels 39 | self.k = growth_rate 40 | self.layers = self.__make_layers() 41 | 42 | def __make_layers(self): 43 | layer_list = [] 44 | for i in range(self.num_layers): 45 | layer_list.append( 46 | nn.Sequential( 47 | BN_Conv2d(self.k0 + i * self.k, 4 * self.k, 1, 1, 0), 48 | BN_Conv2d(4 * self.k, self.k, 3, 1, 1))) 49 | return layer_list 50 | 51 | def forward(self, x): 52 | feature = self.layers[0](x) 53 | out = torch.cat((x, feature), 1) 54 | for i in range(1, len(self.layers)): 55 | feature = self.layers[i](out) 56 | out = torch.cat((feature, out), 1) 57 | return out 58 | 59 | 60 | class DenseNet(nn.Module): 61 | def __init__(self, layers: object, k, theta, num_classes) -> object: 62 | super(DenseNet, self).__init__() 63 | # params 64 | self.layers = layers 65 | self.k = k 66 | self.theta = theta 67 | # layers 68 | self.conv = BN_Conv2d(3, 2 * k, 7, 2, 3) 69 | self.blocks, patches = self.__make_blocks(2 * k) 70 | self.fc = nn.Linear(patches, num_classes) 71 | 72 | def __make_transition(self, in_chls): 73 | out_chls = int(self.theta * in_chls) 74 | return nn.Sequential(BN_Conv2d(in_chls, out_chls, 1, 1, 0), 75 | nn.AvgPool2d(2)), out_chls 76 | 77 | def __make_blocks(self, k0): 78 | """ 79 | make block-transition structures 80 | :param k0: 81 | :return: 82 | """ 83 | layers_list = [] 84 | patches = 0 85 | for i in range(len(self.layers)): 86 | layers_list.append(DenseBlock(k0, self.layers[i], self.k)) 87 | patches = k0 + self.layers[ 88 | i] * self.k # output feature patches from Dense Block 89 | if i != len(self.layers) - 1: 90 | transition, k0 = self.__make_transition(patches) 91 | layers_list.append(transition) 92 | return nn.Sequential(*layers_list), patches 93 | 94 | def forward(self, x): 95 | out = self.conv(x) 96 | out = F.max_pool2d(out, 3, 2, 1) 97 | # print(out.shape) 98 | out = self.blocks(out) 99 | # print(out.shape) 100 | out = F.avg_pool2d(out, 7) 101 | # print(out.shape) 102 | out = out.view(out.size(0), -1) 103 | out = F.softmax(self.fc(out)) 104 | return out 105 | -------------------------------------------------------------------------------- /DenseNet/main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | sys.path.append("..") 4 | from functions import Test 5 | import torch 6 | import torch.nn as nn 7 | from torch.optim import Adam 8 | import torch.utils.data as Data 9 | import torchvision.datasets as datasets 10 | import torchvision.transforms as transforms 11 | from tensorboardX import SummaryWriter 12 | from ResNet import * 13 | 14 | 15 | def main(): 16 | transform_train = transforms.Compose([ 17 | transforms.RandomHorizontalFlip(), 18 | transforms.ToTensor(), 19 | transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)) 20 | ]) 21 | 22 | transform_test = transforms.Compose([ 23 | transforms.ToTensor(), 24 | transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)) 25 | ]) 26 | 27 | train_dataset = datasets.CIFAR10(root="../Datasets/CIFAR10/train", 28 | train=True, 29 | transform=transform_train, 30 | download=True) 31 | 32 | test_dataset = datasets.CIFAR10(root="../Datasets/CIFAR10/test", 33 | train=False, 34 | transform=transform_test, 35 | download=True) 36 | 37 | train_dataloader = Data.DataLoader(dataset=train_dataset, 38 | batch_size=128, 39 | shuffle=True, 40 | num_workers=4) 41 | 42 | test_dataloader = Data.DataLoader(dataset=test_dataset, 43 | batch_size=128, 44 | shuffle=True, 45 | num_workers=4) 46 | 47 | # 定义设备 48 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 49 | print("使用设备:", device) 50 | 51 | # 定义网络 52 | torch.manual_seed(13) 53 | model = DenseNet().to(device) 54 | writer = SummaryWriter(log_dir="data/log") 55 | optimizer = Adam(model.parameters(), lr=1e-3) 56 | loss_func = nn.CrossEntropyLoss() 57 | 58 | total_train_step = 0 59 | total_test_step = 0 60 | epoch = 80 61 | print_step = 100 62 | acc = 0.0 63 | 64 | for e in range(epoch): 65 | print("=========== EPOCH: {}/{}, ACC: {} ==========".format( 66 | e + 1, round(epoch, ), round(acc, 3))) 67 | # Train 68 | model.train() 69 | for step, (b_x, b_y) in enumerate(train_dataloader): 70 | b_x = b_x.to(device) 71 | b_y = b_y.to(device) 72 | output = model(b_x) 73 | loss = loss_func(output, b_y) 74 | optimizer.zero_grad() 75 | loss.backward() 76 | optimizer.step() 77 | total_train_step += 1 78 | 79 | # 迭代输出日志 80 | if total_train_step % print_step == 0: 81 | # 控制台输出 82 | print("Train: {}, Loss: {}".format(total_train_step, 83 | round(loss.item(), 3))) 84 | # 记录损失 85 | writer.add_scalar("train loss", 86 | scalar_value=loss.item(), 87 | global_step=total_train_step) 88 | 89 | # 绘制参数分布 90 | for name, param in model.named_parameters(): 91 | writer.add_histogram(name, 92 | param.data.cpu().numpy(), 93 | total_train_step) 94 | 95 | acc = Test(model, test_dataloader, device) 96 | writer.add_scalar("test_acc", acc, total_test_step) 97 | total_test_step += 1 98 | 99 | # 保存模型 100 | torch.save(model.state_dict(), 101 | "data/saved_module/dennet_{}.pkl".format(e)) 102 | 103 | 104 | if __name__ == "__main__": 105 | main() 106 | -------------------------------------------------------------------------------- /GoogLeNet/GoogLeNet.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | 4 | 5 | def conv(in_channels, out_channels, kernel_size, stride=1, padding=0): 6 | return nn.Sequential( 7 | nn.Conv2d(in_channels, 8 | out_channels, 9 | kernel_size=kernel_size, 10 | stride=stride, 11 | padding=padding), nn.ReLU(inplace=True)) 12 | 13 | 14 | class Inception(nn.Module): 15 | """Inception""" 16 | 17 | def __init__(self, in_channels, c1, c2, c3, c4): 18 | super(Inception, self).__init__() 19 | self.branch1 = conv(in_channels, c1, kernel_size=1) 20 | self.branch2 = nn.Sequential( 21 | conv(in_channels, c2[0], kernel_size=1), 22 | conv(c2[0], c2[1], kernel_size=3, stride=1, padding=1)) 23 | self.branch3 = nn.Sequential( 24 | conv(in_channels, c3[0], kernel_size=1), 25 | conv(c3[0], c3[1], kernel_size=5, stride=1, padding=2)) 26 | self.branch4 = nn.Sequential( 27 | nn.MaxPool2d(kernel_size=3, stride=1, padding=1), 28 | conv(in_channels, c4, kernel_size=1)) 29 | 30 | def forward(self, x): 31 | block1 = self.branch1(x) 32 | block2 = self.branch2(x) 33 | block3 = self.branch3(x) 34 | block4 = self.branch4(x) 35 | 36 | block = (block1, block2, block3, block4) 37 | 38 | return torch.cat(block, dim=1) 39 | 40 | 41 | class GoogLeNet(nn.Module): 42 | """GoogLeNet""" 43 | 44 | def __init__(self, class_nums, init_weights=False): 45 | super(GoogLeNet, self).__init__() 46 | self.block1 = nn.Sequential( 47 | conv(3, 64, kernel_size=7, stride=2, padding=3), 48 | nn.MaxPool2d(kernel_size=3, stride=2, ceil_mode=True)) 49 | 50 | self.block2 = nn.Sequential( 51 | conv(64, 64, kernel_size=1), 52 | conv(64, 192, kernel_size=3, stride=1, padding=1), 53 | nn.MaxPool2d(kernel_size=3, stride=2, ceil_mode=True)) 54 | 55 | self.block3 = nn.Sequential( 56 | Inception(192, 64, (96, 128), (16, 32), 32), 57 | Inception(256, 128, (128, 192), (32, 96), 64), 58 | nn.MaxPool2d(kernel_size=3, stride=2, ceil_mode=True)) 59 | 60 | self.block4 = nn.Sequential( 61 | Inception(480, 192, (96, 208), (16, 48), 64), 62 | Inception(512, 160, (112, 224), (24, 64), 64), 63 | Inception(512, 128, (128, 256), (24, 64), 64), 64 | Inception(512, 112, (144, 288), (32, 64), 64), 65 | Inception(528, 256, (160, 320), (32, 128), 128), 66 | nn.MaxPool2d(kernel_size=3, stride=2, ceil_mode=True)) 67 | 68 | self.block5 = nn.Sequential( 69 | Inception(832, 256, (160, 320), (32, 128), 128), 70 | Inception(832, 384, (192, 384), (48, 128), 128), 71 | nn.AdaptiveAvgPool2d((1, 1)), nn.Dropout(0.4), nn.Flatten()) 72 | 73 | self.classifier = nn.Linear(1024, class_nums) 74 | if init_weights: 75 | self._initialize_weights() 76 | 77 | def _initialize_weights(self): 78 | for m in self.modules(): 79 | if isinstance(m, nn.Conv2d): 80 | nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') 81 | if m.bias is not None: 82 | nn.init.constant_(m.bias, 0) 83 | elif isinstance(m, nn.Linear): 84 | nn.init.normal_(m.weight, 0, 0.01) 85 | nn.init.constant_(m.bias, 0) 86 | 87 | def forward(self, x): 88 | x = self.block1(x) 89 | x = self.block2(x) 90 | x = self.block3(x) 91 | x = self.block4(x) 92 | x = self.block5(x) 93 | # x = torch.flatten(x, start_dim=1) 94 | x = self.classifier(x) 95 | 96 | return x 97 | 98 | # print(LeNet()) 99 | -------------------------------------------------------------------------------- /GoogLeNet/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | sys.path.append("..") 5 | from functions import Test 6 | import torch 7 | import torch.nn as nn 8 | import torch.optim as optim 9 | import torch.utils.data as Data 10 | import torchvision.datasets as datasets 11 | import torchvision.transforms as transforms 12 | from tensorboardX import SummaryWriter 13 | from GoogLeNet import * 14 | from tqdm import tqdm 15 | 16 | 17 | def main(): 18 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 19 | print("Using {} device.".format(device)) 20 | 21 | transform_train = transforms.Compose([ 22 | transforms.RandomHorizontalFlip(), 23 | transforms.ToTensor(), 24 | transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)) 25 | ]) 26 | 27 | transform_test = transforms.Compose([ 28 | transforms.ToTensor(), 29 | transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)) 30 | ]) 31 | 32 | train_dataset = datasets.CIFAR10(root="../Datasets/CIFAR10/train", 33 | train=True, 34 | transform=transform_train, 35 | download=True) 36 | 37 | val_dataset = datasets.CIFAR10(root="../Datasets/CIFAR10/test", 38 | train=False, 39 | transform=transform_test, 40 | download=True) 41 | train_num = len(train_dataset) 42 | val_num = len(val_dataset) 43 | 44 | batch_size = 32 45 | nw = min(os.cpu_count(), batch_size if batch_size > 1 else 0) 46 | print('Using {} dataloader workers every process'.format(nw)) 47 | 48 | train_dataloader = Data.DataLoader(dataset=train_dataset, 49 | batch_size=128, 50 | shuffle=True, 51 | num_workers=4) 52 | 53 | val_dataloader = Data.DataLoader(dataset=val_dataset, 54 | batch_size=128, 55 | shuffle=True, 56 | num_workers=4) 57 | 58 | # 定义设备 59 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 60 | print("使用设备:", device) 61 | 62 | # 定义网络 63 | torch.manual_seed(13) 64 | model = GoogLeNet(10, init_weights=True).to(device) 65 | writer = SummaryWriter(log_dir="data/log") 66 | optimizer = optim.Adam(model.parameters(), lr=1e-3) 67 | loss_func = nn.CrossEntropyLoss() 68 | 69 | train_steps = len(train_dataloader) 70 | print_step = 100 71 | epoch = 30 72 | best_acc = 0.0 73 | save_path = 'data/saved_module/GoogLeNet.pth' 74 | 75 | for e in range(epoch): 76 | # Train 77 | model.train() 78 | running_loss = 0.0 79 | train_bar = tqdm(train_dataloader, file=sys.stdout) 80 | for step, (b_x, b_y) in enumerate(train_bar): 81 | if torch.cuda.is_available(): 82 | b_x = b_x.to(device) 83 | b_y = b_y.to(device) 84 | optimizer.zero_grad() 85 | output = model(b_x) 86 | loss = loss_func(output, b_y) 87 | loss.backward() 88 | optimizer.step() 89 | 90 | running_loss += loss.item() 91 | 92 | train_bar.desc = "Train epoch[{}/{}] loss:{:.3f}".format( 93 | e + 1, epoch, loss) 94 | # train_steps += 1 95 | 96 | # # 迭代输出日志 97 | # if train_steps % print_step == 0: 98 | # # 控制台输出 99 | # print("Train: {}, Loss: {}".format(train_steps, 100 | # round(loss.item(), 3))) 101 | # # 记录损失 102 | # writer.add_scalar("train loss", 103 | # scalar_value=loss.item(), 104 | # global_step=train_steps) 105 | # 106 | # # 绘制参数分布 107 | # for name, param in model.named_parameters(): 108 | # writer.add_histogram(name, 109 | # param.data.cpu().numpy(), 110 | # train_steps) 111 | 112 | # Validate 113 | model.eval() 114 | acc = 0.0 115 | with torch.no_grad(): 116 | val_bar = tqdm(val_dataloader, file=sys.stdout) 117 | for val_images, val_labels in val_bar: 118 | if torch.cuda.is_available(): 119 | val_images, val_labels = val_images.to( 120 | device), val_labels.to(device) 121 | outputs = model(val_images) 122 | # loss = loss_function(outputs, test_labels) 123 | predict_y = torch.max(outputs, dim=1)[1] 124 | acc += torch.eq(predict_y, val_labels).sum().item() 125 | 126 | val_bar.desc = "Valid epoch[{}/{}]".format(e + 1, epoch) 127 | 128 | val_accurate = acc / val_num 129 | print('[Epoch %d] train_loss: %.3f val_accuracy: %.3f' % 130 | (e + 1, running_loss / train_steps, val_accurate)) 131 | 132 | if val_accurate > best_acc: 133 | best_acc = val_accurate 134 | torch.save(model.state_dict(), save_path) 135 | 136 | print("FINISHED TRAINING, THE BEST ACCURACY IS: {}".format(best_acc)) 137 | # acc = Test(model, test_dataloader, device) 138 | # writer.add_scalar("test_acc", acc, total_test_step) 139 | # total_test_step += 1 140 | # 141 | # # 保存模型 142 | # torch.save(model.state_dict(), 143 | # "data/saved_module/resnet_{}.pkl".format(e)) 144 | 145 | 146 | if __name__ == "__main__": 147 | main() 148 | -------------------------------------------------------------------------------- /LeNet/LeNet.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | 4 | 5 | class LeNet(nn.Module): 6 | """LeNet""" 7 | def __init__(self): 8 | super(LeNet, self).__init__() 9 | self.conv1 = nn.Sequential( 10 | nn.Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2)), 11 | nn.Sigmoid(), 12 | nn.MaxPool2d(kernel_size=2, 13 | stride=2, 14 | padding=0, 15 | dilation=1, 16 | ceil_mode=False)) 17 | self.conv2 = nn.Sequential( 18 | nn.Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1)), nn.Sigmoid(), 19 | nn.MaxPool2d(kernel_size=2, 20 | stride=2, 21 | padding=0, 22 | dilation=1, 23 | ceil_mode=False)) 24 | self.fc = nn.Sequential(nn.Flatten(), nn.Linear(16 * 5 * 5, 120), 25 | nn.Sigmoid(), nn.Linear(120, 84), nn.Sigmoid(), 26 | nn.Linear(84, 10)) 27 | 28 | # self.apply(self.init_weights) 29 | 30 | def init_weights(self, m): 31 | if isinstance(m, (nn.Linear, nn.Conv2d)): 32 | nn.init.xavier_uniform_(m.weight) 33 | 34 | def forward(self, x): 35 | x = self.conv1(x) 36 | x = self.conv2(x) 37 | x = self.fc(x) 38 | return x 39 | 40 | 41 | # print(LeNet()) 42 | -------------------------------------------------------------------------------- /LeNet/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | sys.path.append("..") 5 | import torch 6 | import torch.nn as nn 7 | import torch.optim as optim 8 | import torch.utils.data as Data 9 | import torchvision.datasets as datasets 10 | import torchvision.transforms as transforms 11 | from tensorboardX import SummaryWriter 12 | from tqdm import tqdm 13 | 14 | from LeNet import LeNet 15 | 16 | 17 | def main(): 18 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 19 | print("Using {} device.".format(device)) 20 | 21 | transform_train = transforms.Compose([ 22 | transforms.ToTensor(), 23 | ]) 24 | 25 | transform_test = transforms.Compose([ 26 | transforms.ToTensor(), 27 | ]) 28 | 29 | train_dataset = datasets.MNIST(root="../Datasets/MNIST/train", 30 | train=True, 31 | transform=transform_train, 32 | download=True) 33 | 34 | val_dataset = datasets.MNIST(root="../Datasets/MNIST/test", 35 | train=False, 36 | transform=transform_test, 37 | download=True) 38 | 39 | train_num = len(train_dataset) 40 | val_num = len(val_dataset) 41 | 42 | batch_size = 128 43 | nw = min(os.cpu_count(), batch_size if batch_size > 1 else 0) 44 | print('Using {} dataloader workers every process'.format(nw)) 45 | 46 | train_dataloader = Data.DataLoader(dataset=train_dataset, 47 | batch_size=batch_size, 48 | shuffle=True, 49 | num_workers=4) 50 | 51 | val_dataloader = Data.DataLoader(dataset=val_dataset, 52 | batch_size=128, 53 | shuffle=True, 54 | num_workers=4) 55 | print("using {} images for training, {} images for validation.".format( 56 | train_num, val_num)) 57 | 58 | 59 | # 定义网络 60 | torch.manual_seed(13) 61 | model = LeNet().to(device) 62 | optimizer = optim.Adam(model.parameters(), lr=1e-3) 63 | loss_func = nn.CrossEntropyLoss() 64 | 65 | train_steps = len(train_dataloader) 66 | print_step = 100 67 | epoch = 30 68 | best_acc = 0.0 69 | save_path = 'data/saved_module/LeNet.pth' 70 | 71 | # writer = SummaryWriter(log_dir="data/log") 72 | for e in range(epoch): 73 | # Train 74 | model.train() 75 | running_loss = 0.0 76 | train_bar = tqdm(train_dataloader, file=sys.stdout) 77 | for step, (b_x, b_y) in enumerate(train_bar): 78 | if torch.cuda.is_available(): 79 | b_x = b_x.to(device) 80 | b_y = b_y.to(device) 81 | optimizer.zero_grad() 82 | output = model(b_x) 83 | loss = loss_func(output, b_y) 84 | loss.backward() 85 | optimizer.step() 86 | 87 | running_loss += loss.item() 88 | 89 | train_bar.desc = "Train epoch[{}/{}] loss:{:.3f}".format( 90 | e + 1, epoch, loss) 91 | # train_steps += 1 92 | 93 | # # 迭代输出日志 94 | # if train_steps % print_step == 0: 95 | # # 控制台输出 96 | # print("Train: {}, Loss: {}".format(train_steps, 97 | # round(loss.item(), 3))) 98 | # # 记录损失 99 | # writer.add_scalar("train loss", 100 | # scalar_value=loss.item(), 101 | # global_step=train_steps) 102 | # 103 | # # 绘制参数分布 104 | # for name, param in model.named_parameters(): 105 | # writer.add_histogram(name, 106 | # param.data.cpu().numpy(), 107 | # train_steps) 108 | 109 | # Validate 110 | model.eval() 111 | acc = 0.0 112 | with torch.no_grad(): 113 | val_bar = tqdm(val_dataloader, file=sys.stdout) 114 | for val_images, val_labels in val_bar: 115 | if torch.cuda.is_available(): 116 | val_images, val_labels = val_images.to( 117 | device), val_labels.to(device) 118 | outputs = model(val_images) 119 | # loss = loss_function(outputs, test_labels) 120 | predict_y = torch.max(outputs, dim=1)[1] 121 | acc += torch.eq(predict_y, val_labels).sum().item() 122 | 123 | val_bar.desc = "Valid epoch[{}/{}]".format(e + 1, epoch) 124 | 125 | val_accurate = acc / val_num 126 | print('[Epoch %d] train_loss: %.3f val_accuracy: %.3f' % 127 | (e + 1, running_loss / train_steps, val_accurate)) 128 | 129 | if val_accurate > best_acc: 130 | best_acc = val_accurate 131 | torch.save(model.state_dict(), save_path) 132 | 133 | print("FINISHED TRAINING, THE BEST ACCURACY IS: {}".format(best_acc)) 134 | # acc = Test(model, test_dataloader, device) 135 | # writer.add_scalar("test_acc", acc, total_test_step) 136 | # total_test_step += 1 137 | # 138 | # # 保存模型 139 | # torch.save(model.state_dict(), 140 | # "data/saved_module/resnet_{}.pkl".format(e)) 141 | 142 | 143 | if __name__ == "__main__": 144 | main() 145 | -------------------------------------------------------------------------------- /LeNet/test.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | import torchvision.datasets as datasets 4 | import torchvision.transforms as transforms 5 | import torch.utils.data as Data 6 | from Net import LeNet 7 | 8 | test_dataset = datasets.MNIST(root="../Datasets/MNIST/test", 9 | train=False, 10 | transform=transforms.ToTensor(), 11 | download=True) 12 | 13 | test_dataloader = Data.DataLoader(dataset=test_dataset, 14 | batch_size=100, 15 | shuffle=True, 16 | num_workers=1) 17 | 18 | network = LeNet() 19 | param = torch.load("data/saved_module/lenet_param_22.pkl") # 加载模型 20 | network.load_state_dict(param) # 将参数放入模型当中 21 | acc = [] 22 | for data in test_dataloader: 23 | imgs, targets = data 24 | output = network(imgs) # 输出预测 25 | _, pre_lab = torch.max(output, 1) # 提取预测序列 26 | batch_acc = np.array(pre_lab == targets).sum() / test_dataloader.batch_size 27 | acc.append(batch_acc) 28 | 29 | acc = sum(acc) / len(acc) 30 | print("accuracy: ", acc) # 输出正确率 31 | -------------------------------------------------------------------------------- /MobileNet/main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | 4 | sys.path.append("..") 5 | import torch 6 | import torch.nn as nn 7 | from torch.optim import Adam 8 | import torch.utils.data as Data 9 | import torchvision.datasets as datasets 10 | import torchvision.transforms as transforms 11 | from tqdm import tqdm 12 | from tensorboardX import SummaryWriter 13 | from model_v2 import MobileNetV2 14 | 15 | 16 | def main(): 17 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 18 | print("Using {} device.".format(device)) 19 | 20 | transform_train = transforms.Compose([ 21 | transforms.RandomHorizontalFlip(), 22 | transforms.ToTensor(), 23 | transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)) 24 | ]) 25 | 26 | transform_test = transforms.Compose([ 27 | transforms.ToTensor(), 28 | transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)) 29 | ]) 30 | 31 | train_dataset = datasets.CIFAR10(root="../Datasets/CIFAR10/train", 32 | train=True, 33 | transform=transform_train, 34 | download=True) 35 | 36 | val_dataset = datasets.CIFAR10(root="../Datasets/CIFAR10/test", 37 | train=False, 38 | transform=transform_test, 39 | download=True) 40 | 41 | train_num = len(train_dataset) 42 | val_num = len(val_dataset) 43 | 44 | batch_size = 32 45 | nw = min(os.cpu_count(), batch_size if batch_size > 1 else 0) 46 | print('Using {} dataloader workers every process'.format(nw)) 47 | 48 | train_dataloader = Data.DataLoader(dataset=train_dataset, 49 | batch_size=batch_size, 50 | shuffle=True, 51 | num_workers=nw) 52 | 53 | val_dataloader = Data.DataLoader(dataset=val_dataset, 54 | batch_size=batch_size, 55 | shuffle=False, 56 | num_workers=nw) 57 | 58 | print("using {} images for training, {} images for validation.".format( 59 | train_num, val_num)) 60 | 61 | # 定义网络 62 | # torch.manual_seed(13) 63 | model = MobileNetV2(num_classes=10, alpha=0.75).to(device) 64 | writer = SummaryWriter(log_dir="data/log") 65 | optimizer = Adam(model.parameters(), lr=1e-3) 66 | loss_func = nn.CrossEntropyLoss() 67 | 68 | train_steps = len(train_dataloader) 69 | print_step = 100 70 | epoch = 30 71 | best_acc = 0.0 72 | save_path = 'data/saved_module/MobileNetV2.pth' 73 | 74 | for e in range(epoch): 75 | # Train 76 | model.train() 77 | running_loss = 0.0 78 | train_bar = tqdm(train_dataloader, file=sys.stdout) 79 | for step, (b_x, b_y) in enumerate(train_bar): 80 | if torch.cuda.is_available(): 81 | b_x = b_x.to(device) 82 | b_y = b_y.to(device) 83 | optimizer.zero_grad() 84 | output = model(b_x) 85 | loss = loss_func(output, b_y) 86 | loss.backward() 87 | optimizer.step() 88 | 89 | running_loss += loss.item() 90 | 91 | train_bar.desc = "Train epoch[{}/{}] loss:{:.3f}".format( 92 | e + 1, epoch, loss) 93 | # train_steps += 1 94 | 95 | # # 迭代输出日志 96 | # if train_steps % print_step == 0: 97 | # # 控制台输出 98 | # print("Train: {}, Loss: {}".format(train_steps, 99 | # round(loss.item(), 3))) 100 | # # 记录损失 101 | # writer.add_scalar("train loss", 102 | # scalar_value=loss.item(), 103 | # global_step=train_steps) 104 | # 105 | # # 绘制参数分布 106 | # for name, param in model.named_parameters(): 107 | # writer.add_histogram(name, 108 | # param.data.cpu().numpy(), 109 | # train_steps) 110 | 111 | # Validate 112 | model.eval() 113 | acc = 0.0 114 | with torch.no_grad(): 115 | val_bar = tqdm(val_dataloader, file=sys.stdout) 116 | for val_images, val_labels in val_bar: 117 | if torch.cuda.is_available(): 118 | val_images, val_labels = val_images.to( 119 | device), val_labels.to(device) 120 | outputs = model(val_images) 121 | # loss = loss_function(outputs, test_labels) 122 | predict_y = torch.max(outputs, dim=1)[1] 123 | acc += torch.eq(predict_y, val_labels).sum().item() 124 | 125 | val_bar.desc = "Valid epoch[{}/{}]".format(e + 1, epoch) 126 | 127 | val_accurate = acc / val_num 128 | print('[Epoch %d] train_loss: %.3f val_accuracy: %.3f' % 129 | (e + 1, running_loss / train_steps, val_accurate)) 130 | 131 | if val_accurate > best_acc: 132 | best_acc = val_accurate 133 | torch.save(model.state_dict(), save_path) 134 | 135 | print("FINISHED TRAINING, THE BEST ACCURACY IS: {}".format(best_acc)) 136 | # acc = Test(model, test_dataloader, device) 137 | # writer.add_scalar("test_acc", acc, total_test_step) 138 | # total_test_step += 1 139 | # 140 | # # 保存模型 141 | # torch.save(model.state_dict(), 142 | # "data/saved_module/resnet_{}.pkl".format(e)) 143 | 144 | 145 | if __name__ == "__main__": 146 | main() 147 | -------------------------------------------------------------------------------- /MobileNet/model_v2.py: -------------------------------------------------------------------------------- 1 | from torch import nn 2 | import torch 3 | 4 | 5 | def _make_divisible(ch, divisor=8, min_ch=None): 6 | """ 7 | This function is taken from the original tf repo. 8 | It ensures that all layers have a channel number that is divisible by 8 9 | It can be seen here: 10 | https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet/mobilenet.py 11 | """ 12 | if min_ch is None: 13 | min_ch = divisor 14 | new_ch = max(min_ch, int(ch + divisor / 2) // divisor * divisor) 15 | # Make sure that round down does not go down by more than 10%. 16 | if new_ch < 0.9 * ch: 17 | new_ch += divisor 18 | return new_ch 19 | 20 | 21 | class ConvBNReLU(nn.Sequential): 22 | def __init__(self, in_channel, out_channel, kernel_size=3, stride=1, groups=1): 23 | padding = (kernel_size - 1) // 2 24 | super(ConvBNReLU, self).__init__( 25 | nn.Conv2d(in_channel, out_channel, kernel_size, stride, padding, groups=groups, bias=False), 26 | nn.BatchNorm2d(out_channel), 27 | nn.ReLU6(inplace=True) 28 | ) 29 | 30 | 31 | class InvertedResidual(nn.Module): 32 | def __init__(self, in_channel, out_channel, stride, expand_ratio): 33 | super(InvertedResidual, self).__init__() 34 | hidden_channel = in_channel * expand_ratio 35 | self.use_shortcut = (stride == 1 and in_channel == out_channel) 36 | 37 | layers = [] 38 | if expand_ratio != 1: 39 | # 1x1 pointwise conv 40 | layers.append(ConvBNReLU(in_channel, hidden_channel, kernel_size=1)) 41 | layers.extend([ 42 | # 3x3 depthwise conv 43 | ConvBNReLU(hidden_channel, hidden_channel, stride=stride, groups=hidden_channel), 44 | # 1x1 pointwise conv(linear) 45 | nn.Conv2d(hidden_channel, out_channel, kernel_size=1, bias=False), 46 | nn.BatchNorm2d(out_channel), 47 | ]) 48 | 49 | self.conv = nn.Sequential(*layers) 50 | 51 | def forward(self, x): 52 | if self.use_shortcut: 53 | return x + self.conv(x) 54 | else: 55 | return self.conv(x) 56 | 57 | 58 | class MobileNetV2(nn.Module): 59 | def __init__(self, num_classes=1000, alpha=1.0, round_nearest=8): 60 | super(MobileNetV2, self).__init__() 61 | block = InvertedResidual 62 | input_channel = _make_divisible(32 * alpha, round_nearest) 63 | last_channel = _make_divisible(1280 * alpha, round_nearest) 64 | 65 | inverted_residual_setting = [ 66 | # t, c, n, s 67 | [1, 16, 1, 1], 68 | [6, 24, 2, 2], 69 | [6, 32, 3, 2], 70 | [6, 64, 4, 2], 71 | [6, 96, 3, 1], 72 | [6, 160, 3, 2], 73 | [6, 320, 1, 1], 74 | ] 75 | 76 | features = [] 77 | # conv1 layer 78 | features.append(ConvBNReLU(3, input_channel, stride=2)) 79 | # building inverted residual residual blockes 80 | for t, c, n, s in inverted_residual_setting: 81 | output_channel = _make_divisible(c * alpha, round_nearest) 82 | for i in range(n): 83 | stride = s if i == 0 else 1 # 每个组第一轮的stride为设定的值,其余为一 84 | features.append(block(input_channel, output_channel, stride, expand_ratio=t)) 85 | input_channel = output_channel 86 | # building last several layers 87 | features.append(ConvBNReLU(input_channel, last_channel, 1)) 88 | # combine feature layers 89 | self.features = nn.Sequential(*features) 90 | 91 | # building classifier 92 | self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) 93 | self.classifier = nn.Sequential( 94 | nn.Dropout(0.2), 95 | nn.Linear(last_channel, num_classes) 96 | ) 97 | 98 | # weight initialization 99 | for m in self.modules(): 100 | if isinstance(m, nn.Conv2d): 101 | nn.init.kaiming_normal_(m.weight, mode='fan_out') 102 | if m.bias is not None: 103 | nn.init.zeros_(m.bias) 104 | elif isinstance(m, nn.BatchNorm2d): 105 | nn.init.ones_(m.weight) 106 | nn.init.zeros_(m.bias) 107 | elif isinstance(m, nn.Linear): 108 | nn.init.normal_(m.weight, 0, 0.01) 109 | nn.init.zeros_(m.bias) 110 | 111 | def forward(self, x): 112 | x = self.features(x) 113 | x = self.avgpool(x) 114 | x = torch.flatten(x, 1) 115 | x = self.classifier(x) 116 | return x 117 | -------------------------------------------------------------------------------- /MobileNet/model_v3.py: -------------------------------------------------------------------------------- 1 | from typing import Callable, List, Optional 2 | 3 | import torch 4 | from torch import nn, Tensor 5 | from torch.nn import functional as F 6 | from functools import partial 7 | 8 | 9 | def _make_divisible(ch, divisor=8, min_ch=None): 10 | """ 11 | This function is taken from the original tf repo. 12 | It ensures that all layers have a channel number that is divisible by 8 13 | It can be seen here: 14 | https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet/mobilenet.py 15 | """ 16 | if min_ch is None: 17 | min_ch = divisor 18 | new_ch = max(min_ch, int(ch + divisor / 2) // divisor * divisor) 19 | # Make sure that round down does not go down by more than 10%. 20 | if new_ch < 0.9 * ch: 21 | new_ch += divisor 22 | return new_ch 23 | 24 | 25 | class ConvBNActivation(nn.Sequential): 26 | def __init__(self, 27 | in_planes: int, 28 | out_planes: int, 29 | kernel_size: int = 3, 30 | stride: int = 1, 31 | groups: int = 1, 32 | norm_layer: Optional[Callable[..., nn.Module]] = None, 33 | activation_layer: Optional[Callable[..., nn.Module]] = None): 34 | padding = (kernel_size - 1) // 2 35 | if norm_layer is None: 36 | norm_layer = nn.BatchNorm2d 37 | if activation_layer is None: 38 | activation_layer = nn.ReLU6 39 | super(ConvBNActivation, self).__init__(nn.Conv2d(in_channels=in_planes, 40 | out_channels=out_planes, 41 | kernel_size=kernel_size, 42 | stride=stride, 43 | padding=padding, 44 | groups=groups, 45 | bias=False), 46 | norm_layer(out_planes), 47 | activation_layer(inplace=True)) 48 | 49 | 50 | class SqueezeExcitation(nn.Module): 51 | def __init__(self, input_c: int, squeeze_factor: int = 4): 52 | super(SqueezeExcitation, self).__init__() 53 | squeeze_c = _make_divisible(input_c // squeeze_factor, 8) 54 | self.fc1 = nn.Conv2d(input_c, squeeze_c, 1) 55 | self.fc2 = nn.Conv2d(squeeze_c, input_c, 1) 56 | 57 | def forward(self, x: Tensor) -> Tensor: 58 | scale = F.adaptive_avg_pool2d(x, output_size=(1, 1)) 59 | scale = self.fc1(scale) 60 | scale = F.relu(scale, inplace=True) 61 | scale = self.fc2(scale) 62 | scale = F.hardsigmoid(scale, inplace=True) 63 | return scale * x 64 | 65 | 66 | class InvertedResidualConfig: 67 | def __init__(self, 68 | input_c: int, 69 | kernel: int, 70 | expanded_c: int, 71 | out_c: int, 72 | use_se: bool, 73 | activation: str, 74 | stride: int, 75 | width_multi: float): 76 | self.input_c = self.adjust_channels(input_c, width_multi) 77 | self.kernel = kernel 78 | self.expanded_c = self.adjust_channels(expanded_c, width_multi) 79 | self.out_c = self.adjust_channels(out_c, width_multi) 80 | self.use_se = use_se 81 | self.use_hs = activation == "HS" # whether using h-swish activation 82 | self.stride = stride 83 | 84 | @staticmethod 85 | def adjust_channels(channels: int, width_multi: float): 86 | return _make_divisible(channels * width_multi, 8) 87 | 88 | 89 | class InvertedResidual(nn.Module): 90 | def __init__(self, 91 | cnf: InvertedResidualConfig, 92 | norm_layer: Callable[..., nn.Module]): 93 | super(InvertedResidual, self).__init__() 94 | 95 | if cnf.stride not in [1, 2]: 96 | raise ValueError("illegal stride value.") 97 | 98 | self.use_res_connect = (cnf.stride == 1 and cnf.input_c == cnf.out_c) 99 | 100 | layers: List[nn.Module] = [] 101 | activation_layer = nn.Hardswish if cnf.use_hs else nn.ReLU 102 | 103 | # expand 104 | if cnf.expanded_c != cnf.input_c: 105 | layers.append(ConvBNActivation(cnf.input_c, 106 | cnf.expanded_c, 107 | kernel_size=1, 108 | norm_layer=norm_layer, 109 | activation_layer=activation_layer)) 110 | 111 | # depthwise 112 | layers.append(ConvBNActivation(cnf.expanded_c, 113 | cnf.expanded_c, 114 | kernel_size=cnf.kernel, 115 | stride=cnf.stride, 116 | groups=cnf.expanded_c, 117 | norm_layer=norm_layer, 118 | activation_layer=activation_layer)) 119 | 120 | if cnf.use_se: 121 | layers.append(SqueezeExcitation(cnf.expanded_c)) 122 | 123 | # project 124 | layers.append(ConvBNActivation(cnf.expanded_c, 125 | cnf.out_c, 126 | kernel_size=1, 127 | norm_layer=norm_layer, 128 | activation_layer=nn.Identity)) 129 | 130 | self.block = nn.Sequential(*layers) 131 | self.out_channels = cnf.out_c 132 | self.is_strided = cnf.stride > 1 133 | 134 | def forward(self, x: Tensor) -> Tensor: 135 | result = self.block(x) 136 | if self.use_res_connect: 137 | result += x 138 | 139 | return result 140 | 141 | 142 | class MobileNetV3(nn.Module): 143 | def __init__(self, 144 | inverted_residual_setting: List[InvertedResidualConfig], 145 | last_channel: int, 146 | num_classes: int = 1000, 147 | block: Optional[Callable[..., nn.Module]] = None, 148 | norm_layer: Optional[Callable[..., nn.Module]] = None): 149 | super(MobileNetV3, self).__init__() 150 | 151 | if not inverted_residual_setting: 152 | raise ValueError("The inverted_residual_setting should not be empty.") 153 | elif not (isinstance(inverted_residual_setting, List) and 154 | all([isinstance(s, InvertedResidualConfig) for s in inverted_residual_setting])): 155 | raise TypeError("The inverted_residual_setting should be List[InvertedResidualConfig]") 156 | 157 | if block is None: 158 | block = InvertedResidual 159 | 160 | if norm_layer is None: 161 | norm_layer = partial(nn.BatchNorm2d, eps=0.001, momentum=0.01) 162 | 163 | layers: List[nn.Module] = [] 164 | 165 | # building first layer 166 | firstconv_output_c = inverted_residual_setting[0].input_c 167 | layers.append(ConvBNActivation(3, 168 | firstconv_output_c, 169 | kernel_size=3, 170 | stride=2, 171 | norm_layer=norm_layer, 172 | activation_layer=nn.Hardswish)) 173 | # building inverted residual blocks 174 | for cnf in inverted_residual_setting: 175 | layers.append(block(cnf, norm_layer)) 176 | 177 | # building last several layers 178 | lastconv_input_c = inverted_residual_setting[-1].out_c 179 | lastconv_output_c = 6 * lastconv_input_c 180 | layers.append(ConvBNActivation(lastconv_input_c, 181 | lastconv_output_c, 182 | kernel_size=1, 183 | norm_layer=norm_layer, 184 | activation_layer=nn.Hardswish)) 185 | self.features = nn.Sequential(*layers) 186 | self.avgpool = nn.AdaptiveAvgPool2d(1) 187 | self.classifier = nn.Sequential(nn.Linear(lastconv_output_c, last_channel), 188 | nn.Hardswish(inplace=True), 189 | nn.Dropout(p=0.2, inplace=True), 190 | nn.Linear(last_channel, num_classes)) 191 | 192 | # initial weights 193 | for m in self.modules(): 194 | if isinstance(m, nn.Conv2d): 195 | nn.init.kaiming_normal_(m.weight, mode="fan_out") 196 | if m.bias is not None: 197 | nn.init.zeros_(m.bias) 198 | elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)): 199 | nn.init.ones_(m.weight) 200 | nn.init.zeros_(m.bias) 201 | elif isinstance(m, nn.Linear): 202 | nn.init.normal_(m.weight, 0, 0.01) 203 | nn.init.zeros_(m.bias) 204 | 205 | def _forward_impl(self, x: Tensor) -> Tensor: 206 | x = self.features(x) 207 | x = self.avgpool(x) 208 | x = torch.flatten(x, 1) 209 | x = self.classifier(x) 210 | 211 | return x 212 | 213 | def forward(self, x: Tensor) -> Tensor: 214 | return self._forward_impl(x) 215 | 216 | 217 | def mobilenet_v3_large(num_classes: int = 1000, 218 | reduced_tail: bool = False) -> MobileNetV3: 219 | """ 220 | Constructs a large MobileNetV3 architecture from 221 | "Searching for MobileNetV3" . 222 | 223 | weights_link: 224 | https://download.pytorch.org/models/mobilenet_v3_large-8738ca79.pth 225 | 226 | Args: 227 | num_classes (int): number of classes 228 | reduced_tail (bool): If True, reduces the channel counts of all feature layers 229 | between C4 and C5 by 2. It is used to reduce the channel redundancy in the 230 | backbone for Detection and Segmentation. 231 | """ 232 | width_multi = 1.0 233 | bneck_conf = partial(InvertedResidualConfig, width_multi=width_multi) 234 | adjust_channels = partial(InvertedResidualConfig.adjust_channels, width_multi=width_multi) 235 | 236 | reduce_divider = 2 if reduced_tail else 1 237 | 238 | inverted_residual_setting = [ 239 | # input_c, kernel, expanded_c, out_c, use_se, activation, stride 240 | bneck_conf(16, 3, 16, 16, False, "RE", 1), 241 | bneck_conf(16, 3, 64, 24, False, "RE", 2), # C1 242 | bneck_conf(24, 3, 72, 24, False, "RE", 1), 243 | bneck_conf(24, 5, 72, 40, True, "RE", 2), # C2 244 | bneck_conf(40, 5, 120, 40, True, "RE", 1), 245 | bneck_conf(40, 5, 120, 40, True, "RE", 1), 246 | bneck_conf(40, 3, 240, 80, False, "HS", 2), # C3 247 | bneck_conf(80, 3, 200, 80, False, "HS", 1), 248 | bneck_conf(80, 3, 184, 80, False, "HS", 1), 249 | bneck_conf(80, 3, 184, 80, False, "HS", 1), 250 | bneck_conf(80, 3, 480, 112, True, "HS", 1), 251 | bneck_conf(112, 3, 672, 112, True, "HS", 1), 252 | bneck_conf(112, 5, 672, 160 // reduce_divider, True, "HS", 2), # C4 253 | bneck_conf(160 // reduce_divider, 5, 960 // reduce_divider, 160 // reduce_divider, True, "HS", 1), 254 | bneck_conf(160 // reduce_divider, 5, 960 // reduce_divider, 160 // reduce_divider, True, "HS", 1), 255 | ] 256 | last_channel = adjust_channels(1280 // reduce_divider) # C5 257 | 258 | return MobileNetV3(inverted_residual_setting=inverted_residual_setting, 259 | last_channel=last_channel, 260 | num_classes=num_classes) 261 | 262 | 263 | def mobilenet_v3_small(num_classes: int = 1000, 264 | reduced_tail: bool = False) -> MobileNetV3: 265 | """ 266 | Constructs a large MobileNetV3 architecture from 267 | "Searching for MobileNetV3" . 268 | 269 | weights_link: 270 | https://download.pytorch.org/models/mobilenet_v3_small-047dcff4.pth 271 | 272 | Args: 273 | num_classes (int): number of classes 274 | reduced_tail (bool): If True, reduces the channel counts of all feature layers 275 | between C4 and C5 by 2. It is used to reduce the channel redundancy in the 276 | backbone for Detection and Segmentation. 277 | """ 278 | width_multi = 1.0 279 | bneck_conf = partial(InvertedResidualConfig, width_multi=width_multi) 280 | adjust_channels = partial(InvertedResidualConfig.adjust_channels, width_multi=width_multi) 281 | 282 | reduce_divider = 2 if reduced_tail else 1 283 | 284 | inverted_residual_setting = [ 285 | # input_c, kernel, expanded_c, out_c, use_se, activation, stride 286 | bneck_conf(16, 3, 16, 16, True, "RE", 2), # C1 287 | bneck_conf(16, 3, 72, 24, False, "RE", 2), # C2 288 | bneck_conf(24, 3, 88, 24, False, "RE", 1), 289 | bneck_conf(24, 5, 96, 40, True, "HS", 2), # C3 290 | bneck_conf(40, 5, 240, 40, True, "HS", 1), 291 | bneck_conf(40, 5, 240, 40, True, "HS", 1), 292 | bneck_conf(40, 5, 120, 48, True, "HS", 1), 293 | bneck_conf(48, 5, 144, 48, True, "HS", 1), 294 | bneck_conf(48, 5, 288, 96 // reduce_divider, True, "HS", 2), # C4 295 | bneck_conf(96 // reduce_divider, 5, 576 // reduce_divider, 96 // reduce_divider, True, "HS", 1), 296 | bneck_conf(96 // reduce_divider, 5, 576 // reduce_divider, 96 // reduce_divider, True, "HS", 1) 297 | ] 298 | last_channel = adjust_channels(1024 // reduce_divider) # C5 299 | 300 | return MobileNetV3(inverted_residual_setting=inverted_residual_setting, 301 | last_channel=last_channel, 302 | num_classes=num_classes) 303 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### ClassicNet 2 | 3 | 经典深度学习网络复现。 4 | 5 | ### Models 6 | 7 | 为了方便,除LeNet以外,其他网络均使用CIAIR10数据集。 8 | 9 | 目前已经复现的网络: 10 | 11 | - [x] LeNet 12 | - [x] AlexNet 13 | - [x] VGG 14 | - [x] GoogLeNet 15 | - [x] ResNet 16 | - [x] SENet 17 | - [ ] DenseNet 18 | - [x] MobileNet 19 | - [ ] ShuffleNet 20 | 21 | 由于所选数据集要适配各种网络,网络参数会更改通道数和padding参数等,一般不会改变整体网络结构。 22 | -------------------------------------------------------------------------------- /ResNet/ResNet.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | 4 | sys.path.append("..") 5 | from SENet.senet import SE 6 | import torch.nn as nn 7 | import torch 8 | 9 | 10 | class BasicBlock(nn.Module): 11 | expansion = 1 12 | 13 | def __init__(self, 14 | in_channel, 15 | out_channel, 16 | stride=1, 17 | downsample=None, 18 | is_se=False, 19 | **kwargs): 20 | super(BasicBlock, self).__init__() 21 | self.conv1 = nn.Conv2d(in_channels=in_channel, 22 | out_channels=out_channel, 23 | kernel_size=3, 24 | stride=stride, 25 | padding=1, 26 | bias=False) 27 | self.bn1 = nn.BatchNorm2d(out_channel) 28 | self.relu = nn.ReLU() 29 | self.conv2 = nn.Conv2d(in_channels=out_channel, 30 | out_channels=out_channel, 31 | kernel_size=3, 32 | stride=1, 33 | padding=1, 34 | bias=False) 35 | self.bn2 = nn.BatchNorm2d(out_channel) 36 | self.downsample = downsample 37 | self.is_se = is_se 38 | if self.is_se: 39 | self.se = SE(out_channel, 16) 40 | 41 | def forward(self, x): 42 | identity = x 43 | if self.downsample is not None: 44 | identity = self.downsample(x) 45 | 46 | out = self.conv1(x) 47 | out = self.bn1(out) 48 | out = self.relu(out) 49 | 50 | out = self.conv2(out) 51 | out = self.bn2(out) 52 | if self.is_se: 53 | out *= self.se(out) 54 | 55 | out += identity 56 | out = self.relu(out) 57 | 58 | return out 59 | 60 | 61 | class Bottleneck(nn.Module): 62 | """ 63 | 注意:原论文中,在虚线残差结构的主分支上,第一个1x1卷积层的步距是2,第二个3x3卷积层步距是1。 64 | 但在pytorch官方实现过程中是第一个1x1卷积层的步距是1,第二个3x3卷积层步距是2, 65 | 这么做的好处是能够在top1上提升大概0.5%的准确率。 66 | 可参考Resnet v1.5 https://ngc.nvidia.com/catalog/model-scripts/nvidia:resnet_50_v1_5_for_pytorch 67 | """ 68 | expansion = 4 69 | 70 | def __init__(self, 71 | in_channel, 72 | out_channel, 73 | stride=1, 74 | downsample=None, 75 | is_se=False, 76 | groups=1, 77 | width_per_group=64): 78 | super(Bottleneck, self).__init__() 79 | 80 | width = int(out_channel * (width_per_group / 64.)) * groups 81 | 82 | self.conv1 = nn.Conv2d(in_channels=in_channel, 83 | out_channels=width, 84 | kernel_size=1, 85 | stride=1, 86 | bias=False) # squeeze channels 87 | self.bn1 = nn.BatchNorm2d(width) 88 | # ----------------------------------------- 89 | self.conv2 = nn.Conv2d(in_channels=width, 90 | out_channels=width, 91 | groups=groups, 92 | kernel_size=3, 93 | stride=stride, 94 | bias=False, 95 | padding=1) 96 | self.bn2 = nn.BatchNorm2d(width) 97 | # ----------------------------------------- 98 | self.conv3 = nn.Conv2d(in_channels=width, 99 | out_channels=out_channel * self.expansion, 100 | kernel_size=1, 101 | stride=1, 102 | bias=False) # unsqueeze channels 103 | self.bn3 = nn.BatchNorm2d(out_channel * self.expansion) 104 | self.relu = nn.ReLU(inplace=True) 105 | self.downsample = downsample 106 | self.is_se = is_se 107 | if self.is_se: 108 | self.se = SE(out_channel, 16) 109 | 110 | def forward(self, x): 111 | identity = x 112 | if self.downsample is not None: 113 | identity = self.downsample(x) 114 | 115 | out = self.conv1(x) 116 | out = self.bn1(out) 117 | out = self.relu(out) 118 | 119 | out = self.conv2(out) 120 | out = self.bn2(out) 121 | out = self.relu(out) 122 | 123 | out = self.conv3(out) 124 | out = self.bn3(out) 125 | if self.is_se: 126 | out *= self.se(out) 127 | 128 | out += identity 129 | out = self.relu(out) 130 | 131 | return out 132 | 133 | 134 | class ResNet(nn.Module): 135 | def __init__( 136 | self, 137 | block, 138 | blocks_num, 139 | num_classes=1000, 140 | include_top=True, 141 | is_se=False, 142 | groups=1, # 为一时表示标准的卷积,其他数时表示组卷积 143 | width_per_group=64): 144 | super(ResNet, self).__init__() 145 | self.include_top = include_top 146 | self.in_channel = 64 147 | self.is_se = is_se 148 | 149 | self.groups = groups 150 | self.width_per_group = width_per_group 151 | 152 | self.conv1 = nn.Conv2d(3, 153 | self.in_channel, 154 | kernel_size=7, 155 | stride=2, 156 | padding=3, 157 | bias=False) 158 | self.bn1 = nn.BatchNorm2d(self.in_channel) 159 | self.relu = nn.ReLU(inplace=True) 160 | self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) 161 | 162 | self.layer1 = self._make_layer(block, 64, blocks_num[0]) 163 | self.layer2 = self._make_layer(block, 128, blocks_num[1], stride=2) 164 | self.layer3 = self._make_layer(block, 256, blocks_num[2], stride=2) 165 | self.layer4 = self._make_layer(block, 512, blocks_num[3], stride=2) 166 | if self.include_top: 167 | self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) # output size = (1, 1) 168 | self.fc = nn.Linear(512 * block.expansion, num_classes) 169 | 170 | for m in self.modules(): 171 | if isinstance(m, nn.Conv2d): 172 | nn.init.kaiming_normal_(m.weight, 173 | mode='fan_out', 174 | nonlinearity='relu') 175 | 176 | def _make_layer(self, block, channel, block_num, stride=1): 177 | downsample = None 178 | if stride != 1 or self.in_channel != channel * block.expansion: 179 | downsample = nn.Sequential( 180 | nn.Conv2d(self.in_channel, 181 | channel * block.expansion, 182 | kernel_size=1, 183 | stride=stride, 184 | bias=False), 185 | nn.BatchNorm2d(channel * block.expansion)) 186 | 187 | layers = [] 188 | layers.append( 189 | block(self.in_channel, 190 | channel, 191 | downsample=downsample, 192 | is_se=self.is_se, 193 | stride=stride, 194 | groups=self.groups, 195 | width_per_group=self.width_per_group)) 196 | self.in_channel = channel * block.expansion 197 | 198 | for _ in range(1, block_num): 199 | layers.append( 200 | block(self.in_channel, 201 | channel, 202 | is_se=self.is_se, 203 | groups=self.groups, 204 | width_per_group=self.width_per_group)) 205 | 206 | return nn.Sequential(*layers) 207 | 208 | def forward(self, x): 209 | x = self.conv1(x) 210 | x = self.bn1(x) 211 | x = self.relu(x) 212 | x = self.maxpool(x) 213 | 214 | x = self.layer1(x) 215 | x = self.layer2(x) 216 | x = self.layer3(x) 217 | x = self.layer4(x) 218 | 219 | if self.include_top: 220 | x = self.avgpool(x) 221 | x = torch.flatten(x, 1) 222 | x = self.fc(x) 223 | 224 | return x 225 | 226 | 227 | def resnet18(num_classes=1000, include_top=True, is_se=False): 228 | # https://download.pytorch.org/models/resnet18-5c106cde.pth 229 | return ResNet(BasicBlock, [2, 2, 2, 2], 230 | num_classes=num_classes, 231 | include_top=include_top, 232 | is_se=is_se) 233 | 234 | 235 | def resnet34(num_classes=1000, include_top=True, is_se=False): 236 | # https://download.pytorch.org/models/resnet34-333f7ec4.pth 237 | return ResNet(BasicBlock, [3, 4, 6, 3], 238 | num_classes=num_classes, 239 | include_top=include_top, 240 | is_se=is_se) 241 | 242 | 243 | def resnet50(num_classes=1000, include_top=True, is_se=False): 244 | # https://download.pytorch.org/models/resnet50-19c8e357.pth 245 | return ResNet(Bottleneck, [3, 4, 6, 3], 246 | num_classes=num_classes, 247 | include_top=include_top, 248 | is_se=is_se) 249 | 250 | 251 | def resnet101(num_classes=1000, include_top=True, is_se=False): 252 | # https://download.pytorch.org/models/resnet101-5d3b4d8f.pth 253 | return ResNet(Bottleneck, [3, 4, 23, 3], 254 | num_classes=num_classes, 255 | include_top=include_top, 256 | is_se=is_se) 257 | 258 | 259 | def resnext50_32x4d(num_classes=1000, include_top=True, is_se=False): 260 | # https://download.pytorch.org/models/resnext50_32x4d-7cdf4587.pth 261 | groups = 32 262 | width_per_group = 4 263 | return ResNet(Bottleneck, [3, 4, 6, 3], 264 | num_classes=num_classes, 265 | include_top=include_top, 266 | is_se=is_se, 267 | groups=groups, 268 | width_per_group=width_per_group) 269 | 270 | 271 | def resnext101_32x8d(num_classes=1000, include_top=True, is_se=False): 272 | # https://download.pytorch.org/models/resnext101_32x8d-8ba56ff5.pth 273 | groups = 32 274 | width_per_group = 8 275 | return ResNet(Bottleneck, [3, 4, 23, 3], 276 | num_classes=num_classes, 277 | include_top=include_top, 278 | is_se=is_se, 279 | groups=groups, 280 | width_per_group=width_per_group) 281 | -------------------------------------------------------------------------------- /ResNet/main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | 4 | sys.path.append("..") 5 | import torch 6 | import torch.nn as nn 7 | from torch.optim import Adam 8 | import torch.utils.data as Data 9 | import torchvision.datasets as datasets 10 | import torchvision.transforms as transforms 11 | from tqdm import tqdm 12 | from tensorboardX import SummaryWriter 13 | from ResNet import * 14 | 15 | 16 | def main(): 17 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 18 | print("Using {} device.".format(device)) 19 | 20 | transform_train = transforms.Compose([ 21 | transforms.RandomHorizontalFlip(), 22 | transforms.ToTensor(), 23 | transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)) 24 | ]) 25 | 26 | transform_test = transforms.Compose([ 27 | transforms.ToTensor(), 28 | transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)) 29 | ]) 30 | 31 | train_dataset = datasets.CIFAR10(root="../Datasets/CIFAR10/train", 32 | train=True, 33 | transform=transform_train, 34 | download=True) 35 | 36 | val_dataset = datasets.CIFAR10(root="../Datasets/CIFAR10/test", 37 | train=False, 38 | transform=transform_test, 39 | download=True) 40 | 41 | train_num = len(train_dataset) 42 | val_num = len(val_dataset) 43 | 44 | batch_size = 32 45 | nw = min(os.cpu_count(), batch_size if batch_size > 1 else 0) 46 | print('Using {} dataloader workers every process'.format(nw)) 47 | 48 | train_dataloader = Data.DataLoader(dataset=train_dataset, 49 | batch_size=batch_size, 50 | shuffle=True, 51 | num_workers=nw) 52 | 53 | val_dataloader = Data.DataLoader(dataset=val_dataset, 54 | batch_size=batch_size, 55 | shuffle=False, 56 | num_workers=nw) 57 | 58 | print("using {} images for training, {} images for validation.".format( 59 | train_num, val_num)) 60 | 61 | # 定义网络 62 | # torch.manual_seed(13) 63 | model = resnet18(num_classes=10, is_se=True).to(device) 64 | writer = SummaryWriter(log_dir="data/log") 65 | optimizer = Adam(model.parameters(), lr=1e-3) 66 | loss_func = nn.CrossEntropyLoss() 67 | 68 | train_steps = len(train_dataloader) 69 | print_step = 100 70 | epoch = 30 71 | best_acc = 0.0 72 | save_path = 'data/saved_module/ResNet.pth' 73 | 74 | for e in range(epoch): 75 | # Train 76 | model.train() 77 | running_loss = 0.0 78 | train_bar = tqdm(train_dataloader, file=sys.stdout) 79 | for step, (b_x, b_y) in enumerate(train_bar): 80 | if torch.cuda.is_available(): 81 | b_x = b_x.to(device) 82 | b_y = b_y.to(device) 83 | optimizer.zero_grad() 84 | output = model(b_x) 85 | loss = loss_func(output, b_y) 86 | loss.backward() 87 | optimizer.step() 88 | 89 | running_loss += loss.item() 90 | 91 | train_bar.desc = "Train epoch[{}/{}] loss:{:.3f}".format( 92 | e + 1, epoch, loss) 93 | # train_steps += 1 94 | 95 | # # 迭代输出日志 96 | # if train_steps % print_step == 0: 97 | # # 控制台输出 98 | # print("Train: {}, Loss: {}".format(train_steps, 99 | # round(loss.item(), 3))) 100 | # # 记录损失 101 | # writer.add_scalar("train loss", 102 | # scalar_value=loss.item(), 103 | # global_step=train_steps) 104 | # 105 | # # 绘制参数分布 106 | # for name, param in model.named_parameters(): 107 | # writer.add_histogram(name, 108 | # param.data.cpu().numpy(), 109 | # train_steps) 110 | 111 | # Validate 112 | model.eval() 113 | acc = 0.0 114 | with torch.no_grad(): 115 | val_bar = tqdm(val_dataloader, file=sys.stdout) 116 | for val_images, val_labels in val_bar: 117 | if torch.cuda.is_available(): 118 | val_images, val_labels = val_images.to( 119 | device), val_labels.to(device) 120 | outputs = model(val_images) 121 | # loss = loss_function(outputs, test_labels) 122 | predict_y = torch.max(outputs, dim=1)[1] 123 | acc += torch.eq(predict_y, val_labels).sum().item() 124 | 125 | val_bar.desc = "Valid epoch[{}/{}]".format(e + 1, epoch) 126 | 127 | val_accurate = acc / val_num 128 | print('[Epoch %d] train_loss: %.3f val_accuracy: %.3f' % 129 | (e + 1, running_loss / train_steps, val_accurate)) 130 | 131 | if val_accurate > best_acc: 132 | best_acc = val_accurate 133 | torch.save(model.state_dict(), save_path) 134 | 135 | print("FINISHED TRAINING, THE BEST ACCURACY IS: {}".format(best_acc)) 136 | # acc = Test(model, test_dataloader, device) 137 | # writer.add_scalar("test_acc", acc, total_test_step) 138 | # total_test_step += 1 139 | # 140 | # # 保存模型 141 | # torch.save(model.state_dict(), 142 | # "data/saved_module/resnet_{}.pkl".format(e)) 143 | 144 | 145 | if __name__ == "__main__": 146 | main() 147 | -------------------------------------------------------------------------------- /SENet/senet.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.nn.functional as F 4 | 5 | 6 | class SE(nn.Module): 7 | def __init__(self, in_chnls, ratio: int = 16) -> None: 8 | super(SE, self).__init__() 9 | self.sqeeze = nn.AdaptiveAvgPool2d((1, 1)) 10 | self.compress = nn.Conv2d(in_channels=in_chnls, 11 | out_channels=in_chnls // ratio, 12 | kernel_size=1, 13 | stride=1, 14 | padding=0) 15 | self.excitation = nn.Conv2d(in_channels=in_chnls // ratio, 16 | out_channels=in_chnls, 17 | kernel_size=1, 18 | stride=1, 19 | padding=0) 20 | 21 | def forward(self, x): 22 | out = self.sqeeze(x) 23 | out = self.compress(out) 24 | out = F.relu(out, inplace=True) 25 | out = self.excitation(out) 26 | out = torch.sigmoid(out) 27 | 28 | return out 29 | -------------------------------------------------------------------------------- /VGGNet/VGGNet.py: -------------------------------------------------------------------------------- 1 | import torch.nn as nn 2 | 3 | 4 | class VGGNet11(nn.Module): 5 | """VGGNet11""" 6 | 7 | def __init__(self): 8 | super(VGGNet11, self).__init__() 9 | self.layer1 = nn.Sequential( 10 | nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1), 11 | nn.BatchNorm2d(64), nn.ReLU(inplace=True), nn.MaxPool2d(2, 2)) 12 | self.layer2 = nn.Sequential( 13 | nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1), 14 | nn.BatchNorm2d(128), nn.ReLU(inplace=True), nn.MaxPool2d(2, 2)) 15 | 16 | self.layer3 = nn.Sequential( 17 | nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1), 18 | nn.BatchNorm2d(256), nn.ReLU(inplace=True), 19 | nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1), 20 | nn.BatchNorm2d(256), nn.ReLU(inplace=True), nn.MaxPool2d(2, 2)) 21 | self.layer4 = nn.Sequential( 22 | nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1), 23 | nn.BatchNorm2d(512), nn.ReLU(inplace=True), 24 | nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1), 25 | nn.BatchNorm2d(512), nn.ReLU(inplace=True), nn.MaxPool2d(2, 2)) 26 | self.layer5 = nn.Sequential( 27 | nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1), 28 | nn.BatchNorm2d(512), nn.ReLU(inplace=True), 29 | nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1), 30 | nn.BatchNorm2d(512), nn.ReLU(inplace=True), nn.MaxPool2d(2, 2)) 31 | self.conv = nn.Sequential(self.layer1, self.layer2, self.layer3, 32 | self.layer4, self.layer5) 33 | self.fc = nn.Sequential(nn.Flatten(), nn.Linear(512, 512), 34 | nn.ReLU(inplace=True), nn.Dropout(), 35 | nn.Linear(512, 256), nn.ReLU(inplace=True), 36 | nn.Dropout(), nn.Linear(256, 10)) 37 | 38 | def forward(self, x): 39 | x = self.conv(x) 40 | x = self.fc(x) 41 | return x 42 | 43 | 44 | class VGGNet13(nn.Module): 45 | """VGGNet13""" 46 | 47 | def __init__(self): 48 | super(VGGNet13, self).__init__() 49 | self.layer1 = nn.Sequential( 50 | nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1), 51 | nn.BatchNorm2d(64), nn.ReLU(inplace=True), 52 | nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1), 53 | nn.BatchNorm2d(64), nn.ReLU(inplace=True), nn.MaxPool2d(2, 2)) 54 | self.layer2 = nn.Sequential( 55 | nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1), 56 | nn.BatchNorm2d(128), nn.ReLU(inplace=True), 57 | nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1), 58 | nn.BatchNorm2d(128), nn.ReLU(inplace=True), nn.MaxPool2d(2, 2)) 59 | 60 | self.layer3 = nn.Sequential( 61 | nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1), 62 | nn.BatchNorm2d(256), nn.ReLU(inplace=True), 63 | nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1), 64 | nn.BatchNorm2d(256), nn.ReLU(inplace=True), nn.MaxPool2d(2, 2)) 65 | self.layer4 = nn.Sequential( 66 | nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1), 67 | nn.BatchNorm2d(512), nn.ReLU(inplace=True), 68 | nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1), 69 | nn.BatchNorm2d(512), nn.ReLU(inplace=True), nn.MaxPool2d(2, 2)) 70 | self.layer5 = nn.Sequential( 71 | nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1), 72 | nn.BatchNorm2d(512), nn.ReLU(inplace=True), 73 | nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1), 74 | nn.BatchNorm2d(512), nn.ReLU(inplace=True), nn.MaxPool2d(2, 2)) 75 | self.conv = nn.Sequential(self.layer1, self.layer2, self.layer3, 76 | self.layer4, self.layer5) 77 | self.fc = nn.Sequential(nn.Flatten(), nn.Linear(512, 512), 78 | nn.ReLU(inplace=True), nn.Dropout(), 79 | nn.Linear(512, 256), nn.ReLU(inplace=True), 80 | nn.Dropout(), nn.Linear(256, 10)) 81 | 82 | def forward(self, x): 83 | x = self.conv(x) 84 | x = self.fc(x) 85 | return x 86 | 87 | 88 | class VGGNet16(nn.Module): 89 | """VGGNet16""" 90 | 91 | def __init__(self, layer: int = 1 | 3): 92 | super(VGGNet16, self).__init__() 93 | self.layer1 = nn.Sequential( 94 | nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1), 95 | nn.BatchNorm2d(64), nn.ReLU(inplace=True), 96 | nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1), 97 | nn.BatchNorm2d(64), nn.ReLU(inplace=True), nn.MaxPool2d(2, 2)) 98 | self.layer2 = nn.Sequential( 99 | nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1), 100 | nn.BatchNorm2d(128), nn.ReLU(inplace=True), 101 | nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1), 102 | nn.BatchNorm2d(128), nn.ReLU(inplace=True), nn.MaxPool2d(2, 2)) 103 | 104 | self.layer3 = nn.Sequential( 105 | nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1), 106 | nn.BatchNorm2d(256), nn.ReLU(inplace=True), 107 | nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1), 108 | nn.BatchNorm2d(256), nn.ReLU(inplace=True), 109 | nn.Conv2d(256, 256, kernel_size=layer, stride=1, padding=1), 110 | nn.BatchNorm2d(256), nn.ReLU(inplace=True), nn.MaxPool2d(2, 2)) 111 | self.layer4 = nn.Sequential( 112 | nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1), 113 | nn.BatchNorm2d(512), nn.ReLU(inplace=True), 114 | nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1), 115 | nn.BatchNorm2d(512), nn.ReLU(inplace=True), 116 | nn.Conv2d(512, 512, kernel_size=layer, stride=1, padding=1), 117 | nn.BatchNorm2d(512), nn.ReLU(inplace=True), nn.MaxPool2d(2, 2)) 118 | self.layer5 = nn.Sequential( 119 | nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1), 120 | nn.BatchNorm2d(512), nn.ReLU(inplace=True), 121 | nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1), 122 | nn.BatchNorm2d(512), nn.ReLU(inplace=True), 123 | nn.Conv2d(512, 512, kernel_size=layer, stride=1, padding=1), 124 | nn.BatchNorm2d(512), nn.ReLU(inplace=True), nn.MaxPool2d(2, 2)) 125 | self.conv = nn.Sequential(self.layer1, self.layer2, self.layer3, 126 | self.layer4, self.layer5) 127 | self.fc = nn.Sequential(nn.Flatten(), nn.Linear(512, 512), 128 | nn.ReLU(inplace=True), nn.Dropout(), 129 | nn.Linear(512, 256), nn.ReLU(inplace=True), 130 | nn.Dropout(), nn.Linear(256, 10)) 131 | 132 | def forward(self, x): 133 | x = self.conv(x) 134 | x = self.fc(x) 135 | return x 136 | 137 | 138 | class VGGNet19(nn.Module): 139 | """VGGNet19""" 140 | 141 | def __init__(self, layer: int = 1 | 3): 142 | super(VGGNet19, self).__init__() 143 | self.layer1 = nn.Sequential( 144 | nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1), 145 | nn.BatchNorm2d(64), nn.ReLU(inplace=True), 146 | nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1), 147 | nn.BatchNorm2d(64), nn.ReLU(inplace=True), nn.MaxPool2d(2, 2)) 148 | self.layer2 = nn.Sequential( 149 | nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1), 150 | nn.BatchNorm2d(128), nn.ReLU(inplace=True), 151 | nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1), 152 | nn.BatchNorm2d(128), nn.ReLU(inplace=True), nn.MaxPool2d(2, 2)) 153 | 154 | self.layer3 = nn.Sequential( 155 | nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1), 156 | nn.BatchNorm2d(256), nn.ReLU(inplace=True), 157 | nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1), 158 | nn.BatchNorm2d(256), nn.ReLU(inplace=True), 159 | nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1), 160 | nn.BatchNorm2d(256), nn.ReLU(inplace=True), 161 | nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1), 162 | nn.BatchNorm2d(256), nn.ReLU(inplace=True), nn.MaxPool2d(2, 2)) 163 | self.layer4 = nn.Sequential( 164 | nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1), 165 | nn.BatchNorm2d(512), nn.ReLU(inplace=True), 166 | nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1), 167 | nn.BatchNorm2d(512), nn.ReLU(inplace=True), 168 | nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1), 169 | nn.BatchNorm2d(512), nn.ReLU(inplace=True), 170 | nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1), 171 | nn.BatchNorm2d(512), nn.ReLU(inplace=True), nn.MaxPool2d(2, 2)) 172 | self.layer5 = nn.Sequential( 173 | nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1), 174 | nn.BatchNorm2d(512), nn.ReLU(inplace=True), 175 | nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1), 176 | nn.BatchNorm2d(512), nn.ReLU(inplace=True), 177 | nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1), 178 | nn.BatchNorm2d(512), nn.ReLU(inplace=True), 179 | nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1), 180 | nn.BatchNorm2d(512), nn.ReLU(inplace=True), nn.MaxPool2d(2, 2)) 181 | self.conv = nn.Sequential(self.layer1, self.layer2, self.layer3, 182 | self.layer4, self.layer5) 183 | self.fc = nn.Sequential(nn.Flatten(), nn.Linear(512, 512), 184 | nn.ReLU(inplace=True), nn.Dropout(), 185 | nn.Linear(512, 256), nn.ReLU(inplace=True), 186 | nn.Dropout(), nn.Linear(256, 10)) 187 | 188 | def forward(self, x): 189 | x = self.conv(x) 190 | x = self.fc(x) 191 | return x 192 | -------------------------------------------------------------------------------- /VGGNet/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | sys.path.append("..") 5 | from functions import Test 6 | import torch 7 | import torch.nn as nn 8 | from torch.optim import Adam 9 | import torch.utils.data as Data 10 | import torchvision.datasets as datasets 11 | import torchvision.transforms as transforms 12 | from tensorboardX import SummaryWriter 13 | from tqdm import tqdm 14 | from VGGNet import * 15 | 16 | 17 | def main(): 18 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 19 | print("Using {} device.".format(device)) 20 | 21 | transform_train = transforms.Compose([ 22 | transforms.RandomHorizontalFlip(), 23 | transforms.ToTensor(), 24 | transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)) 25 | ]) 26 | 27 | transform_test = transforms.Compose([ 28 | transforms.ToTensor(), 29 | transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)) 30 | ]) 31 | 32 | train_dataset = datasets.CIFAR10(root="../Datasets/CIFAR10/train", 33 | train=True, 34 | transform=transform_train, 35 | download=True) 36 | 37 | val_dataset = datasets.CIFAR10(root="../Datasets/CIFAR10/test", 38 | train=False, 39 | transform=transform_test, 40 | download=True) 41 | 42 | train_num = len(train_dataset) 43 | val_num = len(val_dataset) 44 | 45 | batch_size = 128 46 | nw = min(os.cpu_count(), batch_size if batch_size > 1 else 0) 47 | print('Using {} dataloader workers every process'.format(nw)) 48 | 49 | train_dataloader = Data.DataLoader(dataset=train_dataset, 50 | batch_size=batch_size, 51 | shuffle=True, 52 | num_workers=4) 53 | 54 | val_dataloader = Data.DataLoader(dataset=val_dataset, 55 | batch_size=batch_size, 56 | shuffle=True, 57 | num_workers=4) 58 | 59 | # 定义设备 60 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 61 | print("使用设备:", device) 62 | 63 | # 定义网络 64 | torch.manual_seed(13) 65 | model = VGGNet19().to(device) 66 | writer = SummaryWriter(log_dir="data/log") 67 | optimizer = Adam(model.parameters(), lr=1e-3) 68 | loss_func = nn.CrossEntropyLoss() 69 | 70 | train_steps = len(train_dataloader) 71 | print_step = 100 72 | epoch = 30 73 | best_acc = 0.0 74 | save_path = 'data/saved_module/VGGNet.pth' 75 | 76 | for e in range(epoch): 77 | # Train 78 | model.train() 79 | running_loss = 0.0 80 | train_bar = tqdm(train_dataloader, file=sys.stdout) 81 | for step, (b_x, b_y) in enumerate(train_bar): 82 | if torch.cuda.is_available(): 83 | b_x = b_x.to(device) 84 | b_y = b_y.to(device) 85 | optimizer.zero_grad() 86 | output = model(b_x) 87 | loss = loss_func(output, b_y) 88 | loss.backward() 89 | optimizer.step() 90 | 91 | running_loss += loss.item() 92 | 93 | train_bar.desc = "Train epoch[{}/{}] loss:{:.3f}".format( 94 | e + 1, epoch, loss) 95 | # train_steps += 1 96 | 97 | # # 迭代输出日志 98 | # if train_steps % print_step == 0: 99 | # # 控制台输出 100 | # print("Train: {}, Loss: {}".format(train_steps, 101 | # round(loss.item(), 3))) 102 | # # 记录损失 103 | # writer.add_scalar("train loss", 104 | # scalar_value=loss.item(), 105 | # global_step=train_steps) 106 | # 107 | # # 绘制参数分布 108 | # for name, param in model.named_parameters(): 109 | # writer.add_histogram(name, 110 | # param.data.cpu().numpy(), 111 | # train_steps) 112 | 113 | # Validate 114 | model.eval() 115 | acc = 0.0 116 | with torch.no_grad(): 117 | val_bar = tqdm(val_dataloader, file=sys.stdout) 118 | for val_images, val_labels in val_bar: 119 | if torch.cuda.is_available(): 120 | val_images, val_labels = val_images.to( 121 | device), val_labels.to(device) 122 | outputs = model(val_images) 123 | # loss = loss_function(outputs, test_labels) 124 | predict_y = torch.max(outputs, dim=1)[1] 125 | acc += torch.eq(predict_y, val_labels).sum().item() 126 | 127 | val_bar.desc = "Valid epoch[{}/{}]".format(e + 1, epoch) 128 | 129 | val_accurate = acc / val_num 130 | print('[Epoch %d] train_loss: %.3f val_accuracy: %.3f' % 131 | (e + 1, running_loss / train_steps, val_accurate)) 132 | 133 | if val_accurate > best_acc: 134 | best_acc = val_accurate 135 | torch.save(model.state_dict(), save_path) 136 | 137 | print("FINISHED TRAINING, THE BEST ACCURACY IS: {}".format(best_acc)) 138 | # acc = Test(model, test_dataloader, device) 139 | # writer.add_scalar("test_acc", acc, total_test_step) 140 | # total_test_step += 1 141 | # 142 | # # 保存模型 143 | # torch.save(model.state_dict(), 144 | # "data/saved_module/resnet_{}.pkl".format(e)) 145 | 146 | 147 | if __name__ == "__main__": 148 | main() 149 | -------------------------------------------------------------------------------- /functions.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | def Test(model, test_dataloader, device): 4 | """Test""" 5 | correct = 0.0 6 | total = 0 7 | acclist = [] 8 | acc = 0.0 9 | model.eval() 10 | with torch.no_grad(): 11 | for inputs, targets in test_dataloader: 12 | if torch.cuda.is_available: 13 | inputs, targets = inputs.to(device), targets.to(device) 14 | outputs = model(inputs) 15 | pred = outputs.argmax(dim=1) 16 | total += inputs.size(0) 17 | correct += torch.eq(pred, targets).sum().item() 18 | acclist.append((correct/total)) 19 | acc = sum(acclist)/len(test_dataloader) 20 | return acc 21 | --------------------------------------------------------------------------------