成都最好的汽车网站建设,热词搜索排行榜,将wordpress压缩包解压至一个空文件夹_并上传它,2345网址大全官网9.12. 实战Kaggle比赛#xff1a;图像分类(CIFAR-10)到目前为止#xff0c;我们一直在用Gluon的data包直接获取NDArray格式的图像数据集。然而#xff0c;实际中的图像数据集往往是以图像文件的形式存在的。在本节中#xff0c;我们将从原始的图像文件开始#xff0c;一步…9.12. 实战Kaggle比赛图像分类(CIFAR-10)到目前为止我们一直在用Gluon的data包直接获取NDArray格式的图像数据集。然而实际中的图像数据集往往是以图像文件的形式存在的。在本节中我们将从原始的图像文件开始一步步整理、读取并将其变换为NDArray格式。我们曾在“图像增广”一节中实验过CIFAR-10数据集。它是计算机视觉领域的一个重要数据集。现在我们将应用前面所学的知识动手实战CIFAR-10图像分类问题的Kaggle比赛。该比赛的网页地址是https://www.kaggle.com/c/cifar-10 。图9.16展示了该比赛的网页信息。为了便于提交结果请先在Kaggle网站上注册账号。图 9.16 CIFAR-10图像分类比赛的网页信息。比赛数据集可通过点击“Data”标签获取首先导入比赛所需的包或模块。In[1]:importd2lzhasd2lfrommxnetimportautograd,gluon,initfrommxnet.gluonimportdataasgdata,lossasgloss,nnimportosimportpandasaspdimportshutilimporttime9.12.1. 获取和整理数据集比赛数据分为训练集和测试集。训练集包含5万张图像。测试集包含30万张图像其中有1万张图像用来计分其他29万张不计分的图像是为了防止人工标注测试集并提交标注结果。两个数据集中的图像格式都是png高和宽均为32像素并含有RGB三个通道(彩色)。图像一共涵盖10个类别分别为飞机、汽车、鸟、猫、鹿、狗、青蛙、马、船和卡车。图9.16的左上角展示了数据集中部分飞机、汽车和鸟的图像。9.12.1.1. 下载数据集登录Kaggle后可以点击图9.16所示的CIFAR-10图像分类比赛网页上的“Data”标签并分别下载训练数据集train.7z、测试数据集test.7z和训练数据集标签trainLabels.csv。9.12.1.2. 解压数据集下载完训练数据集train.7z和测试数据集test.7z后需要解压缩。解压缩后将训练数据集、测试数据集以及训练数据集标签分别存放在以下3个路径../data/kaggle_cifar10/train/[1-50000].png../data/kaggle_cifar10/test/[1-300000].png../data/kaggle_cifar10/trainLabels.csv。为方便快速上手我们提供了上述数据集的小规模采样其中train_tiny.zip包含100个训练样本而test_tiny.zip仅包含1个测试样本。它们解压后的文件夹名称分别为train_tiny和test_tiny。此外将训练数据集标签的压缩文件解压并得到trainLabels.csv。如果使用上述Kaggle比赛的完整数据集还需要把下面demo变量改为False。In[2]:# 如果使用下载的Kaggle比赛的完整数据集把demo变量改为FalsedemoTrueifdemo:importzipfileforfin[train_tiny.zip,test_tiny.zip,trainLabels.csv.zip]:withzipfile.ZipFile(../data/kaggle_cifar10/f,r)asz:z.extractall(../data/kaggle_cifar10/)9.12.1.3. 整理数据集我们需要整理数据集以方便训练和测试模型。以下的read_label_file函数将用来读取训练数据集的标签文件。该函数中的参数valid_ratio是验证集样本数与原始训练集样本数之比。In[3]:defread_label_file(data_dir,label_file,train_dir,valid_ratio):withopen(os.path.join(data_dir,label_file),r)asf:# 跳过文件头行(栏名称)linesf.readlines()[1:]tokens[l.rstrip().split(,)forlinlines]idx_labeldict(((int(idx),label)foridx,labelintokens))labelsset(idx_label.values())n_train_validlen(os.listdir(os.path.join(data_dir,train_dir)))n_trainint(n_train_valid*(1-valid_ratio))assert0returnn_train// len(labels), idx_label下面定义一个辅助函数从而仅在路径不存在的情况下创建路径。In[4]:defmkdir_if_not_exist(path):# 本函数已保存在d2lzh包中方便以后使用ifnotos.path.exists(os.path.join(*path)):os.makedirs(os.path.join(*path))我们接下来定义reorg_train_valid函数来从原始训练集中切分出验证集。以valid_ratio0.1为例由于原始训练集有50,000张图像调参时将有45,000张图像用于训练并存放在路径input_dir/train下而另外5,000张图像将作为验证集并存放在路径input_dir/valid下。经过整理后同一类图像将被放在同一个文件夹下便于稍后读取。In[5]:defreorg_train_valid(data_dir,train_dir,input_dir,n_train_per_label,idx_label):label_count{}fortrain_fileinos.listdir(os.path.join(data_dir,train_dir)):idxint(train_file.split(.)[0])labelidx_label[idx]mkdir_if_not_exist([data_dir,input_dir,train_valid,label])shutil.copy(os.path.join(data_dir,train_dir,train_file),os.path.join(data_dir,input_dir,train_valid,label))iflabelnotinlabel_countorlabel_count[label]mkdir_if_not_exist([data_dir,input_dir,train,label])shutil.copy(os.path.join(data_dir,train_dir,train_file),os.path.join(data_dir,input_dir,train,label))label_count[label]label_count.get(label,0)1else:mkdir_if_not_exist([data_dir,input_dir,valid,label])shutil.copy(os.path.join(data_dir,train_dir,train_file),os.path.join(data_dir,input_dir,valid,label))下面的reorg_test函数用来整理测试集从而方便预测时的读取。In[6]:defreorg_test(data_dir,test_dir,input_dir):mkdir_if_not_exist([data_dir,input_dir,test,unknown])fortest_fileinos.listdir(os.path.join(data_dir,test_dir)):shutil.copy(os.path.join(data_dir,test_dir,test_file),os.path.join(data_dir,input_dir,test,unknown))最后我们用一个函数分别调用前面定义的read_label_file函数、reorg_train_valid函数以及reorg_test函数。In[7]:defreorg_cifar10_data(data_dir,label_file,train_dir,test_dir,input_dir,valid_ratio):n_train_per_label,idx_labelread_label_file(data_dir,label_file,train_dir,valid_ratio)reorg_train_valid(data_dir,train_dir,input_dir,n_train_per_label,idx_label)reorg_test(data_dir,test_dir,input_dir)我们在这里只使用100个训练样本和1个测试样本。训练数据集和测试数据集的文件夹名称分别为train_tiny和test_tiny。相应地我们仅将批量大小设为1。实际训练和测试时应使用Kaggle比赛的完整数据集并将批量大小batch_size设为一个较大的整数如128。我们将10%的训练样本作为调参使用的验证集。In[8]:ifdemo:# 注意此处使用小训练集和小测试集并将批量大小相应设小。使用Kaggle比赛的完整数据集时可# 设批量大小为较大整数train_dir,test_dir,batch_sizetrain_tiny,test_tiny,1else:train_dir,test_dir,batch_sizetrain,test,128data_dir,label_file../data/kaggle_cifar10,trainLabels.csvinput_dir,valid_ratiotrain_valid_test,0.1reorg_cifar10_data(data_dir,label_file,train_dir,test_dir,input_dir,valid_ratio)9.12.2. 图像增广为应对过拟合我们使用图像增广。例如加入transforms.RandomFlipLeftRight()即可随机对图像做镜面翻转也可以通过transforms.Normalize()对彩色图像RGB三个通道分别做标准化。下面列举了其中的部分操作你可以根据需求来决定是否使用或修改这些操作。In[9]:transform_traingdata.vision.transforms.Compose([# 将图像放大成高和宽各为40像素的正方形gdata.vision.transforms.Resize(40),# 随机对高和宽各为40像素的正方形图像裁剪出面积为原图像面积0.64~1倍的小正方形再放缩为# 高和宽各为32像素的正方形gdata.vision.transforms.RandomResizedCrop(32,scale(0.64,1.0),ratio(1.0,1.0)),gdata.vision.transforms.RandomFlipLeftRight(),gdata.vision.transforms.ToTensor(),# 对图像的每个通道做标准化gdata.vision.transforms.Normalize([0.4914,0.4822,0.4465],[0.2023,0.1994,0.2010])])测试时为保证输出的确定性我们仅对图像做标准化。In[10]:transform_testgdata.vision.transforms.Compose([gdata.vision.transforms.ToTensor(),gdata.vision.transforms.Normalize([0.4914,0.4822,0.4465],[0.2023,0.1994,0.2010])])9.12.3. 读取数据集接下来可以通过创建ImageFolderDataset实例来读取整理后的含原始图像文件的数据集其中每个数据样本包括图像和标签。In[11]:# 读取原始图像文件。flag1说明输入图像有3个通道(彩色)train_dsgdata.vision.ImageFolderDataset(os.path.join(data_dir,input_dir,train),flag1)valid_dsgdata.vision.ImageFolderDataset(os.path.join(data_dir,input_dir,valid),flag1)train_valid_dsgdata.vision.ImageFolderDataset(os.path.join(data_dir,input_dir,train_valid),flag1)test_dsgdata.vision.ImageFolderDataset(os.path.join(data_dir,input_dir,test),flag1)我们在DataLoader中指明定义好的图像增广操作。在训练时我们仅用验证集评价模型因此需要保证输出的确定性。在预测时我们将在训练集和验证集的并集上训练模型以充分利用所有标注的数据。In[12]:train_itergdata.DataLoader(train_ds.transform_first(transform_train),batch_size,shuffleTrue,last_batchkeep)valid_itergdata.DataLoader(valid_ds.transform_first(transform_test),batch_size,shuffleTrue,last_batchkeep)train_valid_itergdata.DataLoader(train_valid_ds.transform_first(transform_train),batch_size,shuffleTrue,last_batchkeep)test_itergdata.DataLoader(test_ds.transform_first(transform_test),batch_size,shuffleFalse,last_batchkeep)9.12.4. 定义模型与“残差网络(ResNet)”一节中的实现稍有不同这里基于HybridBlock类构建残差块。这是为了提升执行效率。In[13]:classResidual(nn.HybridBlock):def__init__(self,num_channels,use_1x1convFalse,strides1,**kwargs):super(Residual,self).__init__(**kwargs)self.conv1nn.Conv2D(num_channels,kernel_size3,padding1,stridesstrides)self.conv2nn.Conv2D(num_channels,kernel_size3,padding1)ifuse_1x1conv:self.conv3nn.Conv2D(num_channels,kernel_size1,stridesstrides)else:self.conv3Noneself.bn1nn.BatchNorm()self.bn2nn.BatchNorm()defhybrid_forward(self,F,X):YF.relu(self.bn1(self.conv1(X)))Yself.bn2(self.conv2(Y))ifself.conv3:Xself.conv3(X)returnF.relu(YX)下面定义ResNet-18模型。In[14]:defresnet18(num_classes):netnn.HybridSequential()net.add(nn.Conv2D(64,kernel_size3,strides1,padding1),nn.BatchNorm(),nn.Activation(relu))defresnet_block(num_channels,num_residuals,first_blockFalse):blknn.HybridSequential()foriinrange(num_residuals):ifi0andnotfirst_block:blk.add(Residual(num_channels,use_1x1convTrue,strides2))else:blk.add(Residual(num_channels))returnblknet.add(resnet_block(64,2,first_blockTrue),resnet_block(128,2),resnet_block(256,2),resnet_block(512,2))net.add(nn.GlobalAvgPool2D(),nn.Dense(num_classes))returnnetCIFAR-10图像分类问题的类别个数为10。我们将在训练开始前对模型进行Xavier随机初始化。In[15]:defget_net(ctx):num_classes10netresnet18(num_classes)net.initialize(ctxctx,initinit.Xavier())returnnetlossgloss.SoftmaxCrossEntropyLoss()9.12.5. 定义训练函数我们将根据模型在验证集上的表现来选择模型并调节超参数。下面定义了模型的训练函数train。我们记录了每个迭代周期的训练时间这有助于比较不同模型的时间开销。In[16]:deftrain(net,train_iter,valid_iter,num_epochs,lr,wd,ctx,lr_period,lr_decay):trainergluon.Trainer(net.collect_params(),sgd,{learning_rate:lr,momentum:0.9,wd:wd})forepochinrange(num_epochs):train_l_sum,train_acc_sum,n,start0.0,0.0,0,time.time()ifepoch0andepoch%lr_period0:trainer.set_learning_rate(trainer.learning_rate*lr_decay)forX,yintrain_iter:yy.astype(float32).as_in_context(ctx)withautograd.record():y_hatnet(X.as_in_context(ctx))lloss(y_hat,y).sum()l.backward()trainer.step(batch_size)train_l_suml.asscalar()train_acc_sum(y_hat.argmax(axis1)y).sum().asscalar()ny.sizetime_stime %.2f sec%(time.time()-start)ifvalid_iterisnotNone:valid_accd2l.evaluate_accuracy(valid_iter,net,ctx)epoch_s(epoch %d, loss %f, train acc %f, valid acc %f, %(epoch1,train_l_sum/n,train_acc_sum/n,valid_acc))else:epoch_s(epoch %d, loss %f, train acc %f, %(epoch1,train_l_sum/n,train_acc_sum/n))print(epoch_stime_s, lr str(trainer.learning_rate))9.12.6. 训练并验证模型现在我们可以训练并验证模型了。下面的超参数都是可以调节的如增加迭代周期等。由于lr_period和lr_decay分别设为80和0.1优化算法的学习率将在每80个迭代周期后自乘0.1。简单起见这里仅训练1个迭代周期。In[17]:ctx,num_epochs,lr,wdd2l.try_gpu(),1,0.1,5e-4lr_period,lr_decay,net80,0.1,get_net(ctx)net.hybridize()train(net,train_iter,valid_iter,num_epochs,lr,wd,ctx,lr_period,lr_decay)epoch1,loss5.998157,train acc0.055556,valid acc0.100000,time1.34sec,lr0.19.12.7. 对测试集分类并在Kaggle提交结果得到一组满意的模型设计和超参数后我们使用所有训练数据集(含验证集)重新训练模型并对测试集进行分类。In[18]:net,predsget_net(ctx),[]net.hybridize()train(net,train_valid_iter,None,num_epochs,lr,wd,ctx,lr_period,lr_decay)forX,_intest_iter:y_hatnet(X.as_in_context(ctx))preds.extend(y_hat.argmax(axis1).astype(int).asnumpy())sorted_idslist(range(1,len(test_ds)1))sorted_ids.sort(keylambdax:str(x))dfpd.DataFrame({id:sorted_ids,label:preds})df[label]df[label].apply(lambdax:train_valid_ds.synsets[x])df.to_csv(submission.csv,indexFalse)epoch1,loss6.620115,train acc0.090000,time1.24sec,lr0.1执行完上述代码后我们会得到一个submission.csv文件。这个文件符合Kaggle比赛要求的提交格式。提交结果的方法与“实战Kaggle比赛房价预测”一节中的类似。9.12.8. 小结可以通过创建ImageFolderDataset实例来读取含原始图像文件的数据集。可以应用卷积神经网络、图像增广和混合式编程来实战图像分类比赛。9.12.9. 练习使用Kaggle比赛的完整CIFAR-10数据集。把批量大小batch_size和迭代周期数num_epochs分别改为128和300。可以在这个比赛中得到什么样的准确率和名次如果不使用图像增广的方法能得到什么样的准确率参与讨论在社区交流方法和结果。你能发掘出其他更好的技巧吗