中企动力 > 头条 > python中的search

网站性能检测评分

注:本网站页面html检测工具扫描网站中存在的基本问题,仅供参考。

python中的search

TensorFlow和Caffe、MXNet、Keras等其他深度学习框架的对比 公司视频课程

img

Daqr

关注

雷锋网按:本文作者黄文坚,PPmoney 大数据算法总监,《 TensorFlow 实战》作者。本文节选自《 TensorFlow 实战》第二章。

在下周二(2月28日)雷锋网硬创公开课栏目将会推出黄文坚老师的公开课《深度学习之经典卷积神经网络的技术浅析》(),欢迎大家报名!点击了解详情

Google 近日发布了 TensorFlow 1.0 候选版,这第一个稳定版将是深度学习框架发展中的里程碑的一步。自 TensorFlow 于 2015 年底正式开源,距今已有一年多,这期间 TensorFlow 不断给人以惊喜。在这一年多时间,TensorFlow 已从初入深度学习框架大战的新星,成为了几近垄断的行业事实标准。

主流深度学习框架对比

深度学习研究的热潮持续高涨,各种开源深度学习框架也层出不穷,其中包括 TensorFlow、Caffe、Keras、CNTK、Torch7、MXNet、Leaf、Theano、DeepLearning4、Lasagne、Neon 等等。然而 TensorFlow 却杀出重围,在关注度和用户数上都占据绝对优势,大有一统江湖之势。表 2-1 所示为各个开源框架在GitHub上的数据统计(数据统计于 2017 年 1 月 3 日),可以看到 TensorFlow 在 star 数量、fork 数量、contributor 数量这三个数据上都完胜其他对手。

究其原因,主要是 Google 在业界的号召力确实强大,之前也有许多成功的开源项目,以及 Google 强大的人工智能研发水平,都让大家对 Google 的深度学习框架充满信心,以至于 TensorFlow 在 2015 年 11 月刚开源的第一个月就积累了 10000+ 的 star 。其次,TensorFlow 确实在很多方面拥有优异的表现,比如设计神经网络结构的代码的简洁度,分布式深度学习算法的执行效率,还有部署的便利性,都是其得以胜出的亮点。如果一直关注着 TensorFlow 的开发进度,就会发现基本上每星期 TensorFlow 都会有1万行以上的代码更新,多则数万行。产品本身优异的质量、快速的迭代更新、活跃的社区和积极的反馈,形成了良性循环,可以想见 TensorFlow 未来将继续在各种深度学习框架中独占鳌头。

表2-1 各个开源框架在 GitHub 上的数据统计

观察表2-1还可以发现,Google、Microsoft、Facebook 等巨头都参与了这场深度学习框架大战,此外,还有毕业于伯克利大学的贾扬清主导开发的 Caffe,蒙特利尔大学 Lisa Lab 团队开发的 Theano,以及其他个人或商业组织贡献的框架。另外,可以看到各大主流框架基本都支持 Python,目前 Python 在科学计算和数据挖掘领域可以说是独领风骚。虽然有来自 R、Julia 等语言的竞争压力,但是 Python 的各种库实在是太完善了,Web 开发、数据可视化、数据预处理、数据库连接、爬虫等无所不能,有一个完美的生态环境。仅在数据挖据工具链上,Python 就有 NumPy、SciPy、Pandas、Scikit-learn、XGBoost 等组件,做数据采集和预处理都非常方便,并且之后的模型训练阶段可以和 TensorFlow 等基于 Python 的深度学习框架完美衔接。

表 2-1 和图 2-1 所示为对主流的深度学习框架 TensorFlow、Caffe、CNTK、Theano、Torch 在各个维度的评分,本书 2.2 节会对各个深度学习框架进行比较详细的介绍。

表2-2 主流深度学习框架在各个维度的评分

图2-1 主流深度学习框架对比图

各深度学习框架简介

在本节,我们先来看看目前各流行框架的异同,以及各自的特点和优势。

TensorFlow

TensorFlow 是相对高阶的机器学习库,用户可以方便地用它设计神经网络结构,而不必为了追求高效率的实现亲自写 C++或 CUDA 代码。它和 Theano 一样都支持自动求导,用户不需要再通过反向传播求解梯度。其核心代码和 Caffe 一样是用 C++编写的,使用 C++简化了线上部署的复杂度,并让手机这种内存和CPU资源都紧张的设备可以运行复杂模型(Python 则会比较消耗资源,并且执行效率不高)。除了核心代码的 C++接口,TensorFlow 还有官方的 Python、Go 和 Java 接口,是通过 SWIG(Simplified Wrapper and Interface Generator)实现的,这样用户就可以在一个硬件配置较好的机器中用 Python进行实验,并在资源比较紧张的嵌入式环境或需要低延迟的环境中用 C++部署模型。SWIG 支持给 C/C++代码提供各种语言的接口,因此其他脚本语言的接口未来也可以通过 SWIG 方便地添加。不过使用 Python 时有一个影响效率的问题是,每一个 mini-batch 要从 Python 中 feed 到网络中,这个过程在 mini-batch 的数据量很小或者运算时间很短时,可能会带来影响比较大的延迟。现在 TensorFlow 还有非官方的 Julia、Node.js、R 的接口支持,地址如下。

Julia: http://github/malmaud/TensorFlow.jl

Node.js: http://github/node-tensorflow/node-tensorflow

R: http://github/rstudio/tensorflow

TensorFlow 也有内置的 TF.Learn 和 TF.Slim 等上层组件可以帮助快速地设计新网络,并且兼容 Scikit-learn estimator 接口,可以方便地实现 evaluate、grid search、cross validation 等功能。同时 TensorFlow 不只局限于神经网络,其数据流式图支持非常自由的算法表达,当然也可以轻松实现深度学习以外的机器学习算法。事实上,只要可以将计算表示成计算图的形式,就可以使用 TensorFlow 。用户可以写内层循环代码控制计算图分支的计算,TensorFlow 会自动将相关的分支转为子图并执行迭代运算。TensorFlow 也可以将计算图中的各个节点分配到不同的设备执行,充分利用硬件资源。定义新的节点只需要写一个 Python 函数,如果没有对应的底层运算核,那么可能需要写 C++或者 CUDA 代码实现运算操作。

在数据并行模式上,TensorFlow 和 Parameter Server 很像,但 TensorFlow 有独立的 Variable node,不像其他框架有一个全局统一的参数服务器,因此参数同步更自由。TensorFlow 和 Spark 的核心都是一个数据计算的流式图,Spark 面向的是大规模的数据,支持 SQL 等操作,而 TensorFlow 主要面向内存足以装载模型参数的环境,这样可以最大化计算效率。

TensorFlow 的另外一个重要特点是它灵活的移植性,可以将同一份代码几乎不经过修改就轻松地部署到有任意数量 CPU 或 GPU 的 PC、服务器或者移动设备上。相比于 Theano,TensorFlow 还有一个优势就是它极快的编译速度,在定义新网络结构时,Theano 通常需要长时间的编译,因此尝试新模型需要比较大的代价,而 TensorFlow 完全没有这个问题。TensorFlow 还有功能强大的可视化组件 TensorBoard,能可视化网络结构和训练过程,对于观察复杂的网络结构和监控长时间、大规模的训练很有帮助。TensorFlow 针对生产环境高度优化,它产品级的高质量代码和设计都可以保证在生产环境中稳定运行,同时一旦 TensorFlow 广泛地被工业界使用,将产生良性循环,成为深度学习领域的事实标准。

除了支持常见的网络结构(卷积神经网络(Convolutional Neural Network,CNN)、循环神经网络(Recurent Neural Network,RNN))外,TensorFlow 还支持深度强化学习乃至其他计算密集的科学计算(如偏微分方程求解等)。TensorFlow 此前不支持 symbolic loop,需要使用 Python 循环而无法进行图编译优化,但最近新加入的 XLA 已经开始支持 JIT 和 AOT,另外它使用 bucketing trick 也可以比较高效地实现循环神经网络。TensorFlow 的一个薄弱地方可能在于计算图必须构建为静态图,这让很多计算变得难以实现,尤其是序列预测中经常使用的 beam search。

TensorFlow 的用户能够将训练好的模型方便地部署到多种硬件、操作系统平台上,支持 Intel 和 AMD 的 CPU,通过 CUDA 支持 NVIDIA 的 GPU (最近也开始通过 OpenCL 支持 AMD 的 GPU,但没有 CUDA 成熟),支持 Linux 和 Mac,最近在 0.12 版本中也开始尝试支持 Windows。在工业生产环境中,硬件设备有些是最新款的,有些是用了几年的老机型,来源可能比较复杂,TensorFlow 的异构性让它能够全面地支持各种硬件和操作系统。同时,其在 CPU 上的矩阵运算库使用了 Eigen 而不是 BLAS 库,能够基于 ARM 架构编译和优化,因此在移动设备(Android 和 iOS)上表现得很好。

TensorFlow 在最开始发布时只支持单机,而且只支持 CUDA 6.5 和 cuDNN v2,并且没有官方和其他深度学习框架的对比结果。在 2015 年年底,许多其他框架做了各种性能对比评测,每次 TensorFlow 都会作为较差的对照组出现。那个时期的 TensorFlow 真的不快,性能上仅和普遍认为很慢的 Theano 比肩,在各个框架中可以算是垫底。但是凭借 Google 强大的开发实力,很快支持了新版的 cuDNN (目前支持cuDNN v5.1),在单 GPU 上的性能追上了其他框架。表 2-3 所示为 给出的各个框架在 AlexNet 上单 GPU 的性能评测。https://github/soumith/convnet-benchmarks

表2-3 各深度学习框架在 AlexNet 上的性能对比

目前在单 GPU 的条件下,绝大多数深度学习框架都依赖于 cuDNN,因此只要硬件计算能力或者内存分配差异不大,最终训练速度不会相差太大。但是对于大规模深度学习来说,巨大的数据量使得单机很难在有限的时间完成训练。这时需要分布式计算使 GPU 集群乃至 TPU 集群并行计算,共同训练出一个模型,所以框架的分布式性能是至关重要的。TensorFlow 在 2016 年 4 月开源了分布式版本,使用 16 块 GPU 可达单 GPU 的 15 倍提速,在 50 块 GPU 时可达到 40 倍提速,分布式的效率很高。目前原生支持的分布式深度学习框架不多,只有 TensorFlow、CNTK、DeepLearning4J、MXNet 等。不过目前 TensorFlow 的设计对不同设备间的通信优化得不是很好,其单机的 reduction 只能用 CPU 处理,分布式的通信使用基于 socket 的 RPC,而不是速度更快的 RDMA,所以其分布式性能可能还没有达到最优。

Google 在 2016 年 2 月开源了 TensorFlow Serving,这个组件可以将 TensorFlow 训练好的模型导出,并部署成可以对外提供预测服务的 RESTful 接口,如图 2-2 所示。有了这个组件,TensorFlow 就可以实现应用机器学习的全流程:从训练模型、调试参数,到打包模型,最后部署服务,名副其实是一个从研究到生产整条流水线都齐备的框架。这里引用 TensorFlow 内部开发人员的描述:“ TensorFlow Serving 是一个为生产环境而设计的高性能的机器学习服务系统。它可以同时运行多个大规模深度学习模型,支持模型生命周期管理、算法实验,并可以高效地利用 GPU 资源,让 TensorFlow 训练好的模型更快捷方便地投入到实际生产环境”。除了 TensorFlow 以外的其他框架都缺少为生产环境部署的考虑,而 Google 作为广泛在实际产品中应用深度学习的巨头可能也意识到了这个机会,因此开发了这个部署服务的平台。TensorFlow Serving 可以说是一副王牌,将会帮 TensorFlow 成为行业标准做出巨大贡献。

图2-2 TensorFlow Serving 架构

TensorBoard 是 TensorFlow 的一组 Web 应用,用来监控 TensorFlow 运行过程,或可视化 Computation Graph。TensorBoard 目前支持五种可视化:标量(scalars)、图片(images)、音频(audio)、直方图(histograms)和计算图(Computation Graph)。TensorBoard 的 Events Dashboard 可以用来持续地监控运行时的关键指标,比如 loss、学习速率(learning rate)或是验证集上的准确率(accuracy);Image Dashboard 则可以展示训练过程中用户设定保存的图片,比如某个训练中间结果用 Matplotlib 等绘制(plot)出来的图片;Graph Explorer 则可以完全展示一个 TensorFlow 的计算图,并且支持缩放拖曳和查看节点属性。TensorBoard 的可视化效果如图 2-3 和图 2-4 所示。

图2-3 TensorBoard 的 loss 标量的可视化

图2-4 TensorBoard 的模型结构可视化

TensorFlow 拥有...

Python3中Selenium使用方法(连载) 营销视频课程

img

海利根港

关注

欢迎关注天善智能,我们是专注于商业智能BI,大数据,数据分析领域的垂直社区,学习,问答、求职一站式搞定!

登陆天善社区查看更多系列:

Python3中BeautifulSoup的使用方法

Python3中PyQuery的使用方法

Python3中正则表达式使用方法

基本使用

首先我们来大体看一下Selenium有一些怎样的功能,先用一段实例代码来演示一下:

运行代码之后,如果正确配置好了ChromeDriver,可以发现会自动弹出一个浏览器,浏览器首先会跳转到百度,然后在搜索框中输入Python进行搜索,然后跳转到搜索结果页,等待搜索结果加载出来之后,控制台分别会输出当前的URL,当前的Cookies还有网页源代码。

控制台输出结果:

源代码过长在此省略,那么当前的URL,Cookies,源代码都是浏览器中的真实内容。所以说,如果我们用Selenium来驱动浏览器加载网页的话,我们就可以拿到JavaScrit渲染的结果了。

下面我们来详细介绍一下Selenium的用法。

Selenium支持非常多的浏览器,如Chrome、Firefox、Edge等,还有手机端的浏览器Android、BlackBerry等,另外无界面浏览器PhantomJS也同样支持。

我们可以用如下的方式初始化:

这样我们就完成了一个浏览器对象的初始化,接下来我们要做的就是调用browser对象,让其执行各个动作,就可以模拟浏览器操作了。

我们可以用get()方法来请求一个网页,参数传入链接URL即可,比如在这里我们用get()方法访问淘宝,然后打印出源代码,代码如下:

单个元素

Selenium可以驱动浏览器完成各种操作,比如填充表单,模拟点击等等,比如我们想要完成向某个输入框输入文字的操作,总得需要知道这个输入框在哪里吧?所以Selenium提供了一系列查找元素的方法,我们可以用这些方法来获取想要的元素,以便于下一步执行一些动作或者提取信息。

比如我们想要从淘宝页面中提取搜索框这个元素,首先观察它的源代码:

可以发现它的ID是q,Name也是q,还有许多其他属性,我们获取它的方式就有多种形式了,比如find_element_by_name()是根据Name值获取,ind_element_by_id()是根据ID获取,另外还有根据XPath、CSS Selector等获取。

我们代码实现一下:

在这里我们使用了三种方式获取输入框,根据ID,CSS Selector,和XPath获取,它们返回的结果是完全一致的。

运行结果:

可以看到三个元素都是WebElement类型,是完全一致的。

在这里列出所有获取单个元素的方法:

find_element_by_idfind_element_by_namefind_element_by_xpathfind_element_by_link_textfind_element_by_partial_link_textfind_element_by_tag_namefind_element_by_class_namefind_element_by_css_selector

另外Selenium还提供了通用的find_element()方法,它需要传入两个参数,一个是查找的方式By,另一个就是值,实际上它就是find_element_by_id()这种方法的通用函数版本,比如find_element_by_id(id)就等价于find_element(By.ID, id)。

我们用代码实现一下:

这样的查找方式实际上功能和上面列举的查找函数完全一致,不过参数更加灵活。

如果我们查找的目标在网页中只有一个,那么完全可以用find_element()方法,但如果有多个元素,再用find_element()方法查找就只能得到第一个元素了,如果要查找所有满足条件的元素,那就需要用find_elements()这样的方法了,方法名称中element多了一个s。

比如我们在这里查找淘宝导航条的所有条目就可以这样来写:

在此简化了一下输出结果,中间部分省略。

可以看到得到的内容就变成了list类型,list的每个元素都是WebElement类型。

也就是说,如果我们用find_element()方法,只能获取匹配的第一个元素,结果是WebElement类型,如果用find_elements()方法,则结果是list类型,listd每个元素是WebElement类型。

函数的列表如下:

find_elements_by_idfind_elements_by_namefind_elements_by_xpathfind_elements_by_link_textfind_elements_by_partial_link_textfind_elements_by_tag_namefind_elements_by_class_namefind_elements_by_css_selector

当然我们和刚才一样,也可可以直接find_elements()方法来选择,所以也可以这样来写:

结果是完全一致的。

Selenium可以驱动浏览器来执行一些操作,也就是说我们可以让浏览器模拟执行一些动作,比较常见的用法有:

输入文字用send_keys()方法,清空文字用clear()方法,另外还有按钮点击,用click()方法。

我们用一个实例来感受一下:

在这里我们首先驱动浏览器打开淘宝,然后用find_element_by_id()方法获取输入框,然后用send_keys()方法输入iPhone文字,等待一秒之后用clear()方法清空输入框,再次调用send_keys()方法输入iPad文字,之后再用find_element_by_class_name()方法获取搜索按钮,最后调用click()方法完成搜索动作。

通过上面的方法我们就完成了一些常见元素的动作操作,更多的操作可以参见官方文档的交互动作介绍:http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.remote.webelement

在上面的实例中,一些交互动作都是针对某个元素执行的,比如输入框我们就调用它的输入文字和清空文字方法,按钮就调用它的点击方法,其实还有另外的一些操作它是没有特定的执行对象的。比如鼠标拖拽,键盘按键等操作。所以这些动作我们有另一种方式来执行,那就是加到动作链中。

比如我们现在实现一个元素拖拽操作,将某个元素从一处拖拽到另外一处,我们用代码来感受一下:

首先我们打开网页中的一个拖拽实例,然后依次选中要被拖拽的元素和拖拽到的目标元素,然后声明了ActionChains对象赋值为actions变量,然后通过调用actions变量的drag_and_drop()方法,然后再调用perform()方法执行动作,就完成了拖拽操作。

更多的动作链操作可以参考官方文档的动作链介绍:http://selenium-python.readthedocs.io/api.html#module-selenium.webdrivermon.action_chains

另外对于某些操作,API没有提供的,如下拉进度条等,可以直接模拟运行JavaScript,使用execute_script()方法。

在这里我们就利用了execute_script()方法将进度条下拉到最底部,然后弹出alert提示框。

所以说有了这个,基本上API没有提供的所有的功能都可以用执行JavaScript的方式来实现了。

我们在前面说过通过page_source属性可以获取网页的源代码,获取源代码之后就可以使用解析库如正则、BeautifulSoup、PyQuery等来提取信息了。

不过既然Selenium已经提供了选择元素的方法,返回的是WebElement类型,那么它也有相关的方法和属性来直接提取元素信息,如属性、文本等等。这样的话我们能就不用通过解析源代码来提取信息了,非常方便。

那接下来我们就看一下可以通过怎样的方式来获取元素信息吧。

我们可以使用get_attribute()方法来获取元素的属性,那么这个的前提就是先选中这个元素。

我们用一个实例来感受一下:

运行之后程序便会驱动浏览器打开知乎的页面,然后获取知乎的LOGO元素,然后将它的class打印出来。

控制台输出结果:

我们通过get_attribute()方法,然后传入想要获取的属性名,就可以得到它的值了。

每个WebEelement元素都有text属性,我们可以通过直接调用这个属性就可以得到元素内部的文本信息了,就相当于BeautifulSoup的get_text()方法、PyQuery的text()方法。

我们用一个实例来感受一下:

在这里们依然是先打开知乎页面,然后获取提问按钮这个元素,再将其文本值打印出来。

控制台输出结果:

另外WebElement元素还有一些其他的属性,比如id属性可以获取元素id,location可以获取该元素在页面中的相对位置,tag_name可以获取标签名称 ,size可以获取元素的大小,也就是宽高,这些属性有时候还是很有用的。

我们用实例来感受一下:

在这里我们首先获得了提问按钮这个元素,然后调用其id、location、tag_name、size属性即可获取对应的属性值。

我们知道在网页中有这样一种标签叫做iframe,也就是子Frame,相当于页面的子页面,它的结构和外部网页的结构是完全一致的。Selenium打开页面后,它默认是在父级Frame里面操作,而此时如果页面中还有子Frame,它是不能获取到子Frame里面的元素的。所以这时候我们就需要使用switch_to.frame()方法来切换Frame。

我们首先用一个实例来感受一下:

我们还是以上文演示动作链操作的网页为实例,首先我们通过switch_to.frame()方法切换到子Frame里面,然后我们尝试获取父级Frame里的LOGO元素,是不能找到的,找不到的话就会抛出NoSuchElementException异常,异常被捕捉之后就会输出NO LOGO,接下来我们重新切换回父Frame,然后再次重新获取元素,发现就可以成功获取了。

所以,当页面中包含子Frame时,如果我们想获取子Frame中的元素,需要先调用switch_to.frame()方法切换到对应的Frame,然后再进行操作。

在Selenium中,get()方法会在网页框架加载结束之后就结束执行,此时如果获取page_source可能并不是浏览器完全加载完成的页面,如果某些页面有额外的Ajax请求,我们在网页源代码中也不一定能成功获取到。所以这里我们需要延时等待一定时间确保元素已经加载出来。

在这里等待的方式有两种,一种隐式等待,一种显式等待。

当使用了隐式等待执行测试的时候,如果Selenium没有在DOM中找到元素,将继续等待,超出设定时间后则抛出找不到元素的异常, 换句话说,当查找元素而元素并没有立即出现的时候,隐式等待将等待一段时间再查找 DOM,默认的时间是0。

我们用一个实例来感受一下:

在这里我们用implicitly_wait()方法实现了隐式等待。

隐式等待的效果其实并没有那么好,因为我们只是规定了一个固定时间,而页面的加载时间是受到网络条件影响的。

所以在这里还有一种更合适的显式等待方法,它指定好要查找的元素,然后指定一个最长等待时间。如果在规定时间内加载出来了这个元素,那就返回查找的元素,如果到了规定时间依然没有加载出该元素,则会抛出超时异常。

我们用一个实例来感受一下:

在这里我们首先引入了WebDriverWait这个对象,指定好最长等待时间,然后调用它的until()方法,传入要等待条件expected_conditions,比如在这里我们传入了presence_of_element_located这个条件,就代表元素出现的意思,其参数是元素的定位元组,也就是ID为q的元素搜索框。

所以这样可以做到的效果就是,在10秒内如果ID为q的元素即搜索框成功加载出来了,那就返回该元素,如果超过10秒还没有加载出来,那就抛出异常。

对于按钮,可以更改一下等待条件,比如改为element_to_be_clickable,也就是可点击,所以查找按钮时是查找CSS选择器为.btn-search的按钮,如果10秒内它是可点击的也就是成功加载出来了,那就返回这个按钮元素,如果超过10秒还不可点击,也就是没有加载出来,那就抛出异常。

运行代码,在网速较佳的情况下是可以成功加载出来的。

控制台输出:

可以看到控制台成功输出了两个元素,都是WebElement类型。

如果网络有问题,10秒内没有成功加载,那就抛出TimeoutException,控制台输出如下:

关于等待条件,其实还有很多,比如判断标题内容,判断某个元素内是否出现了某文字,在这里将所有的加载条件列举如下:

等待条件含义

title_is标题是某内容

title_contains标题包含某内容

presence_of_element_located元素加载出,传入定位元组,如(By.ID, 'p')

visibility_of_element_located元素可见,传入定位元组

visibility_of可见,传入元素对象

presence_of_all_elements_located所有元素加载出

text_to_be_present_in_element某个元素文本包含某文字

text_to_be_present_in_element_value某个元素值包含某文字

frame_to_be_available_and_switch_to_it frame加载并切换

invisibility_of_element_located元素不可见

element_to_be_clickable元素可点击

staleness_of判断一个元素是否仍在DOM,可判断页面是否已经刷新

element_to_be_selected元素可选择,传元素对象

element_located_to_be_selected元素可选择,传入定位元组

element_selection_state_to_be传入元素对象以及状态,相等返回True,否则返回False

element_located_selection_state_to_be传入定位元组以及状态,相等返回True,否则返回False

alert_is_present是否出现Alert

更多详细的等待条件的参数及用法介绍可以参考官方文档:http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.support.expected_conditions

我们平常使用浏览器都有前进和后退功能,使用Selenium也可以完成这个操作,使用back()方法可以后退,forward()方法可以前进。

我们用一个实例来感受一下:

在这里我们连续访问三个页面,然后调用back()方法就可以回到第二个页面,接下来再调用forward()方法又可以前进到第三个页面。

使用Selenium还可以方便地对Cookies进行操作,例如获取、添加、删除Cookies等等。

我们再用实例来感受一下:

首先我们访问了知乎,然后加载完成之后,浏览器实际上已经生成了Cookies了,我们调用get_cookies()方法就可以获取所有的Cookies,然后我们添加一个C...

Kaggle首次定义数据科学家:30岁,年薪5万刀,爱Python,最恨脏数据 企业视频课程

img

飘摇

关注

大数据文摘作品

作者:龙牧雪 魏子敏

今日凌晨,全球最大的数据科学社群Kaggle发布了第一份数据科学/机器学习业界现状调查报告。这份调查问卷的受访者囊括了来自50多个国家的16,000+位从业者,根据他们的问卷结果,Kaggle给出了一些有趣的结论:

1、Python可能是机器学习最常用的编程语言,而统计学家更多地使用R语言;

2、数据科学家的年龄中位数是30岁,而各国差异巨大,比如,印度的受访人比澳大利亚平均年龄年轻9岁;

3、受访者中硕士学位所占比重最大,但薪水最高的从业者($150k)多数拥有博士学位。

本次报告的发布也别具一格地采用了交互数据集的方式,并提供了样本数据集供读者自行分析,大数据文摘也得以利用这一数据集分析出了一些与中国数据科学从业者相关的结论,比如:

1、中国从业者更年轻:中国数据玩家年龄中位数25岁,比这一统计值的全球数据(30岁)小五岁;

2、从业者男女比例更加不均:中国仅有72名女性数据玩家填写了问卷,而男性有387人。男女比5.4:1;

关注大数据文摘,在公众号后台对话框内回复“Kaggle”,即可直接下载这份数据集自己玩~

Kaggle同时为这份数据集设置了1000美金的奖项,如果你有新发现,可以将自己的分析上传至Kaggle,地址

https://kaggle/kaggle/kaggle-survey-2017

以下为报告精华:

数据科学从业者画像

定义数据科学从业者的方式很多,Kaggle将从工作和背景的两个方向进行统计:

“你的年龄多大?”

平均来看,问卷调查填写者的年龄中位数在30岁左右,但不同国家的这一数值也不尽相同,比如印度的受访者就比澳大利亚年轻9岁。

中国数据玩家年龄中位数尽管高于印度,但仍然低于全球平均值,只有25岁。

“你的性别是什么?”

在性别这一栏,这份报告给了我们比较符合预期的结论,男女比例不均。

在全球的问卷填写者中,共有13427位男性和2714位女性,男女比4.9:1。

而在中国,仅有72名女性数据玩家填写了问卷,而男性有387人。男女比5.4:1。

“你的就业情况如何?”

数据科学从业者的崛起让自由职业者和兼职工作成为一种新潮流,而这一报告也应证了这一结论。在全球,仅有65%的数据玩家拥有全职工作,而8%是自由职业。

相较之下,中国回答者的“没有工作也不在找工作”的比例非常高(考虑到中国的回答者人数较少-只有400人,文摘菌认为这个结果可能是学生比例较高造成的)。

“你的职位是什么?”

自从“数据科学家”被誉为全球最性感的职位后,这个职位也成为了很多从业者的奋斗目标。而从调查结果看,全球范围内,使用“数据科学家”作为自己Title的从业者比例最高,占到24.4%。

“你的年薪是多少?”

如果看薪酬,最高一级薪酬是年收入20万美元以上,这一档全球有166人,相对于不分薪酬的数据科学家比例(24.4%),数据科学家比例有显著提升(35.5%)。

全球数据相关从业者平均年薪55441美元(约合37万人民币)。

收入上也有男女不均:男性比女性多收入3000美金/年。

中国数据相关从业者平均年薪29835美元(约合20万人民币)。考虑到只有66人回答了这一问题,结果解读需谨慎。

“你的最高学历是什么?”

全球范围内,取得硕士学位的从业者最多。

按薪酬来看,年薪150k-200k美金和200k+美金的人群多数取得了博士学位。

这一题中国有420人回答,仍是取得硕士学位的人最多且比例和全球水平接近。博士的比例(11.2%)比全球(15.6%)少。

数据科学从业者日常工作内容

Kaggle给数据科学家的定义是,“写代码并且分析数据的人群”。通过问询问卷填写者的日常工作,报告得到了如下结论:

“你的工作中用到哪些数据科学方法?”

逻辑回归在数据科学从业者中最常被用到,占63.5%。

“工作中最常用到的工具?”

python python python

但职位是“统计学家”的人还是显著地喜欢用R。

“工作中常用的数据类型是?”

工作中用到的数据主要是关系型数据,主要使用Git共享代码。

“工作中遇到的最大的困难?”

脏数据!看来数据科学领域最大的问题还是脏数据。排名第二的困难是“缺少数据科学人才”。正在学习数据科学的小伙伴们,你们前途无量呀!请带文摘菌一起飞!

新手如何入行数据科学领域?

作为一个数据科学学习社区,Kaggle在这份报告中也提出了一些数据科学老司机给新手学习者的建议,可以说是非常良心了!(这一部分可能是本份报告中最有价值的部分,文摘菌敲黑板划重点啦!)

“你们会推荐新手先学哪门语言?”

先学Python!这是Kaggle综合了超一万名老司机的意见给出的结论。

“你最常使用哪种数据科学学习资源?”

数据科学是一个日新月异的领域,保持持续的学习能力非常重要。据调研问卷显示,数据科学老司机最常用到的学习资源包括Stack Overflow Q&A,相关论坛,以及Podcasts。而关于开源内容,数据科学从业者更多使用官方文档和观看 Youtube 视频。

“你从何获取开源数据?”

没有数据就没有数据科学,所以提到数据科学学习技能,不得不提到获取开源优质数据的能力。报告中提到了一些优质数据获取渠道,包括Dataset aggregator, Google Search等。

“怎么找工作?”

数据科学从业老司机在找工作上的忠告也非常有趣:去公司官网或相关网站的技术板块乃下下策,他们更建议的方式是,直接联系招聘人,或建立自己的关系网。

最后,对所有正在阅读问卷结果的人,文摘菌想特意说明Kaggle在问卷中备注的一句话:每个人都是独特的,不是一个个平均数就能代表的。问卷的结论建立在1.6万名Kaggle使用者的答案上,但他们只是数据从业者的一小部分——年龄、性别、所在地区、职位、薪酬、经验和所受教育的不同都无法阻止我们对数据科学的热爱!

教程 | 如何构建自定义人脸识别数据集 营销视频课程

img

由盼烟

关注

选自pyimagesearch

作者:Adrian Rosebrock

机器之心编译

参与:Geek AI、路

本文介绍了构建自定义人脸识别数据集的三种方法:使用 OpenCV 和 webcam 工具收集人脸图像数据;以编程的方式下载人脸图像;手动收集人脸图像。

在接下来的几篇博文中,作者将带领大家训练一个「计算机视觉+深度学习」的模型来执行人脸识别任务。但是,要想训练出能够识别图像或视频流中人脸的模型,我们首先得收集人脸图像的数据集。

如果你使用的是「Labeled Faces in the Wild」(LFW)这样预先准备好的数据集,那么你可以不用进行这项困难的工作了。你可以使用我们下一篇博文中的方法创建自己的人脸识别应用。

然而,对于大多数人来说,我们希望识别出的人脸往往不包含在任何现有数据集中,例如:我们自己的、朋友的、家人或者同事的人脸图像。

为了完成这个任务,我们需要收集我们想要识别的人脸样本,并且以某种方式量化它们。

这个过程通常被称为「人脸识别注册」(facial recognition enrollment)。我们称之为「注册」是因为在这个过程中,我们会将用户注册、登记为我们的数据集和应用中的一个真人样本。

本文将介绍注册过程的第一步:创建自定义人脸识别数据集。

如何创建自定义人脸识别数据集

本教程中,我们将介绍 3 种创建自定义人脸识别数据集的方法。第一种方法使用 OpenCV 和 webcam 工具完成两个任务:(1)在视频中检测出人脸;(2)将人脸图像或视频帧的样本保存到磁盘上。

第二种方法将讨论如何以编程的方式下载人脸图像。

最后,我们将讨论如何手动收集人脸图像,以及这种方法何时是适用的。

让我们开始构建人脸识别数据集吧!

方法 1:通过 OpenCV 和 webcam 进行人脸注册

图 1:通过使用 OpenCV 和 webcam,我们可以检测出视频流中的人脸,并且将样本存储到磁盘上。这个过程可用于创建一个本地人脸识别数据集。

这种方法适用于以下情况:

1. 你要创建一个」能现场使用的」人脸识别系统;

2. 你需要拥有接触特定人的物理途径,以收集他们的人脸图像数据。

这样的系统尤其适用于公司、学校或者其他人们每天亲自出现在现场的组织。

为了收集这些人的人脸图像样本,我们可能需要将他们置于一个特殊的房间中,房间中事先安装好了视频摄影机,用于:(1)检测视频流中人脸的 (x, y) 坐标;(2)将包含用户人脸的视频帧写入磁盘。我们可能甚至需要好几天或者几周的时间执行上述操作,以收集下列几种情况下的人脸样本:

不同的光照条件一天中不同的时间不同的情绪和情感状态

通过收集不同情况下的人脸样本,我们可以创建一个更加多样化、更具代表性的特定用户人脸图像数据集。

接下来,我们使用一个简单的 Python 脚本构建自定义人脸识别数据集。这个 Python 脚本可以完成以下任务:

1. 连接到我们的 webcam;

2. 检测人脸;

3. 将包含人脸的视频帧写入磁盘。

想要获取本文中使用的代码,请滚动到本文的「Downloads」部分。

准备好之后,请打开 build_face_dataset.py 文件,然后我们来一步一步解读这份代码:

在 2-7 行中,我们导入了所需程序包。尤其是我们所需要的 Opencv 和 imutils 包。安装 Opencv 的方法请参考我提供的这篇安装指南(https://pyimagesearch/opencv-tutorials-resources-guides/)。而 imutils 包则可以很容易地通过 pip 工具进行安装或升级:

$ pip install --upgrade imutils

如果你使用的是 Python 虚拟环境,请不要忘记使用 workon 命令!

环境安装好之后,我们接下来将讨论两个需要用到的命令行参数:

命令行参数会在运行时被一个名为 argparse 的程序包(这个程序包会在安装 Python 环境时被自动安装)解析。如果你对于 argparse 和命令行参数不太熟悉,我强烈推荐你迅速浏览这篇博文(https://pyimagesearch/2018/03/12/python-argparse-command-line-arguments/)。

我们有两个需要用到的命令行参数:

--cascade:哈尔级联(Haar cascade)文件在磁盘上的路径。--output:输出文件夹的路径。人脸图像会被存储在这个文件夹中,因此我推荐你用人脸主人的名字来命名这个文件夹。例如,如果你收集的是「John Smith」的人脸图像,你可以将所有的图片存放在 dataset/john_smith 文件夹中。

下面,我们将加载人脸的哈尔级联文件并且初始化视频流:

在第 18 行中,我们加载了 OpenCV 的哈尔级联 detector。这个 detector 会在接下来的逐帧循环中完成繁重的任务。

我们在第 24 行初始化并开始我们的视频流。

注意:如果你使用的是树莓派,请注释掉第 24 行,并且取消第 25 行的注释。

为了让摄像头预热,我们简单地将程序暂停 2 秒(第 26 行)。

我们还初始化了一个计数器 total,用于表示在磁盘上存储的人脸图像数量(第 27 行)。

现在让我们在视频流上进行逐帧循环:

在第 30 行中,我们开始循环(按下「q」键则退出循环)。

从这一行起,我们获取了一个视频帧 frame,创建了该帧的一个副本,并且改变了图像的尺寸(第 34-36 行)。

现在,是时候执行人脸检测了!

我们可以使用 detectMultiScale 方法检测视频帧 frame 中的人脸。该函数需要用到下列参数:

image:一个灰度图;scaleFactor:指定在每个尺度上,图像缩小多少;minNeighbor:为了保证检测的有效性,该参数指定每一个候选矩形边界框需要有多少相邻的检测点;minSize:可能的最小图片尺寸。

不幸的是,有时我们需要对这种方法进行调优,以消除误判或者检测出一张完整的人脸,但是对于「近距离」拍摄的人脸图像的检测来说,这些参数是一个很好的起点。

话虽如此,你是否也在寻找一种更加先进、更加可靠的方法呢?在之前的博文中(https://pyimagesearch/2018/02/26/face-detection-with-opencv-and-deep-learning/),我用 OpenCV 和深度学习实现了人脸检测。你可以通过文章中使用了预训练模型的深度学习方法很容易地更新本文中的脚本。该方法的好处是,不用调参并且训练十分快。

这种人脸识别方法的结果是一个 rects(矩形边界框)列表。在第 44、45 行中,我们在 rects 上进行循环,并且在帧上画出矩形边框,以方便展示。

最后一步,我们将在循环中进行两个工作:(1)在屏幕上展示视频帧;(2)处理按键响应。具体代码如下:

在第 48 行中,我们在屏幕上展示了视频帧,接下来在第 49 行中获取了键入值。

根据按下的是「k」还是「q」,我们会:

如果按下「k」键,我们将保留视频帧并将它存储到磁盘上(第 53-56 行),并且增加表示获取到的总帧数的计数器 total(第 58 行)。我们需要在想保留的每一帧处按下「k」键。我建议保留不同角度、不同的帧区域、戴/不戴眼镜等不同情况下拍摄的人脸图像。如果按下「q」键,则退出循环,准备退出脚本(quit)。

如果没有按下任何键,我们就回到循环的开头,从视频流中获取一帧。

最终我们将在终端上打印出最终存储的图像数量,并进行清理:

现在让我们运行脚本,收集人脸图像吧!

请确保你已经从本文的「Downloads」部分下载了代码和哈尔级联。

在你的终端设备中执行下列命令:

$ python build_face_dataset.py --cascade haarcascade_frontalface_default.xml --output dataset/adrian[INFO] starting video stream...[INFO] 6 face images stored[INFO] cleaning up...

在运行完脚本之后,我们发现有 6 张图像被存储到了 dataset 文件夹的 adrian 子文件夹中:

$ ls dataset/adrian00000.png 00002.png 00004.png00001.png 00003.png 00005.png

我建议将人脸图像样本存在以图像所属人的名字命名的子文件夹中。

通过这种方式可以强化你的自定义人脸识别数据集的组织结构。

方法 2:通过编程下载人脸图像

图 2:另一种构建人脸识别数据集的方法(如果此人是公众人物,或者在网络上出现过),是通过一个脚本在谷歌上进行图像搜索,或者使用一个利用了 Bing 图像搜索 API 的 Python 脚本。

如果你不能在现场拍摄一个人的图像,或者他们是在网络上存在感很强的公众人物(在某种程度上),你可以通过各种平台上的 API 以编程的方式下载他们的人脸图像样本。选择哪种 API 很大程度上取决于你想要收集的是谁的人脸图像。

例如,如果一个人一直在 Twitter 或 Instagram 上发帖,你可能想要用其中一种(或者其他的)社交网络 API 获取人脸图像。

另一种选择是,使用像谷歌或 Bing 这样的搜索引擎:

使用这篇文章中的方法(https://pyimagesearch/2017/12/04/how-to-create-a-deep-learning-dataset-using-google-images/),你可以使用谷歌图像「Google Images」手动+编程地为给定的查询下载示例图像。在我看来,一个更好的选择可能是,使用 Bing 的图像搜索 API,它是完全自动化的且不需要手动干预。我在这篇文章中实现了这个全自动化方法(https://pyimagesearch/2018/04/09/how-to-quickly-build-a-deep-learning-image-dataset/)。

使用后一种方法,我可以从《侏罗纪公园》和《侏罗纪世界》中下载 218 张人脸图像。

通过 Bing 图像搜索 API 下载 Owen Grady 的人脸图像的命令示例如下:

$ mkdir dataset/owen_grady$ python search_bing_api.py --query "owen grady" --output dataset/owen_grady

现在让我们来看整个数据集(删除不包含该人物人脸的图像后):

$ tree jp_dataset --filelimit 10jp_dataset├── alan_grant [22 entries]├── claire_dearing [53 entries]├── ellie_sattler [31 entries]├── ian_malcolm [41 entries]├── john_hammond [36 entries]└── owen_grady [35 entries]6 directories, 0 files

在短短 20 多分钟内(包括删除误判样本的时间),我就能收集到《侏罗纪公园》/《侏罗纪世界》的自定义人脸数据集:

图 3:通过 Python 和 Bing 图像搜索 API 以编程的方式创建出的人脸识别数据集示例。图中是《侏罗纪公园》系列电影中的六个人物。

方法 3:手动收集人脸图像

图 4:手动下载人脸图像是最不可取的选项,但你不该忘记它。当一个人并不经常在网络上出现,或者图像没有标签时,你可以使用这种方法。

最后一种创建自定义人脸识别数据集的方法也是最不可取的一种,是手动寻找并存储人脸图像样本。

这种方法显然是最乏味的,且需要耗费最多的人工工作时间——通常我们更喜欢「自动化」的解决方案,但是在某些情况下,你不得不付诸人工。

使用此方法,你需要手动检查:

搜索引擎的搜索结果(例如,谷歌和 Bing)社交网络资料(Facebook、Twitter、Instagram、SnapChat 等)图片分享服务(Google Photos、Flickr 等)

然后手动将这些图像存储到磁盘上。

在这些场景下,用户通常具备某种类型的公开资料,但是比以编程的方式用爬虫爬到的图像要少得多。

PyImageSearch Gurus(免费)示范课程

图 5:在 PyImageSearch Gurus 课程(https://pyimagesearch/pyimagesearch-gurus/)中,你将学会构建人脸识别安防系统。当一个未经授权的入侵者坐在你的桌前时,它会通过文本消息(包含图像)提醒你。

总结

本文介绍了三种为人脸识别任务创建自定义人脸数据集的方法。

你具体会选择哪种方法完全取决于你自己的人脸识别应用。

如果你正在构建一个「现场」的人脸识别系统,例如用于教室、公司或其他组织的人脸识别系统,你可能会让用户进入专门用于收集示例人脸图像的房间,然后在那里继续从视频流中捕获人脸图像 (方法 1)。

另一方面,如果你正在构建一个包含公众人物、名人、运动员等的人脸识别系统,那么在网上可能有他们足够多的人脸图像样本。在这种情况下,你可以利用现有的 API 以编程方式下载人脸图像样本 (方法 2)。

最后,如果你试图识别的面孔在网上没有公开的个人资料(或者个人资料非常有限),你可能需要手动收集和管理人脸数据集 (方法 3)。这显然是最人工、最繁琐的方法,但在某些情况下,如果你想识别某些面孔,可能需要使用这种方法。

千字文书法集字检索,用Python辅助只需要8行代码! 企业视频课程

img

尔芙

关注

一般认为《千字文》是南朝梁周兴嗣受梁武帝萧衍的指派,将从书圣王羲之法书中搨选下来的1000个字字相异的字缀集而成,因此《千字文》自然而然与书法艺术结下了不解之缘,又因其蒙养的功用,普及甚广,在中国书法史上占据着独特的地位。历代书家,多有喜好书写《千字文》者,如隋代的智永,唐代的张旭、怀素,宋代的宋徽宗赵佶,元代的赵孟、鲜于枢,明代的祝允明、文徵明、董其昌,清代的傅山、邓石如、赵之谦等等,为我们留下了大量珍贵的《千字文》书迹。从《千字文》中检索单字不难,但是按照词句批量检索就得要有专门的工具了。比如,“三人行必有我师”,在千字文中的分布位置是:

“三”在《千字文》中没有此字。

要实现对《千字文》的集字检索,可以用Python,而且只需要短短的8行代码。首先得准备《千字文》全文,不分行,无空格或标点分隔,并比如我的c:\qzw4search.txt:

这8行代码是

代码的逻辑很简单,基本上接近“自然语义”。我们拿来查询诸葛亮《诫子书》中头几句的结果是:

从中可以看出“俭、澹、泊”这三个字找不到,得专门用书法字典查找。

我们在学习小篆的时候,使用的是邓石如《篆书千字文》:

结合程序查询的结果,手工补充上《千字文》中找不到的几个字,做出来的集字帖样貌是:

看着还不错吧?

增加检测类别?这是一份目标检测的一般指南 行业视频课程

img

神龙

关注

目标检测技术作为计算机视觉的重要方向,被广泛应用于自动驾驶汽车、智能摄像头、人脸识别及大量有价值的应用上。这些系统除了可以对图像中的每个目标进行识别、分类以外,它们还可以通过在该目标周围绘制适当大小的边界框来对其进行定位。本文作者从图像识别与目标检测的区别开始,进一步简单介绍了目标检测的基本模块与实现方法。本文是目标检测的一般指南,它并没有详细介绍主流的目标检测算法,这些算法读者可参考从 RCNN 到 SSD,这应该是最全的一份目标检测算法盘点。

本文受 PyImageSearch 的读者 Ezekiel 的启发,他上个星期在邮件中咨询道:

Adrian 你好,我仔细地浏览了您之前关于深度学习目标检测 的文章及其跟进的实时深度学习目标检测 。感谢你做的这一切,我在自己的样例项目中使用了你的源代码,但是我有两个问题:1. 我该如何过滤/忽略那些我不感兴趣的类?2. 我如何才能向自己的目标检测器中增加新类别?有这个可能吗?如果你能就这两个问题写一篇文章,我将不胜感激。Ezekiel 并不是受此问题困扰的唯一读者。事实上,如果你仔细浏览了我最近关于深度目标检测两篇文章的评论,你会发现最常见的问题可以被表述为:我该如何修改你的源代码来包含我自己的类别?

由于这是一个如此常见的问题,并且是关于神经网络/深度学习目标检测器实际工作的一个误解,所以我决定在今天的博客中重温深度学习目标检测的话题。

具体地,你将在这篇文章中学到以下内容:

图像分类和目标检测的区别深度学习目标检测器的组成:包含不同目标检测架构的区别和基本模型之间的区别如何使用预训练模型进行深度学习目标检测如何从一个深度学习模型中过滤或者忽略一些预测类别向深度神经网络增加类别或从中删除类别时常见的误区和误解

为了更多地了解深度学习目标检测,并解释清楚我们对基于深度学习的目标检测的一些误区和误解,请继续阅读本文。

想要查看本文相关的源码?请查看原文的下载链接(https://pyimagesearch/2018/05/14/a-gentle-guide-to-deep-learning-object-detection/#):

深度学习目标检测的一般指南

今天的博客是对基于深度学习的目标检测的简单介绍。我尽可能对深度学习目标检测器的组成做一个概述,包括使用预训练的目标检测器执行任务的源代码。

你可以使用这份指南来帮助学习深度学习目标检测,但是也要意识到,目标检测是高度细节化的工作,我不可能在一篇文章中包含关于深度学习目标检测的所有细节。

这篇文章将从讨论图像分类和目标检测之间的本质区别开始,其中包括判断一个图像分类网络是否可以用于目标检测,以及在什么情况下可以这样使用等话题。

当我们理解了什么是目标检测时,随后会概述一个深度学习目标检测器的核心模块。它一般包括目标检测架构和基本模型,不熟悉目标检测的读者可能会误解这两个部分。

在这里,我们将使用 OpenCV 来实现实时深度学习目标检测。我也会展示如何在不修改网络架构或者重新训练的情况下忽略或者过滤一些不感兴趣的目标类别。最后,我们通过讨论如何从深度学习目标检测器中增加或者删除类别来总结本文。

图像分类和目标检测的区别

图 1: 图像分类(左)和目标检测(右)的区别是比较直观和简单的。在图像分类中,整幅图像被分类为单一的标签。而在目标检测中,我们的神经网络还要找出图像中目标的位置(有可能是多个)。

在进行标准的图像分类时,我们将一张给定的图像输入到神经网络,然后得到一个最可能的标签,而且也许会同时得到相关的概率。

这个类别标签用来表征整个图像的内容,或者至少是图像最主要的可见内容。例如,上面的图 1 中,给定输入图像(左),我们的 CNN 给它的标签是「比格犬」。所以我们可以认为图像分类具有以下特点:

一张图像输入一个类别标签输出

无论是通过深度学习还是其他计算机视觉技术的目标检测,都是基于图像分类构建的,只不过需要精确定位每个对象在图像中出现的位置。在进行目标检测的时候,给定一张输入图像,我们期望得到:

一个边界框列表,或者一幅图像中每个对象的(x,y)坐标与每个边界框关联的类别标签与每个边界框和类别标签关联的概率或者置信度得分

图 1(右)展示了一个深度学习目标检测的例子。请注意,人物和狗都被用边界框找出了位置,同时类标签也被预测到了。

所以,目标检测允许我们:

向网络输入一张图像得到多个边界框以及类别标签

深度学习图像分类可以被用于目标检测吗?

图 2:非端到端深度学习的目标检测器使用一个滑动窗口(左)+图像金字塔(右)相结合的方法来分类。

所以现在你理解了图像分类和目标检测的根本区别:

在进行图像分类时,我们输入一张图像,得到一个输出类别然而在进行目标检测时,我们输入一张图像,得到多个边界框以及类别标签的输出

这自然引发这么一个问题:

我们可以拿一个已训练的分类网络,将其用于目标检测吗?

这个答案有些棘手,因为这在技术上是可以的,但是理由并不太明显。解决方案涉及:

1. 应用基于计算机视觉的标准目标检测方法(非深度学习方法),例如滑动窗口和图像金字塔等方法通常被用在 HOG+基于线性 SVM 的目标检测器。

2. 采用预训练的网络,并将其作为深度学习目标检测架构的基本网络(例如 Faster R-CNN, SSD, YOLO)。

方法 #1: 传统的目标检测技术路线

第一个方法不是纯端到端的深度学习目标检测器。相反,我们使用:

1. 固定尺寸的滑动窗口,它从左到右,自上而下滑动,来定位不同位置的对象。

2. 图像金字塔,用来检测不同尺度的对象

3. 一个预训练(分类)的 CNN 来分类

在滑动窗和对应图像金字塔每一次停留的时候,我们会提取 ROI(感兴趣区域),将其输入到 CNN 中,得到对 RIO 的分类。

如果标签 L 的分类概率比某个阈值 T 高,我们就将这个 ROI 的边界框标记为该标签(L)。对滑动窗和图像金字塔的每次停留都重复这个过程,我们就得到了目标检测器的输出。最终,我们对边界框应用非极大值抑制(NMS),得到最终输出的检测结果:

图 3:应用 NMS 会抑制重叠的和置信度不高的边界框。这个方法在一些特定的用例中是有效的,但是它通常比较慢和繁琐,也容易出错。

然而,这个方法也是值得学习的,因为它可以将任意图像分类网络转换为一个目标检测器,而不需要显式地训练一个端到端的深度学习目标检测器。这个方法可以节省大量的时间和精力,且效率的高低具体取决于你的用例。

方法 #2:目标检测架构的基本网络

第二个深度学习目标检测的方法允许我们将一个预训练的分类网络作为深度学习目标检测架构(例如 Faster R-CNN、SSD 或者 YOLO)的基本网络。

这个方法的好处是:你可以创建一个基于深度学习的复杂端到端目标检测器。

而其不足之处是:它需要一些关于深度学习目标检测器如何工作的知识,我们将在后面的部分中讨论这个问题。

深度学习目标检测器的模块

图 4: VGG16 基本网络是 SSD 深度学习目标检测框架的一个特征抽取模块。

深度学习目标检测器有很多模块,子模块以及更小的子模块,但是我们今天要重点关注的是深度学习入门读者所困惑的两个:

1. 目标检测框架(不包括 Faster R-CNN, SSD, YOLO)

2. 适合目标检测框架的基本网络

你可能已经比较熟悉基本网络(只是你之前并没听到它被称作基本网络而已)。基本网络就是你常用的分类 CNN 架构,包括:

VGGNetResNetMobileNetDenseNet

通常这些网络在大数据集上进行预训练来进行分类,例如 ImageNet,它们可以学习到很多具有鉴别能力的滤波器。

目标检测框架由很多组成部分和子模块构成。例如,Faster R-CNN 框架包括:

候选区域网络(RPN)一组锚点ROI 池化模块最终基于区域的卷积神经网络

在使用 SSD(单步检测器,single shot detectors)时,具有以下的组成部分:

多框(MultiBox)先验(Priors)固定先验(Fixed priors)

请记住,基本网络只是整个深度学习目标检测框架的众多组件之一,上文图 4 描述了 SSD 框架内部的 VGG-16 网络。通常,我们需要在基本网络上进行「网络手术」。这种修改:

让它变成全卷积的形式,并接受任意输入维度。剪除了基本网络中更深层的卷积和池化层,将它们以一系列新层(SSD)、新模块(Faster R-CNN),或者这两者的一些组合代替。

这里的「网络手术」是一种口语化的说法,它的意思是移除基本网络中的一些原始卷积层,将它们用新层替代。网络手术也是讲究策略的,我们移除一些不需要的部分,然后用一组新的部分来替代它们。

然后,当我们开始训练我们的框架进行目标检测时,(1)新层、模块和(2)基本网络的权重都被修改了。

再强调一次,综述关于不同深度学习目标检测框架是如何工作的(包括基本网络所起的作用)并不属于本文的探讨范围。

如果你对深度学习目标检测的完整综述(包括理论和实现)感兴趣,请参考机器之心曾经发过的文章:从 RCNN 到 SSD,这应该是最全的一份目标检测算法盘点 。

我是如何计算一个深度学习目标检测器的准确度的?

在评价目标检测器的性能时我们使用了一个叫做均值平均精度(mAP)的指标,它是以我们数据集中所有类别的交并比(IoU)为基础的。

交并比(IoU)

图 5: 在这个交并比的可视化例子中,标注边界框(绿色)可以与预测的边界框(红色)进行对比。IoU 与 mAP 一起被用来评价一个深度学习目标检测器的精度。计算 IoU 的简单方程如图 5(右)所示。

你通常会发现 IoU 和 mAP 被用于评价 HOG+线性 SVM 检测器、Haar cascades 以及基于深度学习的方法的性能;但是请记住,实际用于生成预测边界框的算法并不是那么重要。

任何一个以预测边界框作(以及可选择的标签)为输出的算法都可以用 IoU 来评价。更一般的地,为了使用 IoU 来评价任意一个目标检测器,我们需要:

1. 真实的边界框(也就是测试集中表明我们的目标在图像的哪个位置的人工标签)

2. 模型预测到的边界框

3. 如果你想一起计算召回率和精度,那么还需要真实类别标签和预测类别标签

在图 5(左)中,我展示了真实边界框(绿色)与预测边界框(红色)相比的可视化例子。IoU 的计算可以用图 5 右边的方程表示。

仔细检查这个方程你会发现,IoU 就是一个比值。在分子项中,我们计算了真实边界框和预测边界框重叠的区域。分母是一个并集,或者更简单地说,是由预测边界框和真实边界框所包括的区域。两者相除就得到了最终弄的得分:交并比。

平均精度均值(MAP)

图 6:为了计算目标检测器的 mAP@0.5,我们执行了以下计算。对于所有被标记为「正检测」(positive detection)、具备至少 0.5 的交并比(IoU)的对象,我们对所有 N 个类别计算 IoU (>0.5) 均值,然后对 N 个均值再求平均。这个指标就是 mAP@0.5。

为了在我们的数据集中评估目标检测器,我们需要同时基于以下两者的 IoU 来计算 mAP:

1. 基于每个类别(也就是说每个类别的平均 IoU);

2. 数据集中所有类别(也就是说所有类别平均 IoU 的均值,所以这个术语就是平均精度均值)。

为了计算每个类别的平均精度,我们在所有的数据点上计算某个类别的 IoU。一旦我们计算出了一个类别在每个数据点的 IoU,我们对它们求一次平均(第一次平均)。

为了计算 mAP,我们对所有的 N 个类别计算平均 IoU,然后对这 N 个平均值取平均值(均值的平均)。

通常我们使用 mAP@0.5,表示测试集中要被标记为「正检测」的目标必须具备的条件,真值不小于 0.5 的 IoU(并可以被正确地标记)。这里的 0.5 是可以调整的,但是在所有的目标检测数据集和挑战中,0.5 是一个相对标准的数值。

再次强调,这只是一个关于目标检测评价指标的快速指南,所以我将整个过程简化了一些。

使用 OpenCV 进行基于深度学习的目标检测

我们已经在本文以及之前的博客中讨论了深度学习和目标检测。出于完整性考虑,我们将在本文中概述实际的代码。

我们的例子包含以 MobileNet 作为基础模型的单次检测器(SSD)。该模型由 GitHub 用户 chuanqi305(https://github/chuanqi305/MobileNet-SSD)在 COCO 数据集上训练得到。更多细节请浏览我之前的文章(https://pyimagesearch/2017/09/11/object-detection-with-deep-learning-and-opencv/),这篇文章介绍了该模型以及相关的背景信息。

让我们回到 Ezekiel 在本文开始提出的第一个问题上。

1. 我该如何过滤/忽略那些我不感兴趣的类?

我会在下面的示例代码中回答这个问题,但是首先你需要准备一下系统:

你需要在 Python 虚拟环境中安装版本不低于 3.3 的 OpenCV(如果你在使用 python 虚拟环境的话)。OpenCV 3.3+ 包含运行以下代码所需的 DNN 模块。确保使用链接中的 OpenCV 安装教程之一(https://pyima...

TensorFlow和Caffe、MXNet、Keras等其他深度学习框架的对比 行业视频课程

img

唐定帮

关注

雷锋网按:本文作者黄文坚,PPmoney 大数据算法总监,《 TensorFlow 实战》作者。本文节选自《 TensorFlow 实战》第二章。

在下周二(2月28日)雷锋网硬创公开课栏目将会推出黄文坚老师的公开课《深度学习之经典卷积神经网络的技术浅析》(),欢迎大家报名!点击了解详情

Google 近日发布了 TensorFlow 1.0 候选版,这第一个稳定版将是深度学习框架发展中的里程碑的一步。自 TensorFlow 于 2015 年底正式开源,距今已有一年多,这期间 TensorFlow 不断给人以惊喜。在这一年多时间,TensorFlow 已从初入深度学习框架大战的新星,成为了几近垄断的行业事实标准。

主流深度学习框架对比

深度学习研究的热潮持续高涨,各种开源深度学习框架也层出不穷,其中包括 TensorFlow、Caffe、Keras、CNTK、Torch7、MXNet、Leaf、Theano、DeepLearning4、Lasagne、Neon 等等。然而 TensorFlow 却杀出重围,在关注度和用户数上都占据绝对优势,大有一统江湖之势。表 2-1 所示为各个开源框架在GitHub上的数据统计(数据统计于 2017 年 1 月 3 日),可以看到 TensorFlow 在 star 数量、fork 数量、contributor 数量这三个数据上都完胜其他对手。

究其原因,主要是 Google 在业界的号召力确实强大,之前也有许多成功的开源项目,以及 Google 强大的人工智能研发水平,都让大家对 Google 的深度学习框架充满信心,以至于 TensorFlow 在 2015 年 11 月刚开源的第一个月就积累了 10000+ 的 star 。其次,TensorFlow 确实在很多方面拥有优异的表现,比如设计神经网络结构的代码的简洁度,分布式深度学习算法的执行效率,还有部署的便利性,都是其得以胜出的亮点。如果一直关注着 TensorFlow 的开发进度,就会发现基本上每星期 TensorFlow 都会有1万行以上的代码更新,多则数万行。产品本身优异的质量、快速的迭代更新、活跃的社区和积极的反馈,形成了良性循环,可以想见 TensorFlow 未来将继续在各种深度学习框架中独占鳌头。

表2-1 各个开源框架在 GitHub 上的数据统计

观察表2-1还可以发现,Google、Microsoft、Facebook 等巨头都参与了这场深度学习框架大战,此外,还有毕业于伯克利大学的贾扬清主导开发的 Caffe,蒙特利尔大学 Lisa Lab 团队开发的 Theano,以及其他个人或商业组织贡献的框架。另外,可以看到各大主流框架基本都支持 Python,目前 Python 在科学计算和数据挖掘领域可以说是独领风骚。虽然有来自 R、Julia 等语言的竞争压力,但是 Python 的各种库实在是太完善了,Web 开发、数据可视化、数据预处理、数据库连接、爬虫等无所不能,有一个完美的生态环境。仅在数据挖据工具链上,Python 就有 NumPy、SciPy、Pandas、Scikit-learn、XGBoost 等组件,做数据采集和预处理都非常方便,并且之后的模型训练阶段可以和 TensorFlow 等基于 Python 的深度学习框架完美衔接。

表 2-1 和图 2-1 所示为对主流的深度学习框架 TensorFlow、Caffe、CNTK、Theano、Torch 在各个维度的评分,本书 2.2 节会对各个深度学习框架进行比较详细的介绍。

表2-2 主流深度学习框架在各个维度的评分

图2-1 主流深度学习框架对比图

各深度学习框架简介

在本节,我们先来看看目前各流行框架的异同,以及各自的特点和优势。

TensorFlow

TensorFlow 是相对高阶的机器学习库,用户可以方便地用它设计神经网络结构,而不必为了追求高效率的实现亲自写 C++或 CUDA 代码。它和 Theano 一样都支持自动求导,用户不需要再通过反向传播求解梯度。其核心代码和 Caffe 一样是用 C++编写的,使用 C++简化了线上部署的复杂度,并让手机这种内存和CPU资源都紧张的设备可以运行复杂模型(Python 则会比较消耗资源,并且执行效率不高)。除了核心代码的 C++接口,TensorFlow 还有官方的 Python、Go 和 Java 接口,是通过 SWIG(Simplified Wrapper and Interface Generator)实现的,这样用户就可以在一个硬件配置较好的机器中用 Python进行实验,并在资源比较紧张的嵌入式环境或需要低延迟的环境中用 C++部署模型。SWIG 支持给 C/C++代码提供各种语言的接口,因此其他脚本语言的接口未来也可以通过 SWIG 方便地添加。不过使用 Python 时有一个影响效率的问题是,每一个 mini-batch 要从 Python 中 feed 到网络中,这个过程在 mini-batch 的数据量很小或者运算时间很短时,可能会带来影响比较大的延迟。现在 TensorFlow 还有非官方的 Julia、Node.js、R 的接口支持,地址如下。

Julia: http://github/malmaud/TensorFlow.jl

Node.js: http://github/node-tensorflow/node-tensorflow

R: http://github/rstudio/tensorflow

TensorFlow 也有内置的 TF.Learn 和 TF.Slim 等上层组件可以帮助快速地设计新网络,并且兼容 Scikit-learn estimator 接口,可以方便地实现 evaluate、grid search、cross validation 等功能。同时 TensorFlow 不只局限于神经网络,其数据流式图支持非常自由的算法表达,当然也可以轻松实现深度学习以外的机器学习算法。事实上,只要可以将计算表示成计算图的形式,就可以使用 TensorFlow 。用户可以写内层循环代码控制计算图分支的计算,TensorFlow 会自动将相关的分支转为子图并执行迭代运算。TensorFlow 也可以将计算图中的各个节点分配到不同的设备执行,充分利用硬件资源。定义新的节点只需要写一个 Python 函数,如果没有对应的底层运算核,那么可能需要写 C++或者 CUDA 代码实现运算操作。

在数据并行模式上,TensorFlow 和 Parameter Server 很像,但 TensorFlow 有独立的 Variable node,不像其他框架有一个全局统一的参数服务器,因此参数同步更自由。TensorFlow 和 Spark 的核心都是一个数据计算的流式图,Spark 面向的是大规模的数据,支持 SQL 等操作,而 TensorFlow 主要面向内存足以装载模型参数的环境,这样可以最大化计算效率。

TensorFlow 的另外一个重要特点是它灵活的移植性,可以将同一份代码几乎不经过修改就轻松地部署到有任意数量 CPU 或 GPU 的 PC、服务器或者移动设备上。相比于 Theano,TensorFlow 还有一个优势就是它极快的编译速度,在定义新网络结构时,Theano 通常需要长时间的编译,因此尝试新模型需要比较大的代价,而 TensorFlow 完全没有这个问题。TensorFlow 还有功能强大的可视化组件 TensorBoard,能可视化网络结构和训练过程,对于观察复杂的网络结构和监控长时间、大规模的训练很有帮助。TensorFlow 针对生产环境高度优化,它产品级的高质量代码和设计都可以保证在生产环境中稳定运行,同时一旦 TensorFlow 广泛地被工业界使用,将产生良性循环,成为深度学习领域的事实标准。

除了支持常见的网络结构(卷积神经网络(Convolutional Neural Network,CNN)、循环神经网络(Recurent Neural Network,RNN))外,TensorFlow 还支持深度强化学习乃至其他计算密集的科学计算(如偏微分方程求解等)。TensorFlow 此前不支持 symbolic loop,需要使用 Python 循环而无法进行图编译优化,但最近新加入的 XLA 已经开始支持 JIT 和 AOT,另外它使用 bucketing trick 也可以比较高效地实现循环神经网络。TensorFlow 的一个薄弱地方可能在于计算图必须构建为静态图,这让很多计算变得难以实现,尤其是序列预测中经常使用的 beam search。

TensorFlow 的用户能够将训练好的模型方便地部署到多种硬件、操作系统平台上,支持 Intel 和 AMD 的 CPU,通过 CUDA 支持 NVIDIA 的 GPU (最近也开始通过 OpenCL 支持 AMD 的 GPU,但没有 CUDA 成熟),支持 Linux 和 Mac,最近在 0.12 版本中也开始尝试支持 Windows。在工业生产环境中,硬件设备有些是最新款的,有些是用了几年的老机型,来源可能比较复杂,TensorFlow 的异构性让它能够全面地支持各种硬件和操作系统。同时,其在 CPU 上的矩阵运算库使用了 Eigen 而不是 BLAS 库,能够基于 ARM 架构编译和优化,因此在移动设备(Android 和 iOS)上表现得很好。

TensorFlow 在最开始发布时只支持单机,而且只支持 CUDA 6.5 和 cuDNN v2,并且没有官方和其他深度学习框架的对比结果。在 2015 年年底,许多其他框架做了各种性能对比评测,每次 TensorFlow 都会作为较差的对照组出现。那个时期的 TensorFlow 真的不快,性能上仅和普遍认为很慢的 Theano 比肩,在各个框架中可以算是垫底。但是凭借 Google 强大的开发实力,很快支持了新版的 cuDNN (目前支持cuDNN v5.1),在单 GPU 上的性能追上了其他框架。表 2-3 所示为 给出的各个框架在 AlexNet 上单 GPU 的性能评测。https://github/soumith/convnet-benchmarks

表2-3 各深度学习框架在 AlexNet 上的性能对比

目前在单 GPU 的条件下,绝大多数深度学习框架都依赖于 cuDNN,因此只要硬件计算能力或者内存分配差异不大,最终训练速度不会相差太大。但是对于大规模深度学习来说,巨大的数据量使得单机很难在有限的时间完成训练。这时需要分布式计算使 GPU 集群乃至 TPU 集群并行计算,共同训练出一个模型,所以框架的分布式性能是至关重要的。TensorFlow 在 2016 年 4 月开源了分布式版本,使用 16 块 GPU 可达单 GPU 的 15 倍提速,在 50 块 GPU 时可达到 40 倍提速,分布式的效率很高。目前原生支持的分布式深度学习框架不多,只有 TensorFlow、CNTK、DeepLearning4J、MXNet 等。不过目前 TensorFlow 的设计对不同设备间的通信优化得不是很好,其单机的 reduction 只能用 CPU 处理,分布式的通信使用基于 socket 的 RPC,而不是速度更快的 RDMA,所以其分布式性能可能还没有达到最优。

Google 在 2016 年 2 月开源了 TensorFlow Serving,这个组件可以将 TensorFlow 训练好的模型导出,并部署成可以对外提供预测服务的 RESTful 接口,如图 2-2 所示。有了这个组件,TensorFlow 就可以实现应用机器学习的全流程:从训练模型、调试参数,到打包模型,最后部署服务,名副其实是一个从研究到生产整条流水线都齐备的框架。这里引用 TensorFlow 内部开发人员的描述:“ TensorFlow Serving 是一个为生产环境而设计的高性能的机器学习服务系统。它可以同时运行多个大规模深度学习模型,支持模型生命周期管理、算法实验,并可以高效地利用 GPU 资源,让 TensorFlow 训练好的模型更快捷方便地投入到实际生产环境”。除了 TensorFlow 以外的其他框架都缺少为生产环境部署的考虑,而 Google 作为广泛在实际产品中应用深度学习的巨头可能也意识到了这个机会,因此开发了这个部署服务的平台。TensorFlow Serving 可以说是一副王牌,将会帮 TensorFlow 成为行业标准做出巨大贡献。

图2-2 TensorFlow Serving 架构

TensorBoard 是 TensorFlow 的一组 Web 应用,用来监控 TensorFlow 运行过程,或可视化 Computation Graph。TensorBoard 目前支持五种可视化:标量(scalars)、图片(images)、音频(audio)、直方图(histograms)和计算图(Computation Graph)。TensorBoard 的 Events Dashboard 可以用来持续地监控运行时的关键指标,比如 loss、学习速率(learning rate)或是验证集上的准确率(accuracy);Image Dashboard 则可以展示训练过程中用户设定保存的图片,比如某个训练中间结果用 Matplotlib 等绘制(plot)出来的图片;Graph Explorer 则可以完全展示一个 TensorFlow 的计算图,并且支持缩放拖曳和查看节点属性。TensorBoard 的可视化效果如图 2-3 和图 2-4 所示。

图2-3 TensorBoard 的 loss 标量的可视化

图2-4 TensorBoard 的模型结构可视化

TensorFlow 拥有...

Python3中Selenium使用方法(连载) 行业视频课程

img

侯千儿

关注

欢迎关注天善智能,我们是专注于商业智能BI,大数据,数据分析领域的垂直社区,学习,问答、求职一站式搞定!

登陆天善社区查看更多系列:

Python3中BeautifulSoup的使用方法

Python3中PyQuery的使用方法

Python3中正则表达式使用方法

基本使用

首先我们来大体看一下Selenium有一些怎样的功能,先用一段实例代码来演示一下:

运行代码之后,如果正确配置好了ChromeDriver,可以发现会自动弹出一个浏览器,浏览器首先会跳转到百度,然后在搜索框中输入Python进行搜索,然后跳转到搜索结果页,等待搜索结果加载出来之后,控制台分别会输出当前的URL,当前的Cookies还有网页源代码。

控制台输出结果:

源代码过长在此省略,那么当前的URL,Cookies,源代码都是浏览器中的真实内容。所以说,如果我们用Selenium来驱动浏览器加载网页的话,我们就可以拿到JavaScrit渲染的结果了。

下面我们来详细介绍一下Selenium的用法。

Selenium支持非常多的浏览器,如Chrome、Firefox、Edge等,还有手机端的浏览器Android、BlackBerry等,另外无界面浏览器PhantomJS也同样支持。

我们可以用如下的方式初始化:

这样我们就完成了一个浏览器对象的初始化,接下来我们要做的就是调用browser对象,让其执行各个动作,就可以模拟浏览器操作了。

我们可以用get()方法来请求一个网页,参数传入链接URL即可,比如在这里我们用get()方法访问淘宝,然后打印出源代码,代码如下:

单个元素

Selenium可以驱动浏览器完成各种操作,比如填充表单,模拟点击等等,比如我们想要完成向某个输入框输入文字的操作,总得需要知道这个输入框在哪里吧?所以Selenium提供了一系列查找元素的方法,我们可以用这些方法来获取想要的元素,以便于下一步执行一些动作或者提取信息。

比如我们想要从淘宝页面中提取搜索框这个元素,首先观察它的源代码:

可以发现它的ID是q,Name也是q,还有许多其他属性,我们获取它的方式就有多种形式了,比如find_element_by_name()是根据Name值获取,ind_element_by_id()是根据ID获取,另外还有根据XPath、CSS Selector等获取。

我们代码实现一下:

在这里我们使用了三种方式获取输入框,根据ID,CSS Selector,和XPath获取,它们返回的结果是完全一致的。

运行结果:

可以看到三个元素都是WebElement类型,是完全一致的。

在这里列出所有获取单个元素的方法:

find_element_by_idfind_element_by_namefind_element_by_xpathfind_element_by_link_textfind_element_by_partial_link_textfind_element_by_tag_namefind_element_by_class_namefind_element_by_css_selector

另外Selenium还提供了通用的find_element()方法,它需要传入两个参数,一个是查找的方式By,另一个就是值,实际上它就是find_element_by_id()这种方法的通用函数版本,比如find_element_by_id(id)就等价于find_element(By.ID, id)。

我们用代码实现一下:

这样的查找方式实际上功能和上面列举的查找函数完全一致,不过参数更加灵活。

如果我们查找的目标在网页中只有一个,那么完全可以用find_element()方法,但如果有多个元素,再用find_element()方法查找就只能得到第一个元素了,如果要查找所有满足条件的元素,那就需要用find_elements()这样的方法了,方法名称中element多了一个s。

比如我们在这里查找淘宝导航条的所有条目就可以这样来写:

在此简化了一下输出结果,中间部分省略。

可以看到得到的内容就变成了list类型,list的每个元素都是WebElement类型。

也就是说,如果我们用find_element()方法,只能获取匹配的第一个元素,结果是WebElement类型,如果用find_elements()方法,则结果是list类型,listd每个元素是WebElement类型。

函数的列表如下:

find_elements_by_idfind_elements_by_namefind_elements_by_xpathfind_elements_by_link_textfind_elements_by_partial_link_textfind_elements_by_tag_namefind_elements_by_class_namefind_elements_by_css_selector

当然我们和刚才一样,也可可以直接find_elements()方法来选择,所以也可以这样来写:

结果是完全一致的。

Selenium可以驱动浏览器来执行一些操作,也就是说我们可以让浏览器模拟执行一些动作,比较常见的用法有:

输入文字用send_keys()方法,清空文字用clear()方法,另外还有按钮点击,用click()方法。

我们用一个实例来感受一下:

在这里我们首先驱动浏览器打开淘宝,然后用find_element_by_id()方法获取输入框,然后用send_keys()方法输入iPhone文字,等待一秒之后用clear()方法清空输入框,再次调用send_keys()方法输入iPad文字,之后再用find_element_by_class_name()方法获取搜索按钮,最后调用click()方法完成搜索动作。

通过上面的方法我们就完成了一些常见元素的动作操作,更多的操作可以参见官方文档的交互动作介绍:http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.remote.webelement

在上面的实例中,一些交互动作都是针对某个元素执行的,比如输入框我们就调用它的输入文字和清空文字方法,按钮就调用它的点击方法,其实还有另外的一些操作它是没有特定的执行对象的。比如鼠标拖拽,键盘按键等操作。所以这些动作我们有另一种方式来执行,那就是加到动作链中。

比如我们现在实现一个元素拖拽操作,将某个元素从一处拖拽到另外一处,我们用代码来感受一下:

首先我们打开网页中的一个拖拽实例,然后依次选中要被拖拽的元素和拖拽到的目标元素,然后声明了ActionChains对象赋值为actions变量,然后通过调用actions变量的drag_and_drop()方法,然后再调用perform()方法执行动作,就完成了拖拽操作。

更多的动作链操作可以参考官方文档的动作链介绍:http://selenium-python.readthedocs.io/api.html#module-selenium.webdrivermon.action_chains

另外对于某些操作,API没有提供的,如下拉进度条等,可以直接模拟运行JavaScript,使用execute_script()方法。

在这里我们就利用了execute_script()方法将进度条下拉到最底部,然后弹出alert提示框。

所以说有了这个,基本上API没有提供的所有的功能都可以用执行JavaScript的方式来实现了。

我们在前面说过通过page_source属性可以获取网页的源代码,获取源代码之后就可以使用解析库如正则、BeautifulSoup、PyQuery等来提取信息了。

不过既然Selenium已经提供了选择元素的方法,返回的是WebElement类型,那么它也有相关的方法和属性来直接提取元素信息,如属性、文本等等。这样的话我们能就不用通过解析源代码来提取信息了,非常方便。

那接下来我们就看一下可以通过怎样的方式来获取元素信息吧。

我们可以使用get_attribute()方法来获取元素的属性,那么这个的前提就是先选中这个元素。

我们用一个实例来感受一下:

运行之后程序便会驱动浏览器打开知乎的页面,然后获取知乎的LOGO元素,然后将它的class打印出来。

控制台输出结果:

我们通过get_attribute()方法,然后传入想要获取的属性名,就可以得到它的值了。

每个WebEelement元素都有text属性,我们可以通过直接调用这个属性就可以得到元素内部的文本信息了,就相当于BeautifulSoup的get_text()方法、PyQuery的text()方法。

我们用一个实例来感受一下:

在这里们依然是先打开知乎页面,然后获取提问按钮这个元素,再将其文本值打印出来。

控制台输出结果:

另外WebElement元素还有一些其他的属性,比如id属性可以获取元素id,location可以获取该元素在页面中的相对位置,tag_name可以获取标签名称 ,size可以获取元素的大小,也就是宽高,这些属性有时候还是很有用的。

我们用实例来感受一下:

在这里我们首先获得了提问按钮这个元素,然后调用其id、location、tag_name、size属性即可获取对应的属性值。

我们知道在网页中有这样一种标签叫做iframe,也就是子Frame,相当于页面的子页面,它的结构和外部网页的结构是完全一致的。Selenium打开页面后,它默认是在父级Frame里面操作,而此时如果页面中还有子Frame,它是不能获取到子Frame里面的元素的。所以这时候我们就需要使用switch_to.frame()方法来切换Frame。

我们首先用一个实例来感受一下:

我们还是以上文演示动作链操作的网页为实例,首先我们通过switch_to.frame()方法切换到子Frame里面,然后我们尝试获取父级Frame里的LOGO元素,是不能找到的,找不到的话就会抛出NoSuchElementException异常,异常被捕捉之后就会输出NO LOGO,接下来我们重新切换回父Frame,然后再次重新获取元素,发现就可以成功获取了。

所以,当页面中包含子Frame时,如果我们想获取子Frame中的元素,需要先调用switch_to.frame()方法切换到对应的Frame,然后再进行操作。

在Selenium中,get()方法会在网页框架加载结束之后就结束执行,此时如果获取page_source可能并不是浏览器完全加载完成的页面,如果某些页面有额外的Ajax请求,我们在网页源代码中也不一定能成功获取到。所以这里我们需要延时等待一定时间确保元素已经加载出来。

在这里等待的方式有两种,一种隐式等待,一种显式等待。

当使用了隐式等待执行测试的时候,如果Selenium没有在DOM中找到元素,将继续等待,超出设定时间后则抛出找不到元素的异常, 换句话说,当查找元素而元素并没有立即出现的时候,隐式等待将等待一段时间再查找 DOM,默认的时间是0。

我们用一个实例来感受一下:

在这里我们用implicitly_wait()方法实现了隐式等待。

隐式等待的效果其实并没有那么好,因为我们只是规定了一个固定时间,而页面的加载时间是受到网络条件影响的。

所以在这里还有一种更合适的显式等待方法,它指定好要查找的元素,然后指定一个最长等待时间。如果在规定时间内加载出来了这个元素,那就返回查找的元素,如果到了规定时间依然没有加载出该元素,则会抛出超时异常。

我们用一个实例来感受一下:

在这里我们首先引入了WebDriverWait这个对象,指定好最长等待时间,然后调用它的until()方法,传入要等待条件expected_conditions,比如在这里我们传入了presence_of_element_located这个条件,就代表元素出现的意思,其参数是元素的定位元组,也就是ID为q的元素搜索框。

所以这样可以做到的效果就是,在10秒内如果ID为q的元素即搜索框成功加载出来了,那就返回该元素,如果超过10秒还没有加载出来,那就抛出异常。

对于按钮,可以更改一下等待条件,比如改为element_to_be_clickable,也就是可点击,所以查找按钮时是查找CSS选择器为.btn-search的按钮,如果10秒内它是可点击的也就是成功加载出来了,那就返回这个按钮元素,如果超过10秒还不可点击,也就是没有加载出来,那就抛出异常。

运行代码,在网速较佳的情况下是可以成功加载出来的。

控制台输出:

可以看到控制台成功输出了两个元素,都是WebElement类型。

如果网络有问题,10秒内没有成功加载,那就抛出TimeoutException,控制台输出如下:

关于等待条件,其实还有很多,比如判断标题内容,判断某个元素内是否出现了某文字,在这里将所有的加载条件列举如下:

等待条件含义

title_is标题是某内容

title_contains标题包含某内容

presence_of_element_located元素加载出,传入定位元组,如(By.ID, 'p')

visibility_of_element_located元素可见,传入定位元组

visibility_of可见,传入元素对象

presence_of_all_elements_located所有元素加载出

text_to_be_present_in_element某个元素文本包含某文字

text_to_be_present_in_element_value某个元素值包含某文字

frame_to_be_available_and_switch_to_it frame加载并切换

invisibility_of_element_located元素不可见

element_to_be_clickable元素可点击

staleness_of判断一个元素是否仍在DOM,可判断页面是否已经刷新

element_to_be_selected元素可选择,传元素对象

element_located_to_be_selected元素可选择,传入定位元组

element_selection_state_to_be传入元素对象以及状态,相等返回True,否则返回False

element_located_selection_state_to_be传入定位元组以及状态,相等返回True,否则返回False

alert_is_present是否出现Alert

更多详细的等待条件的参数及用法介绍可以参考官方文档:http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.support.expected_conditions

我们平常使用浏览器都有前进和后退功能,使用Selenium也可以完成这个操作,使用back()方法可以后退,forward()方法可以前进。

我们用一个实例来感受一下:

在这里我们连续访问三个页面,然后调用back()方法就可以回到第二个页面,接下来再调用forward()方法又可以前进到第三个页面。

使用Selenium还可以方便地对Cookies进行操作,例如获取、添加、删除Cookies等等。

我们再用实例来感受一下:

首先我们访问了知乎,然后加载完成之后,浏览器实际上已经生成了Cookies了,我们调用get_cookies()方法就可以获取所有的Cookies,然后我们添加一个C...

增加检测类别?这是一份目标检测的一般指南 流量视频课程

img

埃莉卡

关注

目标检测技术作为计算机视觉的重要方向,被广泛应用于自动驾驶汽车、智能摄像头、人脸识别及大量有价值的应用上。这些系统除了可以对图像中的每个目标进行识别、分类以外,它们还可以通过在该目标周围绘制适当大小的边界框来对其进行定位。本文作者从图像识别与目标检测的区别开始,进一步简单介绍了目标检测的基本模块与实现方法。本文是目标检测的一般指南,它并没有详细介绍主流的目标检测算法,这些算法读者可参考从 RCNN 到 SSD,这应该是最全的一份目标检测算法盘点。

本文受 PyImageSearch 的读者 Ezekiel 的启发,他上个星期在邮件中咨询道:

Adrian 你好,我仔细地浏览了您之前关于深度学习目标检测 的文章及其跟进的实时深度学习目标检测 。感谢你做的这一切,我在自己的样例项目中使用了你的源代码,但是我有两个问题:1. 我该如何过滤/忽略那些我不感兴趣的类?2. 我如何才能向自己的目标检测器中增加新类别?有这个可能吗?如果你能就这两个问题写一篇文章,我将不胜感激。Ezekiel 并不是受此问题困扰的唯一读者。事实上,如果你仔细浏览了我最近关于深度目标检测两篇文章的评论,你会发现最常见的问题可以被表述为:我该如何修改你的源代码来包含我自己的类别?

由于这是一个如此常见的问题,并且是关于神经网络/深度学习目标检测器实际工作的一个误解,所以我决定在今天的博客中重温深度学习目标检测的话题。

具体地,你将在这篇文章中学到以下内容:

图像分类和目标检测的区别深度学习目标检测器的组成:包含不同目标检测架构的区别和基本模型之间的区别如何使用预训练模型进行深度学习目标检测如何从一个深度学习模型中过滤或者忽略一些预测类别向深度神经网络增加类别或从中删除类别时常见的误区和误解

为了更多地了解深度学习目标检测,并解释清楚我们对基于深度学习的目标检测的一些误区和误解,请继续阅读本文。

想要查看本文相关的源码?请查看原文的下载链接(https://pyimagesearch/2018/05/14/a-gentle-guide-to-deep-learning-object-detection/#):

深度学习目标检测的一般指南

今天的博客是对基于深度学习的目标检测的简单介绍。我尽可能对深度学习目标检测器的组成做一个概述,包括使用预训练的目标检测器执行任务的源代码。

你可以使用这份指南来帮助学习深度学习目标检测,但是也要意识到,目标检测是高度细节化的工作,我不可能在一篇文章中包含关于深度学习目标检测的所有细节。

这篇文章将从讨论图像分类和目标检测之间的本质区别开始,其中包括判断一个图像分类网络是否可以用于目标检测,以及在什么情况下可以这样使用等话题。

当我们理解了什么是目标检测时,随后会概述一个深度学习目标检测器的核心模块。它一般包括目标检测架构和基本模型,不熟悉目标检测的读者可能会误解这两个部分。

在这里,我们将使用 OpenCV 来实现实时深度学习目标检测。我也会展示如何在不修改网络架构或者重新训练的情况下忽略或者过滤一些不感兴趣的目标类别。最后,我们通过讨论如何从深度学习目标检测器中增加或者删除类别来总结本文。

图像分类和目标检测的区别

图 1: 图像分类(左)和目标检测(右)的区别是比较直观和简单的。在图像分类中,整幅图像被分类为单一的标签。而在目标检测中,我们的神经网络还要找出图像中目标的位置(有可能是多个)。

在进行标准的图像分类时,我们将一张给定的图像输入到神经网络,然后得到一个最可能的标签,而且也许会同时得到相关的概率。

这个类别标签用来表征整个图像的内容,或者至少是图像最主要的可见内容。例如,上面的图 1 中,给定输入图像(左),我们的 CNN 给它的标签是「比格犬」。所以我们可以认为图像分类具有以下特点:

一张图像输入一个类别标签输出

无论是通过深度学习还是其他计算机视觉技术的目标检测,都是基于图像分类构建的,只不过需要精确定位每个对象在图像中出现的位置。在进行目标检测的时候,给定一张输入图像,我们期望得到:

一个边界框列表,或者一幅图像中每个对象的(x,y)坐标与每个边界框关联的类别标签与每个边界框和类别标签关联的概率或者置信度得分

图 1(右)展示了一个深度学习目标检测的例子。请注意,人物和狗都被用边界框找出了位置,同时类标签也被预测到了。

所以,目标检测允许我们:

向网络输入一张图像得到多个边界框以及类别标签

深度学习图像分类可以被用于目标检测吗?

图 2:非端到端深度学习的目标检测器使用一个滑动窗口(左)+图像金字塔(右)相结合的方法来分类。

所以现在你理解了图像分类和目标检测的根本区别:

在进行图像分类时,我们输入一张图像,得到一个输出类别然而在进行目标检测时,我们输入一张图像,得到多个边界框以及类别标签的输出

这自然引发这么一个问题:

我们可以拿一个已训练的分类网络,将其用于目标检测吗?

这个答案有些棘手,因为这在技术上是可以的,但是理由并不太明显。解决方案涉及:

1. 应用基于计算机视觉的标准目标检测方法(非深度学习方法),例如滑动窗口和图像金字塔等方法通常被用在 HOG+基于线性 SVM 的目标检测器。

2. 采用预训练的网络,并将其作为深度学习目标检测架构的基本网络(例如 Faster R-CNN, SSD, YOLO)。

方法 #1: 传统的目标检测技术路线

第一个方法不是纯端到端的深度学习目标检测器。相反,我们使用:

1. 固定尺寸的滑动窗口,它从左到右,自上而下滑动,来定位不同位置的对象。

2. 图像金字塔,用来检测不同尺度的对象

3. 一个预训练(分类)的 CNN 来分类

在滑动窗和对应图像金字塔每一次停留的时候,我们会提取 ROI(感兴趣区域),将其输入到 CNN 中,得到对 RIO 的分类。

如果标签 L 的分类概率比某个阈值 T 高,我们就将这个 ROI 的边界框标记为该标签(L)。对滑动窗和图像金字塔的每次停留都重复这个过程,我们就得到了目标检测器的输出。最终,我们对边界框应用非极大值抑制(NMS),得到最终输出的检测结果:

图 3:应用 NMS 会抑制重叠的和置信度不高的边界框。这个方法在一些特定的用例中是有效的,但是它通常比较慢和繁琐,也容易出错。

然而,这个方法也是值得学习的,因为它可以将任意图像分类网络转换为一个目标检测器,而不需要显式地训练一个端到端的深度学习目标检测器。这个方法可以节省大量的时间和精力,且效率的高低具体取决于你的用例。

方法 #2:目标检测架构的基本网络

第二个深度学习目标检测的方法允许我们将一个预训练的分类网络作为深度学习目标检测架构(例如 Faster R-CNN、SSD 或者 YOLO)的基本网络。

这个方法的好处是:你可以创建一个基于深度学习的复杂端到端目标检测器。

而其不足之处是:它需要一些关于深度学习目标检测器如何工作的知识,我们将在后面的部分中讨论这个问题。

深度学习目标检测器的模块

图 4: VGG16 基本网络是 SSD 深度学习目标检测框架的一个特征抽取模块。

深度学习目标检测器有很多模块,子模块以及更小的子模块,但是我们今天要重点关注的是深度学习入门读者所困惑的两个:

1. 目标检测框架(不包括 Faster R-CNN, SSD, YOLO)

2. 适合目标检测框架的基本网络

你可能已经比较熟悉基本网络(只是你之前并没听到它被称作基本网络而已)。基本网络就是你常用的分类 CNN 架构,包括:

VGGNetResNetMobileNetDenseNet

通常这些网络在大数据集上进行预训练来进行分类,例如 ImageNet,它们可以学习到很多具有鉴别能力的滤波器。

目标检测框架由很多组成部分和子模块构成。例如,Faster R-CNN 框架包括:

候选区域网络(RPN)一组锚点ROI 池化模块最终基于区域的卷积神经网络

在使用 SSD(单步检测器,single shot detectors)时,具有以下的组成部分:

多框(MultiBox)先验(Priors)固定先验(Fixed priors)

请记住,基本网络只是整个深度学习目标检测框架的众多组件之一,上文图 4 描述了 SSD 框架内部的 VGG-16 网络。通常,我们需要在基本网络上进行「网络手术」。这种修改:

让它变成全卷积的形式,并接受任意输入维度。剪除了基本网络中更深层的卷积和池化层,将它们以一系列新层(SSD)、新模块(Faster R-CNN),或者这两者的一些组合代替。

这里的「网络手术」是一种口语化的说法,它的意思是移除基本网络中的一些原始卷积层,将它们用新层替代。网络手术也是讲究策略的,我们移除一些不需要的部分,然后用一组新的部分来替代它们。

然后,当我们开始训练我们的框架进行目标检测时,(1)新层、模块和(2)基本网络的权重都被修改了。

再强调一次,综述关于不同深度学习目标检测框架是如何工作的(包括基本网络所起的作用)并不属于本文的探讨范围。

如果你对深度学习目标检测的完整综述(包括理论和实现)感兴趣,请参考机器之心曾经发过的文章:从 RCNN 到 SSD,这应该是最全的一份目标检测算法盘点 。

我是如何计算一个深度学习目标检测器的准确度的?

在评价目标检测器的性能时我们使用了一个叫做均值平均精度(mAP)的指标,它是以我们数据集中所有类别的交并比(IoU)为基础的。

交并比(IoU)

图 5: 在这个交并比的可视化例子中,标注边界框(绿色)可以与预测的边界框(红色)进行对比。IoU 与 mAP 一起被用来评价一个深度学习目标检测器的精度。计算 IoU 的简单方程如图 5(右)所示。

你通常会发现 IoU 和 mAP 被用于评价 HOG+线性 SVM 检测器、Haar cascades 以及基于深度学习的方法的性能;但是请记住,实际用于生成预测边界框的算法并不是那么重要。

任何一个以预测边界框作(以及可选择的标签)为输出的算法都可以用 IoU 来评价。更一般的地,为了使用 IoU 来评价任意一个目标检测器,我们需要:

1. 真实的边界框(也就是测试集中表明我们的目标在图像的哪个位置的人工标签)

2. 模型预测到的边界框

3. 如果你想一起计算召回率和精度,那么还需要真实类别标签和预测类别标签

在图 5(左)中,我展示了真实边界框(绿色)与预测边界框(红色)相比的可视化例子。IoU 的计算可以用图 5 右边的方程表示。

仔细检查这个方程你会发现,IoU 就是一个比值。在分子项中,我们计算了真实边界框和预测边界框重叠的区域。分母是一个并集,或者更简单地说,是由预测边界框和真实边界框所包括的区域。两者相除就得到了最终弄的得分:交并比。

平均精度均值(MAP)

图 6:为了计算目标检测器的 mAP@0.5,我们执行了以下计算。对于所有被标记为「正检测」(positive detection)、具备至少 0.5 的交并比(IoU)的对象,我们对所有 N 个类别计算 IoU (>0.5) 均值,然后对 N 个均值再求平均。这个指标就是 mAP@0.5。

为了在我们的数据集中评估目标检测器,我们需要同时基于以下两者的 IoU 来计算 mAP:

1. 基于每个类别(也就是说每个类别的平均 IoU);

2. 数据集中所有类别(也就是说所有类别平均 IoU 的均值,所以这个术语就是平均精度均值)。

为了计算每个类别的平均精度,我们在所有的数据点上计算某个类别的 IoU。一旦我们计算出了一个类别在每个数据点的 IoU,我们对它们求一次平均(第一次平均)。

为了计算 mAP,我们对所有的 N 个类别计算平均 IoU,然后对这 N 个平均值取平均值(均值的平均)。

通常我们使用 mAP@0.5,表示测试集中要被标记为「正检测」的目标必须具备的条件,真值不小于 0.5 的 IoU(并可以被正确地标记)。这里的 0.5 是可以调整的,但是在所有的目标检测数据集和挑战中,0.5 是一个相对标准的数值。

再次强调,这只是一个关于目标检测评价指标的快速指南,所以我将整个过程简化了一些。

使用 OpenCV 进行基于深度学习的目标检测

我们已经在本文以及之前的博客中讨论了深度学习和目标检测。出于完整性考虑,我们将在本文中概述实际的代码。

我们的例子包含以 MobileNet 作为基础模型的单次检测器(SSD)。该模型由 GitHub 用户 chuanqi305(https://github/chuanqi305/MobileNet-SSD)在 COCO 数据集上训练得到。更多细节请浏览我之前的文章(https://pyimagesearch/2017/09/11/object-detection-with-deep-learning-and-opencv/),这篇文章介绍了该模型以及相关的背景信息。

让我们回到 Ezekiel 在本文开始提出的第一个问题上。

1. 我该如何过滤/忽略那些我不感兴趣的类?

我会在下面的示例代码中回答这个问题,但是首先你需要准备一下系统:

你需要在 Python 虚拟环境中安装版本不低于 3.3 的 OpenCV(如果你在使用 python 虚拟环境的话)。OpenCV 3.3+ 包含运行以下代码所需的 DNN 模块。确保使用链接中的 OpenCV 安装教程之一(https://pyima...

img

在线咨询

建站在线咨询

img

微信咨询

扫一扫添加
动力姐姐微信

img
img

TOP