├── CNN_show.py ├── CNN_train.py ├── InceptionNetV3_train.py ├── README.md ├── ResNet_Train.py ├── VGG16_train.py ├── VGG19_train.py ├── app.py ├── model ├── CNN.py ├── InceptionNetV3.py ├── VGG16.py ├── VGG19.py └── __pycache__ │ ├── CNN.cpython-39.pyc │ ├── InceptionNetV3.cpython-39.pyc │ ├── VGG16.cpython-39.pyc │ └── VGG19.cpython-39.pyc ├── static └── uploads │ ├── 1695365043.jpg │ ├── 1695365087.jpg │ ├── 1695365100.jpg │ ├── 1695365109.jpg │ ├── 1695365151.jpg │ ├── 1695365182.jpg │ ├── 1695365270.jpg │ ├── 1695365308.jpg │ ├── 1695365324.jpg │ ├── 1695365421.jpg │ ├── 1695365474.jpg │ ├── 1695365599.jpg │ ├── 1695365639.jpg │ ├── 1695365736.jpg │ ├── 1695365806.jpg │ ├── 1695365880.jpg │ ├── 1695365913.jpg │ ├── 1695365973.jpg │ ├── 1695366019.jpg │ ├── 1695366027.jpg │ ├── 1695368807.jpg │ ├── 1695369609.jpg │ ├── 1695369624.jpg │ ├── 1695370527.jpg │ ├── 1695370531.jpg │ ├── 1695370543.jpg │ ├── 1695370557.jpg │ ├── 1695370578.jpg │ ├── 1695370605.jpg │ ├── 1695372115.jpg │ ├── 1695372169.jpg │ ├── 1695372820.jpg │ ├── 1695372825.jpg │ ├── 1695377787.jpg │ ├── 1695377805.jpg │ └── 1695379143.jpg ├── templates ├── index.html └── index_1.html └── train ├── CNN_show.py ├── CNN_train.py ├── InceptionNetV3_train.py ├── ResNet_Train.py ├── VGG16_train.py ├── VGG19_train.py ├── logs ├── events.out.tfevents.1695382060.DESKTOP-MQ6GNBS ├── events.out.tfevents.1695382118.DESKTOP-MQ6GNBS └── events.out.tfevents.1695382165.DESKTOP-MQ6GNBS └── runs ├── CNN_Sep19_12-44-48 └── events.out.tfevents.1695098688.DESKTOP-MQ6GNBS.20108.0 ├── IneceptionNet3_Sep19_16-40-11 ├── 1695112811.2165155 │ └── events.out.tfevents.1695112811.DESKTOP-MQ6GNBS.3080.1 └── events.out.tfevents.1695112811.DESKTOP-MQ6GNBS.3080.0 ├── Sep22_16-30-59_DESKTOP-MQ6GNBS ├── 1695371459.676054 │ └── events.out.tfevents.1695371459.DESKTOP-MQ6GNBS.5652.1 └── events.out.tfevents.1695371459.DESKTOP-MQ6GNBS.5652.0 ├── Sep22_19-29-26_DESKTOP-MQ6GNBSCNNModel └── events.out.tfevents.1695382166.DESKTOP-MQ6GNBS.20932.0 ├── VGG16_WithoutPre_Trained_Sep19_13-22-35 └── events.out.tfevents.1695100955.DESKTOP-MQ6GNBS.14800.0 └── VGG19_WithPre_Trained_Sep19_15-38-29 ├── 1695109109.3126585 └── events.out.tfevents.1695109109.DESKTOP-MQ6GNBS.25540.1 └── events.out.tfevents.1695109109.DESKTOP-MQ6GNBS.25540.0 /CNN_show.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | from tensorboardX import SummaryWriter 4 | 5 | 6 | class CNNModel(nn.Module): 7 | def __init__(self): 8 | super(CNNModel, self).__init__() 9 | self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1) 10 | self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1) 11 | self.fc1 = nn.Linear(64 * 56 * 56, 128) 12 | self.fc2 = nn.Linear(128, 3) # 3个类别 13 | 14 | def forward(self, x): 15 | x = torch.relu(self.conv1(x)) 16 | x = torch.relu(self.conv2(x)) 17 | x = torch.nn.functional.avg_pool2d(x, 4) # 添加全局平均池化层,将尺寸缩小到 (64, 14, 14) 18 | x = x.view(x.size(0), -1) 19 | x = torch.relu(self.fc1(x)) 20 | x = self.fc2(x) 21 | return x 22 | 23 | 24 | -------------------------------------------------------------------------------- /CNN_train.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import torch 4 | import torch.nn as nn 5 | import torch.optim as optim 6 | from torchvision import transforms, datasets 7 | from torch.utils.tensorboard import SummaryWriter 8 | from torch.optim.lr_scheduler import StepLR 9 | from torchsummary import summary 10 | 11 | # 初始化TensorBoard的SummaryWriter 12 | writer = SummaryWriter() 13 | # 记录超参数(例如学习率) 14 | writer.add_hparams({'lr': 0.001, 'batch_size': 32}, {'hparam/accuracy': 0.95, 'hparam/loss': 0.1}) 15 | 16 | # 定义数据增强和加载数据 17 | transform = transforms.Compose([ 18 | transforms.Resize((224, 224)), 19 | transforms.ToTensor(), 20 | transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) 21 | ]) 22 | 23 | train_dataset = datasets.ImageFolder('../dataset_jpg/train', transform=transform) 24 | train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=32, shuffle=True) 25 | 26 | test_dataset = datasets.ImageFolder('../dataset_jpg/test', transform=transform) 27 | test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=32, shuffle=False) 28 | 29 | 30 | # 定义CNN模型 31 | class CNNModel(nn.Module): 32 | def __init__(self): 33 | super(CNNModel, self).__init__() 34 | self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1) 35 | self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1) 36 | self.fc1 = nn.Linear(64 * 56 * 56, 128) 37 | self.fc2 = nn.Linear(128, 3) # 3个类别 38 | 39 | def forward(self, x): 40 | x = torch.relu(self.conv1(x)) 41 | x = torch.relu(self.conv2(x)) 42 | x = torch.nn.functional.avg_pool2d(x, 4) # 添加全局平均池化层,将尺寸缩小到 (64, 14, 14) 43 | x = x.view(x.size(0), -1) 44 | x = torch.relu(self.fc1(x)) 45 | x = self.fc2(x) 46 | return x 47 | 48 | 49 | # 初始化模型和优化器 50 | model = CNNModel() 51 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 52 | device = torch.device("cuda") 53 | model.to(device) 54 | optimizer = optim.Adam(model.parameters(), lr=0.001) 55 | scheduler = StepLR(optimizer, step_size=5, gamma=0.1) # 学习率调度器 56 | 57 | # 打印模型摘要 58 | # summary(model, (3, 224, 224), device=device) 59 | print(model) 60 | 61 | criterion = nn.CrossEntropyLoss() 62 | 63 | # 初始化最佳精度和对应的模型权重 64 | best_accuracy = 0.0 65 | best_model_weights = None 66 | weight_save_path = '../weights/CNN/' 67 | os.makedirs(weight_save_path, exist_ok=True) 68 | # 开始训练 69 | epochs = 30 70 | for epoch in range(epochs): 71 | model.train() 72 | running_loss = 0.0 73 | total_batches = len(train_loader) # 获取批次总数 74 | for batch_idx, (inputs, labels) in enumerate(train_loader): 75 | inputs, labels = inputs.to(device), labels.to(device) 76 | optimizer.zero_grad() 77 | outputs = model(inputs) 78 | loss = criterion(outputs, labels) 79 | loss.backward() 80 | optimizer.step() 81 | running_loss += loss.item() 82 | 83 | # 实时显示损失 84 | print(f"Epoch [{epoch + 1}/{epochs}], Batch [{batch_idx + 1}/{total_batches}], Loss: {loss.item()}") 85 | 86 | # 使用TensorBoard记录训练损失 87 | writer.add_scalar('Train Loss', running_loss / total_batches, epoch) 88 | 89 | # 在测试集上评估模型 90 | model.eval() 91 | correct = 0 92 | total = 0 93 | with torch.no_grad(): 94 | for inputs, labels in test_loader: 95 | inputs, labels = inputs.to(device), labels.to(device) 96 | outputs = model(inputs) 97 | _, predicted = torch.max(outputs.data, 1) 98 | total += labels.size(0) 99 | correct += (predicted == labels).sum().item() 100 | 101 | accuracy = 100 * correct / total 102 | 103 | # 使用TensorBoard记录测试精度 104 | writer.add_scalar('Test Accuracy', accuracy, epoch) 105 | 106 | print(f"Epoch {epoch + 1}/{epochs}, Train Loss: {running_loss / total_batches}, Test Accuracy: {accuracy}%") 107 | 108 | # 更新学习率 109 | scheduler.step() 110 | 111 | # 保存每轮训练的权重 112 | torch.save(model.state_dict(), weight_save_path + f'model_weights_epoch_{epoch + 1}.pth') 113 | 114 | # 更新最佳模型权重 115 | if accuracy > best_accuracy: 116 | best_accuracy = accuracy 117 | best_model_weights = model.state_dict() 118 | 119 | # 保存最佳权重 120 | torch.save(best_model_weights, weight_save_path + 'CNN_best_model_weights.pth') 121 | 122 | # 关闭TensorBoard的SummaryWriter 123 | writer.close() 124 | -------------------------------------------------------------------------------- /InceptionNetV3_train.py: -------------------------------------------------------------------------------- 1 | import os 2 | import torch 3 | import torch.nn as nn 4 | import torch.optim as optim 5 | from torchvision import transforms, datasets, models 6 | from torch.utils.tensorboard import SummaryWriter 7 | from torch.optim.lr_scheduler import StepLR 8 | from torchsummary import summary 9 | 10 | # 初始化TensorBoard的SummaryWriter 11 | writer = SummaryWriter() 12 | # 记录超参数 13 | writer.add_hparams({'lr': 0.001, 'batch_size': 32}, {'hparam/accuracy': 0.95, 'hparam/loss': 0.1}) 14 | 15 | # 定义数据增强和加载数据 16 | transform = transforms.Compose([ 17 | transforms.Resize((299, 299)), # InceptionNet需要输入大小为(299, 299) 18 | transforms.ToTensor(), 19 | transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) 20 | ]) 21 | 22 | train_dataset = datasets.ImageFolder('../dataset_jpg/train', transform=transform) 23 | train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=32, shuffle=True) 24 | 25 | test_dataset = datasets.ImageFolder('../dataset_jpg/test', transform=transform) 26 | test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=32, shuffle=False) 27 | 28 | # 使用预训练的InceptionNet模型 29 | model = models.inception_v3(pretrained=True) 30 | 31 | # 修改最后一个全连接层,以适应您的分类任务(3个类别) 32 | num_features = model.fc.in_features 33 | model.fc = nn.Linear(num_features, 3) # 将3更改为您的类别数 34 | 35 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 36 | model.to(device) 37 | 38 | optimizer = optim.Adam(model.parameters(), lr=0.001) 39 | scheduler = StepLR(optimizer, step_size=5, gamma=0.1) 40 | 41 | # 打印模型摘要 42 | print(model) 43 | 44 | criterion = nn.CrossEntropyLoss() 45 | 46 | # 初始化最佳精度和对应的模型权重 47 | best_accuracy = 0.0 48 | best_model_weights = None 49 | weight_save_path = '../weights/inceptionnet/' 50 | os.makedirs(weight_save_path, exist_ok=True) 51 | 52 | # 开始训练 53 | epochs = 30 54 | for epoch in range(epochs): 55 | model.train() 56 | running_loss = 0.0 57 | total_batches = len(train_loader) # 获取批次总数 58 | for batch_idx, (inputs, labels) in enumerate(train_loader): 59 | inputs, labels = inputs.to(device), labels.to(device) 60 | optimizer.zero_grad() 61 | # 提取主要的模型输出 62 | outputs, _ = model(inputs) 63 | loss = criterion(outputs, labels) 64 | loss.backward() 65 | optimizer.step() 66 | running_loss += loss.item() 67 | 68 | # 实时显示损失 69 | print(f"Epoch [{epoch + 1}/{epochs}], Batch [{batch_idx + 1}/{total_batches}], Loss: {loss.item()}") 70 | 71 | # 使用TensorBoard记录训练损失 72 | writer.add_scalar('Train Loss', running_loss / total_batches, epoch) 73 | 74 | # 在测试集上评估模型 75 | model.eval() 76 | correct = 0 77 | total = 0 78 | with torch.no_grad(): 79 | for inputs, labels in test_loader: 80 | inputs, labels = inputs.to(device), labels.to(device) 81 | outputs = model(inputs) 82 | _, predicted = torch.max(outputs.data, 1) 83 | total += labels.size(0) 84 | correct += (predicted == labels).sum().item() 85 | 86 | accuracy = 100 * correct / total 87 | 88 | # 使用TensorBoard记录测试精度 89 | writer.add_scalar('Test Accuracy', accuracy, epoch) 90 | 91 | print(f"Epoch {epoch + 1}/{epochs}, Train Loss: {running_loss / total_batches}, Test Accuracy: {accuracy}%") 92 | 93 | # 更新学习率 94 | scheduler.step() 95 | 96 | # 保存每轮训练的权重 97 | torch.save(model.state_dict(), weight_save_path + f'model_weights_epoch_{epoch + 1}.pth') 98 | 99 | # 更新最佳模型权重 100 | if accuracy > best_accuracy: 101 | best_accuracy = accuracy 102 | best_model_weights = model.state_dict() 103 | 104 | # 保存最佳权重 105 | torch.save(best_model_weights, weight_save_path + 'inceptionnet_best_model_weights.pth') 106 | 107 | # 关闭TensorBoard的SummaryWriter 108 | writer.close() 109 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BIGC_COVID19_CLS 2 | ## 北京印刷学院人工智能大赛深度学习组作品_基于深度学习的新冠肺炎检测系统 3 | 4 | 本项目设计出多种基于深度学习神经网络模型的新冠肺炎影像特征识别系统以及用于用户进行检测的Web程序。该系统通过对比主流卷积神经网络(CNN)模型,VGG16与VGG19模型以及InceptionNetV3深度学习模型,并通过实验对比算法识别的精确度及进行相应模型参数调整优化,验证多种模型在识别新冠肺炎CT图像中的有效性,导出训练后的模型权重,使用Flask框架构建了一个简单的WebApp,允许用户通过远程访问上传CT图片选择不同的模型进行肺部健康状况的检测。 5 | 6 | 权重文件见云盘 7 | ## 仓库结构 8 | ![仓库结构图](https://github.com/SilverGarros/BIGC_COVID19_CLS/assets/93498846/3a832bb0-248a-4fd9-9bfd-16e3baa799d2) 9 | ## 训练过程记录 10 | Accuracy变化情况 11 | ![训练过程记录Accuracy变化情况](https://github.com/SilverGarros/BIGC_COVID19_CLS/assets/93498846/4b771d1a-196e-470e-9e89-abf9e8a3a405) 12 | Loss变化情况 13 | ![训练过程记录Loss变化情况](https://github.com/SilverGarros/BIGC_COVID19_CLS/assets/93498846/05c2c35b-1467-4afd-aece-6c101665d939) 14 | ## Web展示图 15 | ![Web展示图](https://github.com/SilverGarros/BIGC_COVID19_CLS/assets/93498846/3dba3e85-5829-4351-9d52-24b04a848e96) 16 | ![Web操作展示图1](https://github.com/SilverGarros/BIGC_COVID19_CLS/assets/93498846/9c67c08b-ddf9-4ea9-8c4d-8e5a09f98971) 17 | -------------------------------------------------------------------------------- /ResNet_Train.py: -------------------------------------------------------------------------------- 1 | import os 2 | import torch 3 | import torch.nn as nn 4 | import torch.optim as optim 5 | from torchvision import transforms, datasets, models 6 | from torch.utils.tensorboard import SummaryWriter 7 | from torch.optim.lr_scheduler import StepLR 8 | 9 | # 初始化TensorBoard的SummaryWriter 10 | writer = SummaryWriter() 11 | # 定义数据增强和加载数据 12 | transform = transforms.Compose([ 13 | transforms.Resize((224, 224)), 14 | transforms.ToTensor(), 15 | transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) 16 | ]) 17 | 18 | train_dataset = datasets.ImageFolder('../dataset_jpg/train', transform=transform) 19 | train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=32, shuffle=True) 20 | 21 | test_dataset = datasets.ImageFolder('../dataset_jpg/test', transform=transform) 22 | test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=32, shuffle=False) 23 | 24 | # 设置预训练权重文件的保存路径 25 | pretrained_weights_dir = 'pre-training weights' 26 | os.makedirs(pretrained_weights_dir, exist_ok=True) 27 | 28 | # 检查是否存在预训练权重文件,如果不存在,则下载并保存 29 | pretrained_weights_path = os.path.join(pretrained_weights_dir, 'ResNet18.pth') 30 | if not os.path.exists(pretrained_weights_path): 31 | print(f"Downloading pretrained weights to {pretrained_weights_path}...") 32 | ResNet18 = models.resnet18(pretrained=True) 33 | torch.save(ResNet18.state_dict(), pretrained_weights_path) 34 | print("Pretrained weights downloaded and saved.") 35 | 36 | # 使用预训练的ResNet18模型 37 | model = models.ResNet18(pretrained=True) # 改为False,不使用预训练权重,将从头开始训练 38 | 39 | # 加载判定预训练权重文件 40 | if os.path.exists(pretrained_weights_path): 41 | pretrained_weights = torch.load(pretrained_weights_path) 42 | model.load_state_dict(pretrained_weights) 43 | else: 44 | print(f"Pretrained weights not found at '{pretrained_weights_path}'. Training from scratch.") 45 | 46 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 47 | model.to(device) 48 | optimizer = optim.Adam(model.parameters(), lr=0.001) 49 | scheduler = StepLR(optimizer, step_size=5, gamma=0.1) # 学习率调度器 50 | 51 | # 打印模型摘要 52 | # summary(model, (3, 224, 224), device=device) 53 | print(model) 54 | 55 | criterion = nn.CrossEntropyLoss() 56 | 57 | # 初始化最佳精度和对应的模型权重 58 | best_accuracy = 0.0 59 | best_model_weights = None 60 | weight_save_path = '../weights/ResNet18/' 61 | os.makedirs(weight_save_path, exist_ok=True) 62 | 63 | # 开始训练 64 | epochs = 10 65 | for epoch in range(epochs): 66 | model.train() 67 | running_loss = 0.0 68 | total_batches = len(train_loader) # 获取批次总数 69 | for batch_idx, (inputs, labels) in enumerate(train_loader): 70 | inputs, labels = inputs.to(device), labels.to(device) 71 | optimizer.zero_grad() 72 | outputs = model(inputs) 73 | loss = criterion(outputs, labels) 74 | loss.backward() 75 | optimizer.step() 76 | running_loss += loss.item() 77 | 78 | # 实时显示损失 79 | print(f"Epoch [{epoch + 1}/{epochs}], Batch [{batch_idx + 1}/{total_batches}], Loss: {loss.item()}") 80 | 81 | # 使用TensorBoard记录训练损失 82 | writer.add_scalar('Train Loss', running_loss / total_batches, epoch) 83 | 84 | # 在测试集上评估模型 85 | model.eval() 86 | correct = 0 87 | total = 0 88 | with torch.no_grad(): 89 | for inputs, labels in test_loader: 90 | inputs, labels = inputs.to(device), labels.to(device) 91 | outputs = model(inputs) 92 | _, predicted = torch.max(outputs.data, 1) 93 | total += labels.size(0) 94 | correct += (predicted == labels).sum().item() 95 | 96 | accuracy = 100 * correct / total 97 | 98 | # 使用TensorBoard记录测试精度 99 | writer.add_scalar('Test Accuracy', accuracy, epoch) 100 | 101 | print(f"Epoch {epoch + 1}/{epochs}, Train Loss: {running_loss / total_batches}, Test Accuracy: {accuracy}%") 102 | 103 | # 更新学习率 104 | scheduler.step() 105 | 106 | # 保存每轮训练的权重 107 | torch.save(model.state_dict(), weight_save_path+f'model_weights_epoch_{epoch + 1}.pth') 108 | 109 | # 更新最佳模型权重 110 | if accuracy > best_accuracy: 111 | best_accuracy = accuracy 112 | best_model_weights = model.state_dict() 113 | 114 | # 保存最佳权重 115 | torch.save(best_model_weights, weight_save_path+'ResNet18_best_model_weights.pth') 116 | 117 | # 关闭TensorBoard的SummaryWriter 118 | writer.close() 119 | -------------------------------------------------------------------------------- /VGG16_train.py: -------------------------------------------------------------------------------- 1 | import os 2 | import torch 3 | import torch.nn as nn 4 | import torch.optim as optim 5 | from torchvision import transforms, datasets 6 | from torch.utils.tensorboard import SummaryWriter 7 | from torch.optim.lr_scheduler import StepLR 8 | import torchvision.models as models 9 | import torch.utils.model_zoo as model_zoo 10 | 11 | # 指定预训练权重文件路径 12 | pretrained_weights_path = './pre-trained weights/VGG16.pth' 13 | 14 | # 初始化TensorBoard的SummaryWriter 15 | writer = SummaryWriter(log_dir='./logs') 16 | 17 | # 定义数据增强和加载数据 18 | transform = transforms.Compose([ 19 | transforms.Resize((224, 224)), 20 | transforms.ToTensor(), 21 | transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) 22 | ]) 23 | 24 | train_dataset = datasets.ImageFolder('../dataset_jpg/train', transform=transform) 25 | train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=32, shuffle=True) 26 | 27 | test_dataset = datasets.ImageFolder('../dataset_jpg/test', transform=transform) 28 | test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=32, shuffle=False) 29 | 30 | # 使用自定义预训练权重路径或下载到pretrained_weights_path 31 | if not os.path.exists(pretrained_weights_path): 32 | # 下载VGG16预训练权重 33 | print("Downloading VGG16 pretrained weights...") 34 | model_url = "https://download.pytorch.org/models/vgg16-397923af.pth" 35 | model_zoo.load_url(model_url, model_dir='./pre-trained weights/vgg16.pth') 36 | 37 | # 使用预训练的VGG16模型 38 | model = models.vgg16(pretrained=False) # 不使用内置的预训练权重 39 | model.load_state_dict(torch.load(pretrained_weights_path)) # 加载自定义预训练权重 40 | 41 | # 修改最后一个全连接层,以适应分类任务(3个类别) 42 | model.classifier[6] = nn.Linear(4096, 3) 43 | 44 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 45 | model.to(device) 46 | 47 | optimizer = optim.Adam(model.parameters(), lr=0.001) 48 | scheduler = StepLR(optimizer, step_size=5, gamma=0.1) 49 | 50 | # 打印模型摘要 51 | # summary(model, (3, 224, 224), device=device) 52 | print(model) 53 | 54 | criterion = nn.CrossEntropyLoss() 55 | 56 | # 初始化最佳精度和对应的模型权重 57 | best_accuracy = 0.0 58 | best_model_weights = None 59 | weight_save_path = '../weights/VGG16/' 60 | os.makedirs(weight_save_path, exist_ok=True) 61 | 62 | # 开始训练 63 | epochs = 30 64 | for epoch in range(epochs): 65 | model.train() 66 | running_loss = 0.0 67 | total_batches = len(train_loader) 68 | for batch_idx, (inputs, labels) in enumerate(train_loader): 69 | inputs, labels = inputs.to(device), labels.to(device) 70 | optimizer.zero_grad() 71 | outputs = model(inputs) 72 | loss = criterion(outputs, labels) 73 | loss.backward() 74 | optimizer.step() 75 | running_loss += loss.item() 76 | 77 | print(f"Epoch [{epoch + 1}/{epochs}], Batch [{batch_idx + 1}/{total_batches}], Loss: {loss.item()}") 78 | 79 | writer.add_scalar('Train Loss', running_loss / total_batches, epoch) 80 | 81 | model.eval() 82 | correct = 0 83 | total = 0 84 | with torch.no_grad(): 85 | for inputs, labels in test_loader: 86 | inputs, labels = inputs.to(device), labels.to(device) 87 | outputs = model(inputs) 88 | _, predicted = torch.max(outputs.data, 1) 89 | total += labels.size(0) 90 | correct += (predicted == labels).sum().item() 91 | 92 | accuracy = 100 * correct / total 93 | 94 | writer.add_scalar('Test Accuracy', accuracy, epoch) 95 | if epoch/5 == 0: 96 | print(f"Epoch {epoch + 1}/{epochs}, Train Loss: {running_loss / total_batches}, Test Accuracy: {accuracy}%") 97 | 98 | scheduler.step() 99 | 100 | torch.save(model.state_dict(), weight_save_path + f'model_weights_epoch_{epoch + 1}.pth') 101 | 102 | if accuracy > best_accuracy: 103 | best_accuracy = accuracy 104 | best_model_weights = model.state_dict() 105 | 106 | torch.save(best_model_weights, weight_save_path + 'VGG16_best_model_weights.pth') 107 | 108 | writer.close() 109 | -------------------------------------------------------------------------------- /VGG19_train.py: -------------------------------------------------------------------------------- 1 | import os 2 | import torch 3 | import torch.nn as nn 4 | import torch.optim as optim 5 | from torchvision import transforms, datasets, models 6 | from torch.utils.tensorboard import SummaryWriter 7 | from torch.optim.lr_scheduler import StepLR 8 | from torchsummary import summary 9 | 10 | # 初始化TensorBoard的SummaryWriter 11 | writer = SummaryWriter() 12 | # 记录超参数(例如学习率) 13 | writer.add_hparams({'lr': 0.001, 'batch_size': 32}, {'hparam/accuracy': 0.95, 'hparam/loss': 0.1}) 14 | 15 | # 定义数据增强和加载数据 16 | transform = transforms.Compose([ 17 | transforms.Resize((224, 224)), 18 | transforms.ToTensor(), 19 | transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) 20 | ]) 21 | 22 | train_dataset = datasets.ImageFolder('../dataset_jpg/train', transform=transform) 23 | train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=32, shuffle=True) 24 | 25 | test_dataset = datasets.ImageFolder('../dataset_jpg/test', transform=transform) 26 | test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=32, shuffle=False) 27 | 28 | # 使用预训练的vgg19模型 29 | model = models.vgg19(pretrained=True) 30 | 31 | # 冻结模型的所有层(可选) 32 | for param in model.parameters(): 33 | param.requires_grad = False 34 | 35 | # 修改最后一个全连接层,以适应你的分类任务(3个类别) 36 | model.classifier[6] = nn.Linear(4096, 3) 37 | 38 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 39 | model.to(device) 40 | 41 | optimizer = optim.Adam(model.parameters(), lr=0.001) 42 | scheduler = StepLR(optimizer, step_size=5, gamma=0.1) 43 | 44 | 45 | criterion = nn.CrossEntropyLoss() 46 | 47 | # 初始化最佳精度和对应的模型权重 48 | best_accuracy = 0.0 49 | best_model_weights = None 50 | weight_save_path = '../weights/vgg19/' 51 | os.makedirs(weight_save_path, exist_ok=True) 52 | 53 | # 开始训练 54 | epochs = 30 55 | for epoch in range(epochs): 56 | model.train() 57 | running_loss = 0.0 58 | total_batches = len(train_loader) # 获取批次总数 59 | for batch_idx, (inputs, labels) in enumerate(train_loader): 60 | inputs, labels = inputs.to(device), labels.to(device) 61 | optimizer.zero_grad() 62 | outputs = model(inputs) 63 | loss = criterion(outputs, labels) 64 | loss.backward() 65 | optimizer.step() 66 | running_loss += loss.item() 67 | 68 | # 实时显示损失 69 | print(f"Epoch [{epoch + 1}/{epochs}], Batch [{batch_idx + 1}/{total_batches}], Loss: {loss.item()}") 70 | 71 | # 使用TensorBoard记录训练损失 72 | writer.add_scalar('Train Loss', running_loss / total_batches, epoch) 73 | 74 | # 在测试集上评估模型 75 | model.eval() 76 | correct = 0 77 | total = 0 78 | with torch.no_grad(): 79 | for inputs, labels in test_loader: 80 | inputs, labels = inputs.to(device), labels.to(device) 81 | outputs = model(inputs) 82 | _, predicted = torch.max(outputs.data, 1) 83 | total += labels.size(0) 84 | correct += (predicted == labels).sum().item() 85 | 86 | accuracy = 100 * correct / total 87 | 88 | # 使用TensorBoard记录测试精度 89 | writer.add_scalar('Test Accuracy', accuracy, epoch) 90 | 91 | print(f"Epoch {epoch + 1}/{epochs}, Train Loss: {running_loss / total_batches}, Test Accuracy: {accuracy}%") 92 | 93 | # 更新学习率 94 | scheduler.step() 95 | 96 | # 保存每轮训练的权重 97 | torch.save(model.state_dict(), weight_save_path + f'model_weights_epoch_{epoch + 1}.pth') 98 | 99 | # 更新最佳模型权重 100 | if accuracy > best_accuracy: 101 | best_accuracy = accuracy 102 | best_model_weights = model.state_dict() 103 | 104 | # 保存最佳权重 105 | torch.save(best_model_weights, weight_save_path + 'vgg19_best_model_weights.pth') 106 | 107 | # 关闭TensorBoard的SummaryWriter 108 | writer.close() 109 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | import torchvision 2 | from flask import Flask, render_template, request, session 3 | from PIL import Image 4 | import torch 5 | import torchvision.transforms as transforms 6 | from model.CNN import CNNModel # 导入你的模型定义 7 | from model.VGG16 import VGG16 8 | from model.VGG19 import VGG19 9 | import os 10 | import time 11 | from datetime import datetime 12 | 13 | app = Flask(__name__) 14 | app.config['SECRET_KEY'] = 'BIGC_204010218' 15 | import torchvision.models as models 16 | 17 | # 初始化模型映射 18 | available_models = { 19 | 'CNN': { 20 | 'model': CNNModel(), 21 | 'weight_path': './weights/CNN/CNN_best_model_weights.pth', 22 | }, 23 | 'VGG16': { 24 | 'model': VGG16(), 25 | 'weight_path': './weights/VGG16/VGG16_best_model_weights.pth', 26 | }, 27 | 'VGG19': { 28 | 'model': VGG19(), 29 | 'weight_path': './weights/VGG19/VGG19_best_model_weights.pth', 30 | }, 31 | 'InceptionNetV3': { 32 | 'model': models.inception_v3(pretrained=False), # 使用torchvision中的InceptionV3模型 33 | 'weight_path': './weights/InceptionNetV3/inceptionnet_best_model_weights.pth', 34 | }, 35 | } 36 | 37 | # 图像预处理 38 | transform = transforms.Compose([ 39 | transforms.Resize((224, 224)), 40 | transforms.ToTensor(), 41 | transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) 42 | ]) 43 | 44 | # 存储历史检测结果和上传图像的目录 45 | history_results = [] 46 | upload_dir = './static/uploads' # 存储上传图像的目录 47 | os.makedirs(upload_dir, exist_ok=True) 48 | 49 | 50 | @app.route('/', methods=['GET', 'POST']) 51 | def classify_image(): 52 | uploaded_image_url = None 53 | result = None 54 | selected_model = None 55 | uploaded_image_dir_name = None 56 | if request.method == 'POST': 57 | uploaded_file = request.files['file'] 58 | selected_model = request.form.get('model') # 获取用户选择的模型 59 | 60 | if uploaded_file.filename != '' and selected_model in available_models: 61 | print(uploaded_file) 62 | # 生成上传文件的唯一文件名 63 | timestamp = time.mktime(datetime.now().timetuple()) 64 | image_filename = os.path.join(upload_dir, f'{int(timestamp)}.jpg') 65 | 66 | # 保存上传的文件 67 | uploaded_file.save(image_filename) 68 | uploaded_image_dir = image_filename # 存储上传的图像路径 69 | print("保存文件" + str(uploaded_image_dir)) 70 | 71 | # 获取选定模型的模型对象和权重路径 72 | selected_model_info = available_models[selected_model] 73 | model = selected_model_info['model'] 74 | weight_path = selected_model_info['weight_path'] 75 | print(weight_path) 76 | 77 | # 使用选择的模型进行分类 78 | prediction = get_prediction(image_filename, model, weight_path) 79 | 80 | # 根据选择的模型生成对应的结果 81 | if prediction == 0: 82 | result = 'COVID-19' 83 | elif prediction == 1: 84 | result = 'NORMAL' 85 | elif prediction == 2: 86 | result = 'Viral Pneumonia' 87 | print(history_results) 88 | # 将结果添加到历史检测结果列表中 89 | uploaded_image_dir = uploaded_image_dir.replace("templates/", "") 90 | # 更新uploaded_image_url为图像的URL 91 | uploaded_image_url = f"{image_filename}" # 图像的URL 92 | history_results.append((uploaded_file.filename, selected_model, result, 93 | str(datetime.fromtimestamp(timestamp)), uploaded_image_url)) 94 | print(uploaded_file.filename) 95 | # 更新uploaded_image_url为图像的URL 96 | uploaded_image_url = f"{image_filename}" # 图像的URL 97 | # 将历史结果保存在session中 98 | session['history_results'] = history_results 99 | history_results.reverse() 100 | print(history_results) 101 | uploaded_image_dir_name = uploaded_file.filename 102 | 103 | return render_template('index.html', result=result, 104 | uploaded_image_url=uploaded_image_url, 105 | history_results=history_results, selected_model=selected_model, 106 | available_models=available_models, uploaded_image_dir=uploaded_image_dir_name) 107 | 108 | 109 | # 在 get_prediction 函数中,不需要再次创建模型实例 110 | def get_prediction(image_path, model, weight_path): 111 | image = Image.open(image_path) 112 | if image.mode != 'RGB': 113 | image = image.convert('RGB') # 如果不是RGB,转换为RGB 114 | image = transform(image).unsqueeze(0) 115 | 116 | # 加载模型的预训练权重 117 | checkpoint = torch.load(weight_path, map_location='cpu') 118 | model.load_state_dict(checkpoint) 119 | model.eval() # 设置模型为评估模式 120 | 121 | # 使用模型进行分类 122 | with torch.no_grad(): 123 | output = model(image) 124 | _, predicted = torch.max(output, 1) 125 | 126 | return predicted.item() 127 | 128 | 129 | if __name__ == '__main__': 130 | app.run(debug=True) 131 | -------------------------------------------------------------------------------- /model/CNN.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | from torchvision import models 4 | 5 | 6 | # 定义CNN模型 7 | class CNNModel(nn.Module): 8 | def __init__(self): 9 | super(CNNModel, self).__init__() 10 | self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1) 11 | self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1) 12 | self.fc1 = nn.Linear(64 * 56 * 56, 128) 13 | self.fc2 = nn.Linear(128, 3) # 3个类别 14 | 15 | def forward(self, x): 16 | x = torch.relu(self.conv1(x)) 17 | x = torch.relu(self.conv2(x)) 18 | x = torch.nn.functional.avg_pool2d(x, 4) # 添加全局平均池化层,将尺寸缩小到 (64, 14, 14) 19 | x = x.view(x.size(0), -1) 20 | x = torch.relu(self.fc1(x)) 21 | x = self.fc2(x) 22 | return x 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /model/InceptionNetV3.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | from torchvision import models 4 | 5 | 6 | # 定义InceptionNetV3模型 7 | class InceptionNetV3(nn.Module): 8 | def __init__(self, num_classes=3): 9 | super(InceptionNetV3, self).__init__() 10 | inception = models.inception_v3(pretrained=True) # 加载预训练的InceptionNetV3模型 11 | # 冻结所有层 12 | for param in inception.parameters(): 13 | param.requires_grad = False 14 | # 从InceptionNetV3模型中提取特征部分(卷积层) 15 | self.features = inception.features 16 | # 添加自定义的分类层 17 | self.classifier = nn.Sequential( 18 | nn.AdaptiveAvgPool2d((1, 1)), 19 | nn.Flatten(), 20 | nn.Linear(2048, num_classes) 21 | ) 22 | 23 | def forward(self, x): 24 | x = self.features(x) 25 | x = self.classifier(x) 26 | return x 27 | -------------------------------------------------------------------------------- /model/VGG16.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | from torchvision import models 4 | 5 | 6 | # 定义VGG16模型 7 | class VGG16(nn.Module): 8 | def __init__(self, num_classes=3): 9 | super(VGG16, self).__init__() 10 | vgg16 = models.vgg16(pretrained=False) # 加载预训练的VGG16模型 11 | # 冻结所有层 12 | for param in vgg16.parameters(): 13 | param.requires_grad = False 14 | # 从VGG16模型中提取特征部分(卷积层) 15 | self.features = vgg16.features 16 | # 添加自定义的分类层 17 | self.classifier = nn.Sequential( 18 | nn.Linear(512 * 7 * 7, 4096), 19 | nn.ReLU(True), 20 | nn.Dropout(), 21 | nn.Linear(4096, 4096), 22 | nn.ReLU(True), 23 | nn.Dropout(), 24 | nn.Linear(4096, num_classes) 25 | ) 26 | 27 | def forward(self, x): 28 | x = self.features(x) 29 | x = x.view(x.size(0), -1) 30 | x = self.classifier(x) 31 | return x 32 | -------------------------------------------------------------------------------- /model/VGG19.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | from torchvision import models 4 | 5 | 6 | # 定义VGG19模型 7 | class VGG19(nn.Module): 8 | def __init__(self, num_classes=3): 9 | super(VGG19, self).__init__() 10 | vgg19 = models.vgg19(pretrained=False) # 加载预训练的VGG19模型 11 | # 冻结所有层 12 | for param in vgg19.parameters(): 13 | param.requires_grad = False 14 | # 从VGG19模型中提取特征部分(卷积层) 15 | self.features = vgg19.features 16 | # 添加自定义的分类层 17 | self.classifier = nn.Sequential( 18 | nn.Linear(512 * 7 * 7, 4096), 19 | nn.ReLU(True), 20 | nn.Dropout(), 21 | nn.Linear(4096, 4096), 22 | nn.ReLU(True), 23 | nn.Dropout(), 24 | nn.Linear(4096, num_classes) 25 | ) 26 | 27 | def forward(self, x): 28 | x = self.features(x) 29 | x = x.view(x.size(0), -1) 30 | x = self.classifier(x) 31 | return x 32 | -------------------------------------------------------------------------------- /model/__pycache__/CNN.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/model/__pycache__/CNN.cpython-39.pyc -------------------------------------------------------------------------------- /model/__pycache__/InceptionNetV3.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/model/__pycache__/InceptionNetV3.cpython-39.pyc -------------------------------------------------------------------------------- /model/__pycache__/VGG16.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/model/__pycache__/VGG16.cpython-39.pyc -------------------------------------------------------------------------------- /model/__pycache__/VGG19.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/model/__pycache__/VGG19.cpython-39.pyc -------------------------------------------------------------------------------- /static/uploads/1695365043.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695365043.jpg -------------------------------------------------------------------------------- /static/uploads/1695365087.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695365087.jpg -------------------------------------------------------------------------------- /static/uploads/1695365100.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695365100.jpg -------------------------------------------------------------------------------- /static/uploads/1695365109.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695365109.jpg -------------------------------------------------------------------------------- /static/uploads/1695365151.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695365151.jpg -------------------------------------------------------------------------------- /static/uploads/1695365182.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695365182.jpg -------------------------------------------------------------------------------- /static/uploads/1695365270.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695365270.jpg -------------------------------------------------------------------------------- /static/uploads/1695365308.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695365308.jpg -------------------------------------------------------------------------------- /static/uploads/1695365324.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695365324.jpg -------------------------------------------------------------------------------- /static/uploads/1695365421.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695365421.jpg -------------------------------------------------------------------------------- /static/uploads/1695365474.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695365474.jpg -------------------------------------------------------------------------------- /static/uploads/1695365599.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695365599.jpg -------------------------------------------------------------------------------- /static/uploads/1695365639.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695365639.jpg -------------------------------------------------------------------------------- /static/uploads/1695365736.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695365736.jpg -------------------------------------------------------------------------------- /static/uploads/1695365806.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695365806.jpg -------------------------------------------------------------------------------- /static/uploads/1695365880.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695365880.jpg -------------------------------------------------------------------------------- /static/uploads/1695365913.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695365913.jpg -------------------------------------------------------------------------------- /static/uploads/1695365973.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695365973.jpg -------------------------------------------------------------------------------- /static/uploads/1695366019.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695366019.jpg -------------------------------------------------------------------------------- /static/uploads/1695366027.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695366027.jpg -------------------------------------------------------------------------------- /static/uploads/1695368807.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695368807.jpg -------------------------------------------------------------------------------- /static/uploads/1695369609.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695369609.jpg -------------------------------------------------------------------------------- /static/uploads/1695369624.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695369624.jpg -------------------------------------------------------------------------------- /static/uploads/1695370527.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695370527.jpg -------------------------------------------------------------------------------- /static/uploads/1695370531.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695370531.jpg -------------------------------------------------------------------------------- /static/uploads/1695370543.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695370543.jpg -------------------------------------------------------------------------------- /static/uploads/1695370557.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695370557.jpg -------------------------------------------------------------------------------- /static/uploads/1695370578.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695370578.jpg -------------------------------------------------------------------------------- /static/uploads/1695370605.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695370605.jpg -------------------------------------------------------------------------------- /static/uploads/1695372115.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695372115.jpg -------------------------------------------------------------------------------- /static/uploads/1695372169.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695372169.jpg -------------------------------------------------------------------------------- /static/uploads/1695372820.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695372820.jpg -------------------------------------------------------------------------------- /static/uploads/1695372825.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695372825.jpg -------------------------------------------------------------------------------- /static/uploads/1695377787.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695377787.jpg -------------------------------------------------------------------------------- /static/uploads/1695377805.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695377805.jpg -------------------------------------------------------------------------------- /static/uploads/1695379143.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/static/uploads/1695379143.jpg -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 新冠肺炎检测 5 | 6 | 7 | 8 | 9 |

新冠肺炎检测

10 | 11 |

上传CT图像

12 |
13 | 14 | 20 | 21 |
22 | 23 |

检测结果

24 | {% if result %} 25 |

文件名:{{ uploaded_image_dir }}

26 |

检测结果: 27 | {% if result == 'Viral Pneumonia' or result == 'COVID-19' %} 28 | {{ result }} 29 | {% else %} 30 | {{ result }} 31 | {% endif %} 32 |

33 | 上传图像 34 | {% endif %} 35 | 36 |

历史检测记录

37 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /templates/index_1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 图像分类 6 | 7 | 8 |

上传要分类的图像

9 |
10 | 11 | 12 |
13 | 14 | 15 | {% if uploaded_image %} 16 |

目前上传的图像:

17 | Uploaded Image 18 | {% endif %} 19 | 20 | 21 | {% if result %} 22 |

分类结果: {{ result }}

23 | {% endif %} 24 | 25 | 26 |

历史检测结果:

27 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /train/CNN_show.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | from tensorboardX import SummaryWriter 4 | 5 | 6 | class CNNModel(nn.Module): 7 | def __init__(self): 8 | super(CNNModel, self).__init__() 9 | self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1) 10 | self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1) 11 | self.fc1 = nn.Linear(64 * 56 * 56, 128) 12 | self.fc2 = nn.Linear(128, 3) # 3个类别 13 | 14 | def forward(self, x): 15 | x = torch.relu(self.conv1(x)) 16 | x = torch.relu(self.conv2(x)) 17 | x = torch.nn.functional.avg_pool2d(x, 4) # 添加全局平均池化层,将尺寸缩小到 (64, 14, 14) 18 | x = x.view(x.size(0), -1) 19 | x = torch.relu(self.fc1(x)) 20 | x = self.fc2(x) 21 | return x 22 | 23 | 24 | -------------------------------------------------------------------------------- /train/CNN_train.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import torch 4 | import torch.nn as nn 5 | import torch.optim as optim 6 | from torchvision import transforms, datasets 7 | from torch.utils.tensorboard import SummaryWriter 8 | from torch.optim.lr_scheduler import StepLR 9 | from torchsummary import summary 10 | 11 | # 初始化TensorBoard的SummaryWriter 12 | writer = SummaryWriter() 13 | # 记录超参数(例如学习率) 14 | writer.add_hparams({'lr': 0.001, 'batch_size': 32}, {'hparam/accuracy': 0.95, 'hparam/loss': 0.1}) 15 | 16 | # 定义数据增强和加载数据 17 | transform = transforms.Compose([ 18 | transforms.Resize((224, 224)), 19 | transforms.ToTensor(), 20 | transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) 21 | ]) 22 | 23 | train_dataset = datasets.ImageFolder('../dataset_jpg/train', transform=transform) 24 | train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=32, shuffle=True) 25 | 26 | test_dataset = datasets.ImageFolder('../dataset_jpg/test', transform=transform) 27 | test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=32, shuffle=False) 28 | 29 | 30 | # 定义CNN模型 31 | class CNNModel(nn.Module): 32 | def __init__(self): 33 | super(CNNModel, self).__init__() 34 | self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1) 35 | self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1) 36 | self.fc1 = nn.Linear(64 * 56 * 56, 128) 37 | self.fc2 = nn.Linear(128, 3) # 3个类别 38 | 39 | def forward(self, x): 40 | x = torch.relu(self.conv1(x)) 41 | x = torch.relu(self.conv2(x)) 42 | x = torch.nn.functional.avg_pool2d(x, 4) # 添加全局平均池化层,将尺寸缩小到 (64, 14, 14) 43 | x = x.view(x.size(0), -1) 44 | x = torch.relu(self.fc1(x)) 45 | x = self.fc2(x) 46 | return x 47 | 48 | 49 | # 初始化模型和优化器 50 | model = CNNModel() 51 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 52 | device = torch.device("cuda") 53 | model.to(device) 54 | optimizer = optim.Adam(model.parameters(), lr=0.001) 55 | scheduler = StepLR(optimizer, step_size=5, gamma=0.1) # 学习率调度器 56 | 57 | # 打印模型摘要 58 | # summary(model, (3, 224, 224), device=device) 59 | print(model) 60 | 61 | criterion = nn.CrossEntropyLoss() 62 | 63 | # 初始化最佳精度和对应的模型权重 64 | best_accuracy = 0.0 65 | best_model_weights = None 66 | weight_save_path = '../weights/CNN/' 67 | os.makedirs(weight_save_path, exist_ok=True) 68 | # 开始训练 69 | epochs = 30 70 | for epoch in range(epochs): 71 | model.train() 72 | running_loss = 0.0 73 | total_batches = len(train_loader) # 获取批次总数 74 | for batch_idx, (inputs, labels) in enumerate(train_loader): 75 | inputs, labels = inputs.to(device), labels.to(device) 76 | optimizer.zero_grad() 77 | outputs = model(inputs) 78 | loss = criterion(outputs, labels) 79 | loss.backward() 80 | optimizer.step() 81 | running_loss += loss.item() 82 | 83 | # 实时显示损失 84 | print(f"Epoch [{epoch + 1}/{epochs}], Batch [{batch_idx + 1}/{total_batches}], Loss: {loss.item()}") 85 | 86 | # 使用TensorBoard记录训练损失 87 | writer.add_scalar('Train Loss', running_loss / total_batches, epoch) 88 | 89 | # 在测试集上评估模型 90 | model.eval() 91 | correct = 0 92 | total = 0 93 | with torch.no_grad(): 94 | for inputs, labels in test_loader: 95 | inputs, labels = inputs.to(device), labels.to(device) 96 | outputs = model(inputs) 97 | _, predicted = torch.max(outputs.data, 1) 98 | total += labels.size(0) 99 | correct += (predicted == labels).sum().item() 100 | 101 | accuracy = 100 * correct / total 102 | 103 | # 使用TensorBoard记录测试精度 104 | writer.add_scalar('Test Accuracy', accuracy, epoch) 105 | 106 | print(f"Epoch {epoch + 1}/{epochs}, Train Loss: {running_loss / total_batches}, Test Accuracy: {accuracy}%") 107 | 108 | # 更新学习率 109 | scheduler.step() 110 | 111 | # 保存每轮训练的权重 112 | torch.save(model.state_dict(), weight_save_path + f'model_weights_epoch_{epoch + 1}.pth') 113 | 114 | # 更新最佳模型权重 115 | if accuracy > best_accuracy: 116 | best_accuracy = accuracy 117 | best_model_weights = model.state_dict() 118 | 119 | # 保存最佳权重 120 | torch.save(best_model_weights, weight_save_path + 'CNN_best_model_weights.pth') 121 | 122 | # 关闭TensorBoard的SummaryWriter 123 | writer.close() 124 | -------------------------------------------------------------------------------- /train/InceptionNetV3_train.py: -------------------------------------------------------------------------------- 1 | import os 2 | import torch 3 | import torch.nn as nn 4 | import torch.optim as optim 5 | from torchvision import transforms, datasets, models 6 | from torch.utils.tensorboard import SummaryWriter 7 | from torch.optim.lr_scheduler import StepLR 8 | from torchsummary import summary 9 | 10 | # 初始化TensorBoard的SummaryWriter 11 | writer = SummaryWriter() 12 | # 记录超参数 13 | writer.add_hparams({'lr': 0.001, 'batch_size': 32}, {'hparam/accuracy': 0.95, 'hparam/loss': 0.1}) 14 | 15 | # 定义数据增强和加载数据 16 | transform = transforms.Compose([ 17 | transforms.Resize((299, 299)), # InceptionNet需要输入大小为(299, 299) 18 | transforms.ToTensor(), 19 | transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) 20 | ]) 21 | 22 | train_dataset = datasets.ImageFolder('../dataset_jpg/train', transform=transform) 23 | train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=32, shuffle=True) 24 | 25 | test_dataset = datasets.ImageFolder('../dataset_jpg/test', transform=transform) 26 | test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=32, shuffle=False) 27 | 28 | # 使用预训练的InceptionNet模型 29 | model = models.inception_v3(pretrained=True) 30 | 31 | # 修改最后一个全连接层,以适应您的分类任务(3个类别) 32 | num_features = model.fc.in_features 33 | model.fc = nn.Linear(num_features, 3) # 将3更改为您的类别数 34 | 35 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 36 | model.to(device) 37 | 38 | optimizer = optim.Adam(model.parameters(), lr=0.001) 39 | scheduler = StepLR(optimizer, step_size=5, gamma=0.1) 40 | 41 | # 打印模型摘要 42 | print(model) 43 | 44 | criterion = nn.CrossEntropyLoss() 45 | 46 | # 初始化最佳精度和对应的模型权重 47 | best_accuracy = 0.0 48 | best_model_weights = None 49 | weight_save_path = '../weights/inceptionnet/' 50 | os.makedirs(weight_save_path, exist_ok=True) 51 | 52 | # 开始训练 53 | epochs = 30 54 | for epoch in range(epochs): 55 | model.train() 56 | running_loss = 0.0 57 | total_batches = len(train_loader) # 获取批次总数 58 | for batch_idx, (inputs, labels) in enumerate(train_loader): 59 | inputs, labels = inputs.to(device), labels.to(device) 60 | optimizer.zero_grad() 61 | # 提取主要的模型输出 62 | outputs, _ = model(inputs) 63 | loss = criterion(outputs, labels) 64 | loss.backward() 65 | optimizer.step() 66 | running_loss += loss.item() 67 | 68 | # 实时显示损失 69 | print(f"Epoch [{epoch + 1}/{epochs}], Batch [{batch_idx + 1}/{total_batches}], Loss: {loss.item()}") 70 | 71 | # 使用TensorBoard记录训练损失 72 | writer.add_scalar('Train Loss', running_loss / total_batches, epoch) 73 | 74 | # 在测试集上评估模型 75 | model.eval() 76 | correct = 0 77 | total = 0 78 | with torch.no_grad(): 79 | for inputs, labels in test_loader: 80 | inputs, labels = inputs.to(device), labels.to(device) 81 | outputs = model(inputs) 82 | _, predicted = torch.max(outputs.data, 1) 83 | total += labels.size(0) 84 | correct += (predicted == labels).sum().item() 85 | 86 | accuracy = 100 * correct / total 87 | 88 | # 使用TensorBoard记录测试精度 89 | writer.add_scalar('Test Accuracy', accuracy, epoch) 90 | 91 | print(f"Epoch {epoch + 1}/{epochs}, Train Loss: {running_loss / total_batches}, Test Accuracy: {accuracy}%") 92 | 93 | # 更新学习率 94 | scheduler.step() 95 | 96 | # 保存每轮训练的权重 97 | torch.save(model.state_dict(), weight_save_path + f'model_weights_epoch_{epoch + 1}.pth') 98 | 99 | # 更新最佳模型权重 100 | if accuracy > best_accuracy: 101 | best_accuracy = accuracy 102 | best_model_weights = model.state_dict() 103 | 104 | # 保存最佳权重 105 | torch.save(best_model_weights, weight_save_path + 'inceptionnet_best_model_weights.pth') 106 | 107 | # 关闭TensorBoard的SummaryWriter 108 | writer.close() 109 | -------------------------------------------------------------------------------- /train/ResNet_Train.py: -------------------------------------------------------------------------------- 1 | import os 2 | import torch 3 | import torch.nn as nn 4 | import torch.optim as optim 5 | from torchvision import transforms, datasets, models 6 | from torch.utils.tensorboard import SummaryWriter 7 | from torch.optim.lr_scheduler import StepLR 8 | 9 | # 初始化TensorBoard的SummaryWriter 10 | writer = SummaryWriter() 11 | # 定义数据增强和加载数据 12 | transform = transforms.Compose([ 13 | transforms.Resize((224, 224)), 14 | transforms.ToTensor(), 15 | transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) 16 | ]) 17 | 18 | train_dataset = datasets.ImageFolder('../dataset_jpg/train', transform=transform) 19 | train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=32, shuffle=True) 20 | 21 | test_dataset = datasets.ImageFolder('../dataset_jpg/test', transform=transform) 22 | test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=32, shuffle=False) 23 | 24 | # 设置预训练权重文件的保存路径 25 | pretrained_weights_dir = 'pre-training weights' 26 | os.makedirs(pretrained_weights_dir, exist_ok=True) 27 | 28 | # 检查是否存在预训练权重文件,如果不存在,则下载并保存 29 | pretrained_weights_path = os.path.join(pretrained_weights_dir, 'ResNet18.pth') 30 | if not os.path.exists(pretrained_weights_path): 31 | print(f"Downloading pretrained weights to {pretrained_weights_path}...") 32 | ResNet18 = models.resnet18(pretrained=True) 33 | torch.save(ResNet18.state_dict(), pretrained_weights_path) 34 | print("Pretrained weights downloaded and saved.") 35 | 36 | # 使用预训练的ResNet18模型 37 | model = models.ResNet18(pretrained=True) # 改为False,不使用预训练权重,将从头开始训练 38 | 39 | # 加载判定预训练权重文件 40 | if os.path.exists(pretrained_weights_path): 41 | pretrained_weights = torch.load(pretrained_weights_path) 42 | model.load_state_dict(pretrained_weights) 43 | else: 44 | print(f"Pretrained weights not found at '{pretrained_weights_path}'. Training from scratch.") 45 | 46 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 47 | model.to(device) 48 | optimizer = optim.Adam(model.parameters(), lr=0.001) 49 | scheduler = StepLR(optimizer, step_size=5, gamma=0.1) # 学习率调度器 50 | 51 | # 打印模型摘要 52 | # summary(model, (3, 224, 224), device=device) 53 | print(model) 54 | 55 | criterion = nn.CrossEntropyLoss() 56 | 57 | # 初始化最佳精度和对应的模型权重 58 | best_accuracy = 0.0 59 | best_model_weights = None 60 | weight_save_path = '../weights/ResNet18/' 61 | os.makedirs(weight_save_path, exist_ok=True) 62 | 63 | # 开始训练 64 | epochs = 10 65 | for epoch in range(epochs): 66 | model.train() 67 | running_loss = 0.0 68 | total_batches = len(train_loader) # 获取批次总数 69 | for batch_idx, (inputs, labels) in enumerate(train_loader): 70 | inputs, labels = inputs.to(device), labels.to(device) 71 | optimizer.zero_grad() 72 | outputs = model(inputs) 73 | loss = criterion(outputs, labels) 74 | loss.backward() 75 | optimizer.step() 76 | running_loss += loss.item() 77 | 78 | # 实时显示损失 79 | print(f"Epoch [{epoch + 1}/{epochs}], Batch [{batch_idx + 1}/{total_batches}], Loss: {loss.item()}") 80 | 81 | # 使用TensorBoard记录训练损失 82 | writer.add_scalar('Train Loss', running_loss / total_batches, epoch) 83 | 84 | # 在测试集上评估模型 85 | model.eval() 86 | correct = 0 87 | total = 0 88 | with torch.no_grad(): 89 | for inputs, labels in test_loader: 90 | inputs, labels = inputs.to(device), labels.to(device) 91 | outputs = model(inputs) 92 | _, predicted = torch.max(outputs.data, 1) 93 | total += labels.size(0) 94 | correct += (predicted == labels).sum().item() 95 | 96 | accuracy = 100 * correct / total 97 | 98 | # 使用TensorBoard记录测试精度 99 | writer.add_scalar('Test Accuracy', accuracy, epoch) 100 | 101 | print(f"Epoch {epoch + 1}/{epochs}, Train Loss: {running_loss / total_batches}, Test Accuracy: {accuracy}%") 102 | 103 | # 更新学习率 104 | scheduler.step() 105 | 106 | # 保存每轮训练的权重 107 | torch.save(model.state_dict(), weight_save_path+f'model_weights_epoch_{epoch + 1}.pth') 108 | 109 | # 更新最佳模型权重 110 | if accuracy > best_accuracy: 111 | best_accuracy = accuracy 112 | best_model_weights = model.state_dict() 113 | 114 | # 保存最佳权重 115 | torch.save(best_model_weights, weight_save_path+'ResNet18_best_model_weights.pth') 116 | 117 | # 关闭TensorBoard的SummaryWriter 118 | writer.close() 119 | -------------------------------------------------------------------------------- /train/VGG16_train.py: -------------------------------------------------------------------------------- 1 | import os 2 | import torch 3 | import torch.nn as nn 4 | import torch.optim as optim 5 | from torchvision import transforms, datasets 6 | from torch.utils.tensorboard import SummaryWriter 7 | from torch.optim.lr_scheduler import StepLR 8 | import torchvision.models as models 9 | import torch.utils.model_zoo as model_zoo 10 | 11 | # 指定预训练权重文件路径 12 | pretrained_weights_path = './pre-trained weights/VGG16.pth' 13 | 14 | # 初始化TensorBoard的SummaryWriter 15 | writer = SummaryWriter(log_dir='./logs') 16 | 17 | # 定义数据增强和加载数据 18 | transform = transforms.Compose([ 19 | transforms.Resize((224, 224)), 20 | transforms.ToTensor(), 21 | transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) 22 | ]) 23 | 24 | train_dataset = datasets.ImageFolder('../dataset_jpg/train', transform=transform) 25 | train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=32, shuffle=True) 26 | 27 | test_dataset = datasets.ImageFolder('../dataset_jpg/test', transform=transform) 28 | test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=32, shuffle=False) 29 | 30 | # 使用自定义预训练权重路径或下载到pretrained_weights_path 31 | if not os.path.exists(pretrained_weights_path): 32 | # 下载VGG16预训练权重 33 | print("Downloading VGG16 pretrained weights...") 34 | model_url = "https://download.pytorch.org/models/vgg16-397923af.pth" 35 | model_zoo.load_url(model_url, model_dir='./pre-trained weights/vgg16.pth') 36 | 37 | # 使用预训练的VGG16模型 38 | model = models.vgg16(pretrained=False) # 不使用内置的预训练权重 39 | model.load_state_dict(torch.load(pretrained_weights_path)) # 加载自定义预训练权重 40 | 41 | # 修改最后一个全连接层,以适应分类任务(3个类别) 42 | model.classifier[6] = nn.Linear(4096, 3) 43 | 44 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 45 | model.to(device) 46 | 47 | optimizer = optim.Adam(model.parameters(), lr=0.001) 48 | scheduler = StepLR(optimizer, step_size=5, gamma=0.1) 49 | 50 | # 打印模型摘要 51 | # summary(model, (3, 224, 224), device=device) 52 | print(model) 53 | 54 | criterion = nn.CrossEntropyLoss() 55 | 56 | # 初始化最佳精度和对应的模型权重 57 | best_accuracy = 0.0 58 | best_model_weights = None 59 | weight_save_path = '../weights/VGG16/' 60 | os.makedirs(weight_save_path, exist_ok=True) 61 | 62 | # 开始训练 63 | epochs = 30 64 | for epoch in range(epochs): 65 | model.train() 66 | running_loss = 0.0 67 | total_batches = len(train_loader) 68 | for batch_idx, (inputs, labels) in enumerate(train_loader): 69 | inputs, labels = inputs.to(device), labels.to(device) 70 | optimizer.zero_grad() 71 | outputs = model(inputs) 72 | loss = criterion(outputs, labels) 73 | loss.backward() 74 | optimizer.step() 75 | running_loss += loss.item() 76 | 77 | print(f"Epoch [{epoch + 1}/{epochs}], Batch [{batch_idx + 1}/{total_batches}], Loss: {loss.item()}") 78 | 79 | writer.add_scalar('Train Loss', running_loss / total_batches, epoch) 80 | 81 | model.eval() 82 | correct = 0 83 | total = 0 84 | with torch.no_grad(): 85 | for inputs, labels in test_loader: 86 | inputs, labels = inputs.to(device), labels.to(device) 87 | outputs = model(inputs) 88 | _, predicted = torch.max(outputs.data, 1) 89 | total += labels.size(0) 90 | correct += (predicted == labels).sum().item() 91 | 92 | accuracy = 100 * correct / total 93 | 94 | writer.add_scalar('Test Accuracy', accuracy, epoch) 95 | if epoch/5 == 0: 96 | print(f"Epoch {epoch + 1}/{epochs}, Train Loss: {running_loss / total_batches}, Test Accuracy: {accuracy}%") 97 | 98 | scheduler.step() 99 | 100 | torch.save(model.state_dict(), weight_save_path + f'model_weights_epoch_{epoch + 1}.pth') 101 | 102 | if accuracy > best_accuracy: 103 | best_accuracy = accuracy 104 | best_model_weights = model.state_dict() 105 | 106 | torch.save(best_model_weights, weight_save_path + 'VGG16_best_model_weights.pth') 107 | 108 | writer.close() 109 | -------------------------------------------------------------------------------- /train/VGG19_train.py: -------------------------------------------------------------------------------- 1 | import os 2 | import torch 3 | import torch.nn as nn 4 | import torch.optim as optim 5 | from torchvision import transforms, datasets, models 6 | from torch.utils.tensorboard import SummaryWriter 7 | from torch.optim.lr_scheduler import StepLR 8 | from torchsummary import summary 9 | 10 | # 初始化TensorBoard的SummaryWriter 11 | writer = SummaryWriter() 12 | # 记录超参数(例如学习率) 13 | writer.add_hparams({'lr': 0.001, 'batch_size': 32}, {'hparam/accuracy': 0.95, 'hparam/loss': 0.1}) 14 | 15 | # 定义数据增强和加载数据 16 | transform = transforms.Compose([ 17 | transforms.Resize((224, 224)), 18 | transforms.ToTensor(), 19 | transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) 20 | ]) 21 | 22 | train_dataset = datasets.ImageFolder('../dataset_jpg/train', transform=transform) 23 | train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=32, shuffle=True) 24 | 25 | test_dataset = datasets.ImageFolder('../dataset_jpg/test', transform=transform) 26 | test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=32, shuffle=False) 27 | 28 | # 使用预训练的vgg19模型 29 | model = models.vgg19(pretrained=True) 30 | 31 | # 冻结模型的所有层(可选) 32 | for param in model.parameters(): 33 | param.requires_grad = False 34 | 35 | # 修改最后一个全连接层,以适应你的分类任务(3个类别) 36 | model.classifier[6] = nn.Linear(4096, 3) 37 | 38 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 39 | model.to(device) 40 | 41 | optimizer = optim.Adam(model.parameters(), lr=0.001) 42 | scheduler = StepLR(optimizer, step_size=5, gamma=0.1) 43 | 44 | 45 | criterion = nn.CrossEntropyLoss() 46 | 47 | # 初始化最佳精度和对应的模型权重 48 | best_accuracy = 0.0 49 | best_model_weights = None 50 | weight_save_path = '../weights/vgg19/' 51 | os.makedirs(weight_save_path, exist_ok=True) 52 | 53 | # 开始训练 54 | epochs = 30 55 | for epoch in range(epochs): 56 | model.train() 57 | running_loss = 0.0 58 | total_batches = len(train_loader) # 获取批次总数 59 | for batch_idx, (inputs, labels) in enumerate(train_loader): 60 | inputs, labels = inputs.to(device), labels.to(device) 61 | optimizer.zero_grad() 62 | outputs = model(inputs) 63 | loss = criterion(outputs, labels) 64 | loss.backward() 65 | optimizer.step() 66 | running_loss += loss.item() 67 | 68 | # 实时显示损失 69 | print(f"Epoch [{epoch + 1}/{epochs}], Batch [{batch_idx + 1}/{total_batches}], Loss: {loss.item()}") 70 | 71 | # 使用TensorBoard记录训练损失 72 | writer.add_scalar('Train Loss', running_loss / total_batches, epoch) 73 | 74 | # 在测试集上评估模型 75 | model.eval() 76 | correct = 0 77 | total = 0 78 | with torch.no_grad(): 79 | for inputs, labels in test_loader: 80 | inputs, labels = inputs.to(device), labels.to(device) 81 | outputs = model(inputs) 82 | _, predicted = torch.max(outputs.data, 1) 83 | total += labels.size(0) 84 | correct += (predicted == labels).sum().item() 85 | 86 | accuracy = 100 * correct / total 87 | 88 | # 使用TensorBoard记录测试精度 89 | writer.add_scalar('Test Accuracy', accuracy, epoch) 90 | 91 | print(f"Epoch {epoch + 1}/{epochs}, Train Loss: {running_loss / total_batches}, Test Accuracy: {accuracy}%") 92 | 93 | # 更新学习率 94 | scheduler.step() 95 | 96 | # 保存每轮训练的权重 97 | torch.save(model.state_dict(), weight_save_path + f'model_weights_epoch_{epoch + 1}.pth') 98 | 99 | # 更新最佳模型权重 100 | if accuracy > best_accuracy: 101 | best_accuracy = accuracy 102 | best_model_weights = model.state_dict() 103 | 104 | # 保存最佳权重 105 | torch.save(best_model_weights, weight_save_path + 'vgg19_best_model_weights.pth') 106 | 107 | # 关闭TensorBoard的SummaryWriter 108 | writer.close() 109 | -------------------------------------------------------------------------------- /train/logs/events.out.tfevents.1695382060.DESKTOP-MQ6GNBS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/train/logs/events.out.tfevents.1695382060.DESKTOP-MQ6GNBS -------------------------------------------------------------------------------- /train/logs/events.out.tfevents.1695382118.DESKTOP-MQ6GNBS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/train/logs/events.out.tfevents.1695382118.DESKTOP-MQ6GNBS -------------------------------------------------------------------------------- /train/logs/events.out.tfevents.1695382165.DESKTOP-MQ6GNBS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/train/logs/events.out.tfevents.1695382165.DESKTOP-MQ6GNBS -------------------------------------------------------------------------------- /train/runs/CNN_Sep19_12-44-48/events.out.tfevents.1695098688.DESKTOP-MQ6GNBS.20108.0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/train/runs/CNN_Sep19_12-44-48/events.out.tfevents.1695098688.DESKTOP-MQ6GNBS.20108.0 -------------------------------------------------------------------------------- /train/runs/IneceptionNet3_Sep19_16-40-11/1695112811.2165155/events.out.tfevents.1695112811.DESKTOP-MQ6GNBS.3080.1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/train/runs/IneceptionNet3_Sep19_16-40-11/1695112811.2165155/events.out.tfevents.1695112811.DESKTOP-MQ6GNBS.3080.1 -------------------------------------------------------------------------------- /train/runs/IneceptionNet3_Sep19_16-40-11/events.out.tfevents.1695112811.DESKTOP-MQ6GNBS.3080.0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/train/runs/IneceptionNet3_Sep19_16-40-11/events.out.tfevents.1695112811.DESKTOP-MQ6GNBS.3080.0 -------------------------------------------------------------------------------- /train/runs/Sep22_16-30-59_DESKTOP-MQ6GNBS/1695371459.676054/events.out.tfevents.1695371459.DESKTOP-MQ6GNBS.5652.1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/train/runs/Sep22_16-30-59_DESKTOP-MQ6GNBS/1695371459.676054/events.out.tfevents.1695371459.DESKTOP-MQ6GNBS.5652.1 -------------------------------------------------------------------------------- /train/runs/Sep22_16-30-59_DESKTOP-MQ6GNBS/events.out.tfevents.1695371459.DESKTOP-MQ6GNBS.5652.0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/train/runs/Sep22_16-30-59_DESKTOP-MQ6GNBS/events.out.tfevents.1695371459.DESKTOP-MQ6GNBS.5652.0 -------------------------------------------------------------------------------- /train/runs/Sep22_19-29-26_DESKTOP-MQ6GNBSCNNModel/events.out.tfevents.1695382166.DESKTOP-MQ6GNBS.20932.0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/train/runs/Sep22_19-29-26_DESKTOP-MQ6GNBSCNNModel/events.out.tfevents.1695382166.DESKTOP-MQ6GNBS.20932.0 -------------------------------------------------------------------------------- /train/runs/VGG16_WithoutPre_Trained_Sep19_13-22-35/events.out.tfevents.1695100955.DESKTOP-MQ6GNBS.14800.0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/train/runs/VGG16_WithoutPre_Trained_Sep19_13-22-35/events.out.tfevents.1695100955.DESKTOP-MQ6GNBS.14800.0 -------------------------------------------------------------------------------- /train/runs/VGG19_WithPre_Trained_Sep19_15-38-29/1695109109.3126585/events.out.tfevents.1695109109.DESKTOP-MQ6GNBS.25540.1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/train/runs/VGG19_WithPre_Trained_Sep19_15-38-29/1695109109.3126585/events.out.tfevents.1695109109.DESKTOP-MQ6GNBS.25540.1 -------------------------------------------------------------------------------- /train/runs/VGG19_WithPre_Trained_Sep19_15-38-29/events.out.tfevents.1695109109.DESKTOP-MQ6GNBS.25540.0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilverGarros/BIGC_COVID19_CLS/6742d51d23a473ca7b3dd5bf81bdb89af2afc10b/train/runs/VGG19_WithPre_Trained_Sep19_15-38-29/events.out.tfevents.1695109109.DESKTOP-MQ6GNBS.25540.0 --------------------------------------------------------------------------------