深度学习|李哥考研4图片分类比较详细说明

代码解读------图片分类

一、交叉熵损失函数

CrossEntropyLoss()交叉熵损失函数,

用于多分类任务,

功能:

1.能够计算预测值与真实值之间的差异

2.衡量模型分类的准确性

3.为反向传播提供梯度信号

二、优化器设置:

optimizer = torch.optim.AdamW(model.parameters(), lr=lr, weight_decay=1e-4)

weight_decay:添加权重衰减度,函数中加入权重平方和

限制权重的增长,防止模型参数变化过大

三、半监督的过程

1、数据准备:

收集数据集 DDD。

将其划分为两部分:
Dl=(xi,yi)i=1LD_l = { (x_i, y_i) }{i=1}^LDl=(xi,yi)i=1L:带标签的数据集,数量 LLL 通常较小。
Du=xjj=1UD_u = { x_j }
{j=1}^UDu=xjj=1U:未带标签的数据集,数量 UUU 通常远大于 LLL (U≫LU \gg LU≫L)。

2、选择模型:

选择一个合适的机器学习模型 fff。这个模型可以是分类器(如 SVM、神经网络)或回归器,取决于任务类型(分类或回归)。

模型 fff 的目标是学习一个从输入 xxx 到输出 yyy 的映射 y=f(x;θ)y = f(x; \theta)y=f(x;θ),其中 θ\thetaθ 是模型的参数。

3、设计损失函数:

半监督学习的损失函数 LLL 通常由两部分组成:

(1)监督损失 LsL_sLs: 衡量模型在带标签数据 DlD_lDl 上的预测误差。对于分类任务,常用交叉熵损失;对于回归任务,常用均方误差。其形式通常为: Ls=1L∑(xi,yi)∈Dlℓ(f(xi),yi) L_s = \frac{1}{L} \sum_{(x_i, y_i) \in D_l} \ell(f(x_i), y_i) Ls=L1(xi,yi)∈Dl∑ℓ(f(xi),yi) 其中 ℓ\ellℓ 是具体的损失函数(如交叉熵)。

(2)无监督损失 LuL_uLu: 衡量模型在无标签数据 DuD_uDu 上预测结果的某种"一致性"、"平滑性"或"结构性"。这是利用无标签数据的关键所在。

4、训练过程:

总损失函数 LLL 通常是监督损失和无监督损失的加权和: L=Ls+λLu L = L_s + \lambda L_u L=Ls+λLu 其中 λ\lambdaλ 是一个超参数,用于平衡两者的重要性。

使用优化算法(如随机梯度下降 SGD)最小化总损失 LLL,同时更新模型参数 θ\thetaθ。训练过程中会同时使用 DlD_lDl 和 DuD_uDu。

对于伪标签等方法,训练过程可能是迭代的:训练模型 -> 生成伪标签 -> 加入训练集 -> 重新训练模型。

5、评估:

在一个独立的、从未参与训练的带标签测试集上评估模型的性能(如准确率、F1 值等)。

目标是证明相较于仅使用少量标签数据 DlD_lDl 训练的纯监督模型,半监督模型性能有显著提升。

总结:

利用无标签数据的内在结构: 半监督学习有效的前提假设是,数据本身具有一定的内在结构(如聚类结构、流形结构)。

带标签数据提供了"锚点",而无标签数据则帮助模型更好地理解和泛化这种结构。

四、transform

1.在计算机几何学中对几何图像进行空间操作,平移、旋转、缩放、错切

数据预处理的工具

  • 保证数据的多样性,提高泛化能力
python 复制代码
train_transform = transforms.Compose(
    [
        transforms.ToPILImage(),   #224, 224, 3模型  :3, 224, 224 #数据格式转化
        transforms.RandomResizedCrop(224), #随机拆解并调整大小
        transforms.RandomRotation(50),#随机旋转最多50°
        transforms.ToTensor()
    ]
)
  • 没有旋转裁剪,为了保证数据的原始行
python 复制代码
val_transform = transforms.Compose(
    [
        transforms.ToPILImage(),   #224, 224, 3模型  :3, 224, 224
        transforms.ToTensor()
    ]
)

2.神经网络运用(见后面博客)

  • 自注意力: 让模型在处理序列中某个元素时,关注序列中所有其他元素并权衡其重要性。
  • 多头注意力:并行运行多个自注意力机制,捕捉不同子空间的信息。
  • 位置编码: 为输入序列添加位置信息(如正弦/余弦函数),因为模型本身不包含顺序信息。
  • 前馈神经网络: 对自注意力输出进行进一步处理。
  • 残差连接和层归一化: 帮助稳定训练和提升性能。
  • 应用: BERT, GPT系列等大型语言模型的核心架构。

五、matplotlib.pyplot as plt

用于画图

plt常用的调用函数

  • plt.scatter() 散点图
  • plt.plot(): 折线图
  • plt.title() :设置标题
  • plt.xlabel():设置x标签
  • plt.legend() 显示图例
  • plt.show(): 显示图表
python 复制代码
	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()

六、定义函数------读数据集

有标签和无标签读取数据的方式不同

初始化都需要将x放到创建的np.zero中

python 复制代码
 xi = np.zeros((len(file_list), HW, HW, 3), dtype=np.uint8) # 创建形状,用于存储图像

1、无标签,无需读取y

python 复制代码
        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): # 遍历所有图片 j为索引,img_name为文件名
                img_path = os.path.join(path, img_name) # 获取指定路径下的文件路径
                img = Image.open(img_path)
                img = img.resize((HW, HW)) # 重新将图像调整为3x224x224
                xi[j, ...] = img # 将处理后的图像存入到创建的形状中, 省略号:所有剩余维度
            print("读到了%d个数据" % len(xi))
            return xi

2、 有标签

有y需要读取

python 复制代码
            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) # 与其他数据进行垂直拼接 形成一个矩阵,确保数据图像X能够与Y一一对应
                    Y = np.concatenate((Y, yi), axis=0)
            print("读到了%d个数据" % len(Y))

七、定义函数------调用模型

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

  • model:传入要训练的模型,这里使用initialize_model包导入需要的模型
  • train_loader、val_loader、no_label_loader: 将数据加载
  • device:指定模型和数据运行的设备
  • epochs: 训练轮数,
  • optimizer:优化器负责更新模型参数
  • loss:计算预测值与真实值的误差
  • thres: 半监督学习的置信度阈值,用于筛选置信度高的无标签版本
  • save_path:指定最好模型的保存路径

这里优化可以使用字典 进行管理

python 复制代码
trainpara = {
            "model" : model,
             'train_loader': train_loader,
             'val_loader': val_loader,
             'no_label_Loader': no_label_Loader,
             'optimizer': optimizer,
            'batchSize': batchSize,
             'loss': loss,
             'epoch': epoch,
             'device': device,
             'save_path': save_path,
             'save_acc': True,
             'max_acc': 0.5,
             'val_epoch' : 1,
             'acc_thres' : 0.7,
             'conf_thres' : 0.99,
             'do_semi' : True,
            "pre_path" : None
             }

# 使用字典传递参数,避免函数参数过多,便于快速定位操作修改

if __name__ == '__main__': 
    train_val(trainpara)

1、initialize_model

就是迁移学习:用别人已经预训练好的数据即可,我们只需要调参

python 复制代码
model, _ = initialize_model("vgg", 11, use_pretrained=True)

传入模型名字,和分类数, 返回你想要的模型

  • num_class 最后指定输出的神经元数量,
  • linear_prob 是否为线性探测,当为True时 冻结特征提取器,只训练分类头。 为False是才是允许进行参数更新
  • use_pretrained 是否使用预训练的模型参数。默认是使用预训练的模型参数
python 复制代码
def initialize_model(model_name, num_classes, linear_prob=False, use_pretrained=True):
    # 初始化将在此if语句中设置的这些变量。
    # 每个变量都是模型特定的。
    model_ft = None
    input_size = 0
    if model_name =="MyModel":
        if use_pretrained == True:
            model_ft = torch.load('model_save/MyModel')
        else:
            model_ft = MyModel(num_classes)
        input_size = 224

    elif model_name == "resnet18":
        """ Resnet18
        """
        model_ft = models.resnet18(pretrained=use_pretrained)            # 从网络下载模型  pretrain true 使用参数和架构, false 仅使用架构。
        set_parameter_requires_grad(model_ft, linear_prob)            # 是否为线性探测,Ture:冻结特征提取器,只训练分类头。 False:允许参数更新。
        num_ftrs = model_ft.fc.in_features  #获取分类头的输入维度
        model_ft.fc = nn.Linear(num_ftrs, num_classes)            # 用新的替换原来分类头, 更改最后一层为想要的分类数的分类头。
        input_size = 224

主要是

确定使用什么模型 + 是否使用该架构的参数 + 哪些参数可以更新 + 修改最后架构的输出

2、训练模式

train_loss += train_bat_loss.cpu().item() # 求平均损失

  • .cpu() 将顺势张量从GPU转移到CPU内存
  • .item() 用于累加计算

python 复制代码
 train_acc += np.sum(np.argmax(pred.detach().cpu().numpy(), axis=1) == target.cpu().numpy()) # 求准确率
  • detach():从张量网上面摘下来,断开梯度追踪
  • cpu() : 从GPU -> CPU
  • numpy(): 将tensor 转化成 numpy用于计算
  • np.argmax(,axis=1)获取每一个行的最大索引,就是模型的类别
  • == target.cpu().numpy() 与真实标签进行比较
  • numpy.sum():统计预测正确的模型数量
    累加当前批次中预测正确的样本数,累加到总准确率统计中,用于后续计算模型的准确率

python 复制代码
plt_train_loss.append(train_loss / train_loader.__len__())

计算当前epoch的平均训练损失,并且追加到plt_train_loss()


python 复制代码
plt_train_acc.append(train_acc/train_loader.dataset.__len__()) #记录准确率,

计算当前epoch的平均准确损失,并且追加到plt_train_acc()


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

每3个epoch执行一次半监督学习,当最后一个准确率超过0.6时才能启用进行半监督学习


python 复制代码
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

使用semiDataSet可以进行加载数据,

如果flag == false : 没有找到置信度超过阈值的样本数据

返回为None ,无标签数据不会作为训练数据

else flag 为True ,则该无标签数据会进入模型进行训练


python 复制代码
if val_acc > max_acc:
       torch.save(model, save_path)
       max_acc = val_acc

保存性能最佳的模型版本,记录更新最高准确率


3、验证模式

python 复制代码
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.__len__())
        plt_val_acc.append(val_acc / val_loader.dataset.__len__())

4、模型设置

独立层定义 vs 容器定义

python 复制代码
# 独立层定义
	    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

独立定义

1、 每层单独命名和管理

2、 在forward中需要逐个调用

容器式定义(推荐,更简单在forward调用中)

1、多层封装在一个容器里面

2、 可以一次性调用整个容器的序列

下面就是forward的书写

python 复制代码
    def forward(self, x):
        x = self.conv1(x)
        x = self.bn1(x)
        x = self.relu(x)
        x = self.pool1(x)
        
        x = self.layer1(x)

可以看出是非常简单的调用

最后汇总

python 复制代码
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


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)
#################################################################
seed_everything(0)
###############################################


HW = 224


# 数据预处理的工具
# 保证数据的多样性,提高泛化能力
train_transform = transforms.Compose(
    [
        transforms.ToPILImage(),   #224, 224, 3模型  :3, 224, 224 #数据格式转化
        transforms.RandomResizedCrop(224), #随机拆解并调整大小
        transforms.RandomRotation(50),#随机旋转最多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) #半监督数据只有x
        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): # 遍历所有图片 j为索引,img_name为文件名
                img_path = os.path.join(path, img_name) # 获取指定路径下的文件路径
                img = Image.open(img_path)
                img = img.resize((HW, HW)) # 重新将图像调整为3x224x224
                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) # 与其他数据进行垂直拼接 形成一个矩阵,确保数据图像X能够与Y一一对应
                    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

        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)

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) # 将数据移动到GPU
            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.__len__())
        plt_val_acc.append(val_acc / val_loader.dataset.__len__())

        if epoch%3 == 0 and plt_val_acc[-1] > 0.6: # 取最后的准确率 高于 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)
# use------pretrained= True使用加载大规模的数据上面已经运行训练好的参数,如果是False使用随机初始化权重,从0开始训练
model, _ = initialize_model("vgg", 11, use_pretrained=True)


lr = 0.01
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)
相关推荐
臭东西的学习笔记6 小时前
论文学习——机器学习引导的蛋白质工程
人工智能·学习·机器学习
大王小生6 小时前
说说CSV文件和C#解析csv文件的几种方式
人工智能·c#·csv·csvhelper·csvreader
m0_462605226 小时前
第G3周:CGAN入门|生成手势图像
人工智能
bubiyoushang8887 小时前
基于LSTM神经网络的短期风速预测实现方案
人工智能·神经网络·lstm
中烟创新7 小时前
烟草专卖文书生成智能体与法规案卷评查智能体获评“年度技术最佳实践奖”
人工智能
得一录7 小时前
大模型中的多模态知识
人工智能·aigc
Github掘金计划7 小时前
Claude Work 开源平替来了:让 AI 代理从“终端命令“变成“产品体验“
人工智能·开源
ghgxm5207 小时前
Fastapi_00_学习方向 ——无编程基础如何用AI实现APP生成
人工智能·学习·fastapi
就这个丶调调8 小时前
VLLM部署全部参数详解及其作用说明
深度学习·模型部署·vllm·参数配置