深度学习-分类任务-食物分类

图片的读入

def read_file(path):
    for i in tqdm(range(11)):
        img_path = path + "/%02d/"%i
        img_list = os.listdir(img_path) # 读取文件夹下所有文件
        xi = np.zeros((len(img_list), HW, HW, 3), dtype=np.uint8)  #280 * 224* 224 *3
        yi = np.zeros(len(img_list), dtype=np.uint8)# 280*1
        for j, img in enumerate(img_list):
            true_img_path = img_path + img
            img = Image.open(true_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)
            Y = np.concatenate((Y, yi), axis=0)
    print("读取了%d个数据"%len(Y))
    return  X, Y

xi为一个行数为280的表,每一行都存放着一个图片的数据。

yi为图片的标签,用1维即可。

通过两个循环,将图片和其标签分别保存在xi,yi在中,然后存在X和Y中,每次xi,yi更新一次。

  1. xi 是一个临时的变量,用于存储当前子文件夹(类别)中的所有图像数据。在循环的每次迭代中,都会创建一个新的 xi 数组,用于存储当前子文件夹中所有图像的像素值。xi 的形状是 (len(img_list), HW, HW, 3),其中 len(img_list) 是当前子文件夹中的图像数量。

  2. X 是最终的图像数据数组,用于存储所有子文件夹中的图像数据。在循环的每次迭代中,将当前子文件夹的图像数据添加到 X 中。X 的形状是 (总图像数量, HW, HW, 3),其中 总图像数量 是所有子文件夹中的图像总数。

在代码的循环中,xi 被用来存储当前子文件夹的图像数据,然后将其追加到 X 中。这样,X 包含了所有子文件夹中的图像数据。而 xi 则在每次循环迭代后被重新创建,用于下一个子文件夹的图像数据存储。

总结起来,xi 是循环内每个子文件夹中图像数据的临时存储,而 X 是最终存储所有图像数据的数组。

数据集

class fooddataset(Dataset):
    def __init__(self, path):
        super(fooddataset, self).__init__()
        self.X, self.Y = read_file(path)
        self.Y = torch.LongTensor(self.Y)
        self.transformer = train_transformer

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

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

模型

class myModel(nn.Module):
    def __init__(self):
        super(myModel, self).__init__()
        #3*224*224 - 512*7*7
        self.layer0 = nn.Sequential(
            nn.Conv2d(3, 64, 3, 1, 1),
            nn.BatchNorm2d(64),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )  # 把里面的操作合成一个    64*112*112

        self.layer1 = nn.Sequential(
            nn.Conv2d(64, 128, 3, 1, 1),
            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.pool1 = nn.MaxPool2d(2) #512*7*7
        self.fc1 = nn.Linear(25088, 1000)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(1000, 11)

    def forward(self, x):
        x = self.layer0(x)
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        x = self.pool1(x)

        x = x.view(x.size()[0], -1)
        x = self.fc1(x)
        x = self.relu(x)
        x = self.fc2(x)
        return x

mymodel = myModel()

分类模型,不再保存最佳loss,而是保存最佳准确率,记录每一轮训练的准确率。

训练流程,可以用回归模型的训练流程

def train_val(model, trainloader, valloader,optimizer, loss, epoch, device, save_):
    # trainloader = DataLoader(trainset,batch_size=batch,shuffle=True)
    # valloader = DataLoader(valset,batch_size=batch,shuffle=True)
    model = model.to(device)                # 模型和数据 ,要在一个设备上。  cpu - gpu
    plt_train_loss = []
    plt_val_loss = []


    val_rel = []
    min_val_loss = 100000                 # 记录训练验证loss 以及验证loss和结果

    for i in range(epoch):                 # 训练epoch 轮
        train_acc = 0.0
        val_acc = 0.0
        start_time = time.time()             # 记录开始时间
        model.train()                         # 模型设置为训练状态      结构
        train_loss = 0.0
        val_loss = 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.cpu().data.numpy(), axis=1) == data[1].cpu().numpy())

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

        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_rel.append(val_pred)                 #记录预测结果
        if val_loss < min_val_loss:
            torch.save(model, save_)               #如果loss比之前的最小值小, 说明模型更优, 保存这个模型
        val_acc += np.sum(np.argmax(val_pred.cpu().data.numpy(), axis=1) == val_target[1].cpu().numpy())
        print("val_acc:",val_acc)
        plt_val_loss.append(val_loss/valloader.dataset.__len__())  #记录loss到列表。注意是平均的loss ,因此要除以数据集长度。
        #
        print('[%03d/%03d] %2.2f sec(s) TrainLoss : %.6f | valLoss: %.6f' % \
              (i, epoch, time.time()-start_time, plt_train_loss[-1], plt_val_loss[-1])
              )              #打印训练结果。 注意python语法, %2.2f 表示小数位为2的浮点数, 后面可以对应。

        # print('[%03d/%03d] %2.2f sec(s) TrainLoss : %3.6f | valLoss: %.6f' % \
        #       (i, epoch, time.time()-start_time, 2210.2255411, plt_val_loss[-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()                                 # 画图, 展示


train_val(mymodel, train_loader, val_loader,optimizer, loss, epochs, device, save_)

准确率如何计算:找到张量pred中最大值所在的下标。

train_acc += np.sum(np.argmax(pred.cpu().data.numpy(), axis=1) == data[1].cpu().numpy())

图片增广

train_transformer = transforms.Compose([
    transforms.ToPILImage(),  # 这个img 转为PIL
    transforms.RandomResizedCrop(224),  #随机resize 。 取中间的224.
    transforms.ToTensor()          # 转为张量

])

优化器Adam与Adamw,不再用std

Adwamw,权重衰减

迁移学习:数据量小的最佳选择

大佬们的模型花了很多钱、在千万数据集上训练,提取的特征特别好,所以借用大佬的模型

所以有预训练模型时用预训练模型。

使用时,可以选择训练特征提取器和分类头。

  • 11
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值