____tz_zs

前段时间参加了 kaggle 2018 data science bowl ,初生牛犊不怕虎,于是我撸起袖子就开始干了。

尽管,没能得到好的结果,参与过程中的收获和提高,也是很值得高兴的。

这里记录下这次的失败,以便下次吸取教训、更进一步。

同时,也希望能够帮到那些看到我这篇博客的新人朋友。

一个项目的步骤分为:数据预处理、模型构造、模型训练、模型评估

总体思路:训练一个复杂的卷积神经网络需要非常多的标注数据和很长的训练时间。而 kaggle 的比赛项目所提供的数据量比较小,总共只有 670 张不同的原始图片,数据集相对较小。所以,我决定使用迁移学习(迁移学习能将一个问题上训练好的模型通过调整使其适用于一个新的问题,能够在数据量不大及训练时间不足的情况下,训练出令人满意的神经网络模型)。所用模型为 Google 训练好的 Inception-v3 模型。我将本次 kaggle 项目看成是一个二值图像的生成问题(一个二维数组),将卷积神经网络部分作为原始图片特征向量的提取过程。

·此代码仅作为反面例子,这是最初版,问题很大。

# -*- coding: utf-8 -*-
"""
@author: tz_zs"""
import pathlib
import numpy as np
from skimage import io, data
from skimage.color import rgb2gray
from skimage.filters import threshold_otsu
import matplotlib.pyplot as plt
from scipy import ndimage
import tensorflow as tf
from tensorflow.python.platform import gfile
import os
from PIL import Image# inception-v3 模型瓶颈层的节点个数
BOTTLENECK_TENSOR_SIZE = 2048
# 下载的谷歌训练好的inception-v3模型文件目录
MODEL_DIR = 'D:/kaggle/inception_dec_2015'
# 下载的谷歌训练好的inception-v3模型文件名
MODEL_FILE = 'tensorflow_inception_graph.pb'
# inception-v3 模型中代表瓶颈层结果的张量名称
BOTTLENECK_TENSOR_NAME = 'pool_3/_reshape:0'
# 图像输入张量所对应的名称
JPEG_DATA_TENSOR_NAME = 'DecodeJpeg/contents:0'
# 学习率
LEARNING_RATE = 0.01
STEPS = 400
BATCH = 1# 缩放的尺寸
P = 100# np.set_printoptions(threshold=1e6)  # 设置打印数量的阈值def get_train_data_path():# 用Path类可以创建path路径对象, 属于比os.path更高抽象级别的对象。training_paths = pathlib.Path('D:/kaggle/stage1_train').glob('*')#  每一个文件夹,就是一个样本,获取其路径并保存train_data_path = {}for paths in training_paths:# masks文件夹masks_list = []masks_dir = paths.joinpath('masks')masks_dir_iterdir = masks_dir.iterdir()for masks_paths in masks_dir_iterdir:masks_list.append(masks_paths)# images文件夹images_dir = paths.joinpath('images')images_dir_iterdir = images_dir.iterdir()for images_paths in images_dir_iterdir:images_id = images_paths.stemtrain_data_path[images_id] = [images_paths, masks_list]return train_data_pathif __name__ == '__main__':# 数据准备train_data_path = get_train_data_path()  # 得到路径train_data_masks = []train_data_im = []i = 0for k, v in train_data_path.items():# 将masks解码并合并masks = 0for mask in v[1]:im_mask = Image.open(mask)im_mask.thumbnail((P, P))# im_mask = io.imread(mask)masks += np.array(im_mask)print(masks.shape)train_data_masks.append(masks)# for mask in v[1]:#     image_data = gfile.FastGFile(mask, 'r').read()#     print(image_data)# 解码 image,并清理数据# im = io.imread(v[0])im = Image.open(mask)im.thumbnail((P, P))im = np.array(im)im_gray = rgb2gray(im)  # 使用scikit-image中的rgb2gray,将图像强制转换为灰度格式# train_data_im.append(im_gray) #加入listio.imsave("D:/tmp/im_tmp/{}.png".format(k), im_gray)# 获取图片内容image_data = gfile.FastGFile("D:/tmp/im_tmp/{}.png".format(k), 'rb').read()train_data_im.append(image_data)'''#清理数据(废弃)# 去除背景:Otsu方法将图像建模为双峰分布,并找到最优的分离值。(暂时先这样处理)thresh_val = threshold_otsu(im_gray)mask = np.where(im_gray > thresh_val, 1, 0)if np.sum(mask == 0) < np.sum(mask == 1):  # 比较0和1的区域的大小,保正是背景占多数mask = np.where(mask, 0, 1)  # 0和1交换# 使用ndimage.label函数,查找mask中的所有对象,并标记(ndimage.label会将输入中的任何非零值都被视为特性,零值视为背景)labels, nlabels = ndimage.label(mask)label_arrays = []for label_num in range(1, nlabels + 1):  # 遍历并用list分门别类的装好label_mask = np.where(labels == label_num, 1, 0)label_arrays.append(label_mask)# 使用ndimage.find_objects函数遍历mask,返回图像中每个标签对象的坐标范围列表,去除那些较小的像素点(噪音),得到新的maskfor label_ind, label_coords in enumerate(ndimage.find_objects(labels)):cell = im_gray[label_coords]if np.product(cell.shape) < 10:mask = np.where(labels == label_ind + 1, 0, mask)# 重新生成labelslabels, nlabels = ndimage.label(mask)'''print("数据准备完成")# 读取模型with gfile.FastGFile(os.path.join(MODEL_DIR, MODEL_FILE), 'rb') as f:graph_def = tf.GraphDef()graph_def.ParseFromString(f.read())# 加载模型,返回对应名称的张量bottleneck_tensor, image_data_tensor = tf.import_graph_def(graph_def, return_elements=[BOTTLENECK_TENSOR_NAME,JPEG_DATA_TENSOR_NAME])# 输入bottleneck_input = tf.placeholder(tf.float32, [None, BOTTLENECK_TENSOR_SIZE], name='BottleneckInputPlaceholder')ground_truth_input = tf.placeholder(tf.float32, [None, P * P], name='GroundTruthInput')# 全连接层with tf.name_scope('final_training_ops'):weights = tf.Variable(tf.truncated_normal([BOTTLENECK_TENSOR_SIZE, P * P], stddev=0.001))biases = tf.Variable(tf.zeros([P * P]))logits = tf.matmul(bottleneck_input, weights) + biasesfinal_tensor = tf.nn.softmax(logits)# 损失# cross_entropy = tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=ground_truth_input)# cross_entropy_mean = tf.reduce_mean(cross_entropy)mse = tf.reduce_mean(tf.square(ground_truth_input - final_tensor))# cross_entropy = -tf.reduce_sum(ground_truth_input * tf.log(final_tensor))# 优化train_step = tf.train.GradientDescentOptimizer(LEARNING_RATE).minimize(mse)# 正确率with tf.name_scope('evaluation'):# correct_prediction = tf.equal(tf.argmax(final_tensor, 1), tf.argmax(ground_truth_input, 1))# evaluation_step = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))evaluation_step = tf.reduce_mean(tf.square(ground_truth_input - final_tensor))with tf.Session() as sess:# 初始化参数init = tf.global_variables_initializer()sess.run(init)for i in range(STEPS):# 每次获取一个batch的训练数据# temp = i % BATCH# print("temp:", temp)# masks = train_data_masks[temp:temp + BATCH]# im = train_data_im[temp:temp + BATCH]masks = train_data_masks[i]im = train_data_im[i]# 调整矩阵reshaped_masks = np.reshape(masks, [1, P * P])# 迁移bottleneck_values = sess.run(bottleneck_tensor, feed_dict={image_data_tensor: im})  # (1, 2048)# 训练sess.run(train_step, feed_dict={bottleneck_input: bottleneck_values, ground_truth_input: reshaped_masks})# 检测validation_accuracy = sess.run(evaluation_step, feed_dict={bottleneck_input: bottleneck_values,ground_truth_input: reshaped_masks})print('Step %d ———— %.1f%%' % (i, validation_accuracy * 100))# RLE方法,用于kaggle提交
def rle_encoding(x):'''x: numpy array of shape (height, width), 1 - mask, 0 - backgroundReturns run length as list'''dots = np.where(x.T.flatten() == 1)[0]  # .T sets Fortran order down-then-rightrun_lengths = []prev = -2for b in dots:if (b > prev + 1): run_lengths.extend((b + 1, 0))run_lengths[-1] += 1prev = breturn " ".join([str(i) for i in run_lengths])

·

总结反思:

  • 没有清晰的解决问题的思路和方案,有些地方都是临时去找解决方法,导致各种框架的使用过程混乱,没能很好的配合使用。如:图片的清洗过程使用的是 skimage,而后为了配合 tensorflow 迁移学习的输入,只好将清洗好的图片保存到临时文件夹,然后再使用 tensorflow 读取图片,又耗资源,又繁琐。
  • 没有论证想法能否实现。比如:初期想法中就是拍脑袋决定的把项目看作是一个二值图像的生成问题,却没有考虑到通过 全连接神经网络生成 一个如此大的数组,比如图片大小为256*256,全连接层的参数就有2048*65536+65536个,事实上,这个项目没完成的一个原因就是一运行就直接内存溢出了。
    • 解决方法一:我想用缩放图片的方法来解决却发现需要缩放到很小很小,损失了精度。(不可行)。
    • 解决方法二:将原始图像和叠加后的mask图像做同样的随机截取,这样截取出来的image和mask都是对应的部分,而且图像大小可控,且增加了训练集数据。(还在尝试)
  • 对于自己进行的操作可能造成的一些不利后果没有清晰的认识,比如:对于细胞核相邻的问题(通过神经网络生成的mask之间也可能是相邻接的),我计划是使用ndimage.binary_opening 打开邻接,却没考虑到形态学操作对于精度的影响等问题,甚至我本身对于形态学操作的理解就不够。https://blog.csdn.net/tz_zs/article/details/79765189
  • 对于卷积神经网络的理解不够。卷积神经网络的存在,本身弱化了图片预处理的作用,我做的大量的图像处理或许可能反而 导致丢失了精度?比如将原始图像对应的mask叠加为了一张图像。比如前面的导致出现的形态学问题,或许通过mask图像标签让神经网络学会断开链接是更好的选择。

此次项目总耗时约一个星期,因为思路和方案的缺陷等,失败了╥﹏╥。

后续:

新方案:对于每一个 mask 图像,用一个最小标注框包裹其非零区域,然后在 image 图像上用相同的标注框截取图像。如此,得到一个完整的细胞核图像与其对应的 mask 图像,作为一组数据。所以,在训练集中,如果一张原始图像有 n 个 mask 图像,则可用此方法生成 n 组训练数据。这样,每组数据的图片的尺寸不会很大,然后使用迁移学习。。。

补充本次 kaggle 的数据(2019-11-19):

链接:https://pan.baidu.com/s/1WWb5peDt_2ZStpaHUrzRDg 
提取码:35xl

参考:

从神经网络视角看均方误差与交叉熵作为损失函数时的共同点

https://www.kaggle.com/rakhlin/fast-run-length-encoding-python

https://www.kaggle.com/stkbailey/teaching-notebook-for-total-imaging-newbies

kaggle 2018 data science bowl____一次失败的 kaggle 项目参与经历及反思总结相关推荐

  1. kaggle 2018 data science bowl 细胞核分割学习笔记

    一. 获奖者解决方案 1. 第一名解决方案(Unet 0.631) 主要的贡献 targets: 预测touching borders,将问题作为instance分割 loss function:组合 ...

  2. 全卷积神经网路【U-net项目实战】U-Net网络练习题: Kaggle - 2018 Data Science Bowl

    因为Kaggle有该比赛,而且code写的很简单易懂,于是乎拿来玩一下. https://www.kaggle.com/keegil/keras-u-net-starter-lb-0-277?scri ...

  3. Kaggle Titanic Data Science Solutions 点赞第一 Notebook 学习记录

    Titanic Data Science Solutions 来自 MANAV SEHGAL 的 Titanic Data Science Solutions 本笔记本的目标是遵循循序渐进的工作流程, ...

  4. Kaggle Faster Data Science Education coursera

    https://www.kaggle.com/learn/overview?utm_medium=email&utm_source=intercom&utm_campaign=data ...

  5. 香港中文大学深圳(CUHKSZ)数据科学硕士(MSc in Data Science)笔试面试经验(2018/9/16)

    香港中文大学深圳(CUHKSZ)数据科学硕士(MSc in Data Science)笔试面试经验(2018/9/16) 写在前面的前面(2020.5.3) 写在前面(2019.2.19) 关于申请 ...

  6. Machine Learning 和 Data Science 的最佳公共数据集

    什么是机器学习的最佳数据集?本文整理了一个高质量.多样化的机器学习数据集榜单. AUTHORS: Stacy Stanford, Machine Learning Memoirs Inc. Rober ...

  7. Data Science Challenge / Competition

    文章目录 Kaggle DrivenData CodaLab - Home Challenge Data crowdAI EvalAI Numerai SIGNATE Unearthed Google ...

  8. python选课系统_【精选】在Monash读Data Science,人人都拥有这样一份选课指南。

    点击上方"蓝字",关注最适合你的学习咨询 前言 1.课程难度因人而异,课程作业也可能每学期变动,所以大家结合个人实际情况参考借鉴. 2.本指南系列只描述了比较最主流的课,冷门课程资 ...

  9. 数据挖掘(data mining),机器学习(machine learning),和人工智能(AI)的区别是什么? 数据科学(data science)和商业分析(business analytics

    数据挖掘(data mining),机器学习(machine learning),和人工智能(AI)的区别是什么? 数据科学(data science)和商业分析(business analytics ...

最新文章

  1. 计算机电磁兼容性设计方法,某型號加固计算机电磁兼容性设计.doc
  2. ELK 为什么这么流行?|GIAC 访谈
  3. 香蕉派安装64位linux,在香蕉派里安装配置archlinux到树莓派
  4. 介绍一个欧神写的剪贴板多端同步神器
  5. python中range 函数_Python range()函数用法图文详解
  6. jar k8s 自己的 部署_k8s+jenkins+harbor镜像仓库实现持续集成
  7. 20个MySQL高性能架构设计原则(收藏版)
  8. redis aof 备份和恢复_深入理解Redis持久化
  9. TCP协议最大字节数计算
  10. python dataframe的某一列变为list_手把手教你用Python爬中国电影票房数据
  11. k8s 部署 xxl-job-admin:2.3.0
  12. 感恩陪伴,链接未来 | Conflux杭州应用开发运营中心成立
  13. 【一篇文章告诉你网格策略从理论到实盘的所有内容(python实现)】
  14. Golang | 优雅地定义枚举类型
  15. C语言指针(一)——什么是指针及指针的定义
  16. 中国乳房X射线照相设备市场趋势报告、技术动态创新及市场预测
  17. 滴!您有一份《程序猿耍帅秘籍》,请及时处理
  18. mysql.server 脚本解析
  19. X-VLM: Multi-Grained Vision Language Pre-Training
  20. 电脑上怎么清空我的android手机,格式化也不靠谱?教你如何彻底删除手机上的数据...

热门文章

  1. 全球名校AI课程库(44)| 慕尼黑工大 · 计算机视觉深度学习进阶课『Advanced Deep Learning for Computer Vision』
  2. java 正则 懒惰_正则表达式的最大最小原则(就是懒惰和贪婪定理),java版本
  3. hdu 50722014鞍山现场赛C题(容斥原理+同色三角形)
  4. 搭建Gitea和Drone环境
  5. LVTTL转LVDS GM8285C,28位LVDS发送器,替代GM8283
  6. Yuma格式历书的总结
  7. Android 2.2 Froyo发布
  8. Google可翻译Word或PDF文档
  9. Nginx “邪恶” rewrite
  10. Ubuntu 11.10 Linux 3D桌面完全教程,显卡驱动安装方法,compiz特效介绍,常见问题解答