kaggle季军新手笔记:利用fast.ai对油棕人工林图像进行快速分类(附代码)

一支深度学习的新手队如何在kaggle竞赛中获得第三名?

图:亚历山大·纳格斯塔德 (AlexanderNaglestad)WiDS数据马拉松由女性数据科学工作者与她们的伙伴联合发起,她们面临的挑战是需要建立一个模型,来预测一批卫星图像中存在油棕人工林种植园的情况。

数据集是称为“行星”的人造卫星新近拍摄的经加注后的卫星图像数据集,该图像数据集具有3米的空间分辨率,每幅图像都是基于图像中是否存在油棕种植园进行标记的(0表示没有油棕种植园,1表示有油棕种植园)。任务是需要训练一个模型,该模型以卫星图像为输入,并输出对油棕种植园的图像预测的概率。竞赛创建者为模型开发提供了经过标记后的训练和测试数据集。

详情见这里:https://www.kaggle.com/c/widsdatathon2019

我的队友(Abundshakur,Halimah,和IfeomaOkoh)和我采用了fast.ai框架来应对这一挑战。感谢托马斯·卡贝尔(ThomasCapelle)提供了Kaggle上的入门内核,它给出了如何处理这个问题的深刻见解,同时也为fast.ai团队创造了一门神奇的深度学习课程,从而简化了许多复杂的深度学习的概念。现在,深度学习的初学者也可以赢得kaggle比赛了。

我们从一个简单易学的关于深度学习的教程开始吧

目前,无需为理解所有的东西而担心,文中会伴随着大量的练习。本教程旨在展示fast.ai对于深度学习的初学者来说的神奇之处,前提是假设读者会python语言,并且接触过一些ML(机器学习)。如果你已经具备上述技能,那我们就可以走上正轨了。

文中的所有代码都可以在Google Colaboratory(https://colab.research.google.com/notebooks/welcome.ipynb)上获得,这是一个免费的Jupyter笔记本环境,无需安装,运行在云上。可以采用协作的方式编写和执行代码,存盘和共享分析结果,访问功能强大的计算资源,所有这些都是免费的。点击这里可以访问到我们将要使用到的代码。

导入fast.ai和将要用到的其他库

# This ensures that any edits to libraries you make are reloaded here automatically,

# and also that any charts or images displayed are shown in this notebook.

%reload_ext autoreload

%autoreload 2

%matplotlib inline导入库

# Import libraries

from fastai import *

from fastai.vision import *

from fastai.callbacks import CSVLogger, SaveModelCallback

import seaborn as sns

import warnings

warnings.filterwarnings('ignore')

获取竞赛数据

为了尽可能地直观,Abdishakur将竞赛数据文件上传到dropbox.com,可以在这个竞赛页面上找到竞赛数据文件,而且只有接受竞争规则之后才能访问到这些数据文件。

# Get the data from dropbox link

!wget https://www.dropbox.com/s/6kltw0kqynlijxv/widsdatathon2019.zip

# The downloaded competition data is zipped, let us unzip it

!unzip widsdatathon2019.zip

# The training and testing data have already been seperated, Unzip them as well

!unzip train_images.zip

!unzip leaderboard_holdout_data.zip

!unzip leaderboard_test_data.zip

查看数据

在处理这个问题之前,首先要做的是查看可用的数据。在知道如何解决问题之前,我们首先需要了解问题和数据是什么样子。查看数据意味着了解数据目录的结构,标签是什么,以及一些示例图像是什么。

# Overview of the labels of the training data; 

df = pd.read_csv('data/traininglabels.csv')

df.head()

使用pandas库读取数据
训练模型过程中使用到的数据标签

处理图像分类数据集和表格数据集的主要区别在于标签的存储方式,这里的标签指的是图像中的内容。在这个特定的数据集中,标签存储在CSV文件中。

要了解如何计算分数列的详细信息,请访问此链接:https://success.figure-eight.com/hc/en-us/articles/201855939-How-to-Calculate-a-Confidence-Score

利用countplot函数来查看培训数据的分布情况,从图中可以看到:大约有14,300幅图片没有油棕榈种植园,而只有942幅图片有油棕榈种植园,这可以称为非均衡数据集,关于非均衡数据集这个深度学习问题,我们不打算在此讨论;目前,可以从这里开始起步:

sns.countplot(df.has_oilpalm)

对两类进行计数

训练数据集的分布情况准备数据

所提供的测试数据位于两个独立的文件夹中,即排行榜预留数据(leaderboard holdout data)和排行榜测试数据(leaderboard test data)这两个文件夹。由于竞赛要求对两个数据集提交预测结果,所以我们将二者组合起来,这样一共得到6534张图片。

test_imgs = [i for i in test.iterdir()]

hold_imgs = [i for i in lb_test.iterdir()]

combined_test = test_imgs + hold_imgs

len(combined_test)

将排行榜预留数据(leaderboard holdout data )与排行榜测试数据(leaderboard test data)组合起来

采用fast.ai的DataBlock API来构造数据,这是向模型输送数据集的一种简易的方法。

src = (ImageList.from_df(df, path, folder='train_images')

      .random_split_by_pct(0.2, seed=14)

      .label_from_df('has_oilpalm')

      .add_test(combined_test))      

data = (src.transform(get_transforms(flip_vert=True), size=164)

           .databunch()

           .normalize(imagenet_stats))

创建一个ImageList来保存数据

此步骤要点:

利用ImageList的from_df方法来保存训练数据,这样做是因为将有关训练集的信息存储在名字为df的数据帧中,让它能找到训练图像所在的路径和保存图像的文件夹名称,train_images.

接下来,使用随机分割来对训练集进行分割,留出20%的数据来监控模型在训练过程中的性能。选择一颗种子,以确保再次检查时能得到同样的结果,我们必须知道什么在起作用,什么不起作用。

告诉ImageList在训练集中的数据的标签所在地,利用has_oilpalm方法将组合后的数据添加到测试数据中。

最后,对数据进行转换,使用flip_vert = True翻转图像有助于模型识别图像。利用imagenet_stats对图像归一化处理。注意:这是一种转移学习技术,我要说的是需要保持操作尽可能简单。

图像预览

不管有没有油棕种植园,卫星图像是这样的:

data.show_batch(2)

显示2批图像

有油棕的图像标记为1,无油棕的图像标记为0训练模型

现在开始训练模型,采用卷积神经网络骨干,并使用预先训练的权重,这个权重从一个已经训练好的图像分类的resnet模型中直接获得,无须担心这种方法的细节。目前为止,我们正在构建一个以卫星图像为输入并输出这两种分类的预测概率模型。

learn = create_cnn(data, models.resnet50, metrics=[accuracy, error_rate],

                  callback_fns=[ShowGraph, SaveModelCallback])

# View model architecture

learn.model()

卷积神经网络

learn.lr_find()

learn.recorder.plot()
找出最优的模型学习率接下来,使用lr_find()找到理想的学习率,并利用recorder.plot().对它可视化。

找出最优的模型学习率

选择一个接近坡度最陡之处的学习速率,在这个示例中是1e-2。

learn.fit_one_cycle(5, slice(1e-2))

学习率为1e-2的5个循环的训练模型

利用fit_one_cycle函数对模型训练5个周期 (对所有数据训练5个周期)。
训练和验证损失注意到显示出来的结果,如training_loss 和valid_loss没有?后续,会用它们来监控模型的改进。

在第四个循环,得到了最佳的模型。
训练模型的输出;训练和验证损失的过程fast.ai在运行训练和验证数据集时,内部自动选取和保存最优的那个模型。

评估模型

竞赛组委会根据预测概率与观测目标has_oilpalm之间的工作特性曲线下的面积对参赛作品进行评价。通过以下开发者速成班、视频或Kaggle学习论坛的帖子,可以了解到更多关于AUC 的咨询。

开发者速成班: 

https://developers.google.com/machine-learning/crash-course/classification/roc-and-auc 

视频: 

https://www.dataschool.io/roc-curves-and-auc-explained/ Kaggle

学习论坛: 

https://www.kaggle.com/learn-forum/5378

默认情况下,Fast.ai没有提供这个评价标准的指标度量,所以我们将用到Scikit-Learning库。

from sklearn.metrics import roc_auc_score

def auc_score(y_score,y_true):

    return torch.tensor(roc_auc_score(y_true,y_score[:,1]))

probs,val_labels = learn.get_preds(ds_type=DatasetType.Valid) 

print('Accuracy',accuracy(probs,val_labels)),

print('Error Rate', error_rate(probs, val_labels))

print('AUC', auc_score(probs,val_labels))

打印出验证指标

使用预训练模型和fast.ai的优点是,可以得到一个非常好的预测精度,在这个示例中,在没有多做其他工作的情况下,获得了99.44%精确度。
训练第一阶段的指标将模型存盘,绘制出预测的混淆矩阵

learn.save('resnet50-stg1')

利用混淆矩阵查看结果 

interp = ClassificationInterpretation.from_learner(learn)

interp.plot_confusion_matrix(dpi=120)

绘制混淆矩阵

混淆矩阵是一种图形化的方法,用来查看模型准确或不准确预测的图像数量。
第一阶段训练的混淆矩阵从这幅图中可以看出,模型准确地预测了2863幅没有油棕人工林的图像,对168幅油棕人工林的图像进行了正确的分类。将10幅含有油棕人工林的图像分类为无油棕人工林图像,并将7幅无油棕人工林图像分类为有油棕人工林图像。

对于一个简单的模型来说这个结果还不错。

接下来,找出这个训练迭代理想的学习率

learn.lr_find()

learn.recorder.plot()

找出理想的学习率
选择介于1e-6和1e-4之间的一个学习率利用介于1e-6和1e-4之间的一个学习率最大值对模型进行拟合。

learn.fit_one_cycle(7, max_lr=slice(1e-6,1e-4))

学习率在1e-6和1e-4的范围范围内,对模型进行7次循环训练

训练和验证损失在每个训练周期后,以图形的方式观察训练指标,从而监测模型的性能。

训练模型的输出;训练和验证损失的进度 

保存第二阶段的模型训练结果。

learn.save('resnet50-stg2')

probs,val_labels = learn.get_preds(ds_type=DatasetType.Valid) 

print('Accuracy',accuracy(probs,val_labels)),

print('Error Rate', error_rate(probs, val_labels))

print('AUC', auc_score(probs,val_labels))

准确度、误差率和AUC评分

打印出模型的精度、错误率和曲线下面的面积。
第二阶段训练指标你会注意到,此时,模型的准确度从99.44%提高到99.48%,错误率从0.0056降低到0.0052,AUC也有改善,从99.82%提高到99.87%。

interp = ClassificationInterpretation.from_learner(learn)

interp.plot_confusion_matrix(dpi=120)

绘制混淆矩阵

通过与我们绘制的上一个混淆矩阵的比较,可以发现模型做出了更精准的预测。
第二阶段训练的混淆矩阵先前没有油棕种植园的7张图片被错误分类,现在降到了3张,性能有所提高。

你会注意到在训练过程中遵循了一个模式,在这个过程中调整了一些参数,这便是所谓的精调,绝大多数深度学习训练均遵循类似的迭代模式。

图像变换

我们将对数据执行更多的图像变换,通过这些变换对模型进行改进。

关于每种变换的详细描述,可以在fast.ai的相关文档中找到:https://docs.fast.ai/vision.transform.html

 tfms = get_transforms(flip_vert=True, max_lighting=0.1, max_zoom=1.05, max_warp=0.)

data = (src.transform(tfms, size=200)

        .databunch().normalize(imagenet_stats))

learn.data = data

data.train_ds[0][0].shape

应用不同的变换改进模型

hting:如果非空 None,则在概率p_lighting下使用由max_light控制的随机亮度和对比度变化。

max_zoom:如果非1,或是一个比1更小的数,则在概率p_affine下使用max_zoom到1之间的随机缩放比

max_warp:如果非空None,则使用概率p_affine应用-max_warp和max_warp之间的随机对称翘曲。

再次找出最优学习率

learn.lr_find()

learn.recorder.plot()

找出理想的学习率
选择学习率为1e-6循环训练模型5次:

learn.fit_one_cycle(5, 1e-6)
训练和验证损失将训练指标与先前的指标进行比较,模型在0.0169与0.0163之间的迭代稍差,但是不要失望。

训练模型的输出结果,在第3次迭代时获得了最佳模型将第三阶段的训练模型保存,并打印出指标。可以注意到,目前,模型的准确度是99.38%,在前一阶段是99.48%,AUC评分从99.87%提高到99.91%,达到了比赛评分的标准。

learn.save('resnet50-stg3')

probs,val_labels = learn.get_preds(ds_type=DatasetType.Valid) 

print('Accuracy',accuracy(probs,val_labels)),

print('Error Rate', error_rate(probs, val_labels))

print('AUC', auc_score(probs,val_labels))

准确度、误差率和AUC评分
第三阶段训练指标

最终训练阶段

可以注意到,我们从最初图像大小size = 164的图像开始,然后逐渐递增,最终达到了 size = 256 。这样做是为了利用FAST.ai的累进图像大小进行分类,即在训练开始时使用小图像,并随着训练的进展逐渐增大大小。这样,即便模型早期训练时非常不准确,它也可以快速地看到大量图像并加快进度,在后续的训练中,可以看到更大的图像,从而了解更细粒度的区别。

若要阅读更多有关此信息,请访问此链接:https://www.fast.ai/2018/08/10/fastai-diu-imagenet/

tfms = get_transforms(flip_vert=True, max_lighting=0.1, max_zoom=1.05, max_warp=0.)

data = (src.transform(tfms, size=256)

        .databunch().normalize(imagenet_stats))

learn.data = data

data.train_ds[0][0].shape

应用不同的变换来改进模型

将图像大小增加到256

再次找出优化后的学习率

learn.lr_find()

learn.recorder.plot()
找出理想的学习率learn.fit_one_cycle(5, slice(1e-4)) 

学习率设置为1e-4,训练模型5次循环训练和验证损失

来看一下训练指标,并与过去的指标进行比较,模型略有改进,从0.0169提高到0.0168。

训练模型的输出,在第2次循环时获得最优的模型将最后阶段的模型训练结果保存,并打印出指标:

learn.save('resnet50-stg4') 

probs,val_labels = learn.get_preds(ds_type=DatasetType.Valid) 

print('Accuracy',accuracy(probs,val_labels)),

print('Error Rate', error_rate(probs, val_labels))

print('AUC', auc_score(probs,val_labels))

准确度、误差率和AUC评分

你会注意到,模型的准确度现在是99.44%,比上一阶段的99.38%有所提高:第四阶段训练指标

准备竞赛提交文件

现在可以看到模型是如何对数据进行预测的:

p,t = learn.get_preds(ds_type=DatasetType.Test)

p = to_np(p); 

p.shape

ids = np.array([f.name for f in (combined_test)]);

ids.shape

sample_sub = Path('data/SampleSubmission.csv')

df_sample = pd.read_csv(sample_sub)

sub = pd.DataFrame(np.stack([ids, p[:,1]], axis=1), columns=df_sample.columns)

sub.to_csv(path/'wids-notebook.csv', index=False)

准备CSV格式的提交文件

向WiDS数据马拉松提交文件

现在可以参加WiDS的竞赛,并提交参赛文件了,请转到此处(https://www.kaggle.com/c/widsdatathon2019)的竞赛页面,单击“加入竞赛”并接受竞赛规则,便可以提交参赛内容,如果你参加,看看你会排名第几。

我提交了自己的模型的预测之后

获得的私有和公开分数

免责声明:按照文章中的说明操作后,不会像我那样位列第三,为确保过程尽可能简单,请参看链接(https://www.kaggle.com/c/widsdatathon2019/discussion/82252)中Abdishakur的帖子。

原文标题:

How a team of deep learning newbies came 3rd place in a kaggle contest——Classifying images of oil palm plantations using fast.ai

原文链接:

https://towardsdatascience.com/how-a-team-of-deep-learning-newbies-came-3rd-place-in-a-kaggle-contest-644adcc143c8

译者简介

陈之炎,北京交通大学通信与控制工程专业毕业,获得工学硕士学位,历任长城计算机软件与系统公司工程师,大唐微电子公司工程师,现任北京吾译超群科技有限公司技术支持。目前从事智能化翻译教学系统的运营和维护,在人工智能深度学习自然语言处理(NLP)方面积累有一定的经验。业余时间喜爱翻译创作,翻译作品主要有:IEC-ISO 7816、伊拉克石油工程项目、新财税主义宣言等等,其中中译英作品“新财税主义宣言”在GLOBAL TIMES正式发表。

THU数据派
THU数据派

THU数据派"基于清华,放眼世界",以扎实的理工功底闯荡“数据江湖”。发布全球大数据资讯,定期组织线下活动,分享前沿产业动态。了解清华大数据,敬请关注姐妹号“数据派THU”。

工程图像分类fast.aiKaggle
3
相关数据
深度学习技术

深度学习(deep learning)是机器学习的分支,是一种试图使用包含复杂结构或由多重非线性变换构成的多个处理层对数据进行高层抽象的算法。 深度学习是机器学习中一种基于对数据进行表征学习的算法,至今已有数种深度学习框架,如卷积神经网络和深度置信网络和递归神经网络等已被应用在计算机视觉、语音识别、自然语言处理、音频识别与生物信息学等领域并获取了极好的效果。

混淆矩阵技术

混淆矩阵也称误差矩阵,是表示精度评价的一种标准格式,用n行n列的矩阵形式来表示。具体评价指标有总体精度、制图精度、用户精度等,这些精度指标从不同的侧面反映了图像分类的精度。在人工智能中,混淆矩阵(confusion matrix)是可视化工具,特别用于监督学习,在无监督学习一般叫做匹配矩阵。矩阵的每一行表示预测类中的实例,而每一列表示实际类中的实例(反之亦然)。 这个名字源于这样一个事实,即很容易看出系统是否混淆了两个类。

权重技术

线性模型中特征的系数,或深度网络中的边。训练线性模型的目标是确定每个特征的理想权重。如果权重为 0,则相应的特征对模型来说没有任何贡献。

机器学习技术

机器学习是人工智能的一个分支,是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、计算复杂性理论等多门学科。机器学习理论主要是设计和分析一些让计算机可以自动“学习”的算法。因为学习算法中涉及了大量的统计学理论,机器学习与推断统计学联系尤为密切,也被称为统计学习理论。算法设计方面,机器学习理论关注可以实现的,行之有效的学习算法。

人工智能技术

在学术研究领域,人工智能通常指能够感知周围环境并采取行动以实现最优的可能结果的智能体(intelligent agent)

参数技术

在数学和统计学裡,参数(英语:parameter)是使用通用变量来建立函数和变量之间关系(当这种关系很难用方程来阐述时)的一个数量。

数据科学技术

数据科学,又称资料科学,是一门利用数据学习知识的学科,其目标是通过从数据中提取出有价值的部分来生产数据产品。它结合了诸多领域中的理论和技术,包括应用数学、统计、模式识别、机器学习、数据可视化、数据仓库以及高性能计算。数据科学通过运用各种相关的数据来帮助非专业人士理解问题。

学习率技术

在使用不同优化器(例如随机梯度下降,Adam)神经网络相关训练中,学习速率作为一个超参数控制了权重更新的幅度,以及训练的速度和精度。学习速率太大容易导致目标(代价)函数波动较大从而难以找到最优,而弱学习速率设置太小,则会导致收敛过慢耗时太长

卷积神经网络技术

卷积神经网路(Convolutional Neural Network, CNN)是一种前馈神经网络,它的人工神经元可以响应一部分覆盖范围内的周围单元,对于大型图像处理有出色表现。卷积神经网路由一个或多个卷积层和顶端的全连通层(对应经典的神经网路)组成,同时也包括关联权重和池化层(pooling layer)。这一结构使得卷积神经网路能够利用输入数据的二维结构。与其他深度学习结构相比,卷积神经网路在图像和语音识别方面能够给出更好的结果。这一模型也可以使用反向传播算法进行训练。相比较其他深度、前馈神经网路,卷积神经网路需要考量的参数更少,使之成为一种颇具吸引力的深度学习结构。 卷积网络是一种专门用于处理具有已知的、网格状拓扑的数据的神经网络。例如时间序列数据,它可以被认为是以一定时间间隔采样的一维网格,又如图像数据,其可以被认为是二维像素网格。

自然语言处理技术

自然语言处理(英语:natural language processing,缩写作 NLP)是人工智能和语言学领域的分支学科。此领域探讨如何处理及运用自然语言;自然语言认知则是指让电脑“懂”人类的语言。自然语言生成系统把计算机数据转化为自然语言。自然语言理解系统把自然语言转化为计算机程序更易于处理的形式。

图像分类技术

图像分类,根据各自在图像信息中所反映的不同特征,把不同类别的目标区分开来的图像处理方法。它利用计算机对图像进行定量分析,把图像或图像中的每个像元或区域划归为若干个类别中的某一种,以代替人的视觉判读。

推荐文章
暂无评论
暂无评论~