系列文章:

2022李宏毅作业hw1—新冠阳性人员数量预测。_亮子李的博客-CSDN博客

hw-2 李宏毅2022年作业2 phoneme识别 单strong-hmm详细解释。_亮子李的博客-CSDN博客

git地址:

lihongyi2022homework/hw3_food at main · xiaolilaoli/lihongyi2022homework · GitHub

前言

注意我做的是2021的 ,因为2022的和2020的是一样的 所以之前做过了 ,就选了不一样的2021的。

作业三我准备,做着写着  因为,有点小困难。第三个作业,是需要极强的半监督和数据增广能力。这些我都是现学的,所以怕最后忘掉,所以我走一步记一步,正好用博文来做笔记。

注意在作业3和后面的作业里, 我可能就不再会详细的写怎么代码的每一部分了,因为和hw1和hw2都是大同小异的。 可以参考之前的形成自己的模块。 除非那个作业有很不一样的地方。

我最后的准确率是百分之80左右。 有时候甚至能达到百分之82。 可惜的是目前这个作业关闭了提交入口。 如果说kaggle上面的分数就是准确率的话,那我的准确率就在strongline边上。 可是我实在无法想象90多的准确率是怎么达到的。 注意这个作业是不可以用预训练模型的,如果你用预训练的resnet 那么准确率很容易就达到九十多。 但是就违规了。

可以看到我训练集都没有办法达到95以上的准确率,可能是模型太小了。 我很想换成res50试一试, 可是显卡真的不允许。 我不理解对比学习占空间怎么这么大 。。。。。。。

kaggle数据地址: ml2021spring-hw3 | Kaggle

前戏

数据 是这个任务的重头戏。其实我第一次学李老师的课时做过食物分类的作业,不过当时完全是小白。 徒增笑耳。 这次的作业是把上次的有监督任务改成了半监督任务。

可以看到 有标签的数据只有280 *11, 比测试集还要少,这种一般都没有办法做很高的准确率这样子。所以我们必须用上没有标签的训练数据,足足有6786张。

一般来说 步骤就是 用有标签的数据训练一个模型 , 在模型的准确率达到一定门槛的时候, 用这个模型去预测无标签的数据 如果置信度大于一个阈值 比如 我们认为置信度大于0.85的图片 可以作为训练的图片。 就把这张作为新的训练集。 迭代几次模型后,再次对无标签数据进行预测 再次挑取那些置信度高的数据。

然后我去学习了数据增广的一些知识。我发现数据增广的影响实在是太大了。

train_transform = transforms.Compose([#     transforms.Resize((224, 224)),#     transforms.ToTensor(),transforms.ToPILImage(),# transforms.RandomResizedCrop(224),transforms.RandomHorizontalFlip(),autoaugment.AutoAugment(),transforms.ToTensor(),# transforms.Normalize([0.485,0.456,0.406],[0.229,0.224,0.225])
])

这里是一些可选的数据增广方式  我发现 如果你 加入了最后一项NORMlize后  这个模型几乎完全训练不动

这个原因我不知道是为什么 , 后面再解决吧。 我感觉很奇怪 反正。

而当你去掉这一项 就可以大概的训练起来了。  至少准确率能到30左右

如果你选取一个合适的学习率和模型,比如我选的是res18 那么你大概能达到百分之五十的准确率。

如果你加上半监督, 那么准确率也是一直在浮动, 最高到百分之60左右。 我也不知道怎么样才能做到更高了。

转换思路,对比学习。

正值此时,李沐频道的朱老师发了一个对比学习的综述视频。 看了之后发现, 咦,对比学习不是正好可以用来解决这个问题吗? 拥有大量的无标签数据。

精调细选之后,挑取了simsaim作为我们使用的模型, 第一是因为他够新, 第二是因为他非常的简单,听说。 关于simsaim 来学习食物分类看下面这篇。

对比学习 ——simsiam 代码解析。:_亮子李的博客-CSDN博客

在git里 我也上传了自己用simsaim训练的代码。 用的时候需要改下数据的地址。

经过simsaim之后我们能得到两个模型。 一个是提取特征的res18 模型, 一个是用来分类的classfier模型。 回来后我们可以丢弃classfier,只用那个res18的backbone。 其实就是进行一个抽特征之后线性验证的过程。  现在我们有了抽特征的模型 ,就相当于一个预训练的模型,然后要对分类头进行训练 。

直接看过程吧。  注意复制simsaim的models和optimizer 两个模块 到这个项目里来。

1 数据

train_loader = getDataLoader(filepath, 'train', batchSize)
val_loader = getDataLoader(filepath, 'val', batchSize)
no_label_Loader = getDataLoader(filepath,'train_unl', batchSize)

看看dataset 怎么写的可以。

sim_train_trans = transforms.Compose([transforms.ToPILImage(),transforms.RandomResizedCrop(HW, scale=(0.08, 1.0), ratio=(3.0/4.0,4.0/3.0), interpolation=Image.BICUBIC),transforms.RandomHorizontalFlip(),transforms.ToTensor(),transforms.Normalize(*imagenet_norm)
])sim_test_trans = transforms.Compose([transforms.ToPILImage(),transforms.Resize(int(HW*(8/7)), interpolation=Image.BICUBIC), # 224 -> 256transforms.CenterCrop(HW),transforms.ToTensor(),transforms.Normalize(*imagenet_norm)
])class foodDataset(Dataset):def __init__(self, path, mode):y = Noneself.transform = Noneself.mode = modepathDict = {'train':'training/labeled','train_unl':'training/unlabeled', 'val':'validation', 'test':'testing'}imgPaths = path +'/'+ pathDict[mode]# train_transform = transforms.Compose([#     transforms.RandomResizedCrop(224),#     transforms.RandomHorizontalFlip(),#     # autoaugment.AutoAugment(),#     transforms.Normalize([0.485,0.456,0.406],[0.229,0.224,0.225])# ])if mode == 'test':x = self._readfile(imgPaths,False)self.transform = sim_test_transelif mode == 'train':x, y =self._readfile(imgPaths,True)self.transform = sim_train_transelif mode == 'val':x, y =self._readfile(imgPaths,True)# self.transform = test_transformself.transform = sim_test_transelif mode == 'train_unl':x = self._readfile(imgPaths,False)self.transform = sim_test_transif y is not None:y = torch.LongTensor(y)self.x, self.y = x, ydef __getitem__(self, index):orix = self.x[index]if self.transform == None:xT = torch.tensor(orix).float()else:xT = self.transform(orix)if self.y is not None:y = self.y[index]return xT, y, orixelse:return xT, orixdef _readfile(self,path, label=True):if label:x, y = [], []for i in tqdm(range(11)):label = '/%02d/'%iimgDirpath = path+labelimglist = os.listdir(imgDirpath)xi = np.zeros((len(imglist), HW, HW ,3),dtype=np.uint8)yi = np.zeros((len(imglist)),dtype=np.uint8)for j, each in enumerate(imglist):imgpath = imgDirpath + eachimg = Image.open(imgpath)img = img.resize((HW, HW))xi[j,...] = imgyi[j] = iif i == 0:x = xiy = yielse:x = np.concatenate((x, xi), axis=0)y = np.concatenate((y, yi), axis=0)print('读入有标签数据%d个 '%len(x))return x, yelse:imgDirpath = path + '/00/'imgList = os.listdir(imgDirpath)x = np.zeros((len(imgList), HW, HW ,3),dtype=np.uint8)for i, each in enumerate(imgList):imgpath = imgDirpath + eachimg = Image.open(imgpath)img = img.resize((HW, HW))x[i,...] = imgreturn xdef __len__(self):return len(self.x)

写了一个读文件的函数 。 然后值得注意的是 数据增广和 对比学习时的增广方式一定要保持一致。我这里采取的方式 都是原来simsaim的 ,没有变化。

2 训练

训练方式和以前也有所不同。 主要的不同部分在于 提取特征和分类头分开了 。我们来看。

def load_backBone(model, prepath, is_dict=False):save_dict = torch.load(prepath, map_location='cpu')if is_dict:new_state_dict = save_dictelse:new_state_dict = {'state_dict':save_dict.module.state_dict()}msg = model.load_state_dict({k[9:]:v for k, v in new_state_dict['state_dict'].items()         if k.startswith('backbone.')}, strict=True)return modelbackbone = get_backbone('resnet18_cifar_variant1')
backbone = load_backBone(backbone,SimPrePath,False)classfier = nn.Linear(in_features=512, out_features=11, bias=True)

上面是获取模型。 下面是超参数,我直接搬simsaim的过来 。 学习率也可以自己调调。 我们可以看到原来的学习率是1点多 。有点可怕。 但是还挺好用的。 不可思议。

##lr = 30*batchSize/256optimizer = get_optimizer('sgd', classfier,lr=0.001,momentum=0.9,weight_decay=0)# define lr scheduler
scheduler = LR_Scheduler(optimizer,0, 0*batchSize/256,epoch, 0.001, 0*batchSize/256,len(train_loader),)

下面是训练的代码 。

           classifier.train()for data in tqdm(train_loader):if flag ==0:backBone.eval()if max_acc > 0.74:flag = 1classifier.zero_grad()x , target = data[0].to(device), data[1].to(device)with torch.no_grad():feature = backBone(x)num = random.randint(0,10000)if num == 99:samplePlot(train_loader,True,isbat=False,ori =True)pred = classifier(feature)bat_loss = loss(pred, target)bat_loss.backward()scheduler.step()optimizer.step()else:backBone.train()classifier.zero_grad()backBone.zero_grad()x , target = data[0].to(device), data[1].to(device)feature = backBone(x)num = random.randint(0,10000)if num == 99:samplePlot(train_loader,True,isbat=False,ori =True)pred = classifier(feature)bat_loss = loss(pred, target)bat_loss.backward()scheduler.step()optimizer.step()train_loss += bat_loss.item()    #.detach 表示去掉梯度train_acc += np.sum(np.argmax(pred.cpu().data.numpy(),axis=1)== data[1].numpy())plt_train_loss . append(train_loss/train_loader.dataset.__len__())plt_train_acc.append(train_acc/train_loader.dataset.__len__())

可以看到我是怎么写的。 如果在准确率小于一定阈值的情况下, 这里是0.74 .我选择只训练分类头。(通过.train .eval控制。) 如果大于0.74 我会让分类头和特征提取器一起训练。 我想的是 之前对比学习准确率已经到0.72了 。如果你直接一上来分类头是随机的情况下乱训练, 很容易让对比学习学到的模型崩溃。 所以在一定的准确率之前, 还不能让特征提取器乱动。

这样训练出来的准确率能达到百分之八十多一点点。  但是训练的非常慢

3半监督。

好吧 我承认, 我训练了半天 ,半监督根本没用上,当我尝试加入半监督后,准确率根本就上不去。 但还是自己辛辛苦苦写的。 po上来给大家看看吧。也许大家能看出我哪里有问题才导致上不去。 事实上,我在对比学习前就试过半监督了,准确率根本没有上去过。

半监督的关键在于新数据集的制作。 我们知道 半监督, 就是达到一定准确率的模型 来预测没有标签的图片, 将这些图片达到的定置信度的打上标签作为训练数据。

所以最关键的部分就是打标签的部分啦。 我是这样做的。 上面读取了无标签数据 。 当准确率到80 就启用半监督。

        if do_semi and plt_val_acc[-1] > acc_thres and i % semi_epoch==0:semi_Loader = get_semi_loader(train_loader,no_label_Loader, backBone,classifier, device, conf_thres)
def get_semi_loader(train_loader, dataloader, backBone,classifier, device, thres):semi_set = noLabDataset(train_loader.dataset, dataloader, backBone, classifier, device, thres)dataloader = DataLoader(semi_set, batch_size=dataloader.batch_size,shuffle=True)return dataloader

我们来看这个dataset怎么写的

class noLabDataset(Dataset):def __init__(self,train_dataset, dataloader, backBone,classifier, device, thres=0.85):super(noLabDataset, self).__init__()self.transformers = sim_train_trans    #增广 这个训练时用的self.backBone = backBone          self.classifier = classifier       #模型也要传入进来self.device = deviceself.thres = thres      #这里置信度阈值 我设置的 0.99x, y = self._model_pred(dataloader)        #核心self.x = np.concatenate((np.array(x),train_dataset.x),axis=0)self.y = torch.cat(((torch.LongTensor(y),train_dataset.y)),dim=0)def _model_pred(self, dataloader):backBone = self.backBoneclassifier = self.classifierdevice = self.devicethres = self.threspred_probs = []labels = []x = []y = []with torch.no_grad():for data in dataloader:imgs = data[0].to(device)feature = backBone(imgs)pred = classifier(feature)soft = torch.nn.Softmax(dim=1)pred_p = soft(pred)pred_max, preds = pred_p.max(1)          #得到最大值 ,和最大值的位置 。 就是置信度和标签。 pred_probs.extend(pred_max.cpu().numpy().tolist())labels.extend(preds.cpu().numpy().tolist())for index, prob in enumerate(pred_probs):if prob > thres:x.append(dataloader.dataset[index][1])y.append(labels[index])return x, ydef __getitem__(self, index):x = self.x[index]x= self.transformers(x)y = self.y[index]return x, ydef __len__(self):return len(self.x)

模型 传进来 ,用模型预测图片 如果置信度超过阈值 就记下来。 最后与训练集的数据cat起来 。在制作loader时进行打乱。 这样就得到了带有无标签数据的训练数据集。

然后照常训练即可。 每10个epoch更新一次这个数据集。

结语

这个作业没有办法提交, 所以测试写了也没啥意义。 我的感觉是好难。 真的 ,准确率好难上去,我有时候很想知道我和那些大佬们的差距在哪里,为啥他们的准确率能高这么多,他们是怎么做到的。???而我根本没有办法让模型收敛。唉 ,难过。

想做的尝试是用res50进行训练 ,但是我没有卡呀没有卡。res50的bat只能设为8。训练一个epo要15分钟,令人绝望。

2021李宏毅作业hw3 --食物分类。对比出来的80准确率。相关推荐

  1. 数据增广albumentations用法 -借例 hw3 食物分类-

    previous work: 开启第三个作业 食物分类 , 有的人找不到数据集地址 放一个 :ml2021spring-hw3 | Kaggle 前言: 这个作业 每类带标签的数据很少, 然后又是可以 ...

  2. 2022李宏毅作业hw4 - 挫败感十足的一次作业。

    系列文章: 2022李宏毅作业hw1-新冠阳性人员数量预测._亮子李的博客-CSDN博客_李宏毅hw1 hw-2 李宏毅2022年作业2 phoneme识别 单strong-hmm详细解释._亮子李的 ...

  3. 李宏毅ML作业笔记3: 食物分类(kaggle预测与报告题目)

    kaggle中的任务发布在: https://www.kaggle.com/c/ml2020spring-hw3 本文代码在kaggle公开: https://www.kaggle.com/laugo ...

  4. 百度飞桨2021李宏毅机器学习特训营学习笔记之回归及作业PM2.5预测

    百度飞桨2021李宏毅机器学习特训营学习笔记之回归及作业PM2.5预测 前言 回归 什么是回归(Regression)? 怎么做回归? 线性回归(Linear Regression) 训练集与验证集 ...

  5. 2021李宏毅机器学习笔记--22 Generative Adversarial Network 01

    @[TOC](2021李宏毅机器学习笔记–22 Generative Adversarial Network 01(GAN,生成式对抗网络)) 摘要 GAN是建立于神经网络的基础上的,其核心思想是&q ...

  6. 【文本分类】基于BERT预训练模型的灾害推文分类方法、基于BERT和RNN的新闻文本分类对比

    ·阅读摘要: 两篇论文,第一篇发表于<图学学报>,<图学学报>是核心期刊:第二篇发表于<北京印刷学院学报>,<北京印刷学院学报>没有任何标签. ·参考文 ...

  7. 2021李宏毅机器学习笔记--21 Anomaly Detection

    2021李宏毅机器学习笔记--21 Anomaly Detection(异常侦测) 摘要 一.问题描述 二.Anomaly异常 三.Anomaly Detection(异常侦测)做法 3.1 Bina ...

  8. 2021起重机作业 (Q)Q3起重机械指挥模拟考试题库及软件

    题库来源:特种作业模考题库小程序 2021起重机作业模拟考试题库.结合国家起重机考试最新大纲及真题出具,有助于起重机怎么考考前练习. 1.相交于一点的两个力合成计算是运用平行四边形( ). A A.法 ...

  9. 2021起重机作业 (Q)模拟考试题库

    题库来源:特种作业模考题库小程序 2021起重机作业模拟考试题库.结合国家起重机考试最新大纲及真题出具,有助于起重机怎么考考前练习. 1.指挥人员在发出要主钩.( )的手势或旗语时,要目视司机,同时可 ...

  10. [Python从零到壹] 十四.机器学习之分类算法五万字总结全网首发(决策树、KNN、SVM、分类对比实验)

    欢迎大家来到"Python从零到壹",在这里我将分享约200篇Python系列文章,带大家一起去学习和玩耍,看看Python这个有趣的世界.所有文章都将结合案例.代码和作者的经验讲 ...

最新文章

  1. 紫色回归线:雅虎中国的运筹学
  2. 高级交叉报表例子程序(C#)中明细列统计数据错误改正!
  3. Android运行时识别API版本
  4. 新来的“大神”用策略模式把if else给“优化”了,技术总监说:能不能想好了再改?
  5. vuex ajax dev,vuex中使用ajax的话如何维护状态?
  6. 不存在从node到node*的适当转换函数_C++构造函数和初始化表
  7. NOIP2008 普及组T1 ISBN号码 解题报告-S.B.S.
  8. A Complete Machine Learning Walk-Through in Python
  9. Python函数式编程-map()、zip()、filter()、reduce()、lambda()
  10. php 堵塞 消息队列,PHP的并发处理
  11. Python——Python3.6.0+Scrapy安装方法(总算没有bug了)
  12. 在CentOS上进行虚拟化:QEMU、Xen、KVM、LibVirt、oVirt
  13. 黑苹果内置硬盘识别成外置硬盘_压倒U盘最后一根稻草?ORICO iMatch移动固态硬盘体验...
  14. (一)外显子组数据分析之软件安装大全
  15. mysql保存特殊表情符_mysql 存储表情或者特殊符号
  16. Matplotlib之条形图绘制
  17. [声纹识别]语音识别系统框架[1]
  18. Cmd 移动文件夹及文件
  19. 解决删除Volume报错的问题(二)
  20. 解决计算机被暴风集火(jihuo)后留下的IE,chrome,火狐等所有浏览器主页网址携带有”tn=93453552_hao_pg“后缀的驱动类木马病毒的问题

热门文章

  1. 信息系统项目管理师---第十章 项目沟通管理和项目干系人管理
  2. Markdown写作工具盘点
  3. Excel如何快速删除指定区域公式保留数值
  4. 路由器 android 打印机,用路由器将普通打印机变成网络打印机
  5. php 设置允许跨域请求
  6. 五脏六腑在脸上的反射区图片_痘痘脸部反射区图痘痘的位置反射五脏六腑的病症 [哈哈镜]...
  7. linux中文件颜色,蓝色,白色等各自代表的含义
  8. 基于ESP32的智能家居控制系统-微信小程序界面
  9. 访问小米路由器内置硬盘
  10. Kafka 常用命令