UI2CODE系列文章|如何批量制造高质量样本

在 UI2CODE 项目中,我们大量使用了深度学习方法来做一些物体检测。而深度学习模型的训练,避免不了需要大量的样本,因此如何制造大量样本,来满足模型训练需要是我们必须要解决的一个问题。在这篇文章中,我们将介绍我们如何利用工具,批量泛化出大量样本,为模型训练提供数据保障。

1.样本现状

我们的模型要解决的问题是在一个设计稿图片上识别出基础控件等信息,包括位置和类别。而它所需要的样本,主要存在两个问题:

  1. 数据量少:一个APP的页面是有限的,特别是针对单个APP做优化适配的时候,页面的数量是相对较少的,可能在几十到上百个。而模型的对样本数量的需求是巨大的,特别像较为复杂的模型,对数据量的要求至少是万级别的,单靠真实样本,是远远达不到要求的。
  2. 标注成本高:物体检测的样本标注,不仅需要标注物体的类别,更需要标注出物体的具体位置,而一个样本上会存在多个物体标注。因此,这类样本打标成本非常大。

2.样本获取途径

获取样本,主要有几种途径。

对于真实样本,这类质量是最高的,要想训练出效果很好的模型,这类样本基本是必不可少的,但是由于这类样本数量少,成本高,因此还需要其他方法来补充样本量。

对于数据增广,这种方法简单快速,但是效果也有限,特别是对于我们 UI2CODE 里识别控件这个任务来说,做旋转等操作基本是无效的。

因此,我们需要利用样本Mock,来扩充我们的数据量,尽量模拟出质量又多,量又大的样本。这里我们选择的是利用Weex页面来进行样本的Mock泛化。(当然还有一些其它方法,比如利用 Android 的特性,在运行时的APP页面,抓取页面数据,经过过滤和清洗,得到带标注的样本,这里不做展开)

3.WEEX页面样本泛化

在这里,我们介绍如何利用 Weex 页面,来批量泛化样本,并且得到样本标注的方法。

前端页面特点

之所以选择使用前端页面来生成样本,是因为前端页面更多的是做一些数据展示,并且其拥有完整的 DOM 树,只要我们拿着DOM树就可以解析出里面的各个元素。

对于节点内容,只要我们改变元素内容即可。这样我们就可以由一个前端页面很方便地泛化出不同文字、不同图片的多个样本。

当然,我们的闲鱼APP上有大量的Weex活动页,这也是我们选择做Weex页面泛化的原因之一。

泛化思路

我们需要的基础控件的分类有“文本”、“图片”、“Shape”这三类,对于一个页面来说,我们的文本和图片内容基本都是可替换的,因此我们解析出所有节点以后,对里面的文本和图片进行替换,再进行渲染就可以得到新的样本。

利用 Puppeteer 实现泛化

要想得到Weex页面,需要有一个渲染容器,并且我们可以很方便地修改其内容。这里,我们选择了Google的Puppeteer,它是Google推出的可以运行 Chrome Headless 环境以及对其进行操控的js接口套装。通过它,我们可以模拟一个Chrome运行环境,并且进行操控。官方简介在这里.

首先启动一个不带界面的浏览器:

const browser = await puppeteer.launch({headless: true
});

启动一个页面,然后打开一个网站:


const page = await browser.newPage();
await page.goto(nowUrls, {waitUntil: ['load','domcontentloaded','networkidle0']});

模拟IPhone6环境:

await page.emulate({'name': 'iPhone 6','userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1','viewport': {'width': 750,'height': 1334,'deviceScaleFactor': 1,'isMobile': true,'hasTouch': true,'isLandscape': false}
});

搜索所需控件:

let d_root = document.querySelectorAll('.weex-root');
let nodes_root = [];
collectChildren(d_root, nodes_root);/**
* 遍历节点,搜集所有需要的控件
*/
function collectChildren(d, _nodes) {for(var i = 0,l = d.length;i < l;i++){let hasPushed = false;//nodeType === 1 时 pushif (d[i].nodeType !== 1 && d[i].nodeType !== 3) {continue;}if(d[i].style){let backgrounColorValue = d[i].style['background-color'];if(backgrounColorValue && backgrounColorValue !== 'rgb(255, 255, 255)' &&  backgrounColorValue !== 'rgb(0, 0, 0)' && backgrounColorValue !== 'transparent'){_nodes.push(d[i]);hasPushed = true;}}if(d[i].hasChildNodes()){collectChildren(d[i].childNodes, _nodes);}else{let _node = d[i];let _className = _node.className;if(!_className && _node.nodeName === '#text'){_className = _node.parentNode.className;}if(_className && !hasPushed){if(_className.indexOf('weex-text') > -1 || _className.indexOf('weex-image') > -1){_nodes.push(d[i]);}}}}return _nodes;
}

获取控件信息:

/**
* 获取 基础视图元素的属性
*/
function getRealyStyle(node,attrKey){let wvStyle = window.getComputedStyle(node);if(node[attrKey] && node[attrKey] !== ''){return node[attrKey];}else{return wvStyle[attrKey]}
}/**
* 获取 基础视图元素的位置
*/
function getViewPosition(node){const {top, left, bottom, right} = node.getBoundingClientRect();return {"y": top,"x": left,"height": bottom-top,"width": right-left}
} 

获取页面图片:

await page.screenshot({path: pngName,fullPage : true
});

清理数据:

部分页面会存在弹窗的情况(mask图层),而我们的标注规则是希望只标注上面的图层,因此还需要根据mask图层的位置和大小,过滤掉底下图层里的控件。

通过上述方法,我们就能得到各个文本、图片、Shape以及他们的位置和属性等。基于位置和控件类别信息,我们就能够得到带有位置和类别标注的样本。

泛化文本和图片

通过上面的方法,只要提供一个Weex页面的url,就可以获取到一个带有标注的真实样本,后面我们只要修改里面文本和图片节点的内容,就可以批量泛化出多个样本。这些样本基于真实的页面布局,质量相对较高,并且可以随意控制泛化比例,比如设置 1:10,就可以有100分样本生成出10000份,大大提高了样本量。

5. 总结

通过Weex泛化样本的方法,我们由100多个Weex活动页,泛化出10000+个样本,并且无需手动打标,节省了大量的打标成本。且由于样本质量相对较高,模型的准确率得到了很大的提升。当然,我们也探索了很多其它方法,包括抓取Android运行时的页面数据来生成自动打标的数据,以及利用已训练模型自动预打标来节省手动打标的人力成本等,未来我们还会继续探索更多的样本生成及自动打标方法,为模型训练提供更多有用数据。


原文链接
本文为云栖社区原创内容,未经允许不得转载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/518192.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

javax.management.InstanceNotFoundException: org.springframework.boot:type=Admin,name=SpringApplicati

控制台service端打印javax.management.InstanceNotFoundException: org.springframework.boot:typeAdmin,nameSpringApplication 那个报的就点哪个,将红圈里的对勾去掉 就ok了&#xff01;

极测未来|淘宝千人千面内容下的智能评测技术与实践

背景挑战 全面个性化、内容化的淘宝&#xff0c;构造了基于内容的丰富的导购场景&#xff0c;包括猜你喜欢、有好货、每日好店、必买清单、哇哦视频、微淘、买家秀、头条、洋葱盒子….。个性化&#xff0c;给消费者带来更精准的货品分发。内容化为消费者带来更多惊喜和好的体验…

新时代 新营销 新增长, 纷享销客重磅发布CRM7.0产品,持续赋能企业数字化未来

2020年4月26日&#xff0c;主题为“新时代 新营销 新增长”的纷享销客2020销售增长大会暨春季战略与新品发布会&#xff0c;在GMIC大会期间成功举办。纷享销客创始人&CEO罗旭发表“新时代 新营销 新增长”的主题演讲&#xff0c;同时重磅发布纷享销客连接型CRM7.0新品。 这…

python3-matplotlib基本使用(以折线图为例)

1、什么是matplotlib Matplotlib 是 Python 中最受欢迎的数据可视化软件包之一&#xff0c;支持跨平台运行&#xff0c;它是 Python 常用的 2D 绘图库&#xff0c;同时它也提供了一部分 3D 绘图接口。Matplotlib 通常与 NumPy、Pandas 一起使用&#xff0c;是数据分析中不可或…

flowable 开源项目

企业级工作流引擎开源项目 文章目录一、工作流引擎flowable1. flowable2. cims3. RuoYi-flowable4. springboot-flowable-modeler5. flowable-diagram二、工作流引擎activiti2.1. RuoYi-Vue-Process2.2. RuoYi-Process2.3. ruoyi-vue-activiti2.4. activiti7-workflow2.5. JeeS…

看!闲鱼在ServiceMesh的探索和实践

背景&#xff1a; 在阿里服务端开发以Java为主的大背景下&#xff0c;其他异构语言业务如何调用现有Java服务&#xff0c;如何与集团中间件打通&#xff0c;就成为使用非Java语言团队必须要解决的首要问题。 已有方案问题&#xff1a; 在ServiceMesh方案成熟之前&#xff0c…

编译错误 错误:PL/SQL: ORA-00932: 数据类型不一致: 应为 DATE, 但却获得 NUMBER 行

文章目录1. 现象2. 分析3. 解决方案通过存储过程将临时B表中的数据同步到轨迹表中 1. 现象 PROCEDURE LABS.ASSET_LOANP 编译错误错误&#xff1a;PL/SQL: ORA-00932: 数据类型不一致: 应为 DATE, 但却获得 NUMBER 行&#xff1a;17 文本&#xff1a;(select n.*, trunc(DBMS_R…

如何保证 HBase 服务的高可用?看看这份 HBase 可用性分析与高可用实践吧!

来源 | 阿丸笔记责编 | Carol头图 | CSDN 下载自视觉中国HBase作为一个分布式存储的数据库&#xff0c;它是如何保证可用性的呢&#xff1f;对于分布式系统的CAP问题&#xff0c;它是如何权衡的呢&#xff1f;最重要的是&#xff0c;我们在生产实践中&#xff0c;又应该如何保证…

python3-matplotlib绘制散点图、绘制条形图

matplotlib 支持的图形 https://matplotlib.org/stable/gallery/index.html 1、绘制散点图 from matplotlib import pyplot as plt from matplotlib import font_manager# y_3是三月每天的最高温度 y_10 是十月每天的最高温度 y_3 [11,17,16,11,12,11,12,6,6,7,8,9,12,…

ORA-01858: 在要求输入数字处找到非数字字符 13行

文章目录1. 现象2. 分析3. 解决方案ORA-01858: 在要求输入数字处找到非数字字符13行 1. 现象 insert /*append*/ into ASSET_LOAN(select * from ASSET_LOANB );commit;2. 分析 由于ASSET_LOANB表和ASSET_LOAN表字段顺序不一致导致的 具体分析&#xff1a;由于ASSET_LOANB表倒数…

牛!Python 全栈必备的 150 个实战案例,一次性获得!

Python 全栈将是你升职加薪的硬通货。我见过很多的 Python 讲解教程和书籍&#xff0c;它们大都这样讲 Python 的&#xff1a;先从 Python 的发展历史开始&#xff0c;介绍 Python 的基本语法规则&#xff0c;Python 的 list, dict, tuple 等数据结构&#xff0c;然后再介绍字符…

数据权限实现

权限框架可以根据用户所属角色决定有权限看到的菜单资源权限。 同一个资源下的同一个菜单的数据权限需要单独处理。 案例&#xff1a;一部门的张三和二部门的李四都是普通用户角色&#xff0c;普通用户都有用户管理的查询权限&#xff0c;但是&#xff0c;一部门的张三只能看到…

遍地开花的 Attention ,你真的懂吗?

阿里妹导读&#xff1a;曾被 paper 中各种各样的 Attentioin 搞得晕晕乎乎&#xff0c;尽管零零散散地整理过一些关于Attention 的笔记&#xff0c;重点和线索依然比较凌乱。今天&#xff0c;阿里巴巴工程师楠易&#xff0c;将 Attentioin 的知识系统性地梳理、回顾、总结&…

Wrapper+map实现页面显示

文章目录1. 查询用户数据map集合2. map集合参数拼装1. 查询用户数据map集合 2. map集合参数拼装 用户角色和部门名称&#xff0c;根据角色ID和部门id分别查询替换&#xff0c;简言之&#xff1a;需要的内容分别通过单独查询数据库得到&#xff0c;然后通过遍历依次对比&#xf…

手淘促活那些事儿 | 智能投放算法框架助力用户增长

导读&#xff1a;本文主要介绍以手淘促活为目的的全链路智能投放算法框架&#xff0c;该框架目前接入以 Pagani 为核心的全链路运营平台&#xff0c;首先使用用户意图识别算法圈选出目标人群&#xff0c;然后借助物料智能推荐和权益动态面额等算法实现全链路上用户的个性化触达…

天天用Redis,持久化方案你又知道哪些?

来源 |码猿技术专栏责编 | Carol头图 | CSDN 下载自视觉中国Redis目前已经成为主流的内存数据库了&#xff0c;但是大部分人仅仅是停留在会用的阶段&#xff0c;你真的了解Redis内部的工作原理吗&#xff1f;今天这篇文章将为大家介绍Redis持久化的两种方案&#xff0c;文章将会…

万万没想到,JVM内存结构的面试题可以问的这么难?

在我的博客中&#xff0c;之前有很多文章介绍过JVM内存结构&#xff0c;相信很多看多我文章的朋友对这部分知识都有一定的了解了。 那么&#xff0c;请大家尝试着回答一下以下问题&#xff1a; 1、JVM管理的内存结构是怎样的&#xff1f; 2、不同的虚拟机在实现运行时内存的…

Serverless 落地挑战与蚂蚁金服实践

目前 Serverless 已成为云原生社区关注的重点之一&#xff0c;有人说它是微服务的继承者&#xff0c;将会彻底改变软件研发的现状&#xff0c;那么真实情况如何呢&#xff1f;本文将介绍 Serverless 市场观察、落地挑战&#xff0c;以及蚂蚁金服对 Serverless 的实践。 Server…

程序员感叹一年只能存下15万太少了……网友:潸然泪下

最近有程序员网友晒出自己的年终奖&#xff0c;税后高达15.7万&#xff01;看到这个情形&#xff0c;很多网友表示自己“被打鸡血了”。他强调学习的重要性&#xff0c;学习仍然是在这个时代下&#xff0c;普通人能够逆袭&#xff0c;给家人更好生活的一把利器&#xff01;今天…

机器学习工程师第一年的12点体会

机器学习和数据科学都是广义上的术语&#xff0c;它们涉及超级多的领域以及知识&#xff0c;一位数据科学家所做的事情可能与另一位有很大的不同&#xff0c;机器学习工程师也是如此。通常使用过去&#xff08;数据&#xff09;来理解或预测&#xff08;构建模型&#xff09;未…