使用vgg16 ————对乳腺超声图像进行分类(两种方法)

文章目录

一、对乳腺超声图像进行分类的重要性

乳腺良恶性肿瘤的分类是医疗实践中至关重要的环节。它不仅直接关系到疾病的准确诊断,还深刻影响着治疗方案的制定、预后的评估以及医疗资源的合理配置。通过分类,医生能够明确肿瘤的性质,区分其良恶性,从而为患者提供最适宜的治疗方案。良性肿瘤通常意味着较好的预后和较为简单的治疗流程,而恶性肿瘤则要求更为复杂和个性化的治疗策略,包括手术、化疗、放疗等多种手段的综合运用。此外,分类还有助于预测患者的预后情况,为后续的随访和监测提供指导。总之,乳腺良恶性肿瘤的分类是确保患者获得精准医疗、提高治疗效果和生存质量的关键所在。

二、原始数据

乳腺超声图像

良性肿瘤超声图片以及标记图片

恶行肿瘤图片

恶性肿瘤超声图片以及标记图片

正常乳腺超声照片

正常乳腺超声照片

三、详细代码解释(方法1)

以下这些代码是用于加载、预处理和训练一个深度学习模型来对乳腺超声图像进行分类从而识别乳腺癌。

导入库

首先,导入了所需的库,包括PyTorch、Torchvision、PIL等,用于数据加载、处理、模型构建和训练。

import torch
import torch.nn as nn
import numpy as np
import pandas as pd
import torchvision
from torchvision import datasets, models, transforms
import matplotlib.pyplot as plt
import time
import copy
import os
import matplotlib.pyplot as plt
from tensorflow.keras.preprocessing import image
from PIL import Image
import shutil

import torchvision.transforms as transforms
from torchvision.datasets import ImageFolder
from torch.utils.data import DataLoader, random_split
import random
from sklearn.model_selection import train_test_split

import torch.optim as optim
from torch.optim import lr_scheduler
from sklearn.metrics import classification_report, confusion_matrix

import seaborn as sns
from torchvision.transforms import RandomHorizontalFlip, RandomRotation, ColorJitter
import warnings

print("Imoprted Complitely!")

这些库主要用于深度学习和数据处理。torch和torchvision是PyTorch的核心库,numpy和pandas用于数据操作,matplotlib用于数据可视化,PIL和tensorflow.keras.preprocessing.image用于图像处理,shutil和os用于文件操作,sklearn用于数据集拆分和模型评估,seaborn用于高级数据可视化,warnings用于控制警告消息。

数据预处理和展示

labels是数据集中不同类别的标签。
data_dir是数据集的路径。

labels = ['benign', 'malignant', 'normal']
data_dir = '/kaggle/input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT'

fig, axs = plt.subplots(3, 4, figsize=(18, 12))

desired_width = 300
desired_height = 300

for i, label in enumerate(labels):
    label_dir = os.path.join(data_dir, label)
    
    image_files = [file for file in os.listdir(label_dir) if file.endswith('.png')]
    
    image_files = sorted(image_files)
    
    for j in range(4):
        if j < len(image_files):
            image_path = os.path.join(label_dir, image_files[j])
            image = Image.open(image_path)
            image = image.resize((desired_width, desired_height), Image.ANTIALIAS)
            
            if j % 2 == 0:
                image_label = f'{label} - Image {j // 2 + 1}'
            else:
                image_label = f'{label} - Image {j // 2 + 1} Mask'
            
            axs[i, j].imshow(image)
            axs[i, j].set_title(image_label)
            axs[i, j].axis('off')

该代码块创建一个3x4的图形网格,显示每个标签下的样本图像。
使用PIL库读取和调整图像大小,并在图形网格中显示。

生成结果
图像展示
清理Kaggle工作目录中的输出文件,以确保不会有旧文件干扰当前的实验。

working_dir = '/kaggle/working'

for item in os.listdir(working_dir):
    item_path = os.path.join(working_dir, item)
    if os.path.isfile(item_path):
        os.remove(item_path)
    elif os.path.isdir(item_path):
        shutil.rmtree(item_path)
        
print("working output path cleared!")

读取数据和标签

data_dir = '/kaggle/input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT'

file_paths = []
labels = []

for label in os.listdir(data_dir):
    label_dir = os.path.join(data_dir, label)
    if os.path.isdir(label_dir):
        for image_file in os.listdir(label_dir):
            if image_file.endswith('.png') and not (image_file.endswith('_mask.png') or 
                                                     image_file.endswith('_mask_1.png') or
                                                     image_file.endswith('_mask_2.png')):
                image_path = os.path.join(label_dir, image_file)
                labels.append(label)
                file_paths.append(image_path)

data = pd.DataFrame({'Image_Path': file_paths, 'Label': labels})
  • 数据目录 (data_dir): 指定乳腺超声图像数据集的根目录。
  • 文件路径和标签列表 (file_paths 和 labels): 初始化为空列表,用于存储图像文件路径和对应的标签。
  • 遍历数据集目录结构:
    使用 os.listdir 列出根目录下的所有子目录(每个子目录代表一个类标签)。
    对于每个标签目录,进一步列出其中的所有文件。
    如果文件是PNG格式且不是标注文件(即不以 _mask.png、_mask_1.png 或 _mask_2.png 结尾),则将其路径和标签添加到列表中。
  • 创建数据框 (data): 使用 pandas.DataFrame 创建一个包含图像路径和标签的数据框。

数据集划分

train_data, test_data = train_test_split(data, test_size=0.15, random_state=42, stratify=data['Label'])
train_data, val_data = train_test_split(train_data, test_size=0.15, random_state=42, stratify=train_data['Label'])

  • 训练集和测试集划分 (train_test_split):
    将数据集划分为训练集测试集,测试集占整个数据集的15%。
    使用 random_state=42 确保划分的可重复性。
    使用 stratify=data[‘Label’] 确保每个类标签在训练集和测试集中的比例一致。
  • 训练集和验证集划分 (train_test_split):
    将训练集进一步划分为训练集和验证集,验证集占原始训练集的15%。
    同样使用 random_state=42 和 stratify=train_data[‘Label’] 确保划分的一致性和比例。

创建目录结构

train_dir = '/kaggle/working/train'
val_dir = '/kaggle/working/validation'
test_dir = '/kaggle/working/test'

for label in labels:
    os.makedirs(os.path.join(train_dir, label), exist_ok=True)
    os.makedirs(os.path.join(val_dir, label), exist_ok=True)
    os.makedirs(os.path.join(test_dir, label), exist_ok=True)

  1. 定义目录路径: 指定训练、验证和测试数据集的目标目录。
  2. 创建目录结构:
    遍历所有类标签。
    使用 os.makedirs 为每个类标签在训练、验证和测试目录中创建相应的子目录。
    exist_ok=True 确保如果目录已存在不会抛出错误。

复制图像文件

for _, row in train_data.iterrows():
    image_path = row['Image_Path']
    label = row['Label']
    shutil.copy(image_path, os.path.join(train_dir, label))

for _, row in val_data.iterrows():
    image_path = row['Image_Path']
    label = row['Label']
    shutil.copy(image_path, os.path.join(val_dir, label))

for _, row in test_data.iterrows():
    image_path = row['Image_Path']
    label = row['Label']
    shutil.copy(image_path, os.path.join(test_dir, label))

  • 遍历数据集: 分别遍历训练集、验证集和测试集中的每一行。
  • 复制图像文件:
    获取每一行中的图像路径和标签。
    使用 shutil.copy 将图像文件复制到相应的目标目录中(按标签组织的子目录)。

统计和显示各个数据集中不同类别的图像数量

train_dir = '/kaggle/working/train'
validation_dir = '/kaggle/working/validation'
test_dir = '/kaggle/working/test'

subdirectories = ['benign', 'malignant', 'normal']

file_counts = {}

# 统计训练集中的文件数量
for subdirectory in subdirectories:
    subdirectory_path = os.path.join(train_dir, subdirectory)
    if os.path.exists(subdirectory_path):
        file_count = len(os.listdir(subdirectory_path))
        file_counts[subdirectory] = file_count

for category, count in file_counts.items():
    print(f"Train {category}: {count}")

# 统计验证集中的文件数量
file_counts = {}
for subdirectory in subdirectories:
    subdirectory_path = os.path.join(validation_dir, subdirectory)
    if os.path.exists(subdirectory_path):
        file_count = len(os.listdir(subdirectory_path))
        file_counts[subdirectory] = file_count

for category, count in file_counts.items():
    print(f"Validation {category}: {count}")

# 统计测试集中的文件数量
file_counts = {}
for subdirectory in subdirectories:
    subdirectory_path = os.path.join(test_dir, subdirectory)
    if os.path.exists(subdirectory_path):
        file_count = len(os.listdir(subdirectory_path))
        file_counts[subdirectory] = file_count

for category, count in file_counts.items():
    print(f"Test {category}: {count}")

  • 目录路径和类别定义:
    定义训练、验证和测试数据集的目录路径 (train_dir、validation_dir 和 test_dir)。
    定义类别列表 (subdirectories),包括 ‘benign’(良性)、‘malignant’(恶性)和 ‘normal’(正常)。
  • 统计各个数据集中的文件数量:
    分别遍历训练、验证和测试集的每个类别目录。
    使用 os.listdir 列出每个类别目录中的文件,并统计文件数量。
    将文件数量存储在 file_counts 字典中,并打印每个类别的文件数量。
    图像数量统计

显示训练集中每个类别的样本图像

train_dir = '/kaggle/working/train'

labels = ['benign', 'malignant', 'normal']
label_dirs = [os.path.join(train_dir, label) for label in labels]

fig, axs = plt.subplots(3, 5, figsize=(25, 18))

desired_width = 300
desired_height = 300

for i, label_dir in enumerate(label_dirs):
    images = [image for image in os.listdir(label_dir) if not image.endswith('_mask.png')][:5]

    for j, image_filename in enumerate(images):
        image_path = os.path.join(label_dir, image_filename)
        image = Image.open(image_path)
        
        image = image.resize((desired_width, desired_height), Image.ANTIALIAS)
        
        axs[i, j].imshow(image)
        axs[i, j].set_title(labels[i])
        axs[i, j].axis('off')

  • 定义标签和标签目录:
    定义类别标签列表 (labels) 和相应的目录路径 (label_dirs)。
  • 创建图像子图:
    使用 plt.subplots 创建 3 行 5 列的图像子图,大小为 (25, 18) 英寸。
  • 显示图像:
    对于每个类别目录,列出前5个图像文件(排除标注文件 _mask.png)。
    打开图像文件并调整大小为 300x300 像素。
    在子图中显示图像,并设置标题为对应的类别标签。
    标签对应图像=

使用 ImageFolder 创建训练、验证和测试数据集

data_dir = '/kaggle/working/'

image_datasets = {
    x: ImageFolder(
        root=os.path.join(data_dir, x),
        transform=data_transforms[x]
    )
    for x in ['train', 'validation', 'test']
}

  • 数据目录定义:
    定义数据目录路径 (data_dir)。
  • 创建 ImageFolder 数据集:
    使用 ImageFolder 从目录中加载图像数据集。
    指定数据集的根目录和相应的变换操作 (transform)。
    对训练、验证和测试数据集分别创建 ImageFolder 实例,并存储在 image_datasets 字典中。

数据加载器设置

batch_size = 8

dataloaders = {x: DataLoader(image_datasets[x], batch_size=batch_size, shuffle=True, num_workers=4)
               for x in ['train', 'validation', 'test']}

dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'validation', 'test']}

class_names = image_datasets['train'].classes

print("Dataset Sizes:", dataset_sizes)
print("Class Labels:", class_names)

  • 批处理大小 (batch_size):
    定义每个批次的样本数量为 8。
  • 数据加载器 (dataloaders):
    使用 DataLoader 为训练、验证和测试数据集创建数据加载器。
    设置 batch_size 为 8,每个批次包含 8 张图像。
    设置 shuffle=True 以在每个epoch开始时打乱数据。
    设置 num_workers=4 以使用 4 个子进程加载数据,提高数据加载效率。
  • 数据集大小 (dataset_sizes):
    计算训练、验证和测试数据集中的样本数量。
  • 类别名称 (class_names):
    获取训练数据集中的类别标签。
  • 打印数据集大小和类别标签:
    输出数据集中每个子集(训练、验证、测试)的样本数量和类别标签。

模型训练函数

def train_model_with_early_stopping(model, lossFunction, optimizer, scheduler, dataloaders, dataset_sizes, class_names, device, num_epochs=20, patience=2):
    since = time.time()

    best_model_wts = copy.deepcopy(model.state_dict())
    best_loss = float('inf')
    consecutive_epochs_without_improvement = 0

    train_losses = []
    val_losses = []

    for epoch in range(num_epochs):
        print('Epoch {}/{}'.format(epoch, num_epochs - 1))
        print('-' * 10)

        for phase in ['train', 'validation']:
            if phase == 'train':
                model.train()
            else:
                model.eval()

            running_loss = 0.0
            running_corrects = 0

            for inputs, labels in dataloaders[phase]:
                inputs = inputs.to(device)
                labels = labels.to(device)

                optimizer.zero_grad()

                with torch.set_grad_enabled(phase == 'train'):
                    outputs = model(inputs)
                    _, preds = torch.max(outputs, 1)
                    loss = lossFunction(outputs, labels)

                    if phase == 'train':
                        loss.backward()
                        optimizer.step()

                if phase == 'train':
                    train_losses.append(loss.item())
                else:
                    val_losses.append(loss.item())

                running_loss += loss.item() * inputs.size(0)
                running_corrects += torch.sum(preds == labels.data)

            if phase == 'train':
                scheduler.step()

            epoch_loss = running_loss / dataset_sizes[phase]
            epoch_acc = running_corrects.double() / dataset_sizes[phase]

            print('{} Loss: {:.4f} Acc: {:.4f}'.format(
                phase, epoch_loss, epoch_acc))

            if phase == 'validation':
                if epoch_loss < best_loss:
                    best_loss = epoch_loss
                    best_model_wts = copy.deepcopy(model.state_dict())
                    consecutive_epochs_without_improvement = 0
                else:
                    consecutive_epochs_without_improvement += 1

                val_losses.append(epoch_loss)

        if consecutive_epochs_without_improvement >= patience:
            print(f"Early stopping after {epoch} epochs")
            break

        print()

    time_elapsed = time.time() - since
    print('Training complete in {:.0f}m {:.0f}s'.format(
        time_elapsed // 60, time_elapsed % 60))
    print('Best val Loss: {:.4f}'.format(best_loss))
   
    model.load_state_dict(best_model_wts)
    
    y_true = []
    y_pred = []

    model.eval()

    with torch.no_grad():
        for inputs, labels in dataloaders['validation']:
            inputs = inputs.to(device)
            labels = labels.to(device)

            outputs = model(inputs)
            _, preds = torch.max(outputs, 1)

            y_true.extend(labels.cpu().numpy())
            y_pred.extend(preds.cpu().numpy())

    target_names = [str(class_names[i]) for i in range(len(class_names))]
    print(classification_report(y_true, y_pred, target_names=target_names))

    cm = confusion_matrix(y_true, y_pred)
    print("Confusion Matrix 1:")
    print(cm)

    return model

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

  • 定义训练函数:
    train_model_with_early_stopping 函数用于训练模型并应用早停机制。

早停机制(Early Stopping)是一种用于防止模型过拟合并提高泛化能力的正则化技术。它通过在训练过程中监控模型在验证集上的性能,并在模型性能不再提升时停止训练,从而避免过拟合。

  • 记录训练开始时间:
    since = time.time() 记录训练开始的时间。
  • 初始化最佳模型权重和其他变量:
    best_model_wts 用于存储最佳模型的权重。
    best_loss 初始化为正无穷大,用于存储最佳验证损失。
    consecutive_epochs_without_improvement 用于记录连续未改进的epoch数量。
  • 训练和验证循环:
    对于每个 epoch(总共 num_epochs 个),分别进行训练和验证。
    在训练阶段,设置模型为训练模式 (model.train()),在验证阶段,设置模型为评估模式 (model.eval())。
    对于每个数据批次,前向传播,计算损失,反向传播并更新模型参数(仅在训练阶段)。
    累积每个阶段的损失和正确预测的数量。
  • 更新学习率:
    在训练阶段结束后,更新学习率调度器 (scheduler.step())。

学习率调度器(Learning Rate Scheduler)是指在神经网络或机器学习模型的训练过程中,根据预设的策略动态地调整学习率的一种机制。学习率是控制模型参数更新幅度的关键超参数,对于训练的收敛速度和模型性能具有重要影响。更新学习率调度器的目的通常是为了优化训练过程,提高模型的训练效率和最终性能。

  • 计算并打印每个阶段的损失和准确率:
    计算每个阶段的平均损失和准确率,并打印出来。
  • 早停机制:
    在验证阶段,如果当前验证损失小于最佳验证损失,更新最佳损失和最佳模型权重,并重置连续未改进的epoch计数。
    如果当前验证损失没有改进,增加连续未改进的epoch计数。
    如果连续未改进的epoch数量达到 patience 值,提前停止训练。
  • 训练结束:
    打印训练总时间和最佳验证损失。
    加载最佳模型权重。
  • 评估模型:
    使用最佳模型在验证集上进行评估,计算真实标签和预测标签。
    打印分类报告和混淆矩阵。
  • 返回最佳模型:
    返回加载最佳权重后的模型。
  • 设置计算设备:
    设置 device 为 CUDA(如果可用)或 CPU。

预训练模型加载与微调设置

Vgg = models.vgg.vgg16(pretrained=True)

for param in Vgg.parameters():
    param.requires_grad = True

Vgg_fineTuning = Vgg.to(device)

  • 加载预训练的 VGG16 模型:
    models.vgg.vgg16(pretrained=True) 加载预训练的 VGG16 模型。
  • 设置所有参数可训练:
    for param in Vgg.parameters(): param.requires_grad = True 设置所有参数的 requires_grad 属性为 True,允许在训练过程中更新这些参数。
  • 将模型移动到计算设备(CPU 或 GPU):
    Vgg_fineTuning = Vgg.to(device) 将模型移动到指定的计算设备。

优化器、学习率调度器和损失函数设置

optimizer = optim.Adam(Vgg_fineTuning.parameters(), lr=0.00005)
Decay_Learning_Rate = lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)
Loss_Function = nn.CrossEntropyLoss()

  • 定义优化器:
    optim.Adam(Vgg_fineTuning.parameters(), lr=0.00005) 使用 Adam 优化器,学习率为 0.00005。
  • 设置学习率调度器:
    lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1) 每 7 个 epoch 将学习率衰减到原来的 10%。
  • 定义损失函数:
    nn.CrossEntropyLoss() 使用交叉熵损失函数。

模型训练

model_fineTuning1 = train_model_with_early_stopping(
    Vgg_fineTuning, Loss_Function, optimizer, Decay_Learning_Rate, 
    dataloaders, dataset_sizes, class_names, device, num_epochs=20, patience=2
)
torch.save(model_fineTuning1, "/kaggle/working/Vgg1_approach1.keras")

  • 调用训练函数:
    train_model_with_early_stopping 函数使用之前定义的模型、损失函数、优化器、学习率调度器和数据加载器,进行最多 20 个 epoch 的训练,并应用早停策略(patience=2)。
  • 保存训练好的模型:
    torch.save 函数将训练好的模型保存到指定路径。

模型评估

label_names = [str(class_names[i]) for i in range(len(class_names))]

y_true = []
y_pred = []

model_fineTuning1.eval()

with torch.no_grad():
    for inputs, labels in dataloaders['test']:
        inputs = inputs.to(device)
        labels = labels.to(device)

        outputs = model_fineTuning1(inputs)
        _, preds = torch.max(outputs, 1)

        y_true.extend(labels.cpu().numpy())
        y_pred.extend(preds.cpu().numpy())

classification_rep = classification_report(y_true, y_pred, target_names=label_names, output_dict=True)
confusion_mat = confusion_matrix(y_true, y_pred)

  • 定义标签名称:
    label_names 获取类别标签的名称。
  • 初始化真实标签和预测标签的列表:
    y_true 和 y_pred 分别用于存储真实标签和预测标签。
  • 设置模型为评估模式:
    model_fineTuning1.eval() 将模型设置为评估模式。
  • 在测试集上进行预测:
    使用 torch.no_grad() 禁用梯度计算,依次处理测试集中的每个批次,获取模型的预测结果,并存储真实标签和预测标签。
  • 生成分类报告和混淆矩阵:
    classification_report 生成分类报告,输出为字典形式。
    confusion_matrix 生成混淆矩阵。

可视化结果

plt.figure(figsize=(5, 3))
sns.heatmap(confusion_mat, annot=True, fmt='d', cmap='Blues', cbar=False, xticklabels=label_names, yticklabels=label_names)
plt.xlabel('Predicted')
plt.ylabel('Actual')
plt.title('Confusion Matrix 1')
plt.show()

plt.figure(figsize=(6, 4))
sns.heatmap(pd.DataFrame(classification_rep).iloc[:-1, :].T, annot=True, cmap='Blues', fmt='.2f')
plt.title('Classification Report Heatmap')
plt.show()

print("Simplified Classification Report:")
print(pd.DataFrame(classification_rep).iloc[:-1, :])

  • 绘制并显示混淆矩阵热图:
    使用 sns.heatmap 绘制混淆矩阵的热图,显示每个类别的预测结果与实际结果的对应关系。
  • 绘制并显示分类报告热图:
    将分类报告转换为 DataFrame 格式,使用 sns.heatmap 绘制分类报告的热图,显示每个类别的各项评估指标(如精确度、召回率、F1 分数)。
  • 打印简化的分类报告:
    打印简化版的分类报告(不包括最后一行 “accuracy”)。

运行结果
在这里插入图片描述

使用微调后的模型进行预测

num_images_to_display = 15

test_dataloader = DataLoader(image_datasets['test'], batch_size=num_images_to_display, shuffle=True, num_workers=4)

inputs, labels = next(iter(test_dataloader))

inputs = inputs.to(device)

grayscale_images = inputs.cpu().numpy().mean(axis=1)

with torch.no_grad():
    model_fineTuning1.eval()
    outputs = model_fineTuning1(inputs)
    _, preds = torch.max(outputs, 1)

plt.figure(figsize=(15, 20))
for i in range(num_images_to_display):
    ax = plt.subplot(5, 3, i + 1)
    ax.axis('off')
    ax.set_title(f'Actual: {class_names[labels[i]]}\nPredicted: {class_names[preds[i]]}')
    plt.imshow(grayscale_images[i], cmap='gray')

plt.show()
  • 从测试集中随机选择 15 张图像。
  • 使用训练好的模型进行预测。
  • 将图像转换为灰度图像。
  • 显示每张图像的实际标签与预测标签,并绘制灰度图像。

运行结果
预测结果

可视化经过微调后的模型中第一个卷积层的权重

提取第一个卷积层的第一个滤波器的权重,并显示这些权重的矩阵表示。从而更直观地了解模型卷积层的权重,观察卷积滤波器在学习过程中是如何变化的。

提取经过微调后的 VGG 模型的第一个卷积层的第一个滤波器的权重。 可视化并展示这些权重的矩阵表示,以及其转置后的表示。
保存经过微调后的模型。

1、提取第一个卷积层的权重

conv = next(m for m in model_fineTuning1.modules() if isinstance(m, torch.nn.Conv2d))
weights = conv.weight

  • 找到第一个卷积层:
    next(m for m in model_fineTuning1.modules() if isinstance(m, torch.nn.Conv2d)) 从模型的模块中找到第一个 Conv2d 层。
  • 获取卷积层的权重:
    weights = conv.weight 获取卷积层的权重。

2、提取第一个滤波器的第一个通道的权重

slice = weights[0,0,:,:]  
slice = slice.detach()
slice = slice.cpu()
slice_np = slice.numpy()  

  • 提取第一个滤波器的第一个通道的权重:
    slice = weights[0,0,:,:] 获取第一个滤波器的第一个通道的权重矩阵。
  • 确保权重矩阵不参与梯度计算:
    slice = slice.detach() 将权重矩阵从计算图中分离出来,以确保其不再参与梯度计算。
  • 将权重矩阵从 GPU 移动到 CPU:
    slice = slice.cpu() 将权重矩阵移动到 CPU。
  • 将权重矩阵转换为 NumPy 数组:
    slice_np = slice.numpy() 将权重矩阵转换为 NumPy 数组。

3、打印权重矩阵的形状并可视化

print(slice_np.shape)

plt.matshow(slice_np)
plt.title("Weight Slice Visualization 2")
plt.colorbar()
plt.show()

  • 打印权重矩阵的形状:
    print(slice_np.shape) 打印权重矩阵的形状。
  • 可视化权重矩阵:
    plt.matshow(slice_np) 使用 matshow 显示权重矩阵。
    plt.title(“Weight Slice Visualization 2”) 设置图像标题。
    plt.colorbar() 显示颜色条。
    plt.show() 显示图像。

4、转置并可视化权重矩阵

permuted = np.transpose(slice_np, (1,0))

plt.matshow(permuted)
plt.title("Permuted Weight Visualization 2")  
plt.colorbar()
plt.show()

  • 转置权重矩阵:
    permuted = np.transpose(slice_np, (1,0)) 转置权重矩阵,将行和列互换。
  • 可视化转置后的权重矩阵:
    plt.matshow(permuted) 使用 matshow 显示转置后的权重矩阵。
    plt.title(“Permuted Weight Visualization 2”) 设置图像标题。
    plt.colorbar() 显示颜色条。
    plt.show() 显示图像。

5、打印权重矩阵和转置后的矩阵并保存模型

print("Slice Matrix 2= ",slice_np)
print("permuted Matrix 2= ",permuted)
torch.save(model_fineTuning1, "/kaggle/working/vgg_approach1.keras")

运行结果
运行结果

四、详细代码解释(方法2)

清空 Kaggle 工作目录

working_dir = '/kaggle/working'

# Delete all files and subdirectories in the working directory
for item in os.listdir(working_dir):
    item_path = os.path.join(working_dir, item)
    if os.path.isfile(item_path):
        os.remove(item_path)
    elif os.path.isdir(item_path):
        shutil.rmtree(item_path)

# Confirm that the directory is empty
print("Kaggle working directory has been cleared.")

  • 定义工作目录:
    working_dir 设置为 /kaggle/working,这是 Kaggle 工作目录的路径。
  • 删除目录中的所有文件和子目录:
    os.listdir(working_dir) 列出工作目录中的所有文件和子目录。
    使用 os.path.isfile(item_path) 判断是否为文件,并用 os.remove(item_path) 删除文件。
    使用 os.path.isdir(item_path) 判断是否为目录,并用 shutil.rmtree(item_path) 删除目录及其内容。
  • 确认目录已清空:
    打印确认信息,表明工作目录已清空。

忽略警告

warnings.filterwarnings("ignore", category=DeprecationWarning)
warnings.filterwarnings("ignore", category=ResourceWarning)
  • 忽略弃用警告:
    warnings.filterwarnings(“ignore”, category=DeprecationWarning) 忽略 DeprecationWarning 警告。
  • 忽略资源警告:
    warnings.filterwarnings(“ignore”, category=ResourceWarning) 忽略 ResourceWarning 警告。

定义输入和输出目录,创建输出目录结构

input_dir = '/kaggle/input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT'
output_dir = '/kaggle/working/OverlayedImages'

labels = ['benign', 'malignant', 'normal']
for label in labels:
    os.makedirs(os.path.join(output_dir, label), exist_ok=True)

  • 定义输入和输出目录:
    input_dir 设置为包含乳腺超声图像数据集的目录路径。
    output_dir 设置为保存叠加图像的目录路径。
  • 创建输出目录结构:
    labels 列表定义了图像的三种类别:良性(benign)、恶性(malignant)和正常(normal)。
    使用 os.makedirs(os.path.join(output_dir, label), exist_ok=True) 为每个标签创建对应的输出目录。

定义图像叠加和保存函数

def overlay_and_save(image_path, mask_path, output_path):
    try:
        if os.path.exists(image_path) and os.path.exists(mask_path):
            image = Image.open(image_path)
            mask = Image.open(mask_path)

            if image.mode != mask.mode:
                mask = mask.convert(image.mode)

            if image.size != mask.size:
                image = image.resize(mask.size)

            overlayed = Image.blend(image, mask, alpha=0.5)

            label = os.path.basename(os.path.dirname(image_path))
            output_path = os.path.join(output_dir, label, os.path.basename(image_path))
            overlayed.save(output_path)
        else:
            pass
    except Exception as e:
        print(f"An error occurred for: {image_path} or {mask_path}. Error: {str(e)}")

  • 定义 overlay_and_save 函数:
    接受图像路径、掩码路径和输出路径作为参数。
  • 检查图像和掩码文件是否存在:
    如果图像文件和掩码文件都存在,则继续处理。
  • 打开图像和掩码文件:
    使用 Image.open(image_path) 和 Image.open(mask_path) 打开图像和掩码文件。
  • 匹配图像和掩码的模式和大小:
    如果图像和掩码的模式不同,使用 mask.convert(image.mode) 将掩码转换为图像的模式。
    如果图像和掩码的大小不同,使用 image.resize(mask.size) 调整图像大小。
  • 叠加图像和掩码:
    使用 Image.blend(image, mask, alpha=0.5) 将图像和掩码进行叠加。
  • 保存叠加后的图像:
    构建输出路径并保存叠加后的图像。

遍历目录并处理图像

for label in labels:
    label_dir = os.path.join(input_dir, label)
    if os.path.isdir(label_dir):
        for image_filename in os.listdir(label_dir):
            if image_filename.endswith('.png'):
                image_path = os.path.join(label_dir, image_filename)
                mask_filename = image_filename.replace('.png', '_mask.png')
                mask_path = os.path.join(label_dir, mask_filename)
                overlay_and_save(image_path, mask_path, output_dir)

print("Overlayed images have been saved to /kaggle/working/OverlayedImages directory.")

  • 遍历每个标签目录:
    for label in labels 循环遍历每个标签。
  • 获取标签目录路径:
    label_dir = os.path.join(input_dir, label) 构建当前标签的目录路径。
  • 检查目录是否存在:
    如果目录存在,继续处理。
  • 遍历图像文件:
    for image_filename in os.listdir(label_dir) 循环遍历目录中的所有文件。
  • 处理图像文件:
    如果文件名以 .png 结尾,获取图像路径和掩码路径,并调用 overlay_and_save 函数进行处理。
  • 打印确认信息:
    表明叠加后的图像已保存到指定目录。

定义计数文件的函数

def count_files_in_directory(directory):
    return sum(len(files) for _, _, files in os.walk(directory))

遍历给定目录及其子目录,统计所有文件的总数量。

设置输入和输出目录路径

input_dir = '/kaggle/input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT'
output_dir = '/kaggle/working/OverlayedImages'

input_dir:设置为包含乳腺超声图像数据集的目录路径。
output_dir:设置为保存叠加图像的目录路径。

初始化计数字典

input_counts = {}
output_counts = {}

统计输入输出目录中的文件数量

for label in os.listdir(input_dir):
    label_dir = os.path.join(input_dir, label)
    if os.path.isdir(label_dir):
        input_counts[label] = count_files_in_directory(label_dir)


for label in os.listdir(output_dir):
    label_dir = os.path.join(output_dir, label)
    if os.path.isdir(label_dir):
        output_counts[label] = count_files_in_directory(label_dir)

打印统计结果

print("File Counts Before Overlay-includes masks:")
for label, count in input_counts.items():
    print(f"{label}: {count} files")

print("\nFile Counts After Overlay:")
for label, count in output_counts.items():
    print(f"{label}: {count} files")

打印输入目录中的文件数量:输出每个标签目录中的文件数量(包括图像和掩码)。
打印输出目录中的文件数量:输出每个标签目录中的文件数量(只包括叠加后的图像)。
结果

展示每个标签(良性,恶性,正常)的前四张图片(叠加后)

overlayed_dir = '/kaggle/working/OverlayedImages'

labels = ['benign', 'malignant', 'normal']
label_dirs = [os.path.join(overlayed_dir, label) for label in labels]

fig, axs = plt.subplots(3, 4, figsize=(20, 15))

desired_width = 800
desired_height = 800

for i, label_dir in enumerate(label_dirs):
    images = [image for image in os.listdir(label_dir) if image.endswith('.png')]
    images.sort(key=lambda x: int(x.split('(')[1].split(')')[0]))

    for j, image_filename in enumerate(images[:4]):
        image_path = os.path.join(label_dir, image_filename)
        image = Image.open(image_path)

        image = image.resize((desired_width, desired_height), Image.ANTIALIAS)

        axs[i, j].imshow(image)
        axs[i, j].set_title(f'{labels[i]} Image {j + 1}')
        axs[i, j].axis('off')

plt.show()

从 /kaggle/working/OverlayedImages 目录中加载每个标签类别的前四张叠加图像,并将它们以矩阵形式显示。每行代表一个标签(良性、恶性、正常),每列显示四张图像。
图像

显示每个类别的实际图像、掩码图像和叠加图像

分别显示每个类别(良性、恶性、正常)的实际图像、掩码图像和叠加图像。通过这些图像,可以直观地查看原始图像、掩码和叠加图像的差异。

input_dir = '/kaggle/input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT'
overlayed_dir = '/kaggle/working/OverlayedImages/benign'
# 展示良性图像
fig, axs = plt.subplots(1, 3, figsize=(15, 5))

desired_width = 300
desired_height = 300

image_filename = 'benign (10).png'

actual_image_path = os.path.join(input_dir, 'benign', image_filename)
mask_image_path = os.path.join(input_dir, 'benign', image_filename.replace(".png", "_mask.png"))
overlayed_image_path = os.path.join(overlayed_dir, image_filename)

actual_image = Image.open(actual_image_path)
mask_image = Image.open(mask_image_path)
overlayed_image = Image.open(overlayed_image_path)

actual_image = actual_image.resize((desired_width, desired_height), Image.ANTIALIAS)
mask_image = mask_image.resize((desired_width, desired_height), Image.ANTIALIAS)
overlayed_image = overlayed_image.resize((desired_width, desired_height), Image.ANTIALIAS)

axs[0].imshow(actual_image)
axs[0].set_title('benign -Actual Image')
axs[0].axis('off')

axs[1].imshow(mask_image, cmap='gray')
axs[1].set_title('benign - Mask')
axs[1].axis('off')

axs[2].imshow(overlayed_image)
axs[2].set_title('benign - Overlayed Image')
axs[2].axis('off')

plt.tight_layout()
plt.show()


input_dir = '/kaggle/input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT'
overlayed_dir = '/kaggle/working/OverlayedImages/malignant'
# 展示恶性图像
fig, axs = plt.subplots(1, 3, figsize=(15, 5))

desired_width = 300
desired_height = 300

image_filename = 'malignant (103).png'

actual_image_path = os.path.join(input_dir, 'malignant', image_filename)
mask_image_path = os.path.join(input_dir, 'malignant', image_filename.replace(".png", "_mask.png"))
overlayed_image_path = os.path.join(overlayed_dir, image_filename)

actual_image = Image.open(actual_image_path)
mask_image = Image.open(mask_image_path)
overlayed_image = Image.open(overlayed_image_path)

actual_image = actual_image.resize((desired_width, desired_height), Image.ANTIALIAS)
mask_image = mask_image.resize((desired_width, desired_height), Image.ANTIALIAS)
overlayed_image = overlayed_image.resize((desired_width, desired_height), Image.ANTIALIAS)

axs[0].imshow(actual_image)
axs[0].set_title('malignant - Actual Image')
axs[0].axis('off')

axs[1].imshow(mask_image, cmap='gray')
axs[1].set_title('malignant - Mask')
axs[1].axis('off')

axs[2].imshow(overlayed_image)
axs[2].set_title('malignant - Overlayed Image')
axs[2].axis('off')

plt.tight_layout()
plt.show()

input_dir = '/kaggle/input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT'
overlayed_dir = '/kaggle/working/OverlayedImages/normal'
# 展示正常图像
fig, axs = plt.subplots(1, 3, figsize=(15, 5))

desired_width = 300
desired_height = 300

image_filename = 'normal (1).png'

actual_image_path = os.path.join(input_dir, 'normal', image_filename)
mask_image_path = os.path.join(input_dir, 'normal', image_filename.replace(".png", "_mask.png"))
overlayed_image_path = os.path.join(overlayed_dir, image_filename)

actual_image = Image.open(actual_image_path)
mask_image = Image.open(mask_image_path)
overlayed_image = Image.open(overlayed_image_path)

actual_image = actual_image.resize((desired_width, desired_height), Image.ANTIALIAS)
mask_image = mask_image.resize((desired_width, desired_height), Image.ANTIALIAS)
overlayed_image = overlayed_image.resize((desired_width, desired_height), Image.ANTIALIAS)

axs[0].imshow(actual_image)
axs[0].set_title('Normal - Actual Image')
axs[0].axis('off')

axs[1].imshow(mask_image, cmap='gray')
axs[1].set_title('Normal - Mask')
axs[1].axis('off')

axs[2].imshow(overlayed_image)
axs[2].set_title('Normal- Overlayed Image')
axs[2].axis('off')

plt.tight_layout()
plt.show()

输出结果
三类图像

设置数据增强和标准化策略

通过定义少数类的数据增强变换策略和标准的数据预处理变换,来提高模型的泛化能力。并且为数据加载器准备了文件路径和标签,以便在后续步骤中创建PyTorch的数据集和数据加载器。这种方式有助于处理类别不平衡问题,并提高模型的训练效果。

1、定义类别和数据增强变换

class_names = ['malignant', 'normal', 'benign']
minority_classes = ['malignant', 'normal']

class_names:包含所有类别的列表。
minority_classes:包含少数类的列表,这些类别的数据增强策略将更加激进,以平衡数据集。

minority_class_transforms = transforms.Compose([
    RandomHorizontalFlip(p=0.9),
    RandomRotation(15, expand=False, center=None),
    ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),
])

minority_class_transforms:为少数类定义的数据增强变换,包括随机水平翻转、旋转和颜色抖动。

2、定义数据集变换

data_transforms = {
    'train': transforms.Compose([
        transforms.Resize(256),
        transforms.CenterCrop(224),
        transforms.RandomApply([minority_class_transforms], p=0.5) if any(cls in minority_classes for cls in class_names) else transforms.RandomApply([], p=0.0),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
    'validation': transforms.Compose([
        transforms.Resize(256),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
    'test': transforms.Compose([
        transforms.Resize(256),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
}

train:定义训练集的变换,包括随机应用少数类的增强变换。
validation 和 test:定义验证集和测试集的变换,不包含数据增强,只进行标准化处理。

3、准备数据集文件路径和标签

data_dir = '/kaggle/working/OverlayedImages'
file_paths = []
labels = []

for label in os.listdir(data_dir):
    label_dir = os.path.join(data_dir, label)
    if os.path.isdir(label_dir):
        for image_file in os.listdir(label_dir):
            if image_file.endswith('.png') and not (image_file.endswith('_mask.png') or 
                                                     image_file.endswith('_mask_1.png') or
                                                     image_file.endswith('_mask_2.png')):
                image_path = os.path.join(label_dir, image_file)
                labels.append(label)
                file_paths.append(image_path)

file_paths:存储所有图像文件的路径。
labels:存储每个图像文件的对应标签。
循环逻辑:遍历数据集目录,跳过掩码文件,只保存原始图像文件的路径和标签。

进一步细化数据集的准备工作

将数据划分为训练、验证和测试集,并将文件分别复制到对应的目录中。

1、数据集划分

data = pd.DataFrame({'Image_Path': file_paths, 'Label': labels})

train_data, test_data = train_test_split(data, test_size=0.15, random_state=42, stratify=data['Label'])
train_data, val_data = train_test_split(train_data, test_size=0.15, random_state=42, stratify=train_data['Label'])

data:创建包含图像路径和标签的数据框。
train_test_split:使用train_test_split函数将数据集划分为训练集、验证集和测试集,同时保持标签的比例(stratify)。

2、创建目录

train_dir = '/kaggle/working/train'
val_dir = '/kaggle/working/validation'
test_dir = '/kaggle/working/test'

for label in labels:
    os.makedirs(os.path.join(train_dir, label), exist_ok=True)
    os.makedirs(os.path.join(val_dir, label), exist_ok=True)
    os.makedirs(os.path.join(test_dir, label), exist_ok=True)

3、复制文件到对应目录

for _, row in train_data.iterrows():
    image_path = row['Image_Path']
    label = row['Label']
    shutil.copy(image_path, os.path.join(train_dir, label))

for _, row in val_data.iterrows():
    image_path = row['Image_Path']
    label = row['Label']
    shutil.copy(image_path, os.path.join(val_dir, label))

for _, row in test_data.iterrows():
    image_path = row['Image_Path']
    label = row['Label']
    shutil.copy(image_path, os.path.join(test_dir, label))

4、打印文件数量

file_counts = {}

for subdirectory in subdirectories:
    subdirectory_path = os.path.join(train_dir, subdirectory)
    if os.path.exists(subdirectory_path):
        file_count = len(os.listdir(subdirectory_path))
        file_counts[subdirectory] = file_count

for category, count in file_counts.items():
    print(f"Train {category}: {count}")

validation_dir = '/kaggle/working/validation'

subdirectories = ['benign', 'malignant', 'normal']

file_counts = {}

for subdirectory in subdirectories:
    subdirectory_path = os.path.join(validation_dir, subdirectory)
    if os.path.exists(subdirectory_path):
        file_count = len(os.listdir(subdirectory_path))
        file_counts[subdirectory] = file_count

for category, count in file_counts.items():
    print(f"Validation {category}: {count}")

test_dir = '/kaggle/working/test'

subdirectories = ['benign', 'malignant', 'normal']

file_counts = {}

for subdirectory in subdirectories:
    subdirectory_path = os.path.join(test_dir, subdirectory)
    if os.path.exists(subdirectory_path):
        file_count = len(os.listdir(subdirectory_path))
        file_counts[subdirectory] = file_count

for category, count in file_counts.items():
    print(f"test {category}: {count}")

5、创建数据集对象

data_dir='/kaggle/working/'

image_datasets = {
    x: ImageFolder(
        root=os.path.join(data_dir, x),
        transform=data_transforms[x]
    )
    for x in ['train', 'validation', 'test']
}

ImageFolder:使用ImageFolder类创建训练、验证和测试集的数据集对象,并应用之前定义的变换(data_transforms)。

运行结果
结果

创建数据加载器

batch_size = 8

dataloaders = {x: DataLoader(image_datasets[x], batch_size=batch_size, shuffle=True, num_workers=4)
               for x in ['train', 'validation', 'test']}

DataLoader:使用DataLoader类为训练、验证和测试集创建数据加载器。
batch_size=batch_size:设置批量大小为8。
shuffle=True:数据集在每个epoch开始时打乱。
num_workers=4:使用4个子进程来加载数据。

获取数据集大小和类标签并打印

dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'validation', 'test']}
class_names = image_datasets['train'].classes
print("Dataset Sizes:", dataset_sizes)
print("Class Labels:", class_names)

设置训练目录和子目录

train_dir = '/kaggle/working/train'
subdirectories = ['benign', 'malignant', 'normal']

VGG16模型的微调、训练和评估

加载预训练的VGG16模型

Vgg = models.vgg.vgg16(pretrained=True)

for param in Vgg.parameters():
    param.requires_grad = True

加载预训练模型:从torchvision.models中加载预训练的VGG16模型。
设置所有参数为可训练:通过设置param.requires_grad = True,允许所有参数在训练过程中更新。

1、设备分配和优化器设置

Vgg_fineTuning = Vgg.to(device)
optimizer = optim.Adam(Vgg_fineTuning.parameters(), lr=0.00005)
Decay_Learning_Rate = lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)
Loss_Function = nn.CrossEntropyLoss()

模型分配到设备:将模型移动到指定的设备(CPU或GPU)。
定义优化器:使用Adam优化器并设置学习率为0.00005。
学习率调度器:设置每7个epoch将学习率缩小到原来的0.1。
损失函数:使用交叉熵损失函数。

2、训练模型

model_fineTuning1 = train_model_with_early_stopping(
    Vgg_fineTuning, Loss_Function, optimizer, Decay_Learning_Rate, 
    dataloaders, dataset_sizes, class_names, device, num_epochs=20, patience=2
)

3、训练第二个模型(重复训练过程)

Vgg_fineTuning2 = Vgg.to(device)
optimizer = optim.Adam(Vgg_fineTuning2.parameters(), lr=0.00005)
Decay_Learning_Rate = lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)
Loss_Function = nn.CrossEntropyLoss()
model_fineTuning2 = train_model_with_early_stopping(
    Vgg_fineTuning2, Loss_Function, optimizer, Decay_Learning_Rate, 
    dataloaders, dataset_sizes, class_names, device, num_epochs=20, patience=2
)

4、模型评估

label_names = [str(class_names[i]) for i in range(len(class_names))]

y_true = []
y_pred = []

model_fineTuning2.eval()

with torch.no_grad():
    for inputs, labels in dataloaders['test']:
        inputs = inputs.to(device)
        labels = labels.to(device)

        outputs = model_fineTuning2(inputs)
        _, preds = torch.max(outputs, 1)

        y_true.extend(labels.cpu().numpy())
        y_pred.extend(preds.cpu().numpy())

classification_rep = classification_report(y_true, y_pred, target_names=label_names, output_dict=True)
confusion_mat = confusion_matrix(y_true, y_pred)

设置模型为评估模式:通过model.eval()设置模型为评估模式。
获取预测结果:在测试数据集上进行预测,并收集真实标签和预测标签。
生成分类报告和混淆矩阵:使用classification_report生成分类报告,并使用confusion_matrix生成混淆矩阵。

5、可视化结果

plt.figure(figsize=(5, 3))
sns.heatmap(confusion_mat, annot=True, fmt='d', cmap='Blues', cbar=False, xticklabels=label_names, yticklabels=label_names)
plt.xlabel('Predicted')
plt.ylabel('Actual')
plt.title('Confusion Matrix 2')
plt.show()

plt.figure(figsize=(6, 4))
sns.heatmap(pd.DataFrame(classification_rep).iloc[:-1, :].T, annot=True, cmap='Blues', fmt='.2f')
plt.title('Classification Report Heatmap')
plt.show()

print("Simplified Classification Report:")
print(pd.DataFrame(classification_rep).iloc[:-1, :])

绘制混淆矩阵:使用Seaborn绘制混淆矩阵热图。
绘制分类报告热图:使用Seaborn绘制分类报告的热图。
打印简化的分类报告:打印分类报告的简化版本。

运行结果
训练结果

从测试数据集中随机选择一批图像并预测

num_images_to_display = 15

test_dataloader = DataLoader(image_datasets['test'], batch_size=num_images_to_display, shuffle=True, num_workers=4)

inputs, labels = next(iter(test_dataloader))

inputs = inputs.to(device)

grayscale_images = inputs.cpu().numpy().mean(axis=1)

with torch.no_grad():
    model_fineTuning2.eval()
    outputs = model_fineTuning2(inputs)
    _, preds = torch.max(outputs, 1)

plt.figure(figsize=(15, 20))
for i in range(num_images_to_display):
    ax = plt.subplot(5, 3, i + 1)
    ax.axis('off')
    ax.set_title(f'Actual: {class_names[labels[i]]}\nPredicted: {class_names[preds[i]]}')
    plt.imshow(grayscale_images[i], cmap='gray')

plt.show()
  • 从测试集中随机选择 15 张图像。
  • 使用训练好的模型进行预测。
  • 将图像转换为灰度图像。
  • 显示每张图像的实际标签与预测标签,并绘制灰度图像。

可视化训练模型中第一个卷积层的权重

conv = next(m for m in model_fineTuning2.modules() if isinstance(m, torch.nn.Conv2d))
weights = conv.weight

slice = weights[0,0,:,:]  

slice = slice.detach()

slice = slice.cpu()

slice_np = slice.numpy()  

print(slice_np.shape)

plt.matshow(slice_np)
plt.title("Weight Slice Visualization 2")
plt.colorbar()
plt.show()

permuted = np.transpose(slice_np, (1,0))

plt.matshow(permuted)
plt.title("Permuted Weight Visualization 2")  
plt.colorbar()
plt.show()

print("Slice Matrix 2= ",slice_np)

print("permuted Matrix 2= ",permuted)
torch.save(model_fineTuning1,"/kaggle/working/Vgg_approach1.keras")
torch.save(model_fineTuning2,"/kaggle/working/Vgg_approach2.keras")
print(f'models saved in {working_dir} successfully!')

提取第一个卷积层的第一个滤波器的权重,并显示这些权重的矩阵表示。从而更直观地了解模型卷积层的权重,观察卷积滤波器在学习过程中是如何变化的。

提取经过微调后的 VGG 模型的第一个卷积层的第一个滤波器的权重。 可视化并展示这些权重的矩阵表示,以及其转置后的表示。

运行结果
运行结果

以上代码及数据均来自kaggle

  • 16
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,首先我们需要安装PyTorch,可以通过以下命令安装: ``` pip install torch torchvision ``` 然后我们加载预训练的VGG-16模型,可以使用以下代码: ```python import torch import torch.nn as nn import torchvision.models as models # 加载预训练的VGG-16模型 vgg16 = models.vgg16(pretrained=True) ``` 接下来,我们需要对图像进行预处理,使其能够被VGG-16模型接受。VGG-16模型需要输入的图像大小为224x224,而且需要进行标准化处理。我们可以使用以下代码对图像进行预处理: ```python import torchvision.transforms as transforms # 预处理图像 transform = transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) ``` 接下来,我们可以使用预处理后的图像作为输入,通过VGG-16模型进行前向传播得到预测结果。我们可以使用以下代码: ```python from PIL import Image # 加载图像 image = Image.open("image.jpg") # 预处理图像 image = transform(image) # 增加一个维度 image = image.unsqueeze(0) # 前向传播 output = vgg16(image) # 输出预测结果 print(output) ``` 其中,"image.jpg"是我们要分类图像,可以根据需要替换为其他图像的路径。输出的结果是一个向量,表示图像属于1000个类别中的每一个类别的概率。我们可以使用以下代码获取最终的预测结果: ```python # 加载标签 with open("imagenet_classes.txt", "r") as f: categories = [s.strip() for s in f.readlines()] # 获取概率最大的类别 probs, indices = torch.topk(output, 5) for i in indices[0]: print(categories[i]) ``` 其中,"imagenet_classes.txt"是包含1000个类别标签的文件,可以在https://gist.github.com/yrevar/942d3a0ac09ec9e5eb3a下载到。输出的结果是概率最大的5个类别,我们可以根据需要修改输出的数量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值