2021李宏毅作业hw3 --食物分类。对比出来的80准确率。
系列文章:
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准确率。相关推荐
- 数据增广albumentations用法 -借例 hw3 食物分类-
previous work: 开启第三个作业 食物分类 , 有的人找不到数据集地址 放一个 :ml2021spring-hw3 | Kaggle 前言: 这个作业 每类带标签的数据很少, 然后又是可以 ...
- 2022李宏毅作业hw4 - 挫败感十足的一次作业。
系列文章: 2022李宏毅作业hw1-新冠阳性人员数量预测._亮子李的博客-CSDN博客_李宏毅hw1 hw-2 李宏毅2022年作业2 phoneme识别 单strong-hmm详细解释._亮子李的 ...
- 李宏毅ML作业笔记3: 食物分类(kaggle预测与报告题目)
kaggle中的任务发布在: https://www.kaggle.com/c/ml2020spring-hw3 本文代码在kaggle公开: https://www.kaggle.com/laugo ...
- 百度飞桨2021李宏毅机器学习特训营学习笔记之回归及作业PM2.5预测
百度飞桨2021李宏毅机器学习特训营学习笔记之回归及作业PM2.5预测 前言 回归 什么是回归(Regression)? 怎么做回归? 线性回归(Linear Regression) 训练集与验证集 ...
- 2021李宏毅机器学习笔记--22 Generative Adversarial Network 01
@[TOC](2021李宏毅机器学习笔记–22 Generative Adversarial Network 01(GAN,生成式对抗网络)) 摘要 GAN是建立于神经网络的基础上的,其核心思想是&q ...
- 【文本分类】基于BERT预训练模型的灾害推文分类方法、基于BERT和RNN的新闻文本分类对比
·阅读摘要: 两篇论文,第一篇发表于<图学学报>,<图学学报>是核心期刊:第二篇发表于<北京印刷学院学报>,<北京印刷学院学报>没有任何标签. ·参考文 ...
- 2021李宏毅机器学习笔记--21 Anomaly Detection
2021李宏毅机器学习笔记--21 Anomaly Detection(异常侦测) 摘要 一.问题描述 二.Anomaly异常 三.Anomaly Detection(异常侦测)做法 3.1 Bina ...
- 2021起重机作业 (Q)Q3起重机械指挥模拟考试题库及软件
题库来源:特种作业模考题库小程序 2021起重机作业模拟考试题库.结合国家起重机考试最新大纲及真题出具,有助于起重机怎么考考前练习. 1.相交于一点的两个力合成计算是运用平行四边形( ). A A.法 ...
- 2021起重机作业 (Q)模拟考试题库
题库来源:特种作业模考题库小程序 2021起重机作业模拟考试题库.结合国家起重机考试最新大纲及真题出具,有助于起重机怎么考考前练习. 1.指挥人员在发出要主钩.( )的手势或旗语时,要目视司机,同时可 ...
- [Python从零到壹] 十四.机器学习之分类算法五万字总结全网首发(决策树、KNN、SVM、分类对比实验)
欢迎大家来到"Python从零到壹",在这里我将分享约200篇Python系列文章,带大家一起去学习和玩耍,看看Python这个有趣的世界.所有文章都将结合案例.代码和作者的经验讲 ...
最新文章
- 紫色回归线:雅虎中国的运筹学
- 高级交叉报表例子程序(C#)中明细列统计数据错误改正!
- Android运行时识别API版本
- 新来的“大神”用策略模式把if else给“优化”了,技术总监说:能不能想好了再改?
- vuex ajax dev,vuex中使用ajax的话如何维护状态?
- 不存在从node到node*的适当转换函数_C++构造函数和初始化表
- NOIP2008 普及组T1 ISBN号码 解题报告-S.B.S.
- A Complete Machine Learning Walk-Through in Python
- Python函数式编程-map()、zip()、filter()、reduce()、lambda()
- php 堵塞 消息队列,PHP的并发处理
- Python——Python3.6.0+Scrapy安装方法(总算没有bug了)
- 在CentOS上进行虚拟化:QEMU、Xen、KVM、LibVirt、oVirt
- 黑苹果内置硬盘识别成外置硬盘_压倒U盘最后一根稻草?ORICO iMatch移动固态硬盘体验...
- (一)外显子组数据分析之软件安装大全
- mysql保存特殊表情符_mysql 存储表情或者特殊符号
- Matplotlib之条形图绘制
- [声纹识别]语音识别系统框架[1]
- Cmd 移动文件夹及文件
- 解决删除Volume报错的问题(二)
- 解决计算机被暴风集火(jihuo)后留下的IE,chrome,火狐等所有浏览器主页网址携带有”tn=93453552_hao_pg“后缀的驱动类木马病毒的问题