2018年7月1日星期日

无人车创业正驶入分水岭

李根 发自 凹非寺 量子位 报道 | 公众号 QbitAI

无人车创业窗口早已经关闭。

相比去年你创业我也入局的大珠小珠落玉盘,2018这半年显得平平淡淡。

但并不代表自动驾驶热度衰减。相反,在看不见的比拼竞速中,资本、研发、产品和落地的争夺,让自动驾驶争夺愈加激烈了,而且在创业初期百花齐放之后,如今格局(暂时)有了雏形。

场内选手到底谁实力更强,可能一时很难直接说明,但资本市场的反馈,是一个明确的信号。

我们从估值和成长性来初步盘点一下。

第一梯队

处于第一梯队的主要有两家,最新估值都达到了10亿美元左右——左右幅度要按最最新一轮或官宣来确定。

上一轮,他们处于6-7亿美元阵列,但在半年之后,估值已被推进到了独角兽序列,而且下一轮可能还更恐怖。

一家并不陌生:Pony.ai.

没错,就是彭军和楼教主联手创业的小马智行。

Pony.ai其实在今年1月已经官宣了一轮1.12亿美元的A轮融资,在其后实现了国内首次的无人车试运营,还跟广汽达成战略合作,并招揽一帮大牛建起自动驾驶研究院,最近还以初创公司身份拿下北京路测牌照。

如此进展,自然也少不了资本追逐。量子位打探的消息是,Pony.ai完成了一轮估值10亿美元左右的新融资,但似乎脚步还未停下,所以官宣时间可能还要再等一等。

当然,Pony.ai在这半年里还有一些其他的进展,比如已经开始使用32线激光雷达完成64线甚至128线才能达到的效果。

但之前更被关注的八卦依然是楼教主。之前有传闻称,教主中道改意,出走小马加盟滴滴,出任滴滴外卖CTO,甚至有人亲眼目睹教主频繁进出滴滴。

然而真相是:滴滴外卖和Pony.ai同住一栋楼而已,但滴滴标识太显眼,最后竟在市场中谣传成了"教主加盟滴滴",由此可以得出的结论是:橙色logo的公司总要更显眼一些。

Pony.ai之外,另一家独角兽估值的无人车公司是:Momenta,中文也叫"初速度"。

这是一家之前被严重低估了的公司。

因为之前对Momenta的记述,多是环境感知、高精度地图之类的,而且切入的等级也不是完全无人驾驶,而是偏向L3为目标的高级辅助驾驶。

但本质上,Momenta想要打造的就是一个自动驾驶系统、无人车大脑,不同之处在于Momenta走了一条看起来更快能实现的L3之路——虽然听说L4以上的自动驾驶也在研发。

Momenta相对低调,但团队和实际进展却名声响于行业内。比如团队中,目前执掌研发的联合创始人,就是目标检测和图像识别领域先进框架Faster R-CNN和ResNet的作者任少卿。

而实际进展方面,Momenta先L3,跟车厂供应商合作,走特斯拉模式,然后再L4。Momenta还已得到奔驰母公司戴姆勒、蔚来汽车的产业资本的加持,依靠资本+资源,可能会更快走通技术方案的商业闭环。

这种"闭环"也在最近半年进一步得到资本认可,据称Momenta已经完成了多轮密集融资,推进速度和进展都惊人,而且阿里和腾讯都表示了意向,但最终结果如何,目前没有更进一步的消息。

总之,在过去半年竞速里,Pony.ai和Momenta已经闪出了一个身位。

第二梯队

接下来说说暂时位列第二梯队的无人车公司,这一梯队估值围绕6亿美元上下波动,相比起上一轮,整体也有2-3倍增长。

其中现在身处该梯队但又略显"委屈"的,莫过于景驰科技

景驰创业以来,势头汹涌,是国内声势最响的无人车公司。团队分工配置也相对健全,特别对于这个技术与落地并重,产品和资源同举的行业,前CEO王劲的作用不可谓不关键。

然而百度的精准一击,对景驰造成了不可承受的影响。当时景驰已经对外放话A轮1亿美元以上的融资,并且还要发起募集一支100亿元的生态基金,但最后百度法务和舆论共同出击,在投资层面也施加压力,景驰投资也遇到极大困难,内部分化,最后王劲出局。

其间可惜的不止是创始团队因不可抗力分割重组,核心人员变动,另外可惜的还有——据说当时王劲号召的100亿元生态基金接近完成,但最后结局如斯,王劲在景驰的故事戛然而止。

但或许能让景驰庆幸的是,危机响起和解决都在排位争夺期,还远没到决定输赢的关口。

在王劲之变后,景驰迅速度过了动荡期,也吸引了一批高级人才加盟,技术推进方面也算可圈可点,百度官司也已了断,公司重新进入了稳定发展阶段。

于是之前受影响的新一轮融资也被重启,据称进展还算不错——资本依然认可景驰的团队和技术。

另一家RoadStar.ai,近期刚宣布了一轮1.28亿美元的融资,投后估值5亿美元左右。

RoadStar.ai,之前我们介绍的并不多,这同样是百度车厂开出的无人车公司,其中在职百度最长的是首席科学家周光,他在百度美研负责感知相关工作,CEO佟显乔和CTO衡量在百度则只是短暂停留。

与其他百度系无人车公司差不多,RoadStar.ai也是主打L4以上自动驾驶。但RoadStar.ai显得"大器晚成"一些。

因为去年早些时候就开始的融资,进展算不上一帆风顺,而且如今领投方双湖资本的4000万美元,原计划似乎也更偏向另一家公司一些,但后来那家公司风云突变,RoadStar.ai守得云开见月明。

在这个过程中,RoadStar.ai也算是后来居上,不仅成功完成了A轮融资,而且技术上也得到了一些车厂认可,某车厂员工在横试一圈自动驾驶公司无人车后,对RoadStar.ai的评价不低。

除了乘用自动驾驶,还有几家货运相关的无人车公司也在该梯队中。

图森未来在去年年底官宣了一轮Composite Capital Management领投的5500万美元融资,据说当时投后估值就达到了4.5亿美元,领投方Composite Capital Management其时被翻译为"复合资本",但就是这家复合资本,在国际范围内还投资了乘用无人车公司Zoox。

图森未来最近一次对外亮相是无人集卡在港口的应用,意味着图森开始进入商业化试运营阶段,但当时COO郝佳男告诉量子位:没有更多融资的进展可分享。

在货运自动驾驶领域,2018年上半年最受关注的可能要属何晓飞创办的飞步科技

这位前滴滴研究院创始院长、滴滴无人车开创者,也在今年上半年正式对外亮相,主打轻卡货运,方案落地中包含了城际、高速等场景,而且货运相关的高级辅助驾驶可能会最先对外推出。

飞步科技之所以受关注,还有另一个原因是全栈技术中还包括的专为自动驾驶研发的AI芯片。

何晓飞为此挖到了大规模集成电路领域世界级专家曹宇、前英特尔首席架构师Hang Nguyen,以及前高通首席系统工程师Victor Szeto,光芯片团队,就星光熠熠。

按照AI芯片目前的热度,飞步接下来的进展可能不容小觑。

第三梯队

此外,还有几家更为低调的无人车公司,估值在3亿美元维度。但比起上一轮也有3倍以上的推进。

比如同样出身百度系的领骏科技,该团队5月对外发布的"完全看不出经过改装"的无人驾驶原型车,在一辆国产SUV基础上,领骏实现了整套自动驾驶方案,转向过弯、高速场景、收费站等均在路测中顺畅实现。

最引人注目的是,领骏无人车将所有传感器"隐藏",头顶没有醒目的激光雷达,这可能会是车厂追求的目标,虽然领骏主打的L4,但若方案成本适宜,拿来当L3或L2的高级辅助驾驶使用,毫无疑问会是新车亮点。

相似思路的还有领骏创始人杨文利的"老战友"倪凯。他们在百度都是最早一批无人车团队成员,倪凯创办禾多科技后,也是以L3.5降维应用L2的思路在推进,目前融资进展可获悉的比较有限,但听说跟车厂签到了大单。

另外"闷声发财"的或许还有吴甘沙,驭势科技在今年上半年的新闻并不多,但在无人驾驶清扫、摆渡车和停车场等有限场景的自动驾驶方面,具体落地案例一个接一个,资本方面的消息可能也快了。

与驭势科技落地场景相类似的是酷哇机器人,这家已在长沙橘子洲头落地无人驾驶扫地车的公司,近两月来气势汹汹,而且还在落地中找到了长沙中联重科这样的环境产业龙头。

最近,酷哇宣布了一轮1.35亿元的B轮融资。由软银中国领投,创世伙伴资本联合领投。

也有消息称,新的一轮也已提上议程。

OMT:巨头在侧

最后,可能你也无比关心BAT们的自动驾驶进展。

但完整故事说起来太长,不妨在此简单同步下一些新消息:

百度,起步最早,积累和探索也最丰富,Apollo亦在业内打响了名气和口碑,但陆奇的走,影响很大,不仅影响的是Apollo的对外发展,也影响着百度工程师的心绪。

不少人当初因陆奇到来而留下观望,如今尘归尘土归土,加上今年4月激励方案的变化,造成了一小波离职——但比例很小,主要去向是阿里和腾讯。

目前,百度自动驾驶技术方面启用了"老百度"陈竞凯,这位首席架构师性格谦和、为人低调,内部颇有口碑,也深受李彦宏信任,但能否握稳百度无人车的方向盘,需要一些时间来给出答案。

腾讯,进展最快,量子位之前独家曝光过,腾讯谋定而后动,去年年底完成了组织框架搭建,今年在满世界挖人推进,L3、L4并行,L3方面会最先推出产品,而且腾讯以深圳为大本营,已经拿到了深圳的第一张路测牌照。

阿里巴巴,BAT中布局最晚,实际进展也对外透露不多,半年来最大进展是透露了团队由阿里AI实验室首席科学家王刚在领导,目前团队规模50多人。

最后的最后,华为也在进行自动驾驶研发布局,但进展可能更慢——因为华为还在为团队找leader呢。

总之,目前天下大势就是这样,再过半年可能就要分出胜负,最关键的时间点也已经来临。

无人车初创公司在竞速抢排位,越往后资源可能只会越往头部公司聚集,加之一级市场开始弥散开来的"钱袋缩紧",更是可能无形中加剧自动驾驶竞争。

当然,也别忘了BAT和华为,万一内部推进不力,手握大把现金的巨头,可能也会随时改变战局——就像CV领域已经发生的那样。

欢迎大家关注我们的专栏:量子位 - 知乎专栏

诚挚招聘

量子位正在招募编辑/记者,工作地点在北京中关村。期待有才气、有热情的同学加入我们!相关细节,请在量子位公众号(QbitAI)对话界面,回复"招聘"两个字。

量子位 QbitAI · 头条号签约作者

վ'ᴗ' ի 追踪AI技术和产品新动态



via 量子位 - 知乎专栏 https://ift.tt/2KGcUiK
RSS Feed

RSS5

IFTTT

数据科学正从这七个方向颠覆金融界

近年来,数据科学和机器学习在应对金融领域诸多任务的处理能力已经成为大家关注的焦点。公司希望知道新技术能够为公司带来什么改进以及它们如何重塑公司的经营策略。

我们准备了一份数据科学案例清单,这几个案例已经在金融领域内产生了巨大影响。它们涵盖了从数据管理到交易策略等各个不同的业务方面,拥有广泛的前景。

自动化风险管理

风险管理是金融机构非常重要的领域,它要为公司的安全、可信度和战略决策负责。过去几年来,进行风险管理的方式发生了重大变化,甚至直接改变了金融公司的性质。从未像今天这样,公司可以通过机器学习模型来承载业务发展。

风险可以来源于很多方面,比如竞争对手、投资者、监管机构或公司的客户都可能产生风险。除此以外,风险的重要性和可能带来的潜在损失也不完全正向相关。因此,主要的风险管理步骤一般是识别风险、优先级排序和监控风险,而这正好是机器学习所擅长的任务。基于海量的客户数据、金融借贷数据和保险结果数据进行训练,使得这些算法不仅可以改善风险评价模型,还可以增加效率和可持续性。

数据科学和人工智能(AI)在风险管理中最主要的应用就是判断潜在客户的信誉度。企业使用机器学习算法来分析特定客户在过去的支出行为和方式,以此建立恰当的信用额度值。这种方法同样适用于新客户或者信用记录比较简单的客户。

在金融领域,尽管风险管理数字化和自动化还处于早期阶段,但潜力巨大。金融机构仍然需要通过核心流程自动化,提高团队的分析能力以及战略性技术投资,来为变革做好准备。只要公司开始朝着这个方向发展,那么离盈利也就不远了。

管理客户数据

对于金融公司来说,数据是最重要的资产。因此高效的数据管理是企业成功的关键。今天我们拥有海量多样化的金融数据:从社交媒体活动数据和移动设备通联数据到市场交易数据和交易详情信息。金融专家经常需要处理各种结构化和非结构化的数据,而且手动处理这些数据是一个巨大的挑战。

然而,大多数公司都将机器学习技术和管理过程进行整合,以此从数据中提取有价值的信息。以自然语言处理数据挖掘和文本分析技术为代表的一些人工智能技术,能够将数据转换为有价值的信息,进而取得更智能的数据治理方式和更好的业务解决方案,从而提高公司的盈利能力。例如,机器学习算法可以通过对客户过去的金融数据进行学习,以此来分析一些特定金融趋势和市场发展的影响。最后,这些技术也可用于报告自动生成。

预测分析

当前金融服务的核心就是分析。特别值得关注的是预测分析,它揭示了数据的特定规律,并能够预测未来发生的事件,这样就可以提前采取行动。通过掌握社交媒体、新闻趋势和其他数据源,这些复杂的分析技术已经成功应用于各种场景,比如价格预测、客户价值预测、未来生活事件、预期流失率和股票走势。最重要的是,这种技术可以告诉我们:如何人为干预才能取得最好结果。

实时分析

实时分析从根本上改变了金融处理流程,它通过分析不同来源的大量数据,快速识别任何变化并得出与其相对应的最好应对措施。在金融领域的实时分析应用主要有三个方面:

欺诈识别

金融公司有责任向其用户提供最高级别的安全保障。公司面临的主要挑战就是要找到一个很好用的欺诈检测系统,因为罪犯总是会采用新的方法设置新的陷阱来进行黑客攻击。

只有有经验的数据科学家才能够创建完美的算法来检测预防用户的异常行为或者正在进行的各种欺诈程序。例如,针对指定用户进行交易异常报警或者禁止大额现金提款,除非用户确认他们的操作。在股票交易市场,机器学习工具能够通过交易数据识别那些可能存在股票操纵的行为方式,并提示员工对其进行调查。然而,这种算法最大的优势是其自我学习能力,随着时间的推移,这些算法可以变得更加有效和智能化。

消费者分析

实时分析还有助于更好的了解客户及其个性化需求。复杂的机器学习算法和客户情绪分析技术能够通过客户行为、社交媒体互动和他们的反馈意见中获得感知,能够有效的满足个性化需求并提高利润。由于数据量巨大,只有经验丰富的科学家才能准确解决这一问题。

交易算法

这个领域受实时分析的影响最大,因为每秒都很关键。通过分析传统和非传统中最新的数据信息,金融机构可以实时做出有用的决策。同时因为这些数据只在短时间内具有价值,所以如果想在这个方面具备竞争力意味着必须使用最快的方法去分析数据。

在这个领域,整合实时分析和预测分析同样具备很大前景。在过去,金融公司不得不聘请数学家,让他们开发统计模型并使用历史数据创建预测市场机会的交易算法。然而,今天的人工智能技术使得这一过程更加快速,而且更重要的是,它还在持续优化中。

因此,数据科学和人工智能已经在推动金融交易领域的改革,并创建了算法交易策略这一理念。世界上大多数交易所都在通过计算机相关的算法和合适的策略制定最终决策。人工智能技术能不断地处理海量数据信息,包括微博数据、金融指标、以及从新闻、书籍甚至电视节目中获得的数据。因此,它能够理解当前全球变化趋势,并不断完善对金融市场的预测。

总而言之,实时分析和预测分析显著改变了金融领域的局面。数据工程师们正在通过Hadoop、NOSQL和Storm等技术,利用传统和非传统的数据集以及更准确的算法不断改变着金融领域的工作方式。

个性化深度定制

企业逐渐认识到,在当今市场中取得竞争优势的关键要素之一便是同客户建立高质量和个性化的关系,以此来提高客户黏性。这种方式可以通过分析线上用户的体验,并根据用户的兴趣和偏好不断完善其信息。

人工智能技术在理解人类语言和情感方面取得重大进展,从而将客户个性化提升到一个全新的高度。数据工程师还可以建立模型,研究消费者的行为并发现客户在哪些方面需要财务咨询。通过整合预测分析技术和电子调查问卷可以完成这一复杂工作,基于用户的消费习惯、社交趋势、位置信息和其他偏好等信息,可以向用户在恰当的时机提供最好的金融解决方案和个性化建议。

总结

对于金融机构来说,使用数据科学技术可以为他们提供巨大的机会,让他们能够从竞争中脱颖而出并重塑他们的商业模式。由于不断更新的海量金融数据的存在,造就了机器学习和人工智能技术在各个方面的应用。

我们这次只关注了金融领域最主要的七大数据科学应用方向,但还有很多其他方面值得探讨。如果你有任何其他想法,请在评论区分享观点。

]]> 原文: https://ift.tt/2KBtmRy
RSS Feed

机器知心

IFTTT

目标检测必须要OpenCV?10行Python代码也能实现,亲测好用!

本文作者和他的团队构建了一个名为ImageAI 的Python库,集成了现今流行的深度学习框架和计算机视觉库。本文将手把手教你构建自己的第一个目标检测应用,而且文摘菌已经帮你踩过坑了,亲测有效!

无人超市、人脸识别、无人驾驶,众多的使用场景及案例,使得【目标检测】正成为计算机视觉最有前景的方向。

听起来似乎是个很难实现的技术,需要大量训练数据和算法才能完成。事实上,本文作者开发了一个基于Python的函数库,可以用十行代码高效实现目标检测。

还不熟悉的读者,我们先来看看,目标检测到底是什么,以及软件开发人员面临的挑战。

目标检测是借助于计算机和软件系统在图像/场景中,定位目标并识别出每个目标的类别的技术。目前已广泛用于人脸检测、车辆检测、行人计数、网络图像、安全系统和无人驾驶汽车等领域。随着计算机技术不断发展和软件开发人员的不懈努力,未来目标检测技术将更广泛的普及开来。

在应用程序和系统中使用先进的目标检测方法,以及基于这些方法构建新的应用程序并不容易。早期目标检测是基于经典算法而实现的,如 OpenCV(广受欢迎的计算机视觉库)所支持的一些算法。然而,这些经典算法的性能会因条件而受到限制。

2012年,深度学习领域取得众多突破,学者们提出了一系列全新、高精度的目标检测算法和方法,比如R-CNN, Fast-RCNN, Faster-RCNN, RetinaNet,以及既快又准的SSD和YOLO等。要使用这些基于深度学习的方法和算法(当然深度学习也是基于机器学习),需要对数学和深度学习框架有很深的理解。数百万的软件开发人员致力于整合目标检测技术进行新产品的开发。但是想要理解这项技术并加以使用,对非深度学习领域的程序员来说并不容易。

一位自学了计算机的开发者Moses Olafenwa在几个月前意识到了这个问题,并与同伴一起开发了一个名叫ImageAI的Python函数库。

ImageAI可以让程序员和软件开发者只用几行代码,就能轻易地把最先进的计算机视觉技术整合到他们现有的以及新的应用程序里面。

用ImageAI实现目标检测,你只需要以下步骤:

1. 安装Python

2. 安装ImageAI和相关函数库

3. 下载目标检测模型文件

4. 运行示例代码(只有10行)

准备工作

文摘菌测试环境为Windows 64位系统,Python版本为3.6。在大数据文摘后台回复"检测"可获取代码和模型文件~

1) 从Python官网下载并安装Python 3,并安装pip。

下载地址:

https://python.org

https://ift.tt/1P1OtLj

2)用pip安装下列依赖

找到Pyhthon安装目录下的Scripts文件夹,如C:\XXX \Python\Python36\Scripts,打开cmd命令窗口,依次输入下列安装命令即可。

1. Tensorflow:

pip install tensorflow

2.Numpy:

pip install numpy

3.SciPy

pip install scipy

4.OpenCV

pip install opencv-python

5.Pillow

pip install pillow

6.Matplotlib

pip install matplotlib

7. H5py

pip install h5py

8. Keras

pip install keras

9. ImageAI

pip install https://github.com/OlafenwaMoses/ImageAI/releases/download/2.0.1/imageai-2.0.1-py3-none-any.whl

注:在安装ImageAI时如果出现异常,可先下载.whl文件,并放在Scripts文件夹下,用下列命令进行安装:

pip install imageai-2.0.1-py3-none-any.whl

3) 下载用于目标检测的RetinaNet模型文件:

下载地址:

https://ift.tt/2IJm0tj

准备工作到此结束,你可以写自己的第一个目标检测代码了。新建一个Python文件并命名(如FirstDetection.py),然后将下述代码写入此文件。接着将RetinaNet模型文件、FirstDetection.py和你想检测的图片放在同一路径下,并将图片命名为"image.jpg"。

下面是FirstDetection.py中的10行代码:

from imageai.Detection import ObjectDetection import os execution_path = os.getcwd() detector = ObjectDetection() detector.setModelTypeAsRetinaNet() detector.setModelPath( os.path.join(execution_path , "resnet50_coco_best_v2.0.1.h5")) detector.loadModel() detections = detector.detectObjectsFromImage(input_image=os.path.join(execution_path , "image.jpg"), output_image_path=os.path.join(execution_path , "imagenew.jpg")) for eachObject in detections: print(eachObject["name"] + " : " + eachObject["percentage_probability"] )

然后,双击FirstDetection.py运行代码,并稍等片刻,识别结果就会在控制台打印出来。一旦结果在控制台输出,在包含FirstDetection.py的文件夹里,你会发现一张新保存的图片,文件名为"imagenew.jpg"。

注:如果运行代码时出现下列异常:

则需要安装Numpy+MKL依赖,下载对应的.whl文件并放在Scripts文件夹下,用pip安装.whl文件即可。

下载地址:

https://ift.tt/2Fhw8wD

检测结果

来看看下面这2张示例图片以及经过检测后保存的新图片。

检测前:

检测后:

检测结果:

person : 55.8402955532074

person : 53.21805477142334

person : 69.25139427185059

person : 76.41745209693909

bicycle : 80.30363917350769

person : 83.58567953109741

person : 89.06581997871399

truck : 63.10953497886658

person : 69.82483863830566

person : 77.11606621742249

bus : 98.00949096679688

truck : 84.02870297431946

car : 71.98476791381836

检测结果:

person : 71.10445499420166

person : 59.28672552108765

person : 59.61582064628601

person : 75.86382627487183

motorcycle : 60.1050078868866

bus : 99.39600229263306

car : 74.05484318733215

person : 67.31776595115662

person : 63.53200078010559

person : 78.2265305519104

person : 62.880998849868774

person : 72.93365597724915

person : 60.01397967338562

person : 81.05944991111755

motorcycle : 50.591760873794556

motorcycle : 58.719027042388916

person : 71.69321775436401

bicycle : 91.86570048332214

motorcycle : 85.38855314254761

文摘菌测试了另外几张图片,结果如下:

检测前:

检测后:

检测结果:

car : 59.04694199562073

car : 50.62631368637085

car : 71.59191966056824

car : 52.60368585586548

person : 76.51243805885315

car : 56.73831105232239

car : 50.02853870391846

car : 94.18612122535706

car : 70.23521065711975

car : 75.06842017173767

car : 87.21032738685608

car : 89.46954607963562

person : 73.89532923698425

bicycle : 90.31689763069153

bus : 65.3587281703949

竟然可以检测出牛……

检测结果:

person : 55.15214800834656

person : 62.79672980308533

person : 69.01599168777466

person : 67.26776957511902

person : 75.51649808883667

person : 52.9820442199707

person : 67.23594665527344

person : 69.77047920227051

person : 83.80664587020874

person : 61.785924434661865

person : 82.354336977005

person : 93.08169484138489

cow : 84.69656705856323

检测结果:

person : 65.07909297943115

person : 65.68368077278137

person : 68.6377465724945

person : 83.80006551742554

person : 85.69389581680298

person : 55.40691018104553

person : 56.62997364997864

person : 58.07020664215088

person : 70.90385556221008

person : 95.06895542144775

代码解释

下面我们来解释一下这10行代码的含义。

from imageai.Detection import ObjectDetection import os execution_path = os.getcwd()


上面3行代码中,第一行导入ImageAI的目标检测类,第二行导入Python的os类,第三行定义一个变量,用来保存Python文件、RetianNet模型文件和图片所在文件夹的路径。

detector = ObjectDetection() detector.setModelTypeAsRetinaNet() detector.setModelPath( os.path.join(execution_path , "resnet50_coco_best_v2.0.1.h5")) detector.loadModel() detections = detector.detectObjectsFromImage(input_image=os.path.join(execution_path , "image.jpg"), output_image_path=os.path.join(execution_path , "imagenew.jpg"))

上面5行代码中,第一行定义目标检测类,第二行将模型类型设置为RetinaNet,第三行将模型的路径设为RetinaNet模型文件所在路径,第四行将模型载入目标检测类,然后第五行调用检测函数,并解析输入图片和输出图片的路径。

for eachObject in detections: print(eachObject["name"] + " : " + eachObject["percentage_probability"] )

上面2行代码中,第一行迭代所有detector.detectObjectsFromImage函数返回的结果,然后,第二行打印出模型检测出的图片中每个目标的类型和概率。

ImageAI还支持配置目标检测过程中的其他功能。例如,将检测到的每个目标的图片单独提取出来。通过简单地把extract_detected_objects=True写入detectObjectsFromImage函数,目标检测类就会为图片对象集新建一个文件夹,然后提取出每个图片,将它们存入这个文件夹,并返回一个数组用来保存每个图片的路径,如下所示:

detections, extracted_images = detector.detectObjectsFromImage(input_image=os.path.join(execution_path , "image.jpg"), output_image_path=os.path.join(execution_path , "imagenew.jpg"), extract_detected_objects=True)

我们用第一个示例图片提取出来的检测结果如图所示:

参数配置

为了满足目标检测的生产需求,ImageAI提供了一些可配置的参数,包括:

Adjusting Minimum Probability(可调整最小概率阈值)

默认阈值为50%,如果检测结果的概率值低于50%,则不显示检测结果。你可以根据具体需求对该阈值进行修改。

Custom Objects Detection(自定义目标检测)

使用提供的CustomObject类,你可以让检测结果只显示特定类型的目标。

Detection Speeds(检测速度)

可以将检测速度设置为"fast"、" faster"和"fastest",以减少检测图片所需的时间。

Input Types(输入类型)

你可以解析并修改图像的文件路径,其中,Numpy数组,或是图片文件流都可以作为输入类型。

Output Types(输出类型)

你可以修改detectObjectsFromImage 函数的返回结果,例如返回图片文件或Numpy数组。

详细的说明文档在GitHub上,GitHub链接:

https://github.com/OlafenwaMoses/ImageAI

动手试试吧,欢迎在留言区分享~

相关报道:

https://ift.tt/2My6BPO

]]> 原文: https://ift.tt/2IJPneV
RSS Feed

机器知心

IFTTT

令人困惑的TensorFlow!


导论

这是什么?我是谁?

我叫 Jacob,是 Google AI Resident 项目的研究学者。我是在 2017 年夏天加入该项目的,尽管已经拥有了丰富的编程经验,并且对机器学习的理解也很深刻,但此前我从未使用过 TensorFlow。当时我觉得凭我的能力应该很快就能上手。但让我没想到的是,学习曲线相当的陡峭,甚至在加入该项目几个月后,我还偶尔对如何使用 TensorFlow 代码来实现想法感到困惑。我把这篇博文当作瓶中信写给过去的自己:一篇我希望在学习之初能被给予的入门介绍。我希望这篇博文也能帮助到其他人。

以往的教程缺少了哪些内容?

自 TensorFlow 发布的三年以来,其已然成为深度学习生态系统中的一块基石。然而对于初学者来说,它可能并不直观,特别是与 PyTorch 或 DyNet 这样运行即定义的神经网络库相比。

市面上有许多 TensorFlow 的入门教程,包含从线性回归到 MNIST 分类和机器翻译的内容。这些具体实用的指南是使 TensorFlow 项目启动并运行的良好资源,同时可以作为类似项目的切入点。但对于有些应用开发人员而言,他们开发的应用并没有好的教程,或对于那些想打破常规的人(在研究中很常见)而言,刚接触 TensorFlow 肯定是让人沮丧的。

我试图通过这篇文章去填补这个空白。我没有专注于某个特定的任务,而是提出更一般的方法,并解析 TensorFlow 背后基础的抽象概念。掌握好这些概念之后,用 TensorFlow 进行深度学习就会变得直观易懂。

目标受众

本教程适用于那些在编程和机器学习方面有一定经验,并想要学习 TensorFlow 的人。例如:一位想在机器学习课程的最后一个项目中使用 TensorFlow 的计算机科学专业的学生;一位刚被分配到涉及深度学习项目的软件工程师;或是一位处于困惑中的新的 Google AI Resident 新手(向过去的 Jacob 大声打招呼)。如果你想进一步了解基础知识,请参阅以下资源:

  • https://ift.tt/2iGaGkW

  • http://colah.github.io/

  • https://ift.tt/2tVj1Zy

  • https://ift.tt/1aQjwZG

我们就开始吧!

理解 TensorFlow

TensorFlow 不是一个标准的 Python 库

大多数 Python 库被编写为 Python 的自然扩展形式。当你导入一个库时,你得到的是一组变量、函数和类,他们扩展并补充了你的代码「工具箱」。当你使用它们时,你能预期到返回的结果是怎样的。在我看来,当谈及 TensorfFlow 时,应该把这种认知完全抛弃。思考什么是 TensorFlow 及其如何与其他代码进行交互从根本上来说就是错误的。

Python 和 TensorFlow 之间的关系可以类比 Javascript 和 HTML 之间的关系。Javascript 是一种全功能的编程语言,可以做各种美妙的事情。HTML 是用于表示某种类型的实用计算抽象(此处指可由 Web 浏览器呈现的内容)的框架。Javascript 在交互式网页中的作用是组装浏览器看到的 HTML 对象,然后在需要时通过将其更新为新的 HTML 来与其交互。

与 HTML 类似,TensorFlow 是用于表示某种类型的计算抽象(称为「计算图」)的框架。但我们用 Python 操作 TensorFlow 时,我们用 Pyhton 代码做的第一件事就是构建计算图。一旦完成,我们做的第二件事就是与它进行交互(启动 TensorFlow 的「会话」)。但重要的是,要记住计算图不在变量内部;而是处在全局命名空间中。正如莎士比亚所说:「所有的 RAM 都是一个阶段,所有的变量都仅仅是指针」

第一个关键抽象:计算图

当你在浏览 TensorFlow 文档时,可能会发现对「图形」和「节点」的间接引用。如果你仔细阅读,你甚至可能已经发现了这个页面(https://www.tensorflow.org/programmers_guide/graphs),该页面涵盖了我将以更准确和技术化的方式去解释的内容。本节是一篇高级攻略,把握重要的直觉概念,同时忽略一些技术细节。

那么:什么是计算图?它本质上是一个全局数据结构:是一个有向图,用于捕获有关如何计算的指令。

让我们来看看构建计算图的一个示例。在下图中,上半部分是我们运行的代码及其输出,下半部分是生成的计算图。

import tensorflow as tf

计算图:

可见,仅仅导入 TensorFlow 并不会给我们生成一个有趣的计算图。而只是一个单独的,空白的全局变量。但当我们调用一个 TensorFlow 操作时,会发生什么?

代码:

import tensorflow as tf two_node = tf.constant(2) print two_node

输出:

Tensor("Const:0", shape=(), dtype=int32)

计算图:

快看!我们得到了一个节点。它包含常量 2。很惊讶吧,这来自于一个名为 tf.constant 的函数。当我们打印这个变量时,我们看到它返回一个 tf.Tensor 对象,它是一个指向我们刚刚创建的节点的指针。为了强调这一点,以下是另外一个示例:

代码:

import tensorflow as tf two_node = tf.constant(2) another_two_node = tf.constant(2) two_node = tf.constant(2) tf.constant(3)

计算图:

每次我们调用 tf.constant 时,我们都会在图中创建一个新的节点。即使该节点的功能与现有节点相同,即使我们将节点重新分配给同一个变量,或者即使我们根本没有将其分配给一个变量,结果都是一样的。

代码:

import tensorflow as tf two_node = tf.constant(2) another_pointer_at_two_node = two_node two_node = None print two_node print another_pointer_at_two_node

输出:

None Tensor("Const:0", shape=(), dtype=int32)

计算图:

好啦,让我们更进一步:

代码:

import tensorflow as tf two_node = tf.constant(2) three_node = tf.constant(3) sum_node = two_node + three_node ## equivalent to tf.add(two_node, three_node)

计算图:

现在我们正谈论—这才是我们真正想要的计算图!请注意,+ 操作在 TensorFlow 中过载,因此同时添加两个张量会在图中增加一个节点,尽管它表面上看起来不像是 TensorFlow 操作。

那好,所以 two_node 指向包含 2 的节点,three_node 指向包含 3 的节点,同时 sum_node 指向包含 ...+ 的节点?怎么回事?它不是应该包含 5 吗?

事实证明,并没有。计算图只包含计算步骤;不包含结果。至少……现在还没有!

第二个关键抽象: 会话

如果错误地理解 TensorFlow 抽象概念也有个「疯狂三月」(NCAA 篮球锦标赛,大部分在三月进行),那么会话将成为每年的一号种子选手。会话有着那样令人困惑的殊荣是因为其反直觉的命名却又普遍存在—几乎每个 TensorFlow 呈现都至少一次明确地调用 tf.Session()。

会话的作用是处理内存分配和优化,使我们能够实际执行由计算图指定的计算。你可以将计算图想象为我们想要执行的计算的「模版」:它列出了所有步骤。为了使用计算图,我们需要启动一个会话,它使我们能够实际地完成任务;例如,遍历模版的所有节点来分配一堆用于存储计算输出的存储器。为了使用 TensorFlow 进行各种计算,你既需要计算图也需要会话。

会话包含一个指向全局图的指针,该指针通过指向所有节点的指针不断更新。这意味着在创建节点之前还是之后创建会话都无所谓。

创建会话对象后,可以使用 sess.run(node) 返回节点的值,并且 TensorFlow 将执行确定该值所需的所有计算。

代码:

import tensorflow as tf two_node = tf.constant(2) three_node = tf.constant(3) sum_node = two_node + three_node sess = tf.Session() print sess.run(sum_node)

输出:

5

计算图:

太好了!我们也可以传递一个列表,sess.run([node1, node2, ...]),并让它返回多个输出:

代码:

import tensorflow as tf two_node = tf.constant(2) three_node = tf.constant(3) sum_node = two_node + three_node sess = tf.Session() print sess.run([two_node, sum_node]) 

输出:

[2, 5]

计算图:

一般来说,sess.run() 的调用往往是 TensorFlow 最大的瓶颈之一,因此调用它的次数越少越好。如果可以的话,在一个 sess.run() 的调用中返回多个项目,而不是进行多个调用。

占位符和 feed_dict

迄今为止,我们所做的计算一直很乏味:没有机会获得输入,所以它们总是输出相同的东西。一个更有价值的应用可能涉及构建一个计算图,它接受输入,以某种(一致)方式处理它,并返回一个输出。

最直接的方法是使用占位符。占位符是一种用于接受外部输入的节点。

代码:

import tensorflow as tf input_placeholder = tf.placeholder(tf.int32) sess = tf.Session()  print sess.run(input_placeholder)

输出:

Traceback (most recent call last): ... InvalidArgumentError (see above *for* traceback): You must feed a value *for* placeholder tensor 'Placeholder' *with* dtype int32  [[Node: Placeholder = Placeholder[dtype=DT_INT32, shape=, _device="/job:localhost/replica:0/task:0/device:CPU:0"]()]]

计算图:

... 这是一个糟糕的例子,因为它引发了一个异常。占位符预计会被赋予一个值。但我们没有提供一个值,所以 TensorFlow 崩溃了。

为了提供一个值,我们使用 sess.run() 的 feed_dixt 属性。

代码:

import tensorflow as tf  input_placeholder = tf.placeholder(tf.int32)  sess = tf.Session()  print sess.run(input_placeholder, feed_dict={input_placeholder: 2})

输出:

2

计算图:

这就好多了。注意传递给 feed_dict 的 dict 格式,其关键应该是与图中的占位符节点相对应的变量(如前所述,它实际上意味着指向图中占位符节点的指针)。相应的值是要分配给每个占位符的数据元素——通常是标量或 Numpy 数组。

第三个关键抽象:计算路径

让我们看看另一个使用占位符的示例:

代码:

import tensorflow as tf input_placeholder = tf.placeholder(tf.int32) three_node = tf.constant(3) sum_node = input_placeholder + three_node sess = tf.Session() print sess.run(three_node) print sess.run(sum_node)

输出:

3 Traceback (most recent call last): ... InvalidArgumentError (see above for traceback): You must feed a value *for* placeholder tensor 'Placeholder_2' with dtype int32  [[Node: Placeholder_2 = Placeholder[dtype=DT_INT32, shape=, _device="/job:localhost/replica:0/task:0/device:CPU:0"]()]] 

计算图:

为什么第二次调用 sess.run() 会失败?即使我们没有评估 input_placeholder,为什么仍会引发与 input_placeholder 相关的错误?答案在于最终的关键 TensorFlow 抽象:计算路径。幸运的是,这个抽象非常直观。

当我们在依赖于图中其他节点的节点上调用 sess.run() 时,我们也需要计算那些节点的值。如果这些节点具有依赖关系,那么我们需要计算这些值(依此类推……),直到达到计算图的「顶端」,即节点没有父节点时。

sum_node 的计算路径:


所有三个节点都需要进行求值以计算 sum_node 的值。最重要的是,这包含了我们未填充的占位符,并解释了异常!

现在来看 three_node 的计算路径:

根据图结构,我们不需要计算所有节点才能评估我们想要的节点!因为我们在评估 three_node 时不需要评估 placehoolder_node,所以运行 sess.run(three_node) 不会引发异常。

TensorFlow 仅通过必需的节点自动进行计算这一事实是该框架的一个巨大优势。如果计算图非常大并且有许多不必要的节点,那么它可以节省大量调用的运行时间。它允许我们构建大型的「多用途」计算图,这些计算图使用单个共享的核心节点集合,并根据所采取的不同计算路径去做不同的事情。对于几乎所有应用而言,根据所采取的计算路径考虑 sess.run() 的调用是很重要的。

变量 & 副作用

至此,我们已经看到两种类型的「无祖先」节点(no-ancestor node):每次运行都一样的 tf.constant 和每次运行都不一样的 tf.placeholder。我们常常要考虑第三种情况:一个通常在运行时保持值不变的节点也可以被更新为新值。

这时就需要引入变量。

变量对于使用 TensorFlow 进行深度学习是至关重要的,因为模型的参数就是变量。在训练期间,你希望通过梯度下降在每个步骤更新参数;但在评估时,你希望保持参数不变,并将大量不同的测试集输入模型。通常,模型所有可训练参数都是变量。

要创建变量,就需要使用 tf.get_variable()。tf.get_variable() 的前两个参数是必需的,其余参数是可选的。它们是 tf.get_variable(name,shape)。name 是一个唯一标识这个变量对象的字符串。它必须相对于全局图是唯一的,所以要明了你使用过的所有命名,确保没有重复。shape 是与张量形状对应的整数数组,它的语法非常直观:按顺序,每个维度只有一个整数。例如,一个 3x8 矩阵形状是 [3, 8]。要创建一个标量,就需要使用形状为 [] 的空列表。

代码:

import tensorflow as tf count_variable = tf.get_variable("count", []) sess = tf.Session() print sess.run(count_variable)

输出:

Traceback (most recent call last): ... tensorflow.python.framework.errors_impl.FailedPreconditionError: Attempting to use uninitialized value count  [[Node: _retval_count_0_0 = _Retval[T=DT_FLOAT, index=0, _device="/job:localhost/replica:0/task:0/device:CPU:0"](count)]]

计算图:

噫,另一个异常。当首次创建变量节点时,它的值基本上为「null」,并且任何试图对它求值的操作都会引发这个异常。我们只能在将值放入变量之后才能对其求值。主要有两种将值放入变量的方法:初始化器和 tf.assign()。我们先看看 tf.assign():

代码:

import tensorflow as tf count_variable = tf.get_variable("count", []) zero_node = tf.constant(0.) assign_node = tf.assign(count_variable, zero_node) sess = tf.Session() sess.run(assign_node) print sess.run(count_variable)

输出:

0

计算图:

与我们迄今为止见过的节点相比,tf.assign(target, value) 是具备一些独特属性:

  • 恒等运算。tf.assign(target, value) 不做任何有趣的运算,通常与 value 相等。

  • 副作用。当计算「流经」assign_node 时,副作用发生在图中的其他节点上。此时,副作用是用存储在 zero_node 中的值替换 count_variable 的值。

  • 非依赖边。即使 count_variable 节点和 assign_node 在图中是相连的,但它们彼此独立。这意味着计算任一节点时,计算不会通过边回流。然而,assign_node 依赖于 zero_node,它需要知道分配了什么。

「副作用」节点支撑着大部分 Tensorflow 深度学习工作流程,所以请确保自己真正理解了在该节点发生的事情。当我们调用 sess.run(assign_node) 时,计算路径会通过 assign_node 和 zero_node。

计算图:

当计算流经图中的任何节点时,它还会执行由该节点控制的任何副作用,如图中绿色所示。由于 tf.assign 的特殊副作用,与 count_variable(之前为「null」)关联的内存现在被永久设置为 0。这意味着当我们下一次调用 sess.run(count_variable) 时,不会引发任何异常。相反,我们会得到 0 值。成功!

接下来,让我们看看初始化器:

代码:

import tensorflow as tf const_init_node = tf.constant_initializer(0.) count_variable = tf.get_variable("count", [], initializer=const_init_node) sess = tf.Session() print sess.run([count_variable])

输出:

Traceback (most recent call last): ... tensorflow.python.framework.errors_impl.FailedPreconditionError: Attempting to use uninitialized value count  [[Node: _retval_count_0_0 = _Retval[T=DT_FLOAT, index=0, _device="/job:localhost/replica:0/task:0/device:CPU:0"](count)]]

计算图:

那好,这里发生了什么?为什么初始化器不工作?

问题出现在会话和图之间的分离。我们已将 get_variable 的 initializer 属性设置为指向 const_init_node,但它只是在图中的节点之间添加了一个新的连接。我们还没有做任何解决异常根源的事:与变量节点(存储在会话中,而不是计算图中)相关联的内存仍然设置为「null」。我们需要通过会话使 const_init_node 去更新变量。

代码:

import tensorflow as tf const_init_node = tf.constant_initializer(0.) count_variable = tf.get_variable("count", [], initializer=const_init_node) init = tf.global_variables_initializer() sess = tf.Session() sess.run(init) print sess.run(count_variable)

输出:

0

计算图:

为此,我们添加另一个特殊的节点:init = tf.global_variables_initializer()。与 tf.assign() 类似,这是一个带有副作用的节点。与 tf.assign() 相反,实际上我们不需要指定它的输入是什么!tf.global_variables_initializer() 将在其创建时查看全局图并自动将依赖关系添加到图中的每个 tf.initializer。当我们在之后使用 sess.run(init) 对它求值时,它会告诉每个初始化程序执行变量初始化,并允许我们运行 sess.run(count_variable) 而不出错。

变量共享

你可能会遇到带有变量共享的 Tensorflow 代码,其涉及创建作用域并设置「reuse = True」。我强烈建议不要在自己的代码中使用变量共享。如果你想在多个地方使用单个变量,只需以编程方式记录指向该变量节点的指针,并在需要时重新使用它。换言之,对于想要保存在内存中的每个变量,你只需要调用一次 tf.get_variable()。

优化器

最后:进行真正的深度学习!如果你跟上我的节奏,那么其余概念对你来说应该非常简单。

在深度学习中,典型的「内循环」训练如下:

1. 获取输入和 true_output

2. 根据输入和参数计算「推测」值

3. 根据推测与 true_output 之间的差异计算「损失」

4. 根据损失的梯度更新参数

让我们把所有东西放在一个快速脚本里,解决简单的线性回归问题:

代码:

import tensorflow as tf ### build the graph## first set up the parameters m = tf.get_variable("m", [], initializer=tf.constant_initializer(0.)) b = tf.get_variable("b", [], initializer=tf.constant_initializer(0.)) init = tf.global_variables_initializer() ## then set up the computations input_placeholder = tf.placeholder(tf.float32) output_placeholder = tf.placeholder(tf.float32)  x = input_placeholder y = output_placeholder y_guess = m * x + b  loss = tf.square(y - y_guess) ## finally, set up the optimizer and minimization node optimizer = tf.train.GradientDescentOptimizer(1e-3) train_op = optimizer.minimize(loss) ### start the session sess = tf.Session() sess.run(init) ### perform the training loop*import* random ## set up problem true_m = random.random() true_b = random.random() *for* update_i *in* range(100000):  ## (1) get the input and output  input_data = random.random()  output_data = true_m * input_data + true_b   ## (2), (3), and (4) all take place within a single call to sess.run()!  _loss, _ = sess.run([loss, train_op], feed_dict={input_placeholder: input_data, output_placeholder: output_data})  *print* update_i, _loss ### finally, print out the values we learned for our two variables*print* "True parameters: m=%.4f, b=%.4f" % (true_m, true_b)*print* "Learned parameters: m=%.4f, b=%.4f" % tuple(sess.run([m, b]))

输出:

0 2.32053831 0.57927422 1.552543 1.57332594 0.64356485 2.40612656 1.07462567 2.19987158 1.67751169 1.646242310 2.441034 ...99990 2.9878322e-1299991 5.158629e-1199992 4.53646e-1199993 9.422685e-1299994 3.991829e-1199995 1.134115e-1199996 4.9467985e-1199997 1.3219648e-1199998 5.684342e-1499999 3.007017e-11*True* parameters: m=0.3519, b=0.3242 Learned parameters: m=0.3519, b=0.3242

就像你看到的一样,损失基本上变为零,并且我们对真实参数进行了很好的估计。我希望你只对代码中的以下部分感到陌生:

## finally, set up the optimizer and minimization node optimizer = tf.train.GradientDescentOptimizer(1e-3) train_op = optimizer.minimize(loss)

但是,既然你对 Tensorflow 的基本概念有了很好的理解,这段代码就很容易解释!第一行,optimizer = tf.train.GradientDescentOptimizer(1e-3) 不会向计算图中添加节点。它只是创建一个包含有用的帮助函数的 Python 对象。第二行,train_op = optimizer.minimize(loss) 将一个节点添加到图中,并将一个指针存储在变量 train_op 中。train_op 节点没有输出,但是有一个十分复杂的副作用:

train_op 回溯输入和损失的计算路径,寻找变量节点。对于它找到的每个变量节点,计算该变量对于损失的梯度。然后计算该变量的新值:当前值减去梯度乘以学习率的积。最后,它执行赋值操作更新变量的值。

因此基本上,当我们调用 sess.run(train_op) 时,它对我们的所有变量做了一个梯度下降的步骤。当然,我们也需要使用 feed_dict 填充输入和输出占位符,并且我们还希望打印损失的值,因为这样方便调试。

用 tf.Print 调试

当你用 Tensorflow 开始做更复杂的事情时,你需要进行调试。一般来说,检查计算图中发生了什么是相当困难的。因为你永远无法访问你想打印的值—它们被锁定在 sess.run() 的调用中,所以你不能使用常规的 Python 打印语句。具体来说,假设你是想检查一个计算的中间值。在调用 sess.run() 之前,中间值还不存在。但是,当你调用的 sess.run() 返回时,中间值又不见了!

让我们看一个简单的示例。

代码:

import tensorflow as tf two_node = tf.constant(2) three_node = tf.constant(3) sum_node = two_node + three_node sess = tf.Session() print sess.run(sum_node)

输出:

5

这让我们看到了答案是 5。但是,如果我们想要检查中间值,two_node 和 three_node,怎么办?检查中间值的一个方法是向 sess.run() 中添加一个返回参数,该参数指向要检查的每个中间节点,然后在返回后,打印它的值。

代码:

import tensorflow as tf two_node = tf.constant(2) three_node = tf.constant(3) sum_node = two_node + three_node sess = tf.Session() answer, inspection = sess.run([sum_node, [two_node, three_node]]) print inspection print answer 

输出:

[2, 3]5

这通常是有用的,但当代码变得越来越复杂时,这可能有点棘手。一个更方便的方法是使用 tf.Print 语句。令人困惑的是,tf.Print 实际上是一种具有输出和副作用的 Tensorflow 节点!它有两个必需参数:要复制的节点和要打印的内容列表。「要复制的节点」可以是图中的任何节点;tf.Print 是一个与「要复制的节点」相关的恒等操作,意味着输出的是输入的副本。但是,它的副作用是打印出「打印列表」里的所有当前值。

代码:

import tensorflow as tf two_node = tf.constant(2) three_node = tf.constant(3) sum_node = two_node + three_node print_sum_node = tf.Print(sum_node, [two_node, three_node]) sess = tf.Session() print sess.run(print_sum_node) 

输出:

[2][3]5

计算图:

有关 tf.Print 一个重要且有点微妙的点:打印是一个副作用。像所有其他副作用一样,只要在计算流经 tf.Print 节点时才会进行打印。如果 tf.Print 节点不在计算路径上,则不会打印任何内容。特别的是,即使 tf.Print 节点正在复制的原始节点位于计算路径上,但 tf.Print 节点本身可能不在。请注意这个问题!当这种情况发生时(总会发生的),如果你没有明确地找到问题所在,它会让你感到十分沮丧。一般来说,最好在创建要复制的节点后,立即创建你的 tf.Print 节点。

代码:

import tensorflow as tf two_node = tf.constant(2) three_node = tf.constant(3) sum_node = two_node + three_node### this new copy of two_node is not on the computation path, so nothing prints! print_two_node = tf.Print(two_node, [two_node, three_node, sum_node]) sess = tf.Session()  print sess.run(sum_node) 

输出:

5

计算图:

这里有一个很好的资源(https://wookayin.github.io/tensorflow-talk-debugging/#1),它提供了其他一些实用的调试建议。

结论

希望这篇博文可以帮助你更好地理解什么是 Tensorflow,它是如何工作的以及怎么使用它。总而言之,本文介绍的概念对所有 Tensorflow 项目都很重要,但只是停留在表面。在你探索 Tensorflow 的旅程中,你可能会遇到其他各种你需要的有趣概念:条件、迭代、分布式 Tensorflow、变量作用域、保存和加载模型、多图、多会话和多核、数据加载器队列等等。我将在未来的博文中讨论这些主题。但如果你使用官方文档、一些代码示例和一点深度学习的魔力来巩固你在本文学到的思想,我相信你一定可以弄明白 Tensorflow!

原文链接:https://ift.tt/2KjUIyF

]]> 原文: https://ift.tt/2lNGqIN
RSS Feed

机器知心

IFTTT

LangChain 彻底重写:从开源副业到独角兽,一次“核心迁移”干到 12.5 亿估值 -InfoQ 每周精要No.899期

「每周精要」 NO. 899 2025/10/25 头条 HEADLINE LangChain 彻底重写:从开源副业到独角兽,一次"核心迁移"干到 12.5 亿估值 精选 SELECTED 1000 行代码手搓 OpenAI gpt-oss 推理引...