图片分类任务

本文介绍了如何使用PyTorch进行食物分类项目,包括数据预处理(如图片大小调整至3*224*224),构建卷积神经网络模型(myModel)处理图像,以及训练过程中计算精度和损失的详细步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

食物分类项目学习(瞎写,巩固自用)

步骤1.读取数据

步骤2.要对图片先进行处理,图片大小转化(一般转变为3*224*224大小)

步骤3.通过数据模型

图片分类任务与回归任务相比,在模型中多了一些步骤,要对图片进行卷积运算,(3*224*224)->

(64*112*112)->(128*56*56)->(256*28*28)->(512*14*14)->(512*7*7)经过多次运算后,进行拉伸

x = x.view(x.size()[0], -1)

之后就可以理解为25088(512*7*7)个参数量的回归任务按回归的操作进行即可

具体流程、

1.建立数据集

class foodDataset(Dataset):
    def __init__(self, path, mode):
        self.mode = mode
        if mode == "train":
            self.transform = train_transform
        else:
            self.transform = val_transform

        x, y = self.read_file(path)
        self.X = x
        self.Y = torch.LongTensor(y)

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

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

    def read_file(self, path):
            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)  # 多少图片, 图片大小, 图片层数(RGB),整数类型
                yi = np.zeros(len(file_list))           # 存放标签

                for j, each in enumerate(file_list):    # 枚举函数实现返回列表中的序号和内容
                    img_path = file_dir + "/" + each
                    img = Image.open(img_path)
                    img = img.resize((HW, HW))  # 把图片大小变为224*224,改变尺寸
                    xi[j, ...] = img
                    yi[j] = i
                if i == 0:
                    X = xi
                    Y = yi
                else:
                    X = np.concatenate((X, xi), axis=0)  # 在axis=1方向上(向下)拼接矩阵
                    Y = np.concatenate((Y, yi), axis=0)
            print("read in img:%d" % len(Y))
            return X, Y

在该类中除了必须的__init__,__gititem__,__len__外,额外定义了读取文件的函数,用于读取图片(以矩阵形式读取)

2.建立模型

class myModel(nn.Module):
    def __init__(self , num_class):
        super(myModel, self).__init__()
        # 3*224*224-->512*7*7
        self.layer1 = nn.Sequential(        # 64*112*112
            nn.Conv2d(3, 64, 3, 1, 1),
            nn.BatchNorm2d(64),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )
        self.layer2 = nn.Sequential(         # 128*56*56
            nn.Conv2d(64, 128, 3, 1, 1),
            nn.BatchNorm2d(128),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )
        self.layer3 = nn.Sequential(  # 256*28*28
            nn.Conv2d(128, 256, 3, 1, 1),
            nn.BatchNorm2d(256),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )
        self.layer4 = nn.Sequential(  # 512*14*14
            nn.Conv2d(256, 512, 3, 1, 1),
            nn.BatchNorm2d(512),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )
        self.pool =nn.MaxPool2d(2)      #512*7*7
        self.fc1 = nn.Linear(512*7*7, 1000)
        self.relu =nn.ReLU()
        self.fc2 =nn.Linear(1000,num_class)
    def forward(self, x):
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        x = self.layer4(x)
        x = self.pool(x)
        x = x.view(x.size()[0], -1)
        x = self.fc1(x)
        x = self.relu(x)
        x = self.fc2(x)
        return x

分成了三个层方便书写,每个层中都进行了一次步长为1p,padding为1,卷积核大小为3的运算,层数每次加倍,然后是激活函数(relu)和最大值pooling,图片大小均除以2,最后进行回归操作(25088)->(1000)->(11)。

3.训练样本

训练过程都大同小异,用训练样本进行训练,验证样本进行验证,保存效果最好的模型。分类任务要保证准确率,因此引入了一个精准度的变量max_val_acc去衡量模型,而不是min_val_loss

def train_val(model, trainloader, valloader,optimizer, loss, epoch, device, save_path,no_label_loader, thres):
    model = model.to(device)                # 模型和数据 ,要在一个设备上。  cpu - gpu
    plt_train_loss = []
    plt_val_loss = []
    plt_train_acc = []
    plt_val_acc = []

    max_val_acc = 0.0                # 记录训练验证loss 以及验证loss和结果
    for i in range(epoch):                 # 训练epoch 轮
        start_time = time.time()             # 记录开始时间
        model.train()                         # 模型设置为训练状态      结构
        train_loss = 0.0
        val_loss = 0.0
        train_acc = 0.0
        val_acc = 0.0


        for data in trainloader:                     # 从训练集取一个batch的数据
            optimizer.zero_grad()                   # 梯度清0
            x, target = data[0].to(device), data[1].to(device)       # 将数据放到设备上
            pred = model(x)                          # 用模型预测数据
            bat_loss = loss(pred, target)       # 计算loss
            bat_loss.backward()                        # 梯度回传, 反向传播。
            optimizer.step()                            #用优化器更新模型。  轮到SGD出手了
            train_loss += bat_loss.detach().cpu().item()             #记录loss和
            train_acc += np.sum(np.argmax(pred.detach().cpu().numpy(),axis=1) == target.cpu().numpy())      # 记录一组样本中最大值所在的下标与目标对比,预测对则+1(注意从gpu上取下来)

        plt_train_loss. append(train_loss/trainloader.dataset.__len__())   #记录loss到列表。注意是平均的loss ,因此要除以数据集长度。
        plt_train_acc.append(train_acc / trainloader.dataset.__len__())  # 记录acc到列表。注意是平均的acc ,因此要除以数据集长度。

  

        model.eval()                 # 模型设置为验证状态
        with torch.no_grad():                    # 模型不再计算梯度
            for data in valloader:                      # 从验证集取一个batch的数据
                val_x , val_target = data[0].to(device), data[1].to(device)          # 将数据放到设备上
                val_pred = model(val_x)                 # 用模型预测数据
                val_bat_loss = loss(val_pred, val_target)          # 计算loss
                val_loss += val_bat_loss.detach().cpu().item()                  # 计算loss
                val_acc += np.sum(np.argmax(val_pred.detach().cpu().numpy(),axis=1) == val_target.cpu().numpy())

        plt_val_loss.append(val_loss/valloader.dataset.__len__())  #记录loss到列表。注意是平均的loss ,因此要除以数据集长度。
        plt_val_acc.append(val_acc / valloader.dataset.__len__())  # 记录acc到列表。注意是平均的acc ,因此要除以数据集长度。

        if val_acc > max_val_acc:
            torch.save(model, save_path)               #如果loss比之前的最小值小, 说明模型更优, 保存这个模型
            max_val_acc = val_acc

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

    plt.plot(plt_train_loss)              # 画图, 向图中放入训练loss数据
    plt.plot(plt_val_loss)                # 画图, 向图中放入训练loss数据
    plt.title('loss')                      # 画图, 标题
    plt.legend(['train', 'val'])             # 画图, 图例
    plt.show()                                 # 画图, 展示

    plt.plot(plt_train_acc)              # 画图, 向图中放入训练loss数据
    plt.plot(plt_val_acc)                # 画图, 向图中放入训练loss数据
    plt.title('acc')                      # 画图, 标题
    plt.legend(['train', 'val'])             # 画图, 图例
    plt.show()

相关知识点

1.主要注意的是图片的维度变化和图片大小。

2.计算图片大小

 (p1-q+padding*2)/b+1=p2

p1:原图片大小,q:卷积核大小,padding,b:步长,p2:新图片大小

pooling计算

图片大小长宽分别除以步长(一般为2)

计算卷积核大小

即新图片层数*卷积核大小**2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值