一、导入依赖库

import random  # 随机数生成
import torch  # PyTorch深度学习框架
import torch.nn as nn  # 神经网络(卷积、全连接等)
import numpy as np  # 数组与数值计算
import os  # 文件路径与文件操作
from PIL import Image  # 读取图片数据
from torch.utils.data import Dataset, DataLoader  # 自定义数据集与批量加载数据
from tqdm import tqdm  # 显示进度条
from torchvision import transforms  # 数据增强
import time  # 计算训练时间
import matplotlib.pyplot as plt  # 绘图
from model_utils.model import initialize_model  # 初始化模型的包(自己编写)

二、随机种子的设置(保证实验可复现)

def seed_everything(seed):
    # 设置CPU随机种子
    torch.manual_seed(seed)
    # 设置GPU随机种子
    torch.cuda.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)
    # 保证CUDA计算确定性
    torch.backends.cudnn.benchmark = False
    torch.backends.cudnn.deterministic = True
    # Python和numpy随机数固定
    random.seed(seed)
    np.random.seed(seed)
    # 固定Python哈希随机性
    os.environ['PYTHONHASHSEED'] = str(seed)


#################################################################
# 使用 0 作为随机种子
seed_everything(0)
###############################################
  1. 固定随机数,保证每次训练结果一致:在下面代码的transform(数据增强)和shuffle(打乱数据)部分体现
  2. 若没有该函数会使每次训练的结果都不相同

三、输入图片尺寸

HW = 224
  • 定义图片大小为224*224,这是VGG、ResNet等模型的标准输入尺寸

四、数据增强(Data Augmentation)

train_transform = transforms.Compose(
    [
        transforms.ToPILImage(),  # 224, 224, 3  模型  :3, 224, 224
        transforms.RandomResizedCrop(224),
        transforms.RandomRotation(50),
        transforms.ToTensor()
    ]
)

val_transform = transforms.Compose(
    [
        transforms.ToPILImage(),  # 224, 224, 3模型  :3, 224, 224
        transforms.ToTensor()
    ]
)
  • 数据增强,使输入的图片经过各种变化后还能被计算机识别并认出,提升模型泛化能力
  • 仅训练集需数据增强(裁切和旋转),验证集用来评估模型性能,故无需数据增强,只做必须的预处理即可

在深度学习训练中,训练集通常会进行随机数据增强,例如随机裁剪和旋转,以增加样本多样性、防止过拟合,提高模型的泛化能力。
而验证集的作用是客观评估模型性能,因此不能进行随机增强,否则每次验证数据都会发生变化,导致评估结果不稳定。
所以验证集通常只进行确定性的预处理,例如 resize 和 tensor 转换。

五、food_Dataset 数据集类

class food_Dataset(Dataset):
    def __init__(self, path, mode="train"):
        self.mode = mode
        if mode == "semi":  # 无标签数据
            self.X = self.read_file(path)
        else:  # 有标签数据
            self.X, self.Y = self.read_file(path)
            self.Y = torch.LongTensor(self.Y)  # 标签转为长整形\

        # 训练集和验证集又不同的数据增强
        if mode == "train":
            self.transform = train_transform
        else:
            self.transform = val_transform

    def read_file(self, path):
        if self.mode == "semi":
            file_list = os.listdir(path)
            xi = np.zeros((len(file_list), HW, HW, 3), dtype=np.uint8)
            # 列出文件夹下所有文件名字
            for j, img_name in enumerate(file_list):
                img_path = os.path.join(path, img_name)
                img = Image.open(img_path)
                img = img.resize((HW, HW))
                xi[j, ...] = img
            print("读到了%d个数据" % len(xi))
            return xi
        else:
            for i in tqdm(range(11)):
                file_dir = path + "/%02d" % i
                file_list = os.listdir(file_dir)

                xi = np.zeros((len(file_list), HW, HW, 3), dtype=np.uint8)
                yi = np.zeros(len(file_list), dtype=np.uint8)

                # 列出文件夹下所有文件名字
                for j, img_name in enumerate(file_list):
                    img_path = os.path.join(file_dir, img_name)
                    img = Image.open(img_path)
                    img = img.resize((HW, HW))
                    xi[j, ...] = img
                    yi[j] = i

                if i == 0:
                    X = xi
                    Y = yi
                else:
                    X = np.concatenate((X, xi), axis=0)
                    Y = np.concatenate((Y, yi), axis=0)
            print("读到了%d个数据" % len(Y))
            return X, Y

    def __getitem__(self, item):
        if self.mode == "semi":
            return self.transform(self.X[item]), self.X[item]
        else:
            return self.transform(self.X[item]), self.Y[item]

    def __len__(self):
        return len(self.X)

这个类继承自PyTorch的Dataset,用于加载、预处理和组织食品图像数据,为模型训练提供标准化的数据接口。它能够:

1. 支持三种数据模式

  • 训练模式 (mode="train"):加载带标签的图像,应用训练数据增强
  • 验证模式 (mode="val"):加载带标签的图像,应用验证数据增强(通常不做增强或只做基础处理)
  • 半监督模式 (mode="semi"):加载无标签的图像,为半监督学习准备

2. 数据读取与组织

  • 自动遍历文件夹结构,根据子文件夹名称(00-10)分配类别标签
  • 将所有图像统一调整为固定尺寸 (HW x HW)
  • 将图像数据存储为numpy数组,标签存储为整数

3. 提供标准接口

  • __getitem__:根据索引返回处理后的图像和对应标签
  • __len__:返回数据集大小

此时:

  • x:经过预处理/增强后的图像张量(适合输入神经网络)
  • y:对应的类别标签(训练/验证模式)或原始图像(半监督模式)

这样设计使得数据可以无缝接入PyTorch的DataLoader,方便进行批量训练。

六、semiDataset(半监督数据初始化)

class semiDataset(Dataset):
    def __init__(self, no_label_loder, model, device, thres=0.99):
        x, y = self.get_label(no_label_loder, model, device, thres)
        if x == []:
            self.flag = False

        else:
            self.flag = True
            self.X = np.array(x)
            self.Y = torch.LongTensor(y)
            self.transform = train_transform

    # 生成伪标签
    def get_label(self, no_label_loder, model, device, thres):
        model = model.to(device)
        pred_prob = []
        labels = []
        x = []
        y = []
        soft = nn.Softmax()
        with torch.no_grad():
            for bat_x, _ in no_label_loder:
                bat_x = bat_x.to(device)
                pred = model(bat_x)
                pred_soft = soft(pred)
                pred_max, pred_value = pred_soft.max(1)
                pred_prob.extend(pred_max.cpu().numpy().tolist())
                labels.extend(pred_value.cpu().numpy().tolist())

        for index, prob in enumerate(pred_prob):
            if prob > thres:
                x.append(no_label_loder.dataset[index][1])  # 调用到原始的getitem
                y.append(labels[index])
        return x, y

    def __getitem__(self, item):
        return self.transform(self.X[item]), self.Y[item]

    def __len__(self):
        return len(self.X)
  • 为无标签数据生成伪标签:让x通过模型得到预测值y,若置信度达到阈值,则将其作为新的训练数据

七、半监督数据准备与数据加载

def get_semi_loader(no_label_loder, model, device, thres):
    semiset = semiDataset(no_label_loder, model, device, thres)
    if semiset.flag == False:
        return None
    else:
        semi_loader = DataLoader(semiset, batch_size=16, shuffle=False)
        return semi_loader

生成半监督DataLoader

  • 如果没有高置信度数据:return None
  • 否则:return DataLoader

八、myModel类(自定义CNN模型)

class myModel(nn.Module):
    def __init__(self, num_class):
        super(myModel, self).__init__()
        # 3 *224 *224  -> 512*7*7 -> 拉直 -> 全连接分类
        self.conv1 = nn.Conv2d(3, 64, 3, 1, 1)  # 64*224*224
        self.bn1 = nn.BatchNorm2d(64)  # 对卷积层输出进行标准化处理
        self.relu = nn.ReLU()
        self.pool1 = nn.MaxPool2d(2)  # 64*112*112

        self.layer1 = nn.Sequential(
            nn.Conv2d(64, 128, 3, 1, 1),  # 128*112*112
            nn.BatchNorm2d(128),
            nn.ReLU(),
            nn.MaxPool2d(2)  # 128*56*56
        )
        self.layer2 = nn.Sequential(
            nn.Conv2d(128, 256, 3, 1, 1),
            nn.BatchNorm2d(256),
            nn.ReLU(),
            nn.MaxPool2d(2)  # 256*28*28
        )
        self.layer3 = nn.Sequential(
            nn.Conv2d(256, 512, 3, 1, 1),
            nn.BatchNorm2d(512),
            nn.ReLU(),
            nn.MaxPool2d(2)  # 512*14*14
        )

        self.pool2 = nn.MaxPool2d(2)  # 512*7*7
        self.fc1 = nn.Linear(25088, 1000)  # 25088->1000
        self.relu2 = nn.ReLU()
        self.fc2 = nn.Linear(1000, num_class)  # 1000-11

    def forward(self, x):
        x = self.conv1(x)
        x = self.bn1(x)
        x = self.relu(x)
        x = self.pool1(x)
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        x = self.pool2(x)
        x = x.view(x.size()[0], -1)
        x = self.fc1(x)
        x = self.relu2(x)
        x = self.fc2(x)
        return x

其中:

Conv2d (卷积) → 2. BatchNorm (批归一化) → 3. ReLU (激活) → 4. Pooling (池化)是CNN卷积神经网络最常用的步骤

九、半监督学习训练模块

def train_val(model, train_loader, val_loader, no_label_loader, device, epochs, optimizer, loss, thres, save_path):
    model = model.to(device)
    semi_loader = None
    plt_train_loss = []
    plt_val_loss = []

    plt_train_acc = []
    plt_val_acc = []

    max_acc = 0.0

    for epoch in range(epochs):
        train_loss = 0.0
        val_loss = 0.0
        train_acc = 0.0
        val_acc = 0.0
        semi_loss = 0.0
        semi_acc = 0.0

        start_time = time.time()
        # 开启训练模式
        model.train()
        for batch_x, batch_y in train_loader:
            x, target = batch_x.to(device), batch_y.to(device)
            pred = model(x)  # 预测
            train_bat_loss = loss(pred, target)  # 计算loss
            train_bat_loss.backward()  # 反向传播
            optimizer.step()  # 更新参数 之后要梯度清零否则会累积梯度
            optimizer.zero_grad()  # 梯度清零
            train_loss += train_bat_loss.cpu().item()
            train_acc += np.sum(np.argmax(pred.detach().cpu().numpy(), axis=1) == target.cpu().numpy())
        plt_train_loss.append(train_loss / train_loader.__len__())
        plt_train_acc.append(train_acc / train_loader.dataset.__len__())  # 记录准确率,

        # 如果存在伪标签数据,也对其训练
        if semi_loader != None:
            for batch_x, batch_y in semi_loader:
                x, target = batch_x.to(device), batch_y.to(device)
                pred = model(x)
                semi_bat_loss = loss(pred, target)
                semi_bat_loss.backward()
                optimizer.step()  # 更新参数 之后要梯度清零否则会累积梯度
                optimizer.zero_grad()
                semi_loss += train_bat_loss.cpu().item()
                semi_acc += np.sum(np.argmax(pred.detach().cpu().numpy(), axis=1) == target.cpu().numpy())
            print("半监督数据集的训练准确率为", semi_acc / train_loader.dataset.__len__())

        # 验证评估阶段
        model.eval()
        with torch.no_grad():
            for batch_x, batch_y in val_loader:
                x, target = batch_x.to(device), batch_y.to(device)
                pred = model(x)
                val_bat_loss = loss(pred, target)
                val_loss += val_bat_loss.cpu().item()
                val_acc += np.sum(np.argmax(pred.detach().cpu().numpy(), axis=1) == target.cpu().numpy())
        plt_val_loss.append(val_loss / val_loader.dataset.__len__())
        plt_val_acc.append(val_acc / val_loader.dataset.__len__())

        if epoch % 3 == 0 and plt_val_acc[-1] > 0.6:
            semi_loader = get_semi_loader(no_label_loader, model, device, thres)

        if val_acc > max_acc:
            torch.save(model, save_path)
            max_acc = val_acc

        print('[%03d/%03d] %2.2f sec(s) TrainLoss : %.6f | valLoss: %.6f Trainacc : %.6f | valacc: %.6f' % \
              (epoch, epochs, time.time() - start_time, plt_train_loss[-1], plt_val_loss[-1], plt_train_acc[-1],
               plt_val_acc[-1])
              )  # 打印训练结果。 注意python语法, %2.2f 表示小数位为2的浮点数, 后面可以对应。

    plt.plot(plt_train_loss)
    plt.plot(plt_val_loss)
    plt.title("loss")
    plt.legend(["train", "val"])
    plt.show()

    plt.plot(plt_train_acc)
    plt.plot(plt_val_acc)
    plt.title("acc")
    plt.legend(["train", "val"])
    plt.show()

三阶段训练流程

  • 有监督训练:使用带标签的训练集进行标准训练
  • 伪标签训练:动态生成并利用高置信度无标签数据
  • 验证评估:在验证集上评估模型性能

1. 训练阶段(model.train())

  • 用有标签数据计算损失,反向传播更新参数
  • 如果有伪标签数据,也参与训练

2. 验证阶段(model.eval())

  • 关闭梯度计算,评估模型在验证集上的表现
  • 记录损失和准确率

3. 伪标签更新

  • 基于当前模型重新筛选无标签数据
  • 阈值控制保证伪标签质量

十、完整代码

import random  # 随机数生成
import torch  # PyTorch深度学习框架
import torch.nn as nn  # 神经网络(卷积、全连接等)
import numpy as np  # 数组与数值计算
import os  # 文件路径与文件操作
from PIL import Image  # 读取图片数据
from torch.utils.data import Dataset, DataLoader  # 自定义数据集与批量加载数据
from tqdm import tqdm  # 显示进度条
from torchvision import transforms  # 数据增强
import time  # 计算训练时间
import matplotlib.pyplot as plt  # 绘图
from model_utils.model import initialize_model  # 初始化模型的包(自己编写)

# 训练流程
# 数据读取 → 数据增强 → CNN / VGG模型 → 监督训练 → 无标签数据预测 → 高置信度伪标签 → 加入训练 → 提升模型性能

# 固定随机数,保证每次训练结果一致:在transform(数据增强)和shuffle(打乱数据)体现
# 若没有该函数会使每次训练的结果都不相同
def seed_everything(seed):
    # 设置CPU随机种子
    torch.manual_seed(seed)
    # 设置GPU随机种子
    torch.cuda.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)
    # 保证CUDA计算确定性
    torch.backends.cudnn.benchmark = False
    torch.backends.cudnn.deterministic = True
    # Python和numpy随机数固定
    random.seed(seed)
    np.random.seed(seed)
    # 固定Python哈希随机性
    os.environ['PYTHONHASHSEED'] = str(seed)


#################################################################
# 使用 0 作为随机种子
seed_everything(0)
###############################################

# 指定图片大小为224(为VGG、ResNet等模型的标准输入尺寸)
HW = 224

# 数据增强,使输入的图片经过各种变化后还能被计算机识别并认出,提升模型泛化能力
# 仅训练集需数据增强(裁切和旋转),验证集用来评估模型性能,故无需数据增强,只做必须的预处理即可

# 在深度学习训练中,训练集通常会进行随机数据增强,例如随机裁剪和旋转,以增加样本多样性、防止过拟合,提高模型的泛化能力。
# 而验证集的作用是客观评估模型性能,因此不能进行随机增强,否则每次验证数据都会发生变化,导致评估结果不稳定。
# 所以验证集通常只进行确定性的预处理,例如 resize 和 tensor 转换。
train_transform = transforms.Compose(
    [
        transforms.ToPILImage(),  # 224, 224, 3  模型  :3, 224, 224
        transforms.RandomResizedCrop(224),
        transforms.RandomRotation(50),
        transforms.ToTensor()
    ]
)

val_transform = transforms.Compose(
    [
        transforms.ToPILImage(),  # 224, 224, 3模型  :3, 224, 224
        transforms.ToTensor()
    ]
)


class food_Dataset(Dataset):
    def __init__(self, path, mode="train"):
        self.mode = mode
        if mode == "semi":  # 无标签数据
            self.X = self.read_file(path)
        else:  # 有标签数据
            self.X, self.Y = self.read_file(path)
            self.Y = torch.LongTensor(self.Y)  # 标签转为长整形\

        # 训练集和验证集又不同的数据增强
        if mode == "train":
            self.transform = train_transform
        else:
            self.transform = val_transform

    def read_file(self, path):
        if self.mode == "semi":
            file_list = os.listdir(path)
            xi = np.zeros((len(file_list), HW, HW, 3), dtype=np.uint8)
            # 列出文件夹下所有文件名字
            for j, img_name in enumerate(file_list):
                img_path = os.path.join(path, img_name)
                img = Image.open(img_path)
                img = img.resize((HW, HW))
                xi[j, ...] = img
            print("读到了%d个数据" % len(xi))
            return xi
        else:
            for i in tqdm(range(11)):
                file_dir = path + "/%02d" % i
                file_list = os.listdir(file_dir)

                xi = np.zeros((len(file_list), HW, HW, 3), dtype=np.uint8)
                yi = np.zeros(len(file_list), dtype=np.uint8)

                # 列出文件夹下所有文件名字
                for j, img_name in enumerate(file_list):
                    img_path = os.path.join(file_dir, img_name)
                    img = Image.open(img_path)
                    img = img.resize((HW, HW))
                    xi[j, ...] = img
                    yi[j] = i

                if i == 0:
                    X = xi
                    Y = yi
                else:
                    X = np.concatenate((X, xi), axis=0)
                    Y = np.concatenate((Y, yi), axis=0)
            print("读到了%d个数据" % len(Y))
            return X, Y

    def __getitem__(self, item):
        if self.mode == "semi":
            return self.transform(self.X[item]), self.X[item]
        else:
            return self.transform(self.X[item]), self.Y[item]

    def __len__(self):
        return len(self.X)


# 为无标签数据生成伪标签
# 让x通过模型得到预测值y,若置信度达到阈值,则将其作为新的训练数据
class semiDataset(Dataset):
    def __init__(self, no_label_loder, model, device, thres=0.99):
        x, y = self.get_label(no_label_loder, model, device, thres)
        if x == []:
            self.flag = False

        else:
            self.flag = True
            self.X = np.array(x)
            self.Y = torch.LongTensor(y)
            self.transform = train_transform

    # 生成伪标签
    def get_label(self, no_label_loder, model, device, thres):
        model = model.to(device)
        pred_prob = []
        labels = []
        x = []
        y = []
        soft = nn.Softmax()
        with torch.no_grad():
            for bat_x, _ in no_label_loder:
                bat_x = bat_x.to(device)
                pred = model(bat_x)
                pred_soft = soft(pred)
                pred_max, pred_value = pred_soft.max(1)
                pred_prob.extend(pred_max.cpu().numpy().tolist())
                labels.extend(pred_value.cpu().numpy().tolist())

        for index, prob in enumerate(pred_prob):
            if prob > thres:
                x.append(no_label_loder.dataset[index][1])  # 调用到原始的getitem
                y.append(labels[index])
        return x, y

    def __getitem__(self, item):
        return self.transform(self.X[item]), self.Y[item]

    def __len__(self):
        return len(self.X)


# 生成半监督DataLoader
def get_semi_loader(no_label_loder, model, device, thres):
    semiset = semiDataset(no_label_loder, model, device, thres)
    if semiset.flag == False:
        return None
    else:
        semi_loader = DataLoader(semiset, batch_size=16, shuffle=False)
        return semi_loader


# 卷积神经网络
class myModel(nn.Module):
    def __init__(self, num_class):
        super(myModel, self).__init__()
        # 3 *224 *224  -> 512*7*7 -> 拉直 -> 全连接分类
        self.conv1 = nn.Conv2d(3, 64, 3, 1, 1)  # 64*224*224
        self.bn1 = nn.BatchNorm2d(64)  # 对卷积层输出进行标准化处理
        self.relu = nn.ReLU()
        self.pool1 = nn.MaxPool2d(2)  # 64*112*112

        self.layer1 = nn.Sequential(
            nn.Conv2d(64, 128, 3, 1, 1),  # 128*112*112
            nn.BatchNorm2d(128),
            nn.ReLU(),
            nn.MaxPool2d(2)  # 128*56*56
        )
        self.layer2 = nn.Sequential(
            nn.Conv2d(128, 256, 3, 1, 1),
            nn.BatchNorm2d(256),
            nn.ReLU(),
            nn.MaxPool2d(2)  # 256*28*28
        )
        self.layer3 = nn.Sequential(
            nn.Conv2d(256, 512, 3, 1, 1),
            nn.BatchNorm2d(512),
            nn.ReLU(),
            nn.MaxPool2d(2)  # 512*14*14
        )

        self.pool2 = nn.MaxPool2d(2)  # 512*7*7
        self.fc1 = nn.Linear(25088, 1000)  # 25088->1000
        self.relu2 = nn.ReLU()
        self.fc2 = nn.Linear(1000, num_class)  # 1000-11

    def forward(self, x):
        x = self.conv1(x)
        x = self.bn1(x)
        x = self.relu(x)
        x = self.pool1(x)
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        x = self.pool2(x)
        x = x.view(x.size()[0], -1)
        x = self.fc1(x)
        x = self.relu2(x)
        x = self.fc2(x)
        return x


def train_val(model, train_loader, val_loader, no_label_loader, device, epochs, optimizer, loss, thres, save_path):
    model = model.to(device)
    semi_loader = None
    plt_train_loss = []
    plt_val_loss = []

    plt_train_acc = []
    plt_val_acc = []

    max_acc = 0.0

    for epoch in range(epochs):
        train_loss = 0.0
        val_loss = 0.0
        train_acc = 0.0
        val_acc = 0.0
        semi_loss = 0.0
        semi_acc = 0.0

        start_time = time.time()
        # 开启训练模式
        model.train()
        for batch_x, batch_y in train_loader:
            x, target = batch_x.to(device), batch_y.to(device)
            pred = model(x)  # 预测
            train_bat_loss = loss(pred, target)  # 计算loss
            train_bat_loss.backward()  # 反向传播
            optimizer.step()  # 更新参数 之后要梯度清零否则会累积梯度
            optimizer.zero_grad()  # 梯度清零
            train_loss += train_bat_loss.cpu().item()
            train_acc += np.sum(np.argmax(pred.detach().cpu().numpy(), axis=1) == target.cpu().numpy())
        plt_train_loss.append(train_loss / train_loader.__len__())
        plt_train_acc.append(train_acc / train_loader.dataset.__len__())  # 记录准确率,

        # 如果存在伪标签数据,也对其训练
        if semi_loader != None:
            for batch_x, batch_y in semi_loader:
                x, target = batch_x.to(device), batch_y.to(device)
                pred = model(x)
                semi_bat_loss = loss(pred, target)
                semi_bat_loss.backward()
                optimizer.step()  # 更新参数 之后要梯度清零否则会累积梯度
                optimizer.zero_grad()
                semi_loss += train_bat_loss.cpu().item()
                semi_acc += np.sum(np.argmax(pred.detach().cpu().numpy(), axis=1) == target.cpu().numpy())
            print("半监督数据集的训练准确率为", semi_acc / train_loader.dataset.__len__())

        # 验证评估阶段
        model.eval()
        with torch.no_grad():
            for batch_x, batch_y in val_loader:
                x, target = batch_x.to(device), batch_y.to(device)
                pred = model(x)
                val_bat_loss = loss(pred, target)
                val_loss += val_bat_loss.cpu().item()
                val_acc += np.sum(np.argmax(pred.detach().cpu().numpy(), axis=1) == target.cpu().numpy())
        plt_val_loss.append(val_loss / val_loader.dataset.__len__())
        plt_val_acc.append(val_acc / val_loader.dataset.__len__())

        if epoch % 3 == 0 and plt_val_acc[-1] > 0.6:
            semi_loader = get_semi_loader(no_label_loader, model, device, thres)

        if val_acc > max_acc:
            torch.save(model, save_path)
            max_acc = val_acc

        print('[%03d/%03d] %2.2f sec(s) TrainLoss : %.6f | valLoss: %.6f Trainacc : %.6f | valacc: %.6f' % \
              (epoch, epochs, time.time() - start_time, plt_train_loss[-1], plt_val_loss[-1], plt_train_acc[-1],
               plt_val_acc[-1])
              )  # 打印训练结果。 注意python语法, %2.2f 表示小数位为2的浮点数, 后面可以对应。

    plt.plot(plt_train_loss)
    plt.plot(plt_val_loss)
    plt.title("loss")
    plt.legend(["train", "val"])
    plt.show()

    plt.plot(plt_train_acc)
    plt.plot(plt_val_acc)
    plt.title("acc")
    plt.legend(["train", "val"])
    plt.show()


# 数据路径
# path = r"F:\pycharm\beike\classification\food_classification\food-11\training\labeled"
# train_path = r"F:\pycharm\beike\classification\food_classification\food-11\training\labeled"
# val_path = r"F:\pycharm\beike\classification\food_classification\food-11\validation"
train_path = r"F:\pycharm\beike\classification\food_classification\food-11_sample\training\labeled"
val_path = r"F:\pycharm\beike\classification\food_classification\food-11_sample\validation"
no_label_path = r"F:\pycharm\beike\classification\food_classification\food-11_sample\training\unlabeled\00"

train_set = food_Dataset(train_path, "train")
val_set = food_Dataset(val_path, "val")
no_label_set = food_Dataset(no_label_path, "semi")

# 批量加载数据
train_loader = DataLoader(train_set, batch_size=16, shuffle=True)
val_loader = DataLoader(val_set, batch_size=16, shuffle=True)
no_label_loader = DataLoader(no_label_set, batch_size=16, shuffle=False)

# model = myModel(11)
model, _ = initialize_model("vgg", 11, use_pretrained=True)

lr = 0.001
loss = nn.CrossEntropyLoss()
optimizer = torch.optim.AdamW(model.parameters(), lr=lr, weight_decay=1e-4)
device = "cuda" if torch.cuda.is_available() else "cpu"
save_path = "model_save/best_model.pth"
epochs = 15
thres = 0.99

train_val(model, train_loader, val_loader, no_label_loader, device, epochs, optimizer, loss, thres, save_path)

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐