项目笔记《DeepLung:Deep 3D Dual Path Nets for Automated Pulmonary Nodule Detection and Classification》(三)(上)结果评估
在(一)中,我将肺结节检测项目总结为三阶段,这里我要讲讲这个项目的第三阶段,至于第二阶段,由于数据增强部分的代码我始终看不大懂,先不讲。
结果评估的程序在evaluationScript文件夹下,这个文件夹下的文件名比较烦,看的比较懵。
annotations文件夹里面放的是结节标签文件,无关结节标签文件(是结节,但是不统计在内,也不作为非结节区域,就是评估的时候如果你检测到了它,既不算正确,也不算错误,略过),还有用户id文件。
tool文件夹放的是读取csv文件的模块。
frocwrtdetpepchluna16.py用来将输出的.npy格式的结果转化为.csv格式。
noduleCADEvaluationLUNA16.py用来对.csv文件中的结果进行评估,得出froc曲线图。
下面详细分析下代码,首先是frocwrtdetpepchluna16.py。
def getcsv(detp, eps): #给定阈值和epoch
for ep in eps:#针对每个epoch
bboxpath = results_path + str(ep) + '/' #找到每个epoch的路径
for detpthresh in detp:
print 'ep', ep, 'detp', detpthresh
f = open(bboxpath + 'predanno'+ str(detpthresh) + 'd3.csv', 'w') #根据阈值分别创建与之对应的文件
fwriter = csv.writer(f)
fwriter.writerow(firstline) #写入第一行,包括用户id,结节坐标x,y,z,结节概率p
fnamelist = []
for fname in os.listdir(bboxpath):
if fname.endswith('_pbb.npy'): #找到以_pbb.npy结尾的文件(输出的结节预测值),添加进文件列表
fnamelist.append(fname) print(len(fnamelist))
convert = functools.partial(convertcsv, bboxpath = bboxpath, detp = detpthresh) #这个函数对convertcsv函数进行修饰,其实就是预设定几个参数,不用再输入
for fname in fnamelist:
print fname
rowlist = convert(fname) #将每一个_pbb.npy文件转换为csv文件
for row in rowlist:
print row
fwriter.writerow(row)
#这段注释掉的是原来的代码,用来对那末多pbb.npy文件并行处理,事实证明,确实快了好几倍,实际运行应该用下面这段
#map函数也是修饰函数,将fnamelist的元素并行送给convert处理
#predannolist = p.map(functools.partial(convertcsv, bboxpath=bboxpath, detp=detpthresh), fnamelist)
#for predanno in predannolist:
# print predanno
# for row in predanno:
# print row
# fwriter.writerow(row)
f.close()
上面这段代码不是核心代码,这段的作用是对输出的结果文件调用convertcsv函数处理,结果就是每一个epoch都生成一个csv文件,存放80多个测试病例的预测结节位置及概率。
那么接下来就说说比较核心的convertcsv函数
def convertcsv(bboxfname, bboxpath, detp):#给定pbb.npy的文件名,pbb.npy的路径,阈值
sliceim,origin,spacing,isflip = load_itk_image(datapath+bboxfname[:-8]+'.mhd')#加载原始数据
origin = np.load(sideinfopath+bboxfname[:-8]+'_origin.npy', mmap_mode='r') #以下几行加载预处理后的坐标原点,分辨率,拓展box
spacing = np.load(sideinfopath+bboxfname[:-8]+'_spacing.npy', mmap_mode='r')
resolution = np.array([1, 1, 1])
extendbox = np.load(sideinfopath+bboxfname[:-8]+'_extendbox.npy', mmap_mode='r')
pbb = np.load(bboxpath+bboxfname, mmap_mode='r') #加载pbb.npy文件
#print "load finished!"
pbbold = np.array(pbb[pbb[:,0] > detp]) #根据阈值过滤掉概率低的
pbbold = np.array(pbbold[pbbold[:,-1] > 3]) #根据半径过滤掉小于3mm的
pbbold = pbbold[np.argsort(-pbbold[:,0])][:1000] #这条是我加上的,取概率值前1000的结节作为输出,不然直接进行nms耗时太长 pbb = nms(pbbold, nmsthresh) #对输出的结节进行nms
#print "after nms bboxs:",pbb.shape[0]
# print len(pbb), pbb[0]
# print bboxfname, pbbold.shape, pbb.shape, pbbold.shape
pbb = np.array(pbb[:, :-1]) #去掉直径
# print pbb[:, 0]
pbb[:, 1:] = np.array(pbb[:, 1:] + np.expand_dims(extendbox[:,0], 1).T) #对输出加上拓展box的坐标,其实就是恢复为原来的坐标,我对这个拓展box深恶痛绝
pbb[:, 1:] = np.array(pbb[:, 1:] * np.expand_dims(resolution, 1).T / np.expand_dims(spacing, 1).T) #将输出恢复为原来的分辨率,这样就对应了原始数据中的体素坐标
if isflip:#如果有翻转的情况,将坐标翻转(我理解是这样的,原始数据有翻转的情况,但是label还是未翻转的label,那么将label翻转,所以模型的输出也是翻转的,现在要再翻转回去,与label对应)
#拓展box与翻转这两个操作让我神烦
Mask = np.load(sideinfopath+bboxfname[:-8]+'_mask.npy', mmap_mode='r')
pbb[:, 2] = Mask.shape[1] - pbb[:, 2]
pbb[:, 3] = Mask.shape[2] - pbb[:, 3]
pos = VoxelToWorldCoord(pbb[:, 1:], origin, spacing) #将输出转换为世界坐标
#print "voxel to world finished!"
rowlist = []
# print pos.shape
for nk in xrange(pos.shape[0]): # pos[nk, 2], pos[nk, 1], pos[nk, 0] #现在依次将文件名,z,y,x,概率(经过sigmoid处理)写入rowlist,每行都是一个输出结节
rowlist.append([bboxfname[:-8], pos[nk, 2], pos[nk, 1], pos[nk, 0], 1/(1+np.exp(-pbb[nk,0]))])
# print len(rowlist), len(rowlist[0])
return rowlist#bboxfname[:-8], pos[:K, 2], pos[:K, 1], pos[:K, 0], 1/(1+np.exp(-pbb[:K,0]))
这段代码各种操作是真的繁琐,看着都头疼。这段主要完成的就是对输出结节应用阈值和nms,输出的结果再转换为与label一样的坐标体系,因为最后的准确与否全看与label是否一致。看一下打印的输出信息,这里用的是subset9为验证集,我只贴出了一个epoch的测试结果,阈值取为-0.125,这是sigmoid函数的输入,对应概率值0.4695。
ep 1 detp -0.125
write to/home/code/DeepLung/detector/results/new_arch/retrft969/val1/predanno-0.125pbb.csv
至此,输出处理完毕,可以求取最后的FROC值了,离大功告成只差一步。
不过,每个epoch都会对应一个csv结果文件,我们还要选取一个最好的结果,选取标准就是FROC值,这些都是如何做的呢,不妨看一下代码。
def getfroc(detp, eps):
maxfroc = 0
maxep = 0
for ep in eps: #对每个epoch分别处理
bboxpath = results_path + str(ep) + '/'
predannofnamalist = []
for detpthresh in detp: #此处的detp就是阈值,只不过这里采用的是一个阈值列表,就我自己而言,我采用的阈值是-0.125,列表中只有一个元素
predannofnamalist.append(bboxpath + 'predanno'+ str(detpthresh) + 'pbb.csv')
#froclist = p.map(getfrocvalue, predannofnamalist)
froclist = [getfrocvalue(predanno) for predanno in predannofnamalist] #调用getfrocvalue求取froc值
if maxfroc < max(froclist):
maxep = ep
maxfroc = max(froclist)
print froclistprint maxfroc, maxep
接下来调用getfrocvalue函数,这个函数其实是调用了noduleCADEvaluationLUNA16.py,也就是核心模块,刚才的frocwrtdetpepchluna16.py只是做了一层处理,对输出进行筛选和变换,以用来进行最后的大决战。
def getfrocvalue(results_filename):
return noduleCADEvaluation(annotations_filename,annotations_excluded_filename,seriesuids_filename,results_filename,'./')
可以看到,我们将标签文件,无关标签文件,用户id文件,以及最后的结果文件也就是之前的csv文件作为输入,输出会是一个标量值,也就是评分。
对noduleCADEvaluationLUNA16.py的分析我想放到(三)(下)去讲,因为会比较长。
项目笔记《DeepLung:Deep 3D Dual Path Nets for Automated Pulmonary Nodule Detection and Classification》(三)(上)结果评估的更多相关文章
- 项目笔记《DeepLung:Deep 3D Dual Path Nets for Automated Pulmonary Nodule Detection and Classification》(二)(上)模型设计
我只讲讲检测部分的模型,后面两样性分类的试验我没有做,这篇论文采用了很多肺结节检测论文都采用的u-net结构,准确地说是具有DPN结构的3D版本的u-net,直接上图. DPN是颜水成老师团队的成果, ...
- 项目笔记《DeepLung:Deep 3D Dual Path Nets for Automated Pulmonary Nodule Detection and Classification》(三)(下)结果评估
在(上)中讲了如何得到csv文件并调用noduleCADEvaluationLUNA16.py求取froc值,这里就讲一讲froc值是如何求取的. annotations_filename = './ ...
- 项目笔记《DeepLung:Deep 3D Dual Path Nets for Automated Pulmonary Nodule Detection and Classification》(一)预处理
最近一个月都在做肺结节的检测,学到了不少东西,运行的项目主要是基于这篇论文,在github上可以查到项目代码. 我个人总结的肺结节检测可以分为三个阶段,数据预处理,网络搭建及训练,结果评估. 这篇博客 ...
- Django商城项目笔记No.2项目准备工作
Django商城项目笔记No.2项目准备工作 接着上篇开始,创建好工程之后,随之而来的是怎么配置工程,这篇文章记录如何进行相关的配置 1.pycharm打开工程,进行相关的配置 通过pycharm打开 ...
- Django项目笔记:sessions处理以及复杂对象序列化
前言:一点题外话 我发现,不更新博客的时候,不是非常忙,就是效率非常低.最近没怎么更新博客,原因是第二种= =.惭愧惭愧. 今天效率出奇的高,一天时间把PassNote后端的接口全部写完了,Djang ...
- Dual Path Networks(DPN)——一种结合了ResNet和DenseNet优势的新型卷积网络结构。深度残差网络通过残差旁支通路再利用特征,但残差通道不善于探索新特征。密集连接网络通过密集连接通路探索新特征,但有高冗余度。
如何评价Dual Path Networks(DPN)? 论文链接:https://arxiv.org/pdf/1707.01629v1.pdf在ImagNet-1k数据集上,浅DPN超过了最好的Re ...
- 《BI项目笔记》——微软BI项目笔记连载
本系列文章主要是结合实际项目,加上自己的总结,整理出来的一系列项目笔记,涉及微软SQL Server2008中商务智能开发中的SSAS.SSIS模块: 准备工作: <BI项目笔记>基于雪 ...
- A Statistical View of Deep Learning (IV): Recurrent Nets and Dynamical Systems
A Statistical View of Deep Learning (IV): Recurrent Nets and Dynamical Systems Recurrent neural netw ...
- 项目笔记---CSharp图片处理
原文:项目笔记---CSharp图片处理 项目笔记---CSharp图片处理 最近由于项目上需要对图片进行二值化处理,就学习了相关的图片处理上的知识,从开始的二值化的意义到动态阀值检测二值化等等,并用 ...
随机推荐
- tar命令解压jdk.tar.gz包 报错 gzip: stdin: not in gzip format
转自:https://blog.csdn.net/LL_zhuo/article/details/44173355 遇到和这篇博文一样的问题了.用wget 从oracle官网下载jdk, http:/ ...
- DAY11-MYSQL索引原理与慢查询优化
一 介绍 为何要有索引? 一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,在生产环境中,我们遇到最多的,也是最容易出问题的,还是一些复杂的查询操作,因此对查询语句 ...
- (转)newInstance()和new()
在Java开发特别是数据库开发中,经常会用到Class.forName( )这个方法.通过查询Java Documentation我们会发现使用Class.forName( )静态方法的目的是为了动态 ...
- 2-3 zookeeper文件夹主要目录介绍
zookeeper-3.4.11.jar.zookeeper-3.4.11.jar.md5.zookeeper-3.4.11.sha1都是通过打包或者编译之后产生的相关的文件.那么maven相关的东西 ...
- git 本地代码到github(转)
git 本地代码到github 一·什么是gitHub? 官网解释:gitHub是一个让无论处于何地的代码工作者能工作于同一个项目,同一个版本的平台.(GitHub is a code hosti ...
- 下拉菜单控件JComboBox的使用
---------------siwuxie095 工程名:TestUI 包名:com.siwuxie095.ui 类名:TestList.ja ...
- 指静脉屏幕说明usart hmi
1. 1.usart HMI 下载最新版软件 2.如上图可以设置横屏 3.txt的最大字符默认是10 要改大一些 4.t0.txt="aaa" 这是串口通讯命令但前面还有开始码
- HDOJ 1023 Train Problem II 卡特兰数
火车进站出站的问题满足卡特兰数...卡特兰数的相关知识如下: 卡特兰数又称卡塔兰数,是组合数学中一个常出现在各种计数问题中出现的数列.由以比利时的数学家欧仁·查理·卡塔兰 (1814–1894)命名. ...
- Win10 VS2013 PCL1.8.1和依赖项VTK8.0.1, QHuall(2.15.2), FLANN1.9.1,Boost1.59.0,Zbil1.2.11和libPNG1.6.34编译安装
编译和安装过程最好使用管理员权限去操作,避免不必要的错误. 一般而言为了区分Debug和Release库,添加输入变量 Name: CMAKE_DEBUG_POSTFIX Type: STRING V ...
- SSH (Struts2+Spring3.0+Hibernate3)框架(一) 理论
典型的J2EE三层结构,分为表现层.中间层(业务逻辑层)和数据服务层.三层体系将业务规则.数据访问及合法性校验等工作放在中间层处理.客户端不直接与数据库交互,而是通过组件与中间层建立连接,再由中间层与 ...