精华内容
下载资源
问答
  • 无人工标注数据的Landsat影像云检测深度学习方法.pdf
  • 为此,研究利用深度学习技术解决僵尸云检测问题。首先,从网络流中提取基本特征;然后将其映射为灰度图像;最后利用卷积神经网络算法进行特征学习,提取出更加抽象的特征,用以表达网络流数据中隐藏的模式及结构关系...
  • 多层次的云检测遥感图像基于深度学习
  • 通过深度学习对遥感影像进行云检测
  • 深度学习在僵尸云检测中的应用研究.pdf
  • 深度学习在遥感影像云检测中的应用.pdf
  • 针对资源三号卫星影像波段少、光谱范围受限的特点, 提出了基于深度学习的资源三号卫星遥感影像的云检测方法。首先, 采用主成分分析非监督预训练网络结构, 获得了待测遥感影像特征; 其次, 为减少在池化过程中影像特征...
  • 基于深度学习的多角度遥感影像云检测方法.pdf
  • 基于深度学习的嵌入式云检测系统的设计与实现.pdf
  • 基于深度学习的资源三号遥感影像云检测方法。摘要 针对资源三号卫星影像波段少、光谱范围受限的特点,本文提出了基于深度学习的资源三号遥感影像云检测方法。首先,采用主成分分析非监督预训练网络结构,获得待测...
  • 口罩 检测 识别 深度学习 数据集 口罩 检测 识别 深度学习 数据集 口罩 检测 识别 深度学习 数据集 口罩 检测 识别 深度学习 数据集 口罩 检测 识别 深度学习 数据集 口罩 检测 识别 深度学习 数据集
  • 基于深度学习的FY3D_MERSI和EOS_MODIS云检测模型研究.pdf
  • 基于深度学习环境动态恶意代码检测平台.pdf
  • 阿里天池安全Ai挑战者计划图像篡改检测 博主此次比赛rank23 这是在在学校做宣讲时的材料 包括深度学习入门指导,比赛所需知识获取方式,常见比赛类型解读以及此次比赛的TOP选手方案解读
  • 作者:陈迪豪,小米深度学习工程师,负责小米云深度学习平台的架构和实现,目前专注于TensorFlow和Kubernetes社区。 责编:何永灿,欢迎人工智能领域技术投稿、约稿、给文章纠错,请发送邮件至heyc#csdn.net(#改...

    作者:陈迪豪,小米深度学习工程师,负责小米云深度学习平台的架构和实现,目前专注于TensorFlow和Kubernetes社区。
    责编:何永灿,欢迎人工智能领域技术投稿、约稿、给文章纠错,请发送邮件至heyc#csdn.net(#改为@)
    本文为《程序员》原创文章,未经允许不得转载,更多精彩文章请订阅《程序员》

    深度学习服务介绍

    机器学习与人工智能,相信大家已经耳熟能详,随着大规模标记数据的积累、神经网络算法的成熟以及高性能通用GPU的推广,深度学习逐渐成为计算机专家以及大数据科学家的研究重点。近年来,无论是图像的分类、识别和检测,还是语音生成、自然语言处理,甚至是AI下围棋或者打游戏都基于深度学习有了很大的突破。而随着TensorFlow、Caffe等开源框架的发展,深度学习的门槛变得越来越低,甚至初中生都可以轻易实现一个图像分类或者自动驾驶的神经网络模型,但目前最前沿的成果主要还是出自Google、微软等巨头企业。

    Google不仅拥有优秀的人才储备和大数据资源,其得天独厚的基础架构也极大推动了AI业务的发展,得益于内部的大规模集群调度系统Borg,开发者可以快速申请大量GPU资源进行模型训练和上线模型服务,并且通过资源共享和自动调度保证整体资源利用率也很高。Google开源了TensorFlow深度学习框架,让开发者可以在本地轻易地组合MLP、CNN和RNN等模块实现复杂的神经网络模型,但TensorFlow只是一个数值计算库,并不能解决资源隔离、任务调度等问题,将深度学习框架集成到基于云计算的基础架构上将是下一个关键任务。

    除了Google、微软,国内的百度也开源了PaddlePaddle分布式计算框架,并且官方集成了Kubernetes等容器调度系统,用户可以基于PaddlePaddle框架实现神经网络模型,同时利用容器的隔离性和Kubernetes的资源共享、自动调度、故障恢复等特性,但平台不能支持更多深度学习框架接口。而亚马逊和腾讯云相继推出了面向开发者的公有云服务,可以同时支持多种主流的开源深度学习框架,阿里、金山和小米也即将推出基于GPU的云深度学习服务,还有无数企业在默默地研发内部的机器学习平台和大数据服务。

    面对如此眼花缭乱的云服务和开源技术,架构师该如何考虑其中的技术细节,从用户的角度又该如何选择这些平台或者服务呢。我将介绍小米云深度学习平台的架构设计与实现细节,希望能给AI领域的研发人员提供一些思考和启示。

    云深度学习平台设计

    云深度学习平台,我定义为Cloud Machine Learning,就是基于云计算的机器学习和深度学习平台。首先TensorFlow、MXNet是深度学习框架或者深度学习平台,但并不是云深度学习平台,它们虽然可以组成一个分布式计算集群进行模型训练,但需要用户在计算服务器上手动启动和管理进程,并没有云计算中任务隔离、资源共享、自动调度、故障恢复以及按需计费等功能。因此我们需要区分深度学习类库以及深度学习平台之间的关系,而这些类库实现的随机梯度下降和反向传播等算法却是深度学习应用所必须的,这是一种全新的编程范式,需要我们已有的基础架构去支持。

    云计算和大数据发展超过了整整十年,在业界催生非常多优秀的开源工具,如实现了类似AWS IaaS功能的OpenStack项目,还有Hadoop、Spark、Hive等大数据存储和处理框架,以及近年很火的Docker、Kubernetes等容器项目,这些都是构建现代云计算服务的基石。这些云服务有共同的特点,例如我们使用HDFS进行数据存储,用户不需要手动申请物理资源就可以做到开箱即用,用户数据保存在几乎无限制的公共资源池中,并且通过租户隔离保证数据安全,集群在节点故障或者水平扩容时自动触发Failover且不会影响用户业务。虽然Spark通过MLib接口提供部分机器学习算法功能,但绝不能替代TensorFlow、Caffe等深度学习框架的作用,因此我们仍需要实现Cloud Machine Learning服务,并且确保实现云服务的基本特性——我将其总结为下面几条:

    • 屏蔽硬件资源保证开箱即用
    • 缩短业务环境部署和启动时间
    • 提供“无限”的存储和计算能力
    • 实现多租户隔离保证数据安全
    • 实现错误容忍和自动故障迁移
    • 提高集群利用率和降低性能损耗

    相比于MapReduce或者Spark任务,深度学习的模型训练时间周期长,而且需要调优的超参数更多,平台设计还需要考虑以下几点

    • 支持通用GPU等异构化硬件
    • 支持主流的深度学习框架接口
    • 支持无人值守的超参数自动调优
    • 支持从模型训练到上线的工作流

    这是我个人对云深度学习平台的需求理解,也是小米在实现cloud-ml服务时的基本设计原则。虽然涉及到高可用、分布式等颇具实现难度的问题,但借助目前比较成熟的云计算框架和开源技术,我们的架构和实现基本满足了前面所有的需求,当然如果有更多需求和想法欢迎随时交流。

    云深度学习平台架构

    遵循前面的平台设计原则,我们的系统架构也愈加清晰明了,为了满足小米内部的所有深度学习和机器学习需求,需要有一个多租户、任务隔离、资源共享、支持多框架和GPU的通用服务平台。通过实现经典的MLP、CNN或RNN算法并不能满足业务快速发展的需求,因此我们需要支持TensorFlow等用户自定义的模型结构,并且支持高性能GPU和分布式训练是这个云深度学习平台的必须功能,不仅仅是模型训练,我们还希望集成模型服务等功能来最大化用户的使用效益。

    计算机领域有句名言“任何计算机问题都可以通过增加一个中间层来解决”。无论是AWS、OpenStack、Hadoop、Spark还是TCP/IP都是这样做的,通过增加一个抽象层来屏蔽底层资源,对上层提供更易用或者更可靠的访问接口。小米的cloud-ml平台也需要实现对底层物理资源的屏蔽,尤其是对GPU资源的抽象和调度,但我们不需要重新实现,因为社区已经有了很多成熟的分布式解决方案,如OpenStack、Yarn和Kubernetes。目前OpenStack和Yarn对GPU调度支持有所欠缺,虚拟机也存在启动速度慢、性能overhead较大等问题,而容器方案中的Kubernetes和Mesos发展迅速,支持GPU调度等功能,是目前最值得推荐的架构选型之一。

    目前小米cloud-ml平台的任务调度和物理机管理基于多节点的分布式Kubernetes集群,对于OpenStack、Yarn和Mesos我们也保留了实现接口,可以通过实现Mesos后端让用户的任务调度到Mesos集群进行训练,最终返回给用户一致的使用接口。目前Kubernetes最新稳定版是1.6,已经支持Nvidia GPU的调度和访问,对于其他厂商GPU暂不支持但基本能满足企业内部的需求,而且Pod、Deployment、Job、StatefulSet等功能日趋稳定,加上Docker、Prometheus、Harbor等生态项目的成熟,已经在大量生产环境验证过,可以满足通用PaaS或者Cloud Machine learning等定制服务平台的需求。

    使用Kubernetes管理用户的Docker容器,还解决了资源隔离的问题,保证不同深度学习训练任务间的环境不会冲突,并且可以针对训练任务和模型服务使用Job和Deployment等不同的接口,充分利用分布式容器编排系统的重调度和负载均衡功能。但是,Kubernetes并没有完善的多租户和Quota管理功能,难以与企业内部的权限管理系统对接,这要求我们对Kubernetes API进行再一次“抽象”。我们通过API Server实现了内部的AKSK签名和认证授权机制,在处理用户请求时加入多租户和Quota配额功能,并且对外提供简单易用的RESTful API,进一步简化了整个云深度学习平台的使用流程,整体架构设计如图1。

    图片描述

    图1 云深度学习平台整体架构

    通过实现API Server,我们对外提供了API、SDK、命令行以及Web控制台多种访问方式,最大程度上满足了用户复杂多变的使用环境。集群内置了Docker镜像仓库服务,托管了我们支持的17个深度学习框架的容器镜像,让用户不需要任何初始化命令就可以一键创建各框架的开发环境、训练任务以及模型服务。多副本的API Server和Etcd集群,保证了整个集群所有组件的高可用,和Hadoop或者Spark一样,我们的cloud-ml服务在任意一台服务器经历断网、宕机、磁盘故障等暴力测试下都能自动Failover保证业务不受任何影响。

    前面提到,我们通过抽象层定义了云深度学习平台的接口,无论后端使用Kubernetes、Mesos、Yarn甚至是OpenStack、AWS都可以支持。通过容器的抽象可以定义任务的运行环境,目前已经支持17个主流的深度学习框架,用户甚至可以在不改任何一行代码的情况下定义自己的运行环境或者使用自己实现的深度学习框架。在灵活的架构下,我们还实现了分布式训练、超参数自动调优、前置命令、NodeSelector、Bring Your Own Image和FUSE集成等功能,将在下面逐一介绍。

    云深度学习平台实现

    前面提到我们后端使用Kubernetes编排系统,通过API Server实现授权认证和Quota配额功能。由于云深度学习服务是一个计算服务,和我以前做过的分布式存储服务有着本质的区别,计算服务离线运算时间较长,客户端请求延时要求较低而且吞吐很小,因此我们的API服务在易用性和高性能上可以选择前者,目前主流的Web服务器都可以满足需求。基于Web服务器我们可以实现集成内部权限管理系统的业务逻辑,小米生态云提供了类似AWS的AKSK签名认证机制,用户注册登录后可以自行创建Access key和Secret key,请求时在客户端进行AKSK的签名后发送,这样用户不需要把账号密码或密钥加到请求中,即使密钥泄露也可以由用户来禁用,请求时即使签名被嗅探也只能重放当前的请求内容,是非常可靠的安全机制。除此之外,我们参考OpenStack项目的体系架构,实现了多租户和Quota功能,通过认证和授权的请求需要经过Quota配额检查,在高可用数据库中持久化相应的数据,这样平台管理员就可以动态修改每个租户的Quota,而且用户可以随时查看自身的审计信息。

    小米cloud-ml服务实现了深度学习模型的开发、训练、调优、测试、部署和预测等完整功能,都是通过提交到后端的Kubernetes集群来实现,完整的功能介绍可以查看官方文档http://docs.api.xiaomi.com/cloud-ml/ 。Kubernetes对外提供了RESTful API访问接口,通过YAML或者JSON来描述不同的任务类型,不同编程语言实现的系统也可以使用社区开发的SDK来访问。对于我们支持的多个深度学习框架,还有开发环境、训练任务、模型服务等功能,都需要定制Docker镜像,提交到Kubernetes时指定使用的容器镜像、启动命令等参数。通过对Kubernetes API的封装,我们可以简化Kubernetes的使用细节,保证了对Mesos、Yarn等后端支持的兼容性,同时避免了直接暴露Kubernetes API带来的授权问题以及安全隐患。

    除了可以启动单个容器执行用户的训练代码,小米cloud-ml平台也支持TensorFlow的分布式训练,使用时只需要传入ps和worker个数即可。考虑到对TensorFlow原生API的兼容性,我们并没有定制修改TensorFlow代码,用户甚至可以在本地安装开源的TensorFlow测试后再提交,同样可以运行在云平台上。但本地运行分布式TensorFlow需要在多台服务器上手动起进程,同时要避免进程使用的端口与其他服务冲突,而且要考虑系统环境、内存不足、磁盘空间等问题,代码更新和运维压力成倍增加,Cloud Machine Learning下的分布式TensorFlow只需要在提交任务时多加两个参数即可。有人觉得手动启动分布式TensorFlow非常繁琐,在云端实现逻辑是否更加复杂?其实并不是,通过云服务的控制节点,我们在启动任务前就可以分配不会冲突的端口资源,启动时通过容器隔离环境资源,而用户不需要传入Cluster spec等繁琐的参数,我们遵循Google CloudML标准,会自动生成Cluster spec等信息通过环境变量加入到容器的启动任务中。这样无论是单机版训练任务,还是几个节点的分布式任务,甚至是上百节点的分布式训练任务,cloud-ml平台都可以通过相同的镜像和代码来运行,只是启动时传入的环境变量不同,在不改变任何外部依赖的情况下优雅地实现了看似复杂的分布式训练功能。

    图片描述

    图2 云深度学习平台分布式训练

    看到这里大家可能认为,小米的cloud-ml平台和Google的CloudML服务,都有点类似之前很火的PaaS(Platform as a Service)或者CaaS(Container as a Service)服务。确实如此,基于Kubernetes或者Mesos我们可以很容易实现一个通用的CaaS,用户上传应用代码和Docker镜像,由平台调度和运行,但不同的是Cloud Machine Learning简化了与机器学习无关的功能。我们不需要用户了解PaaS的所有功能,也不需要支持所有编程语言的运行环境,暴露提交任务、查看任务、删除任务等更简单的使用接口即可,而要支持不同规模的TensorFlow应用代码,用户需要以标准的Python打包方式上传代码。Python的标准打包方式独立于TensorFlow或者小米cloud-ml平台,幸运的是目前Google CloudML也支持Python的标准打包方式,通过这种标准接口,我们甚至发现Google CloudML打包好的samples代码甚至可以直接提交到小米cloud-ml平台上训练。这是非常有意思的尝试,意味着用户可以使用原生的TensorFlow接口来实现自己的模型,在本地计算资源不充足的情况下可以提交到Google CloudML服务上训练,同时可以一行代码不用改直接提交到小米或者其他云服务厂商中的云平台上训练。如果大家在实现内部的云深度学习平台,不妨也参考下标准的Python打包方式,这样用户同一份代码就可以兼容所有云平台,避免厂商绑定。

    除了训练任务,Cloud Machine Learning平台最好也能集成模型服务、开发环境等功能。对于模型服务,TensorFlow社区开源了TensorFlow Serving项目,可以加载任意TensorFlow模型并且提供统一的访问接口,而Caffe社区也提供了Web demo项目方便用户使用。目前Kubernetes和Mesos都实现了类似Deployment的功能,通过制作TensorFlow Serving等服务的容器镜像,我们可以很方便地为用户快速启动对应的模型服务。通过对Kubernetes API的封装,我们在暴露给用户API时也提供了replicas等参数,这样用户就可以直接通过Kubernetes API来创建多副本的Deployment实例,并且由Kubernetes来实现负载均衡等功能。除此之外,TensorFlow Serving本身还支持在线模型升级和同时加载多个模型版本等功能,我们在保证TensorFlow Serving容器正常运行的情况下,允许用户更新分布式对象存储中的模型文件就可以轻易地支持在线模型升级的功能。

    对于比较小众但有特定使用场景的深度学习框架,Cloud Macine Learning的开发环境、训练任务和模型服务都支持Bring Your Own Image功能,也就是说用户可以定制自己的Docker镜像并在提交任务时指定使用。这种灵活的设置极大地降低了平台管理者的维护成本,我们不需要根据每个用户的需求定制通用的Golden image,事实上也不可能有完美的镜像可以满足所有需求,用户不同的模型可能有任意的Python或者非Python依赖,甚至是自己实现的私有深度学习框架也可以直接提交到Cloud Machine Learning平台上训练。内测BYOI功能时,我们还惊喜地发现这个功能对于我们开发新的深度学习框架支持,以及提前测试镜像升级有非常大的帮助,同时用户自己实现的Caffe模型服务和XGBoost模型服务也可以完美支持。

    当然Cloud Machine Learning平台还可以实现很多有意思的功能,例如通过对线上不同GPU机型打label,通过NodeSelector功能可以允许用户选择具体的GPU型号进行更细粒度的调度,这需要我们暴露更底层Kubernetes API实现,这在集群测试中也是非常有用的功能。而无论是基于GPU的训练任务还是模型服务,我们都制作了对应的CUDA容器镜像,通过Kubernetes调度到对应的GPU计算节点就可以访问本地图像处理硬件进行高性能运算了。小米cloud-ml还开放了前置命令和后置命令功能,允许用户在启动训练任务前和训练任务结束后执行自定义命令,对于不支持分布式存储的深度学习框架,可以在前置命令中挂载S3 fuse和FDS fuse到本地目录,或者初始化HDFS的Kerberos账号,灵活的接口可以实现更多用户自定义的功能。还有超参数自动调优功能,与Google CloudML类似,用户可以提交时指定多组超参数配置,云平台可以自动分配资源起多实例并行计算,为了支持读取用户自定义的指标数据,我们实现了类似TensorBoard的Python接口直接访问TensorFlow event file数据,并通过命令行返回给用户最优的超参数组合。最后还有TensorFlow Application Template功能,在Cloud Machine Learning平台上用户可以将自己的模型代码公开或者使用官方维护的开源TensorFlow应用,用户提交任务时可以直接指定这些开源模板进行训练,模板已经实现了MLP、CNN、RNN和LR等经典神经网络结构,还可以通过超参数来配置神经网络每一层的节点数和层数,而且可以支持任意稠密和稀疏的数据集,这样不需要编写代码就可以在云平台上训练自己的数据快速生成AI模型了。

    在前面的平台设计和平台架构后,要实现完整的云深度学习服务并不困难,尤其是集成了Docker、Etcd、Kubernetes、TensorFlow等优秀开源项目,组件间通过API松耦合地交互,需要的重复工作主要是打通企业内部权限系统和将用户请求转化成Kubernetes等后端请求而已,而支持标准的打包方式还可以让业务代码在任意云平台上无缝迁移。

    云深度学习平台实践

    目前小米云深度学习平台已经在内部各业务部门推广使用,相比于直接使用物理机,云服务拥有超高的资源利用率、快速的启动时间、近乎“无限”的计算资源、自动的故障迁移、支持分布式训练和超参数自动调优等优点,相信可以得到更好的推广和应用。

    除了完成上述的功能,我们在实践时也听取了用户反馈进行改进。例如有内部用户反馈,在云端训练的TensorFlow应用把event file也导出到分布式存储中,使用TensorBoard需要先下载文件再从本地起服务相对麻烦,因此我们在原有基础架构实现了TensorboardService功能,可以一键启动TensorBoard服务,用户只需要用浏览器就可以打开使用。

    管理GPU资源和排查GPU调度问题也是相当繁琐的,尤其是需要管理不同GPU设备和不同CUDA版本的异构集群,我们统一规范了CUDA的安装方式,保证Kubernetes调度的容器可以正常访问宿主机的GPU设备。当然对于GPU资源的调度和释放,我们有完善的测试文档可以保证每一个GPU都可以正常使用,根据测试需求实现的NodeSelector功能也帮忙我们更快地定位问题。

    由于已经支持几十个功能和十几个深度学习框架,每次升级都可能影响已有服务的功能,因此我们会在多节点的分布式staging集群进行上线演习和测试,并且实现smoke test脚本进行完整的功能性测试。服务升级需要更新代码,但是为了保证不影响线上业务,无论是Kubernetes还是我们实现的API Server都有多副本提供服务,通过高可用技术先迁移服务进行滚动升级,对于一些单机运行的脚本也通过Etcd实现了高可用的抢主机制,保证所有组件没有单点故障。

    大家可以通过前面提到的文档地址和cloud-ml-sdk项目了解到更多细节,或者关注我微博(@tobe-陈迪豪)与我交流。

    总结

    本文介绍了实现企业级云深度学习平台需要的概念和知识,基于小米cloud-ml服务探讨了云平台的设计、架构、实现以及实践这四方面的内容,希望大家看完有所收获。


    订阅《程序员》(含iOS、Android及印刷版)请访问 http://dingyue.programmer.com.cn
    图片描述


    2017中国人工智能大会(CCAI 2017)| 7月22日-23日 杭州
    本届CCAI由中国人工智能学会、蚂蚁金服主办,由CSDN承办,最专业的年度技术盛宴:
    - 40位以上实力讲师
    - 8场权威专家主题报告
    - 4场开放式专题研讨会
    - 超过100家媒体报道
    - 超过2000位技术精英和专业人士参会
    与大牛面对面,到官网报名:http://ccai.caai.cn/
    图片描述

    展开全文
  • 目标检测问题方法2.1传统目标检测方法到深度学习目标检测方法的变迁2.2算法基本流程2.3传统目标检测方法2.4深度学习目标检测方法2.5传统目标检测方法VS深度学习目标检测方法2.6目标检测应用场景3.传统目标检测算法...


    1.目标检测问题定义

    1.1目标检测定义

    目标检测是在图片中对可变数量的目标进行分类和查找。
    主要难点:

    1. 目标种类与数量问题
    2. 目标尺度问题
    3. 外在环境干扰问题
    4. 形态、视角等变化

    1.2目标检测vs图像分类

    在这里插入图片描述

    1.3目标检测vs目标分割

    在这里插入图片描述
    图三为语义分割,图四为实例分割。实例分割不仅要区分语义层面上的目标,同一类别的目标也需要划分出不同的实例。目标检测相对于目标分割更关注语义层面的分割结果,而目标分割更关注于像素级别处理的任务。目标检测主要定位物体的位置,主要表示为一个矩形,一个矩形可以通过一个四维的数据进行表示,目标分割需要对每一个像素点来进行不同类别的划分,我们的结果就需要同原始的图片大小保持一致,所以目标分割往往会采用上采样、反卷积这样的方式来得到原始图像大小的输出结果。
    .

    2.目标检测问题方法

    2.1传统目标检测方法到深度学习目标检测方法的变迁

    在这里插入图片描述
    (1)传统目标检测算法比较有代表性的算法有V计算法,HOG,DPM等,这些方法主要是传统的手动提取特征并结合滑动窗口的方式来进行目标检测定位,存在问题主要有:

    1. 通过传统方式设计特征,特征难设计、特征存在的问题较多不鲁棒,比如特征对某些特定条件不适应、效率也不高
    2. 通过滑动窗口的方式生成目标框并对目标框进行分类判定这种策略比较繁琐,慢,耗时,所以在2008年DPM算法提出后目标检测算法遇到了很大的瓶颈,很难在DPM上进行提升。

    (2)2012年卷积神经网络兴起之后利用卷积神经网络代替传统手工设计特征的方式来完成目标检测的任务,这也是基于深度学习目标检测算法的一个里程碑的事件,例如overfeat,RCNN方法的提出,但是这些方法在使用深度学习的时候只是利用卷积神经网络来提取特征,并没有从本质上改变搜索框提取目标区域的策略,因此这些方法在速度上依然存在瓶颈。

    (3)Faster Rcnn等方法提出以后,通过RPN网络来代替原始的窗口策略,标志基于深度学习的目标检测方法彻底完成了一个端到端的过程,使得基于深度学习的目标检测方法在性能和速度上都得到很大地提升。

    (4)Yolo SSD等方法不采用提取候选框的策略,而采用直接回归目标框的位置这一策略来完成目标检测和定位,再一次对目标检测算法速度进行了提升,而且在精度上也能保证原先基于propersal 候选框策略的算法基本一致。

    2.2算法基本流程

    在这里插入图片描述
    上面图表示两种方法,有候选框特征提取的方法,和特征提取直接回归的方法。两种方法目前用得比较多的都是深度学习的方法,但是这个框架同样也适用于传统方法。

    2.3传统目标检测方法

    (1)viola-Jones方法。主要采用积分图特征,结合Adaboost分类器进行人脸检测等目标检测的任务。
    (2)HOG+SVM。主要用于行人检测任务。通过对行人目标候选区域提取HOG特征并结合SVM分类器来进行判定。
    (3)DPM。是基于HOG特征的一种变种,但DPM会加入很多的额外的策略来提升检测的精度,它是目前非深度学习目标检测方法中效果性能最优的一种方法。

    2.4深度学习目标检测方法

    (1)One-stage(YOLO和SSD系列) 它主要通过直接回归目标的位置这种方法来进行目标检测定位
    (2)Two-stage(Faster RCNN系列)主要通过利用RPN网络对候选区域进行推荐
    在这里插入图片描述

    2.5传统目标检测方法VS深度学习目标检测方法

    传统目标检测方法深度学习目标检测方法
    手动设计特征深度网络学习特征
    滑动窗口Proposal或者直接回归
    传统分类器深度网络
    多步骤端到端
    准确度和实时性差准确度高和实时性好

    2.6目标检测应用场景

    人脸检测、文本检测、交通检测、通用物体识别、卫星图像等
    .

    3.传统目标检测算法

    3.1综述

    在这里插入图片描述
    输入图片,然后滑动窗口提取候选框,对窗口中的局部图像信息进行特征提取,如基于颜色的方法、基于纹理的方法、基于形状的方法以及一些中高层次语义特征的方法,这些方法有些是需要经过学习来得到的方法,比如抽取最基本的直方图特征,以及纹理特征如HOG特征等,这样的一些稠密特征之后经过PCA算法进行特征降维,或者LDA算法进行空间投影,对抽取出的基本特征来进行进一步学习,来挖掘一些更加鲁棒的特征出来,因此对于传统计算机视觉中常见的特征提取方法分为三大类:

    1. 底层特征。颜色纹理等最基本的特征。
    2. 中层次特征。对底层特征进行机器学习的方法来进行特征挖掘、特征学习后得到的特征,比如PCA特征,LDA学习之后的特征等一些基于优化理论来完成的特征的学习。
    3. 高层次的特征。将低层次或中层次特征进行进一步挖掘和表示,比如可以把一个人可以用是否戴帽子、头发的长短、所穿的服装等来表示。

    目标检测算法中通常使用低层次特征和中层次特征。
    然后对提取出来的特征用学习好的分类器进行分类判定。得出一系列可能为当前检测目标的候选框,这些候选框可能会存在一些重叠的状况,然后通过NMS非极大值抑制的算法来对候选框进行合并,最后得到最终需要检测的目标,也就是算法输出的结果。
    .

    3.2Viola-Jones

    它主要用于人脸检测 ,它的主要关键点有:

    1. Haar特征提取
    2. 训练人脸分类器(Adaboost算法等)
    3. 滑动窗口

    (1)特征
    最终特征的表示形式为表示为直方图,它需要统计下面四种不同类别的特征
    在这里插入图片描述
    具体可以看这个博客:https://www.cnblogs.com/mikewolf2002/p/3438181.html

    (2)Adaboost算法

    1. 初始化样本的权重w,样本权重之和为1
    2. 训练弱分类器
    3. 更新样本权重
    4. 循环第二步
    5. 结合各个分类器结果,进行投票

    3.3HOG+SVM

    它主要用于行人检测,行人检测的难点主要在于行人一般处于运动状态,行人的姿态存在比较多的差异,它的步骤如下:

    1. 提取HOG特征
    2. 训练SVM分类器
    3. 利用滑动窗口提取目标区域,进行分类判断
    4. NMS
    5. 输出检测结果

    (1)HOG特征
    hog特征通过计算梯度方向来统计最后的直方图,也是纹理特征的一种,它的流程如下:

    1. 灰度化+Gamma变换。hog特征主要用在灰度图上,gamma变换指对整个像素的值开根号,这样整个像素的值会变小
    2. 计算梯度map。即计算每个点在x方向和y方向上的梯度值,并利用这个梯度值在计算梯度夹角,方向角a=arctan(x/y),然后将a量化到0-360°,再划分为x个段,比如18个段,20°为一个段。
    3. 图像划分成小的cell,统计每个cell梯度直方图。如果上面划分18个段,那么统计出的直方图维度就是18维
    4. 多个cell组成一个block,特征归一化。假如每个cell得到一个18维的特征,每四个cell组合成一个block,那么一个block的特征维度就是4*18,然后归一化。
    5. 多个block串联,并归一化。

    hog特征的维度跟量化的角度有关,然后跟cell的大小有关系,通常hog特征有几千维,所以直接用hog特征计算的时候计算难度也比较大,所以可以采用PCA降维的方法进行降维

    (2)SVM
    SVM的东西比较多,有需要的可以好好学习一下。

    3.4 DPM

    它是传统目标检测算法的巅峰之作,它是对HOG算法的一种扩展,进行特征提取时基于HOG特征进行扩展和优化,利用SVM训练得到物体的梯度。它的流程如下:

    1. 计算DPM特征图
    2. 计算响应图
    3. Latent SVM分类器训练
    4. 检测识别

    (1)计算DPM特征图
    对于方向特征,如果我们统计0-360°一整圈的方向特征,则称之为有符号的梯度,如果不考虑方向,只考虑0-180°的变换,则称之为无符号的梯度。
    DPM算法在特征提取时分别针对有符号梯度无符号梯度这两种特征进行提取。
    在这里插入图片描述
    在有符号梯度方向表示的时候将整个角度空间表示为18维的向量,对于无符号梯度方向直方图将整个角度空间表示为9维的向量,这样就能得到27维的特征,也就是说对每个cell可以得到27维的直方图。

    针对HOG+SVM中,HOG维度过高的弊端,通常会采用PCA对HOG特征进行降维,在DPM算法中则采用一种逼近PCA的方法来进行一种近似的处理,即对每一个cell所提取出的27维的直方图进行求和来表示,在水平方向上求和得到4个值,在垂直方向上进行求和来得到27个值,然后将4和27个值得到拼接得到最终37维的特征向量,这样一方面避免了PCA降维过程,因为PCA可能会带来性能上的消耗。直接采用累加方式首先速度上有很大地提升,另外也能达到一个较好的降维的效果。

    (2)计算响应图(root_filter和part filter)
    得到特征图后悔进一步计算响应图,响应图表示当前区域可能为目标的值,这个值可以理解为能量分布,当前的能量分布越高则可能为检测目标的概率越大。
    Alt
    响应图包括局部区域值的检测和整体的检测。比如对于一个行人来说可能要去检测他的头,检测他的胳膊,检测他的躯干,将他的局部区域检测出来之后,我们就能进一步地判定当前的目标是否是行人。
    (3)Laten SVM分类器训练
    针对响应图我们训练SVM分类器进行分类识别,然后结合NMS算法进行分类框的合并。

    3.5NMS(非极大值抑制算法)

    目的:为了消除多余的框,找到最佳的物体检测的位置
    思想:选取那些邻域里分数最高的窗口,同时抑制那些分数低的窗口
    soft-NMS
    在这里插入图片描述
    如上图右边框过多,我们只需要保留最佳的框。
    (1)NMS:

    1. 对所有检测到的框按照得分进行排序,选出得分最高的检测框
    2. 将同得分最高的检测框的IOU面积大于某个阈值的框(即重叠率高的框)删除。
    3. 对没有处理过的检测框重新排序,选出得分最大的检测框
    4. 将同当前得分最大的检测框的IOU面积大于某个阈值的框 ,再进行删除。
    5. 不断迭代这个过程,直到所有检测框都被处理后我们输出最终的检测框。
      在这里插入图片描述
      (2)soft-NMS
    6. 相邻区域内的检测框的分数进行调整而非彻底抑制,从而提高了高检索率情况下的准确率
    7. 在低检索率时扔能对物体检测性能有明显提升
      在这里插入图片描述

    4.基于深度学习的目标检测算法

    4.1Two-stage基本介绍

    4.1.1概述

    (1)Two-stage目标检测算法主要通过一个完整的卷积神经网络来完成目标检测的过程。通过卷积来提取候选区域目标的特征的描述。

    (2)它的典型代表有R-CNN到fast RCNN、faster RCNN

    (3)如果不考虑two-stage算法需要单独训练RPN网络这一过程,可以将它理解为广义的端到端的目标检测算法。实际上它也不是完全意义上的端到端,因为在训练网络的过程中需要分为两个步骤,第一步是训练RPN网络,第二步才是训练目标检测区域的网络。但相对于传统目标检测算法,它不需要再去额外训练分类器、做特征表示这一过程,整个目标检测的过程都通过一个从A到B的一个完整的卷积神经网络来完成,相对于传统的目标检测算法,它的精度得到了较大的提升。

    (4)准确度高,速度相对one-stage慢

    4.1.2two-stage基本流程:

    在这里插入图片描述

    1. 首先输入一个图片
    2. 然后对图片通过卷积神经网络进行深度特征的提取,我们把这里的卷积神经网络称为主干网络,典型的主干网络有如VGG,Resnet等。
    3. 通过一个RPN网络来产生候选区域,并将候选区域分为背景和目标两种,并对目标位置进行初步预测。
    4. ROI_Pooling 。对于多个feature map,我们想要不去重复地计算CNN特征,所以就要ROI Pooling。
    5. fc全连接进行分类和回归分别完成对候选目标类别的判定和位置的精修。

    4.1.3 two-stage常见算法

    在这里插入图片描述

    4.2Two-stage核心组件

    Two-stage核心组件有CNN网络和RPN网络。

    4.2.1CNN网络

    CNN网络我们通常有以下几个设计原则:

    1. 从简到繁再到简的卷积神经网络。最开始的网络如LENET1非常简单,只有几个卷积层池化层,结构简单,但在大规模任务中可能性能没那么好 。后面VGG,densenet,resnet等复制的网络被提出,它们一般尽可能增加网络深度来增强非线性表达能力,如densenet,resnet且越深层次的网络对图像最初的变换更不敏感,也就是说越深层次的特征鲁棒性越好,但越深的网络会加大网络规模和导致梯度消失梯度爆炸;或者尽可能加大网络宽度来增加网络的表达能力,如googlenet 。在后面设计的轻量网络如mobilenet是最后简的部分。
    2. 多尺度特征融合的网络
    3. 更轻量级的CNN网络,因为有些网络需要跑在终端而不是云端。如mobilenet。可以对网络进行压缩裁剪等进行轻量化来减小网络的大小,使网络在尽可能小地损失性能的情况下压缩模型的大小,使网络最终能跑在一些性能比较差的机器上。

    4.2.2 RPN网络

    经过主干网络之后我们会得到feature map, 它通常为一个ncw*h维度的特征。n为batch_size的数量,c为channle的个数,w和h为长宽。把feature map送给RPN网络来完成区域推荐和候选目标的筛选。这相当于传统目标检测算法的滑动窗口策略。

    1. 区域推荐(Anchor 机制)feature map的每个锚点,用9个不同的尺度在提取9个候选区域。所以一个wh的feature map可以提取wh*9个候选区域,然后对候选区域进行筛选划分为背景和目标。用与GT的IOU来筛选是否是目标,比如IOU大于0.7为正样本,小于0.3为负样本。 此时候选区域是针对特征图的,我们要找到相对于原图的特征区域的话可以通过原图下采样来找。
    2. ROI Pooling
      输入:特征图、rois(151*1)区域的坐标(I(索引),X,Y,W,H)、ROI参数。
      输出:固定尺寸的feature map,通过ROI参数来设定。因为后面要进入fc,所以要固定尺寸。
    3. 分类和回归

    改进方向

    1. 更好的网络特征
    2. 更精准的RPN
    3. 更完善的ROI分类
    4. 样本后处理
    5. 更大的mini-batch

    4.3 One-stage基本介绍

    4.3.1One-stage 综述

    (1)使用CNN卷积特征
    (2)直接回归物体的类别概率和位置坐标值(无region proposal)
    (3)准确度低、速度相对two-stage快

    4.3.2 One-stage基本流程

    在这里插入图片描述
    给定输入后进入一个主干网络进行特征提取,然后直接进行区域的回归和目标的分类。在很多嵌入式产品中更加倾向于one-stage的目标检测。

    4.3.3 One-stage常见算法

    (1)Yolo V1/V2/V3
    (2)SSD/DSSD等
    (3)Retina-Net
    等等
    在这里插入图片描述
    其中YOLO和SSD用得最多。

    4.4One-stage核心组件

    4.4.1CNN网络

    CNN网络设计原则:

    1. 从简到繁再到简的卷积神经网络
    2. 多尺度特征融合的网络
    3. 更轻量级的CNN网络

    4.4.2回归网络

    (1)区域回归(置信度、位置、类别)
    (2)Anchor机制(SSD)
    在这里插入图片描述
    SSD算法同样采用了Anchor机制来回归目标区域,对于经过主干网络卷积之后得到的feature map,我们考虑feature map中的每个点都是一个anchor,每个anchor提取不同尺度的长宽比,然后对这些目标区域进行位置回归和类别判定

    4.4.3回归网络预测过程

    以yolo为例:
    在这里插入图片描述
    yolo算法进行预测的时候会针对整张图片进行划分成S*S的格子,每个网格分别预测当前网格为中心的目标区域的位置信息,预测出中心之后再给出格子的尺寸,就能在图片中找到一个矩形区域,然后再预测一个置信度。然后针对每一个格子预测出当前的格子所属的目标的类别的概率分布值。后面的省略。。
    由于我们采用格子划分的方式,认为每一个格子点都是目标检测的中心点,但有可能划分的格子都不是目标的中心点,所以基于中心点来预测目标区域所对应的boundingbox这种假设会导致检测框准确度会更低;它也可能一个格子中包含两个中心点,这时候会漏检。

    4.5 One-stage VS Two-stage

    One-stageTwo-stage
    优点速度快精度高(定位、检出率)
    避免背景错误、产生false positivesAnchor机制
    学到物体的泛化特征共享计算量
    缺点精度低(定位、检出率)速度慢
    小物体的检测效果不好训练时间长
    误报高

    一些解释:对于共享计算量,Two-stage中提取出目标候选区域后通过共享参数的方式减小网络的模型,这一点因为one-stage网络上所以不会被用到,Two-stage中相当于对模型进行了正则。
    具体的算法选型通常依赖于计算的瓶颈,也就是在产品中会分配给多少资源给目标检测,如果很难做到任意资源的分配的话,需要平衡算法的性能以及算法模型大小和功耗。实际中在一些终端产品上用one-stage多一点,在云端的设备上通常用two-stage多一点

    展开全文
  • 滴滴的GPU可以用了,冲着3元一小时的价格,我去试了一把。 1、好吧,先注册滴滴,这个简单略过。 2、要购买GPU实例,先要实名认证,要上传身份证的正反面,JPG格式,好吧,我上传。 3、开始购买了啦,发现...

    滴滴云的GPU云可以用了,冲着3元一小时的价格,我去试了一把。

    1、好吧,先注册滴滴云,这个简单略过。

    2、要购买GPU实例,先要实名认证,要上传身份证的正反面,JPG格式,好吧,我上传。

    3、开始购买了啦,发现可用地区有且只有广州一区和广州二区,还有北京一区,北京一区暂时没有GPU服务器。

    4、切换到控制台-计算

     

     

     

     

     

    付费我是按时发费

     

    选择最低配置

     

    选择带宽1M的话是0.03元每小时(按小时收费哦),开始配置服务器时应该要分配大一点,因为肯定要下载一些环境之类的。

    最后再设一下密码(用户名固定为dc2-user):

    好吧,最后用微信付款3.224元(6M带宽),申请到如下配置的GPU服务器一个小时的使用时间

    可以看出来,收费主要有三项,一个是镜像占有空间收费(20G内免费,我们现在还没有创建镜像),实例收费,带宽收费。

     

     

     

    注意点:

    当你创建完实例以后,系统就开始收钱喽,如果你不想让它收钱要怎么办,你可能会认为把实例关机就不收钱了,答案是错的,你得把这个实例删除,删除哦,当你把实例删除时,连带网络也要删了哦,也就是说当你不想付钱时,我好容易配好的环境训练一次,删了以后,后面再用又要再配环境,所以你在删除之间先做个镜像,然后删除实例和网络。后面再用的时候,再创建实例的时候选择这个自己的镜像,就可以还原到上次的系统了,但是镜像空间免费赠送20G,超过20G就要收费。

     

    好吧,我们终于建好了实例,有了ssh的帐号和密码,我们在windows上要装个ssh的客户端来登陆吧,常用的应该是winscp+putty吧,要上传下载文件就用winscp,要命令行就用putty,在winscp里可以打开putty,但要先装好putty,并且做一下配置关联起来。

     

     

     

    putty登陆上去以后,可以发现它已经装好的显卡驱动+cuda(9.0)+cudnn(7.0),但是其它像tensorflow之类都是没有的。

    我上去的第一次事是启用root,为root设置密码以后,把ssh的允许root登陆,

    相关指令是:

    sudo passwd root

    /etc/ssh/sshd_config 修改该配置文件(PermitRootLogin yes 意思是允许root登陆):

    # Authentication:
    LoginGraceTime 120
    PermitRootLogin yes
    StrictModes yes

    修改完以后重启服务,或是重启实例:

    service sshd restart

    现在再用winscp直接以root登录以后,就可以无限制的做各种动作了。

    登陆时会弹出一个提示,给它打勾不显示。

    如果只是一台训练机,我个人感觉不用担心安全问题,因为训练完我马上关掉,而且在防火墙上默认只开了443,80,22等端口,可以按自己的需求关掉除22外的其它外网端口。

    下载一个putty,并给winscp设置好putty位置

    设置以后就可以通过此按钮启动putty

    打开putty,使用root连接上实例,先给它装个anaconda先,注意不要装最新版的anaconda,因为最新anaconda用的是python3.7,当前版的tensorflow不支持,导致pip install tensorflow-gpu时找不到文件。

    wget https://repo.anaconda.com/archive/Anaconda3-5.2.0-Linux-x86_64.sh
    chmod 777 Anaconda3-5.2.0-Linux-x86_64.sh
    sh Anaconda3-5.2.0-Linux-x86_64.sh

    按q,然后yes,然后一路按提示yes,最后提示是否加到bashrc,这是需要的。

    装完以后

    source ~/.barshrc

    另外cuda的lib也要加到barshrc里,不然后面使用tensorflow时有问题

    nano ~/.barshrc

    再最后加上

    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/cuda-9.0/lib64
    ctrl-o +回车  //保存
    ctrl-x      //退出
    nano ~/.barshrc

    看看python装好了没

    python --version  

    安装tensorflow(这里用了-i的参数,使用了清华的镜像,可以加快下载速度)

    pip install tensorflow-gpu -i https://pypi.tuna.tsinghua.edu.cn/simple 

    装完tensorflow以后,我们就可以做事了,比如做对象检测,将https://github.com/sanfooh/tensorflow_object_detection_api_demo 这里的脚本一脑的粘进去

     
    #在根目录下创建一个output目录
    mkdir /output
    cd /output/
    
    #下载旧版本的tensorflow model(object api 包含在model里),最新版本的api存在问题(当前2018.4.20)
    wget  https://github.com/tensorflow/models/archive/dcfe009a024854207c9067d785c105f5ebf5a01b.zip
    unzip dcfe009a024854207c9067d785c105f5ebf5a01b.zip 
    mv models-dcfe009a024854207c9067d785c105f5ebf5a01b models
    rm dcfe009a024854207c9067d785c105f5ebf5a01b.zip 
    
    #安装依赖项
    pip install Cython
    pip install pillow
    pip install lxml
    pip install jupyter
    pip install matplotlib
    pip install opencv-python
    pip install pycocotools
    
    #安装object detection api 并验证
    cd /output/models/research/
    protoc object_detection/protos/*.proto --python_out=.
    export PYTHONPATH=$PYTHONPATH:`pwd`:`pwd`/slim
    python object_detection/builders/model_builder_test.py
    
    #下载图片及标注文件
    cd /output
    git clone https://github.com/sanfooh/tensorflow_object_detection_api_demo.git
    
    #下载预训练文件
    cd /output/tensorflow_object_detection_api_demo
    wget  http://download.tensorflow.org/models/object_detection/ssd_mobilenet_v1_coco_2017_11_17.tar.gz
    tar -xzvf ssd_mobilenet_v1_coco_2017_11_17.tar.gz
    rm -r ssd_mobilenet_v1_coco_2017_11_17.tar.gz
    
    #生成tfrecord数据集
    python create_tf_record.py 
    
    #可使用check_tfrecord.ipynb验证一下tfrecord是否有问题
    

     

    问题来了,如果出现无法下载或是下载很慢的时候,在这台服务器上是拿不下来的。所以只能想其它的办法,比如使用mybinder的服务先把它下载到本地来,然后再通过winscp传上去,由于winscp是用root登录的,所以就不会出现没有权限之类的。

     

    当我们要启动jupter notebook时:

    jupyter notebook --allow-root --ip=实例的内网ip --port=80

    要注意的是,这里的ip要设置为实例的内网ip,而不能设为外网ip,然后在防火墙组里默认开了80,所以用就指定80好了,如果不指定,默认开启6006,那就要滴滴云安全-防火墙组里手动打开这个端口了。

     

    同样的查看tensorboard

    tensorboard --logdir=mytrain --port=80

    搞七搞八之后,时间差不多了,我们需要对这个实例生成一个快照(镜像)保存下来,生成快照之前最好瘦身一下系统,不必要的文件删除掉,因为超过20G是要收费的,生成完镜像以后,我们就可以把实例删掉,再把网络-弹性公网ip也删除,就可以洗洗睡了,然后啥时有项目要训练,就利用此快照创建一个实例,再通过winscp把样本传上去进行训练,最后通过winscp把模型拿下来用了。

    现在就去滴滴云看看

    展开全文
  • 这是《使用腾讯GPU学习深度学习》系列文章的第四篇,主要举例介绍了深度学习计算过程中的一些数据预处理方法。本系列文章主要介绍如何使用 腾讯GPU服务器 进行深度学习运算,前面主要介绍原理部分,后期则以实践...

    这是《使用腾讯云GPU学习深度学习》系列文章的第四篇,主要举例介绍了深度学习计算过程中的一些数据预处理方法。本系列文章主要介绍如何使用 腾讯云GPU服务器 进行深度学习运算,前面主要介绍原理部分,后期则以实践为主。

    往期内容:
    使用腾讯云 GPU 学习深度学习系列之一:传统机器学习的回顾

    使用腾讯云 GPU 学习深度学习系列之二:Tensorflow 简明原理

    使用腾讯云 GPU 学习深度学习系列之三:搭建深度神经网络

    上一节,我们基于Keras设计了一个用于 CIFAR-10 数据集的深度学习网络。我们的代码主要包括以下部分:

    • 批量输入模块
    • 各种深度学习零件搭建的深度神经网络
    • 凸优化模块
    • 模型的训练与评估

    我们注意到,批量输入模块中,实际上就是运用了一个生成器,用来批量读取图片文件,保存成矩阵,直接用于深度神经网络的训练。由于在训练的过程中,图片的特征,是由卷积神经网络自动获取的,因此深度学习通常被认为是一种 端对端(End to end) 的训练方式,期间不需要人为的过多干预。

    但是,在实际的运用过程中,这一条并不总是成立。深度神经网络在某些特定的情况下,是需要使用某些特定方法,在批量输入模块之前,对输入数据进行预处理,并且处理结果会极大的改善。

    本讲将主要介绍几种数据预处理方法,并且通过这些预处理方法,进行特征提取,提升模型的准确性。

    1. 结合传统数据处理方法的特征提取

    这一部分我们举医学影像学的一个例子,以 Kaggle 社区第三届数据科学杯比赛的肺部 CT 扫描结节数据为例,来说明如何进行数据的前处理。以下代码改编自该 kaggle 比赛的官方指导教程,主要是特异性的提取 CT 影像图片在肺部的区域的扫描结果,屏蔽无关区域,进而对屏蔽其他区域后的结果,使用深度学习方法进行进一步分析。

    屏蔽的程序本身其实并未用到深度学习相关内容,这里主要使用了skimage库。下面我们详细介绍一下具体方法。

    第一步,读取医学影像图像。这里以 LUNA16数据集 中的1.3.6.1.4.1.14519.5.2.1.6279.6001.179049373636438705059720603192 这张CT 影像数据为例,这张片子可以在这里下载,然后解压缩,用下面的代码分析。其他片子请在 LUNA16 数据集)下载:

    from __future__ import print_function, division
    
    import numpy as np
    import os
    import csv
    from glob import glob
    import pandas as pd
    import numpy as np
    import SimpleITK as sitk
    
    from skimage import measure,morphology
    from sklearn.cluster import KMeans
    from skimage.transform import resize
    import matplotlib.pyplot as plt
    import seaborn as sns
    
    from glob import glob
    
    try:
        from tqdm import tqdm # long waits are not fun
    except:
        print('TQDM does make much nicer wait bars...')
        tqdm = lambda x: x
    
    def make_mask(center,diam,z,width,height,spacing,origin):
        '''
        Center : centers of circles px -- list of coordinates x,y,z
        diam : diameters of circles px -- diameter
        widthXheight : pixel dim of image
        spacing = mm/px conversion rate np array x,y,z
        origin = x,y,z mm np.array
        z = z position of slice in world coordinates mm
        '''
        mask = np.zeros([height,width]) # 0's everywhere except nodule swapping x,y to match img
        #convert to nodule space from world coordinates
    
        # Defining the voxel range in which the nodule falls
        v_center = (center-origin)/spacing
        v_diam = int(diam/spacing[0]+5)
        v_xmin = np.max([0,int(v_center[0]-v_diam)-5])
        v_xmax = np.min([width-1,int(v_center[0]+v_diam)+5])
        v_ymin = np.max([0,int(v_center[1]-v_diam)-5])
        v_ymax = np.min([height-1,int(v_center[1]+v_diam)+5])
    
        v_xrange = range(v_xmin,v_xmax+1)
        v_yrange = range(v_ymin,v_ymax+1)
    
        # Convert back to world coordinates for distance calculation
        x_data = [x*spacing[0]+origin[0] for x in range(width)]
        y_data = [x*spacing[1]+origin[1] for x in range(height)]
    
        # Fill in 1 within sphere around nodule
        for v_x in v_xrange:
            for v_y in v_yrange:
                p_x = spacing[0]*v_x + origin[0]
                p_y = spacing[1]*v_y + origin[1]
                if np.linalg.norm(center-np.array([p_x,p_y,z]))<=diam:
                    mask[int((p_y-origin[1])/spacing[1]),int((p_x-origin[0])/spacing[0])] = 1.0
        return(mask)
    
    def matrix2int16(matrix):
        '''
        matrix must be a numpy array NXN
        Returns uint16 version
        '''
        m_min= np.min(matrix)
        m_max= np.max(matrix)
        matrix = matrix-m_min
        return(np.array(np.rint( (matrix-m_min)/float(m_max-m_min) * 65535.0),dtype=np.uint16))
    
    df_node = pd.read_csv('./annotation.csv')
    for fcount, img_file in enumerate(tqdm(df_node['seriesuid'])):
        mini_df = df_node[df_node["seriesuid"]==img_file] #get all nodules associate with file
        if mini_df.shape[0]>0: # some files may not have a nodule--skipping those
            # load the data once
            itk_img = sitk.ReadImage("%s.mhd" % img_file)
            img_array = sitk.GetArrayFromImage(itk_img) # indexes are z,y,x (notice the ordering)
            num_z, height, width = img_array.shape        #heightXwidth constitute the transverse plane
            origin = np.array(itk_img.GetOrigin())      # x,y,z  Origin in world coordinates (mm)
            spacing = np.array(itk_img.GetSpacing())    # spacing of voxels in world coor. (mm)
            # go through all nodes (why just the biggest?)
            for node_idx, cur_row in mini_df.iterrows():       
                node_x = cur_row["coordX"]
                node_y = cur_row["coordY"]
                node_z = cur_row["coordZ"]
                diam = cur_row["diameter_mm"]
                # just keep 3 slices
                imgs = np.ndarray([3,height,width],dtype=np.float32)
                masks = np.ndarray([3,height,width],dtype=np.uint8)
                center = np.array([node_x, node_y, node_z])   # nodule center
                v_center = np.rint((center-origin)/spacing)  # nodule center in voxel space (still x,y,z ordering)
                for i, i_z in enumerate(np.arange(int(v_center[2])-1,
                                 int(v_center[2])+2).clip(0, num_z-1)): # clip prevents going out of bounds in Z
                    mask = make_mask(center, diam, i_z*spacing[2]+origin[2],
                                         width, height, spacing, origin)
                    masks[i] = mask
                    imgs[i] = img_array[i_z]
                np.save(os.path.join("./images_%04d_%04d.npy" % (fcount,node_idx)),imgs)
                np.save(os.path.join("./masks_%04d_%04d.npy"  % (fcount,node_idx)),masks)
    

    简单解释下,首先,CT 影像是一个三维的图像,以三维矩阵的形式保存在1.3.6.1.4.1.14519.5.2.1.6279.6001.179049373636438705059720603192.raw 这个文件中,.mhd文件则保存了影像文件的基本信息。具体而言,annotation.csv 文件中,图像中结节的坐标是:

    x seriesuid coordX coordY coordZ diameter_mm
    0 1.3.6.1.4.1.14519.5.2.1.6279.6001.179049373636... 56.208405 86.343413 -115.867579 23.350644

    这里结节坐标的 coordX~Z 都是物理坐标, .mhd文件保存的,就是从这些物理坐标到 .raw文件中矩阵坐标的映射。于是上面整个函数,其实就是在从 CT 影像仪器的原始文件读取信息,转换物理坐标为矩阵坐标,并且 将结节附近的CT 切片存储成对应的 python 矩阵,用来进行进一步的分析。

    然后,我们看一下读取的结果。可见输入文件中标注的结节就在右下方。

    img_file = "./images_0000_0000.npy"
    imgs_to_process = np.load(img_file).astype(np.float64)
    
    fig = plt.figure(figsize=(12,4))
    for i in range(3):
        ax = fig.add_subplot(1,3,i+1)
        ax.imshow(imgs_to_process[i,:,:], 'bone')
        ax.set_axis_off()
    

    可见图中,除了中间亮度较低的肺部,还有亮度较高的脊柱、肋骨,以及肌肉、脂肪等组织。我们的一个思路,就是 留下暗的区域,去掉亮的区域。当然这里,亮度多高才算亮?这个我们可以对一张图中所有像素点的亮度做概率密度分布,然后用 Kmeans 算法,找出这个明暗分解的阈值(下文图中左上角):

    i = 0
    img = imgs_to_process[i]
    
    #Standardize the pixel values
    mean = np.mean(img)
    std = np.std(img)
    img = img-mean
    img = img/std
    
    # Find the average pixel value near the lungs
    #         to renormalize washed out images
    middle = img[100:400,100:400]
    mean = np.mean(middle)  
    max = np.max(img)
    min = np.min(img)
    
    # To improve threshold finding, I'm moving the
    #         underflow and overflow on the pixel spectrum
    img[img==max]=mean
    img[img==min]=mean
    
    
    # Using Kmeans to separate foreground (radio-opaque tissue)
    #     and background (radio transparent tissue ie lungs)
    # Doing this only on the center of the image to avoid
    #     the non-tissue parts of the image as much as possible
    kmeans = KMeans(n_clusters=2).fit(np.reshape(middle,[np.prod(middle.shape),1]))
    centers = sorted(kmeans.cluster_centers_.flatten())
    threshold = np.mean(centers)
    thresh_img = np.where(img<threshold,1.0,0.0)  # threshold the image
    

    然后使用 skimage 工具包。 skimage 是python一种传统图像处理的工具,我们这里,主要使用这个工具包,增强图像的轮廓,去除图像的细节,进而根据图像的轮廓信息,进行图像的分割,得到目标区域(Region of Interests, ROI)。

    # 对一张图中所有像素点的亮度做概率密度分布, 用竖线标注阈值所在
    fig = plt.figure(figsize=(8,12))
    ax1 = fig.add_subplot(321)
    sns.distplot(middle.ravel(), ax=ax1)
    ax1.vlines(x=threshold, ymax=10, ymin=0)
    ax1.set_title('Threshold: %1.2F' % threshold)
    ax1.set_xticklabels([])
    
    # 展示阈值对图像切割的结果。小于阈值的点标注为1,白色。大于阈值的点标注为0,黑色。
    ax2 = fig.add_subplot(322)
    ax2.imshow(thresh_img, "gray")
    ax2.set_axis_off()
    ax2.set_title('Step1, using threshold as cutoff')
    
    # 增大黑色部分(非ROI)的区域,使之尽可能的连在一起
    eroded = morphology.erosion(thresh_img,np.ones([4,4]))
    ax3 = fig.add_subplot(323)
    ax3.imshow(eroded, "gray")
    ax3.set_axis_off()
    ax3.set_title('Step2,  erosion shrinks bright\nregions and enlarges dark regions.')
    
    # 增大白色部分(ROI)的区域,尽可能的消除面积较小的黑色区域
    dilation = morphology.dilation(eroded,np.ones([10,10]))
    ax4 = fig.add_subplot(324)
    ax4.imshow(dilation, "gray")
    ax4.set_axis_off()
    ax4.set_title('Step3,  dilation shrinks dark\nregions and enlarges bright regions.')
    
    # 上一张图中共有三片连续区域,即最外层的体外区域,内部的肺部区域,以及二者之间的身体轮廓区域。这里将其分别标出
    labels = measure.label(dilation)
    ax5 = fig.add_subplot(325)
    ax5.imshow(labels, "gray")
    #ax5.set_axis_off()
    ax5.set_title('Step4, label connected regions\n of an integer array.')
    
    
    # 提取regions 信息,这张图片的 region的 bbox位置分别在 [[0,0,512,512],[141, 86, 396, 404]],
    #   分别对应 体外+轮廓 以及 肺部区域的左上角、右下角坐标。
    #   于是这里通过区域的宽度 B[2]-B[0]、高度 B[3]-B[1]
    #   以及距离图片上下的距离  B[0]>40 and B[2]<472,
    #   最终保留需要的区域。
    regions = measure.regionprops(labels)
    good_labels = []
    for prop in regions:
        B = prop.bbox
        if B[2]-B[0]<475 and B[3]-B[1]<475 and B[0]>40 and B[2]<472:
            good_labels.append(prop.label)
    
    mask = np.zeros_like(labels)
    for N in good_labels:
        mask = mask + np.where(labels==N,1,0)
    
    mask = morphology.dilation(mask,np.ones([10,10])) # one last dilation
    
    ax6 = fig.add_subplot(326)
    ax6.imshow(mask, "gray")
    ax6.set_axis_off()
    ax6.set_title('Step5, remain the region of interests.')
    

    最后再看一下提取的效果如何:

    fig = plt.figure(figsize=(8,4))
    
    ax1 = fig.add_subplot(1,2,1)
    ax1.imshow(imgs_to_process[0,:,:], 'bone')
    ax1.set_axis_off()
    ax1.set_title("Raw CT image")
    
    ax2 = fig.add_subplot(1,2,2)
    ax2.imshow(imgs_to_process[0,:,:]*mask, 'bone')
    ax2.set_axis_off()
    ax2.set_title("Pre-processed Images with\nregion of interest in lung")
    

    右图将进一步的放入深度学习模型,进行肺部结节的进一步检测。

    2. 结合深度学习技术的特征提取增强

    除了通过传统手段进行数据预先处理,我们同样可以使用深度学习技术进行这一步骤。

    可能大家对手写数字识别数据集(MNIST)非常熟悉,Tensorflow 官网就有教程,指导如何搭建卷积神经网络,训练一个准确率高达 99.2% 的模型。

    png

    但实际运用过程中,我们会发现其实 MNIST 数据集其实书写的比较工整,于是我们就考虑到,对于比较潦草的书写,直接训练卷积神经网络,是否是最好的选择?是否可以将“草书”字体的数字,变得正规一点,然后放进卷积神经网络训练?于是我们利用一个“草书”版的 MNIST 数据集,来介绍一下spatial_transform 模块:

    首先需要下载这个“草书”版的手写数字集:

    wget https://github.com/daviddao/spatial-transformer-tensorflow/raw/master/data/mnist_sequence1_sample_5distortions5x5.npz
    

    画风如下,明显凌乱了许多,但其实人还是可以看懂,所以我们可以尝试使用深度神经网络来解决。
    png

    我们开始分析数据。首先读数据:

    import tensorflow as tf
    # https://github.com/tensorflow/models/tree/master/transformer
    from spatial_transformer import transformer  
    import numpy as np
    from tf_utils import weight_variable, bias_variable, dense_to_one_hot
    import matplotlib.pyplot as plt
    from keras.backend.tensorflow_backend import set_session
    
    np.random.seed(0)
    tf.set_random_seed(0)
    
    config = tf.ConfigProto()
    config.gpu_options.allow_growth=True
    set_session(tf.Session(config=config))
    %matplotlib inline
    
    mnist_cluttered = np.load('./mnist_sequence1_sample_5distortions5x5.npz')
    
    X_train = mnist_cluttered['X_train']
    y_train = mnist_cluttered['y_train']
    X_valid = mnist_cluttered['X_valid']
    y_valid = mnist_cluttered['y_valid']
    X_test = mnist_cluttered['X_test']
    y_test = mnist_cluttered['y_test']
    
    Y_train = dense_to_one_hot(y_train, n_classes=10)
    Y_valid = dense_to_one_hot(y_valid, n_classes=10)
    Y_test = dense_to_one_hot(y_test, n_classes=10)
    

    初始化参数,然后直接得到一批原始数据,放入xout

    x = tf.placeholder(tf.float32, [None, 1600])
    keep_prob = tf.placeholder(tf.float32)
    
    iter_per_epoch = 100
    n_epochs = 500
    train_size = 10000
    indices = np.linspace(0, 10000 - 1, iter_per_epoch)
    indices = indices.astype('int')
    iter_i = 0
    
    batch_xs = X_train[indices[iter_i]:indices[iter_i+1]]
    x_tensor = tf.reshape(x, [-1, 40, 40, 1])
    
    sess = tf.Session()
    sess.run(tf.global_variables_initializer())
    xout = sess.run(x_tensor, feed_dict={x: batch_xs})
    

    然后搭建一个 spatial_transform 网络。网络结构如下图:

    png

    x = tf.placeholder(tf.float32, [None, 1600])
    y = tf.placeholder(tf.float32, [None, 10])
    
    x_tensor = tf.reshape(x, [-1, 40, 40, 1])
    W_fc_loc1 = weight_variable([1600, 20])
    b_fc_loc1 = bias_variable([20])
    
    W_fc_loc2 = weight_variable([20, 6])
    initial = np.array([[1., 0, 0], [0, 1., 0]])
    initial = initial.astype('float32')
    initial = initial.flatten()
    b_fc_loc2 = tf.Variable(initial_value=initial, name='b_fc_loc2')
    
    # %% Define the two layer localisation network
    h_fc_loc1 = tf.nn.tanh(tf.matmul(x, W_fc_loc1) + b_fc_loc1)
    
    # %% We can add dropout for regularizing and to reduce overfitting like so:
    keep_prob = tf.placeholder(tf.float32)
    h_fc_loc1_drop = tf.nn.dropout(h_fc_loc1, keep_prob)
    
    # %% Second layer
    h_fc_loc2 = tf.nn.tanh(tf.matmul(h_fc_loc1_drop, W_fc_loc2) + b_fc_loc2)
    
    # %% We'll create a spatial transformer module to identify discriminative
    # %% patches
    out_size = (40, 40)
    h_trans = transformer(x_tensor, h_fc_loc2, out_size)
    

    再得到一批经过变换后的数据,放入xtransOut

    iter_i = 0
    batch_xs = X_train[0:101]
    batch_ys = Y_train[0:101]
    
    sess = tf.Session()
    sess.run(tf.global_variables_initializer())
    
    xtransOut = sess.run(h_trans,
                                feed_dict={
                                    x: batch_xs,
                                    y: batch_ys,
                                    keep_prob: 1.0
    })
    

    展示两批数据。上面一行是原始数据,下面一行是变换后的数据。可见数字在局部被放大,有的数字写的歪的被自动正了过来:

    fig = plt.figure(figsize=(10,2))
    
    for idx in range(10):
        ax1 = fig.add_subplot(2,10,idx+1)
        ax2 = fig.add_subplot(2,10,idx+11)
    
        ax1.imshow(xout[idx,:,:,0], "gray")
        ax2.imshow(xtransOut[idx,:,:,0], "gray")
        ax1.set_axis_off()
        ax2.set_axis_off()
        ax1.set_title(np.argmax(batch_ys, axis=1)[idx])
        ax2.set_title(np.argmax(batch_ys, axis=1)[idx])
    

    也就是说,通过 spatial_transform 层,对同一批输入数据的参数学习,我们最后实际上得到了一个坐标的映射 Grid generator
    $T_{\theta(G)}$ ,可以将一个倾斜的、“草书”书写的数字,变得更正一点。

    png

    接下来,我们构建一个卷积神经网络:

    x = tf.placeholder(tf.float32, [None, 1600])
    y = tf.placeholder(tf.float32, [None, 10])
    keep_prob = tf.placeholder(tf.float32)
    
    def Networks(x,keep_prob, SpatialTrans=True):
        x_tensor = tf.reshape(x, [-1, 40, 40, 1])
        W_fc_loc1 = weight_variable([1600, 20])
        b_fc_loc1 = bias_variable([20])
    
        W_fc_loc2 = weight_variable([20, 6])
        initial = np.array([[1., 0, 0], [0, 1., 0]])
        initial = initial.astype('float32')
        initial = initial.flatten()
        b_fc_loc2 = tf.Variable(initial_value=initial, name='b_fc_loc2')
    
        # %% Define the two layer localisation network
        h_fc_loc1 = tf.nn.tanh(tf.matmul(x, W_fc_loc1) + b_fc_loc1)
        # %% We can add dropout for regularizing and to reduce overfitting like so:
    
        h_fc_loc1_drop = tf.nn.dropout(h_fc_loc1, keep_prob)
        # %% Second layer
        h_fc_loc2 = tf.nn.tanh(tf.matmul(h_fc_loc1_drop, W_fc_loc2) + b_fc_loc2)
    
        # %% We'll create a spatial transformer module to identify discriminative
        # %% patches
        out_size = (40, 40)
        h_trans = transformer(x_tensor, h_fc_loc2, out_size)
    
        # %% We'll setup the first convolutional layer
        # Weight matrix is [height x width x input_channels x output_channels]
        filter_size = 3
        n_filters_1 = 16
        W_conv1 = weight_variable([filter_size, filter_size, 1, n_filters_1])
    
        # %% Bias is [output_channels]
        b_conv1 = bias_variable([n_filters_1])
    
        # %% Now we can build a graph which does the first layer of convolution:
        # we define our stride as batch x height x width x channels
        # instead of pooling, we use strides of 2 and more layers
        # with smaller filters.
        if SpatialTrans:
            h_conv1 = tf.nn.relu(
                tf.nn.conv2d(input=h_trans,
                             filter=W_conv1,
                             strides=[1, 2, 2, 1],
                             padding='SAME') +
                b_conv1)
        else:
            h_conv1 = tf.nn.relu(
                tf.nn.conv2d(input=x_tensor,
                             filter=W_conv1,
                             strides=[1, 2, 2, 1],
                             padding='SAME') +
                b_conv1)
    
        # %% And just like the first layer, add additional layers to create
        # a deep net
        n_filters_2 = 16
        W_conv2 = weight_variable([filter_size, filter_size, n_filters_1, n_filters_2])
        b_conv2 = bias_variable([n_filters_2])
        h_conv2 = tf.nn.relu(
            tf.nn.conv2d(input=h_conv1,
                         filter=W_conv2,
                         strides=[1, 2, 2, 1],
                         padding='SAME') +
            b_conv2)
    
        # %% We'll now reshape so we can connect to a fully-connected layer:
        h_conv2_flat = tf.reshape(h_conv2, [-1, 10 * 10 * n_filters_2])
    
        # %% Create a fully-connected layer:
        n_fc = 1024
        W_fc1 = weight_variable([10 * 10 * n_filters_2, n_fc])
        b_fc1 = bias_variable([n_fc])
        h_fc1 = tf.nn.relu(tf.matmul(h_conv2_flat, W_fc1) + b_fc1)
    
        h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
    
        # %% And finally our softmax layer:
        W_fc2 = weight_variable([n_fc, 10])
        b_fc2 = bias_variable([10])
        y_logits = tf.matmul(h_fc1_drop, W_fc2) + b_fc2
        return y_logits
    
    
    # %% We'll now train in minibatches and report accuracy, loss:
    iter_per_epoch = 100
    n_epochs = 100
    train_size = 10000
    
    indices = np.linspace(0, 10000 - 1, iter_per_epoch)
    indices = indices.astype('int')
    

    首先训练一个未经过变换的:

    y_logits_F = Networks(x, keep_prob, SpatialTrans=False)
    cross_entropy_F = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=y_logits_F, labels=y))
    opt = tf.train.AdamOptimizer()
    optimizer_F = opt.minimize(cross_entropy_F)
    grads_F = opt.compute_gradients(cross_entropy_F, [b_fc_loc2])
    correct_prediction_F = tf.equal(tf.argmax(y_logits_F, 1), tf.argmax(y, 1))
    accuracy_F = tf.reduce_mean(tf.cast(correct_prediction_F, 'float'))
    
    sessF = tf.Session()
    sessF.run(tf.global_variables_initializer())
    
    l_acc_F = []
    for epoch_i in range(n_epochs):
        for iter_i in range(iter_per_epoch - 1):
            batch_xs = X_train[indices[iter_i]:indices[iter_i+1]]
            batch_ys = Y_train[indices[iter_i]:indices[iter_i+1]]
            sessF.run(optimizer_F, feed_dict={
                x: batch_xs, y: batch_ys, keep_prob: 0.8})
    
        acc = sessF.run(accuracy_F,
                                                         feed_dict={
                                                             x: X_valid,
                                                             y: Y_valid,
                                                             keep_prob: 1.0
                                                         })
        l_acc_F.append(acc)
        if epoch_i % 10 == 0:
            print('Accuracy (%d): ' % epoch_i + str(acc))
    
    Accuracy (0): 0.151
    Accuracy (10): 0.813
    Accuracy (20): 0.832
    Accuracy (30): 0.825
    Accuracy (40): 0.833
    Accuracy (50): 0.837
    Accuracy (60): 0.832
    Accuracy (70): 0.837
    Accuracy (80): 0.833
    Accuracy (90): 0.843
    

    可见这个神经网络对直接输入变形数据效果不好。我们再训练一个进过变换的:

    y_logits = Networks(x, keep_prob)
    cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=y_logits, labels=y))
    opt = tf.train.AdamOptimizer()
    optimizer = opt.minimize(cross_entropy)
    grads = opt.compute_gradients(cross_entropy, [b_fc_loc2])
    correct_prediction = tf.equal(tf.argmax(y_logits, 1), tf.argmax(y, 1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, 'float'))
    
    sess = tf.Session()
    sess.run(tf.global_variables_initializer())
    
    l_acc = []
    for epoch_i in range(n_epochs):
        for iter_i in range(iter_per_epoch - 1):
            batch_xs = X_train[indices[iter_i]:indices[iter_i+1]]
            batch_ys = Y_train[indices[iter_i]:indices[iter_i+1]]
            sess.run(optimizer, feed_dict={
                x: batch_xs, y: batch_ys, keep_prob: 0.8})
    
        acc = sess.run(accuracy,
                                                         feed_dict={
                                                             x: X_valid,
                                                             y: Y_valid,
                                                             keep_prob: 1.0
                                                         })
        l_acc.append(acc)
        if epoch_i % 10 == 0:
            print('Accuracy (%d): ' % epoch_i + str(acc))
    

    发现变换后正确率还可以接受:

    Accuracy (0): 0.25
    Accuracy (10): 0.92
    Accuracy (20): 0.94
    Accuracy (30): 0.955
    Accuracy (40): 0.943
    Accuracy (50): 0.944
    Accuracy (60): 0.957
    Accuracy (70): 0.948
    Accuracy (80): 0.941
    Accuracy (90): 0.948
    

    画图比较正确率与训练次数

    plt.plot(l_acc, label="Using Spatial Transform")
    plt.plot(l_acc_F, label="Raw input")
    plt.legend(loc=8)
    

    可见 Spatial Transform 确实可以提升分类的正确率。

    最后,我们专门提出来直接分类分错、Spatial Transform 后分类正确的数字。上面一行是直接预测的结果(错误),下面一行是转换后分类的结果:

    通过 Spatial Transform,我们确实可以强化数据的特征,增加数据分类的准确性。

    此外,Spatial Transform 除了可以识别“草书”字体的手写数字,同样在交通标志分类中表现优异,通过Spatial Transform 元件与 LeNet-5 网络的组合,Yann LeCun团队实现了42种交通标志分类99.1%准确性(笔者直接用LeNet-5发现准确率只有87%左右),文章地址Traffic Sign Recognition with Multi-Scale Convolutional Networks

    png

    目前腾讯云 GPU 服务器已经在5月27日盛大公测,本章代码也可以用较小的数据量、较低的nb_epoch在普通云服务器上尝试一下,但是随着处理运算量越来越大,必须租用 云GPU服务器 才可以快速算出结果。服务器的租用方式、价格,详情请见 腾讯云 GPU 云服务器今日全量上线!

    展开全文
  • 深度学习目标检测工具箱mmdetection,训练自己的数据 商汤科技(2018 COCO 目标检测挑战赛冠军)和香港中文大学最近开源了一个基于Pytorch实现的深度学习目标检测工具箱mmdetection,支持Faster-RCNN,Mask-RCNN,...
  • 因此,提出了一种基于深度学习的故障检测方法。 具有稀疏去噪的自动编码器用于构建并行结构网络。 它可以自动学习和提取故障数据特征,并通过深度学习实现故障检测。 实验表明,在故障特征数据较少的情况下,该...
  • 使用主机进行深度学习

    千次阅读 2018-04-09 10:41:02
    偶然发现一款简单好用的主机(极客首页),有广告嫌疑,但用着的确不错,因此分享一下。 初次申请时系统会送10元代金券,有推荐人的话送20(可以填我的:15909831575…└(^o^)┘)。另外,它有多种GPU环境可以...
  • 华为云深度学习kaggle猫狗识别

    千次阅读 2018-10-10 16:28:17
    使用华为云深度学习服务完成kaggle猫狗识别竞赛 参考: kaggle猫狗竞赛kernel第一名的代码 Tensorflow官网代码 华为DLS服务github代码 1. 环境配置与数据集处理 首先我们需要从kaggle上面找到猫狗竞赛的页面,...
  • 针对以上问题,提出了一种基于深度残差全卷积网络的高精度云检测方法,能够实现对遥感影像云层目标像素级别的分割。首先,编码器通过残差模块的不断降采样提取图像深层特征;然后,应用双线性插值进行上采样,结合多层次...
  • 深度学习-物体检测-YOLO系列,完整版11章,附源码+课件+数据,2020年最新录制;整体风格通俗易懂,原理+实战实战 章节1 深度学习经典检测方法概述 章节2 YOLO-V1整体思想与网络架构 章节3 YOLO-V2改进细节详解 章节4...
  • 基于深度学习的日志数据异常检测

    万次阅读 多人点赞 2020-12-27 12:00:12
    基于日志数据的异常检测 数据对象 智能运维(AIOps)是通过机器学习等算法分析来自于多种运维工具和设备的大规模数据。智能运维的分析数据对象多源运维数据包括系统运行时数据和历史记录数据,历史记录数据主要包含...
  • 基于深度学习的内容安全检测与管控 安全 APT 安全 安全防御 信息安全
  • 进军深度学习佳项目实战:人脸检测项目视频培训课程,从数据的收集以及预处理开始,一步步带着大家完成整个人脸检测的项目,其中涉及了如何使用深度学习框架Caffe完成整个项目的架构,对于每一个核心步骤详细演示...
  • 无人驾驶汽车系统入门(二十六)——基于深度学习的实时激光雷达点云目标检测及ROS实现 在前两篇文章中,我们使用PCL实现了在点云中对地面的过滤和点云的分割聚类,通常来说,在这两步以后我们将对分割出来的对象...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 23,833
精华内容 9,533
关键字:

云检测深度学习