1. 导入必要的库
import random import torch 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
-
作用: 导入项目所需的库和模块,包括随机数生成、PyTorch框架、数据处理、图像处理、进度条显示、数据增强、时间计算、绘图工具等。
2. 设置随机种子
def seed_everything(seed): torch.manual_seed(seed) torch.cuda.manual_seed(seed) torch.cuda.manual_seed_all(seed) torch.backends.cudnn.benchmark = False torch.backends.cudnn.deterministic = True random.seed(seed) np.random.seed(seed) os.environ['PYTHONHASHSEED'] = str(seed)
-
作用: 设置随机种子,确保实验的可重复性。通过固定随机种子,使得每次运行代码时生成的随机数相同,从而保证实验结果的一致性。
3. 设置随机种子为0
seed_everything(0)
-
作用: 调用
seed_everything
函数,设置随机种子为0。
4. 定义图像大小
HW = 224
-
作用: 定义图像的高度和宽度为224,通常用于输入到卷积神经网络(CNN)中的图像大小。
5. 定义数据增强和预处理
train_transform = transforms.Compose( [ transforms.ToPILImage(), # 将numpy数组或tensor转换为PIL图像 transforms.RandomResizedCrop(224), # 随机裁剪并调整大小 transforms.RandomRotation(50), # 随机旋转 transforms.ToTensor() # 转换为tensor ] ) val_transform = transforms.Compose( [ transforms.ToPILImage(), # 将numpy数组或tensor转换为PIL图像 transforms.ToTensor() # 转换为tensor ] )
-
作用: 定义训练和验证时的数据预处理流程。训练时使用数据增强(如随机裁剪、旋转),验证时只进行简单的转换。
6. 定义数据集类
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)
-
作用: 定义自定义数据集类
food_Dataset
,用于加载和处理食物分类数据集。根据模式(训练、验证、半监督)加载数据,并进行相应的预处理。
7. 定义半监督数据集类
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)
-
作用: 定义半监督数据集类
semiDataset
,用于从无标签数据中生成伪标签数据。通过模型预测无标签数据的标签,并根据置信度阈值筛选出高置信度的样本。
8. 获取半监督数据加载器
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
-
作用: 根据无标签数据加载器和模型生成半监督数据加载器。如果生成的半监督数据集为空,则返回
None
。
9. 定义自定义模型
class myModel(nn.Module): def __init__(self, num_class): super(myModel, self).__init__() 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
-
作用: 定义一个自定义的卷积神经网络模型
myModel
,用于食物分类任务。模型包含多个卷积层、池化层和全连接层。
10. 定义训练和验证函数
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) 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_loss 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()
-
作用: 定义训练和验证函数
train_val
,用于训练模型并在验证集上评估模型性能。函数还支持半监督学习,通过无标签数据生成伪标签数据来增强训练集。
11. 定义数据路径
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"
-
作用: 定义训练集、验证集和无标签数据集的路径。
12. 加载数据集
python
复制
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)
-
作用: 加载训练集、验证集和无标签数据集,并将其转换为
DataLoader
对象,以便在训练过程中进行批量加载。
13. 初始化模型
# model = myModel(11) model, _ = initialize_model("vgg", 11, use_pretrained=True)
-
作用: 初始化模型。可以选择使用自定义模型
myModel
或预训练的VGG模型。
14. 定义优化器和损失函数
lr = 0.001 loss = nn.CrossEntropyLoss() optimizer = torch.optim.AdamW(model.parameters(), lr=lr, weight_decay=1e-4)
-
作用: 定义学习率、损失函数(交叉熵损失)和优化器(AdamW)。
15. 设置设备
device = "cuda" if torch.cuda.is_available() else "cpu"
-
作用: 检查是否有可用的GPU,如果有则使用GPU,否则使用CPU。
16. 定义保存路径和训练参数
save_path = "model_save/best_model.pth" epochs = 15 thres = 0.99
-
作用: 定义模型保存路径、训练轮数和置信度阈值。
17. 开始训练
train_val(model, train_loader, val_loader, no_label_loader, device, epochs, optimizer, loss, thres, save_path)
-
作用: 调用
train_val
函数,开始训练模型,并在验证集上评估模型性能。训练过程中会保存最佳模型,并绘制损失和准确率曲线。
总结
这段代码实现了一个食物分类项目,包括数据加载、模型定义、训练和验证等功能。通过半监督学习,利用无标签数据生成伪标签数据来增强训练集,从而提高模型性能。
# 导入必要的库 import random # 用于生成随机数 import torch # PyTorch深度学习框架 import torch.nn as nn # PyTorch的神经网络模块 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): torch.manual_seed(seed) # 设置PyTorch的随机种子 torch.cuda.manual_seed(seed) # 设置GPU的随机种子 torch.cuda.manual_seed_all(seed) # 设置所有GPU的随机种子 torch.backends.cudnn.benchmark = False # 关闭cuDNN的自动优化 torch.backends.cudnn.deterministic = True # 确保cuDNN的结果是确定的 random.seed(seed) # 设置Python随机模块的种子 np.random.seed(seed) # 设置NumPy的随机种子 os.environ['PYTHONHASHSEED'] = str(seed) # 设置Python哈希种子 # 调用seed_everything函数,设置随机种子为0 seed_everything(0) # 定义图像的高度和宽度 HW = 224 # 定义训练数据的预处理和数据增强 train_transform = transforms.Compose( [ transforms.ToPILImage(), # 将numpy数组或tensor转换为PIL图像 transforms.RandomResizedCrop(224), # 随机裁剪并调整大小 transforms.RandomRotation(50), # 随机旋转 transforms.ToTensor() # 转换为tensor ] ) # 定义验证数据的预处理 val_transform = transforms.Compose( [ transforms.ToPILImage(), # 将numpy数组或tensor转换为PIL图像 transforms.ToTensor() # 转换为tensor ] ) # 定义自定义数据集类 class food_Dataset(Dataset): def __init__(self, path, mode="train"): self.mode = mode # 数据集模式(train, val, semi) 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)): # 遍历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 # 初始化X Y = yi # 初始化Y 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) # 定义半监督数据集类 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 # 如果没有生成伪标签数据,标志为False else: self.flag = True # 如果生成了伪标签数据,标志为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() # 定义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) # 计算Softmax概率 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]) # 存储图像数据 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) # 获取半监督数据加载器 def get_semi_loader(no_label_loder, model, device, thres): semiset = semiDataset(no_label_loder, model, device, thres) # 创建半监督数据集 if semiset.flag == False: return None # 如果没有生成伪标签数据,返回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__() self.conv1 = nn.Conv2d(3, 64, 3, 1, 1) # 第一层卷积 self.bn1 = nn.BatchNorm2d(64) # 批归一化 self.relu = nn.ReLU() # ReLU激活函数 self.pool1 = nn.MaxPool2d(2) # 最大池化 self.layer1 = nn.Sequential( nn.Conv2d(64, 128, 3, 1, 1), # 第二层卷积 nn.BatchNorm2d(128), # 批归一化 nn.ReLU(), # ReLU激活函数 nn.MaxPool2d(2) # 最大池化 ) self.layer2 = nn.Sequential( nn.Conv2d(128, 256, 3, 1, 1), # 第三层卷积 nn.BatchNorm2d(256), # 批归一化 nn.ReLU(), # ReLU激活函数 nn.MaxPool2d(2) # 最大池化 ) self.layer3 = nn.Sequential( nn.Conv2d(256, 512, 3, 1, 1), # 第四层卷积 nn.BatchNorm2d(512), # 批归一化 nn.ReLU(), # ReLU激活函数 nn.MaxPool2d(2) # 最大池化 ) self.pool2 = nn.MaxPool2d(2) # 最大池化 self.fc1 = nn.Linear(25088, 1000) # 全连接层 self.relu2 = nn.ReLU() # ReLU激活函数 self.fc2 = nn.Linear(1000, num_class) # 输出层 # 定义前向传播 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): # 遍历每个epoch 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) # 计算损失 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: # 每3个epoch且验证准确率大于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_loss # 更新最大准确率 # 打印训练结果 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])) # 绘制训练和验证损失曲线 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() # 定义数据路径 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) # 使用预训练的VGG模型 # 定义学习率、损失函数和优化器 lr = 0.001 # 学习率 loss = nn.CrossEntropyLoss() # 交叉熵损失函数 optimizer = torch.optim.AdamW(model.parameters(), lr=lr, weight_decay=1e-4) # AdamW优化器 # 设置设备 device = "cuda" if torch.cuda.is_available() else "cpu" # 使用GPU或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)