本文为一个使用深度学习经典模型对isic中的恶黑malignant和nevus痣进行分类任务的文章html
智能医疗领域是如今一个很是火的领域,使用AI去解决医疗领域的一些痛点如今已是不少企业和组织正在作或者即将作的一件事情,虽然AI在医疗领域中的落地应用上还不能看到明确的道路,但能够预见各个企业个组织必然会在本身的领域上有更多的成果,有更多的能够落地的应用。网络
皮肤病是发生在皮肤和皮肤附属器官疾病的总称。皮肤是人体最大的器官,皮肤病的种类不但繁多,多种内脏发生的疾病也能够在皮肤上有表现。严重的皮肤病,如恶黑,极可能致人死亡,误诊的后果会很是严重,症状轻的皮肤病,如痣,也许并不能称之为皮肤病,而是皮损,不少人不选择去治疗。更严肃的是不少致死皮肤病和清症状皮肤病形态学及其类似,如上面提到的恶黑和痣,去有效的识别疾病,对挽救患者的生命起着相当重要的做用。app
有幸拜读了谷歌发出的一篇XXX论文,论文地址
先说说论文的思路。这篇论文是在一个公开数据集isic上面进行的训练和测试,这个数据集包含1万多张皮肤病图片,其中包含恶黑和痣这两种形态学很是类似,可是后果彻底不同的两个皮肤镜下图片数据集,恶黑是一种可致死的疾病,而痣通常不会有重大影响,但医学上常常会有恶黑和痣的误诊存在,给患者形成了很大的损害,所以这篇论文中使用了深度神经网络的方法进行恶黑和痣的识别,也是打开了一个新视野,形成了很大的影响。机器学习
论文使用了经典的神经网络inception_v3,使用在imageNet中已经训练好的参数进行了迁移学习,论文结果对恶黑的皮肤病图片识别也达到了92%左右的准确率,在这以后的另一篇论文XXX中则使用了一个5层的简单网络结构,分别在皮肤病图片的rgb空间、hsv空间和fft空间进行了训练,获得了三个模型,最终对模型进行了模型融合,对恶黑的预测达到了97%的准确率。ide
首先,须要搭建一个神经网络,使用当下最流行的tensorflow进行了网络结构的搭建和模型的训练,在tensorflow的slim库中提供了inception_v3的封装好的网络结构,我能够直接使用该网络结构进行训练。以下图,网络结构函数
而后,下载isic的数据集(PS:数据集网站居然不提供现成的下载连接,可是提供了能够下载数据的API),而后整理出其中的恶黑和痣的图片,人为的将他们分红了训练集和测试集,训练集数据和测试集数据的比例大体为2:1,训练集的恶黑大约1500张,痣约为6500张,测试集恶黑大约为750张,痣3000张左右,这里主要采起随机分配的方式,并无刻意去筛选质量好的图片做为训练集。学习
而后,编写数据读取方法(我并无将图片转化为tensorflow推荐的tfrecords文件再去训练,而是直接读入图片训练),将训练集数据目录所有加载,打乱后,每次读取batch_size个图片,读取数据时,用图片路径读取图片,将256X的图片resize为224224的大小,并作基本的翻转和左右变换,测试
而后,编写神经网络训练的训练过程,对fearture maps进行softmax,定义损失函数,选择优化器,编写验证方法优化
而后,使用已经训练好的inception_v3的模型,进行迁移学习,并在训练中对验证集和测试集进行同步输出结果网站
最后,学出模型
学习率0.1,batchsize为64,参数初始化采用必定范围内的正态分布
可喜可贺可喜可贺可喜可贺,最终的结果很是好,对恶黑识别的准确率达到了惊人的50%左右,意不意外,惊不惊喜,以后固然就是例行的优化程序,所谓一天写网络,一月调参数就是这样的。
这之间我发现再这个数据集上面进行迁移学习和重头开始学习,区别并不大,故以后的训练都是重头开始训练的.
在调参数以前,首先要知道须要调的参数是什么.能够参考下面连接,学习率、权重初始化方法,加减网络层数,增长正则化都是常见的能够调节的参数。
http://blog.csdn.net/qq_20259...
一、 首先是学习率
这是可能在调参数过程当中第一个应该调的参数,调整学习率能够调大或者调小。
上面网络的初始的学习率为0.1,这对不少数据集的分类来讲已经够了,一般来讲也不该该有太小的初始化学习率,这一般会致使过拟合,但并不老是这样,何凯明大神一次接受采访时说过,在有些状况下即便学习率达到0.000001,也不会太小。也不该该有过大的学习率,这会致使结果在极值点两边跳动。
分析训练结果,基本能够知道咱们的学习率过大了。逐渐的下降学习率并逐步对照,观察训练结果的变化,发现预测的整体精度确实在上升,在学习率达到0.005时测试集总体平均精度达到了最高,为75%左右,再调小会出现测试集精度降低的状况,且训练速度变慢。
这一步的训练结果在测试集上面出现了使人不愉快的表现,召回率很是低,大部分预测都偏向了痣,即恶黑的测试集大部分都预测为了痣,这显然是不对的。
二、 解决数据的问题
首先,在出现上面的结果后,我查了一些资料,对样本不均衡有了一些新的认识。考虑当前训练出现了样本不均衡,致使训练出现一些问题.参考文章
在分类中如何处理训练集中不平衡问题
深度 | 解决真实世界问题:如何在不平衡类上使用机器学习?
通常推荐从增长数据来源开始,但在此例中,由于数据集来源于公开数据集,而且含有恶黑和痣的分类数据的公开数据集几乎不存在,已不存在增长数据集的可能性。
这时咱们考虑使用重采样和降采样
1> 首先降采样,即把痣的训练集减小到和恶黑同样,调整了痣数据的训练集和测试集的比例。继续训练,获得的结果在测试集上中,对恶黑的测试精度获得了大幅提高,但对于负样本痣的精度确降低到合格线如下
2> 而后再采用重采样的方式,将恶黑的图片进行复制,将其扩展到和痣的数量相等。继续训练,获得的结果正好和降采样相反,在测试集上,恶黑精度不高,但整体的精度确实比以前高了,这样的结果一样也是咱们不能接受的
上面出现的两个极端状况,再必定程度上来讲就是发生了欠拟合和过拟合。减小痣的训练集,致使对痣的训练出现了欠拟合,对恶黑重采样,致使对恶黑的训练出现了过拟合。
那么是否能够经过必定方式生成一些数据呢,考虑原图是256X的尺寸,考虑采用剪裁的方式而不是经过resize的方式去获取图片。对图片进行预处理,对每一幅图片从左上角开始,水平方向每隔1个像素进行一次224高度(数据集中高度不固定,但都小于224)的裁剪,而且对高度垂直方向进行了zero padding,而后对生成的图片进行了水平和垂直方向的随机翻转,生成了新的训练数据集和测试数据集(一样保持训练集中正样本和负样本数量基本相同)。继续训练,状况并无多少改善,提高也有限,而且依然是痣的精度明显高于恶黑的精度.
这个时候我不对数据集产生了怀疑,是否是由于痣的数据集存在一些过大的噪声干扰呢,因而我将痣的数据集换成脂溢性角化病,即老年斑的数据集进行训练。
isic数据集中也含有1000多例的脂溢性角化病的数据,比恶黑的数据略少,采用上一次的网络进行训练,发现再两个分类上的精度均可以达到98%以上,因而我再返回对痣的数据集进行了审视,发现其中有一半以上的数据中包含不知是用来干什么用的有色圆圈
我将训练集中把这部分去除掉,用剩下的数据进行训练,把带有有色圆圈的数据先行搁置,对剩余的数据进行训练(恶黑和痣),发现结果有了明显的改善, 在恶黑数据集上的召回率能够达到85%左右,准确率达到89%左右。
但实际上咱们并无达到原论文中的对rgb空间中预测准确率93%的结果,但这个时候训练集的精度已经达到了99%,已经到了没法再继续训练的情况,继续训练就必须考虑提高模型的泛化能力,调整drop率从0.8到0.七、0.六、0.5,没有明显提升,就考虑继续从训练集下手。
测试集精度低于训练集精度,这种现象就是过拟合的现象,加强泛化能力就必须减轻过拟合的影响。考虑到上一步中对原图像每隔1像素进行裁剪获取训练集和测试机的方法是否是和以前的重采样同样,出现了很大程度的过拟合呢?虽然从一张图片中新生成的训练集都不相同,但他们都是从一张原图中裁剪出来的,对生成的训练图像进行训练是否是至关于对原图进行了屡次训练呢?
为了验证这个状况,我调整了生成图片的间隔,即把每隔1像素裁剪,变成每隔5个像素再去裁剪一次,经过在这种方式生成的训练数据和测试数据中的实践,在恶黑的表现召回率能够达到88%左右,准确率达到94.5%左右。同时,考虑到咱们的测试集是滑动生成的,预测时是根据原测试集生成的数据预测,但实际要进行的预测则是,对原图进行滑动裁剪,计算全部裁剪图片的分类几率分布,统计平均值得出预测结果的方法,那么能够想一想最终的预测效果必然会更好(没有验证过,但至少结果不会比当前结果差,由于准确率和召回率都超过了50%)
在以上工做的基础上,继续采用一些常见的优化模型的方法,如修改常规的梯度降低优化器, 尝试带有动量的梯度降低优化器和学习率降低的优化器,尝试采用不一样的激活函数,尝试使用不一样的drop率等经常使用的优化训练过程,再训练和收敛速度上,最终训练结果再测试集上的表现都有少许的提高
在使用inception_v3进行训练时,由于inception_v3网络结构中存在batch_norm,由于以前对batch_norm的不充分了解,致使踩到了一个坑里面。
batch norm在网络训练过程当中会起到关键性的做用,他能够加速训练过程,而且必定程度上提高模型的效果。原理是在训练过程当中,计算mini-batch的平均值和标准差,对数据进行正则化,将数据约束到一个范围内,保持他们的平均值和标准差不变,对正则化以后的数据进行训练,
在学习卷积核和偏置项参数时,同时会学习batch norm的β和γ,但在测试时就彻底不一样了,在测试时不须要对测试的mini-batch范围进行约束,只须要使用训练获得的固化的参数进行预测就行,而我就犯了相同的错误。
我起初在训练和测试的时候没有要求is_training这个参数,这个参数指定了是要取当前mini-batch的平均值和标准差,仍是使用固化的参数,tensorflow中提供的inception_v3网络的is_training默认为True,因此我在训练好模型以后作预测时,不一样的加载数据方式,总会获得不一样的结果,如,顺序加载全部类的数据,打乱加载全部类数据,每一个mini-batch中各种数量相同等,从新调整了batch_norm后解决(slim.batch_norm有坑,虽然不知道什么缘由,但is_training如何设置都会有问题),编写了一个batch_norm方法解决了这个问题
def batch_norm(x, is_training, decay=0.9, eps=1e-5): shape = x.get_shape().as_list() assert len(shape) in [2, 4] n_out = shape[-1] beta = tf.Variable(tf.zeros([n_out])) gamma = tf.Variable(tf.ones([n_out])) if len(shape) == 2: batch_mean, batch_var = tf.nn.moments(x, [0]) else: batch_mean, batch_var = tf.nn.moments(x, [0, 1, 2]) ema = tf.train.ExponentialMovingAverage(decay=decay) def mean_var_with_update(): ema_apply_op = ema.apply([batch_mean, batch_var]) with tf.control_dependencies([ema_apply_op]): return tf.identity(batch_mean), tf.identity(batch_var) mean, var = tf.cond(is_training, mean_var_with_update, lambda: (ema.average(batch_mean), ema.average(batch_var))) return tf.nn.batch_normalization(x, mean, var, beta, gamma, eps)