QCon北京「鸿蒙专场」火热来袭!即刻报名,与创新同行~ 了解详情
写点什么

阿里 99 大促模型识别背后的样本生成

  • 2019-09-29
  • 本文字数:2868 字

    阅读完需:约 9 分钟

阿里99大促模型识别背后的样本生成

背景

在上一篇文章《详解阿里99大促活动页内容识别技术实现》里,我们介绍了在淘宝 99 大促中,我们使用了怎样的算法模型去识别并完成自动化测试的。

样本问题的困难点

淘宝大促有近百个模块、上千个页面,模块间具有相似性,并且模块内部具备多种状态,如果想要准确识别每个模块类型,单模块的样本数量至少要达到万级,而人工标注成本高、效率低下、数据量少,纯靠人力是无法满足模型诉求的。基于此,今天,我来介绍下,模型识别背后的大批量数据样本生成的技术方案。

思路

总体技术方案如下,后面会分别详细讲:


模型的样本要求

算法模型识别的输入是 99 大促的各个会场截图,输出是目标模块名称及其在截图中的坐标位置。


模型训练时,就是把模块渲染图、相应坐标位置与模块类型输入给模型,交给模型去进行监督学习。而模型需要的,就是各个模块大批量的图片样本。



一个模块,是由 View 和 ViewModel 组合而成,而 View 是固定的,ViewModel 跟随会场场景不同,是动态变化的。


那么,如果我们能拿到描述模块的 View 的这一层 DSL,辅助以动态的 ViewModel 数据,再把 View 和 ViewModel 渲染成图片,那我们就可以生成无穷无尽的样本数据了。

DSL 描述 View


仔细梳理之后,View 拆分为原子级元素(Text、Image、Shape)和原子级元素的组合关系(Group),即与 HTML DOM 树状结构中的各层级容器嵌套与叶子节点类型是同样的逻辑。


基于节点类型和节点样式的 DSL,我们就能描述一个完整的 View 了。


{  "layers": [{    "frame": {      "y": 354,      "x": 44,      "height": 32,      "width": 312    },    "id": 2,    "type": "text",    "value": "Adidas Stan Smith",    "textStyles": {      "fontFamily": "Helvetica, sans-serif",      "fontSize": 24    }  }, {    "frame": {      "y": 0,      "x": 384,      "height": 342,      "width": 342    },    "id": 3,    "type": "image",    "value": "//img.alicdn.com/bao/uploaded/i1/TB1.mcuNpXXXXctXFXXSutbFXXX.jpg_350x350Q50s50.jpg_.webp",    "styles": {      "height": 342,      "width": 342    }  }, {    "frame": {      "y": 0,      "x": 384,      "height": 342,      "width": 342    },    "id": 4,    "type": "shape",    "styles": {      "height": 342,      "width": 342,      "backgroundColor": "rgba(0, 0, 0, 0.1)"    }  }],  "frame": {    "y": 0,    "x": 0,    "height": 4920,    "width": 750  },  "id": 1,  "type": "group",  "moduleName": "pmod-zebra-recommand-item"}
复制代码


其中,除了节点类型和节点样式之外,最外层的 moduleName 代表模块名称,id 是为了标记每一个子元素,frame 是每个子元素的坐标位置、辅助算法模型识别模块内部子元素,value 值只有 text 和 image 才有,对应相应的文本值还有图片链接。

获取模块 View 的 DSL

有 3 种方案可以获取到模块 View 的 DSL,分别是:


  1. 从代码仓库中获取;

  2. 从 sketch 视觉稿中生成;

  3. 从浏览器渲染好的页面中获取。


我最后选择了第三种方案,放弃第一个方案是因为代码写法千差万别,很多展现逻辑还包含在 js 代码中,并且还要处理各种 for 循环子 View、style 的映射关系等等,复杂度太高。第二个方案目前集团内已有技术方案 imgcook,这一块的准确率听说还不错,并且一直在持续优化,而最终选择第三个方案的原因是,能 100%准确地还原模块 DSL,并且只需要关注模块最终展现给用户时候的形态,不需要理会过程中开发者做得各种复杂业务逻辑,复杂度相对低很多。

技术方案

在开发流程上,每个模块在开发完成后,都会有对应的模块预览页面。我使用了 puppeteer 模拟真实浏览器,对模块的节点信息进行提取,并保存为规范的 DSL。


清洗 window.getComputedStyle

通过 window.getComputedStyle 获取 DOM 节点的样式,会返回包含 280 个样式属性的对象,如果把每个 DOM 节点的所有 280 个样式属性都存储到 DSL 中,会造成两个问题:


  • DSL 文件冗余,且文件大小过大,解析耗时。

  • 增加算法同学对 DSL 的理解和调整成本。


第一步,隐藏默认属性值;


大部分的样式属性都是默认值,我们首先把默认的样式属性剔除出去。


css{alignSelf: 'auto',...}
复制代码


第二步,剔除无效属性;


开发者常用的样式属性在 20 个左右,有很多的样式是不具备实际效用的,把无效用的样式属性剔除掉,比如说:


{zoom: '1',writingMode: 'horizontal-tb',...}
复制代码


第三步,transform 动态计算


通过 getComputedStyle 拿到的 transform 属性值是一个矩阵方法 matrix(),感兴趣的同学可以去学习理解下 2D 转换矩阵。我们使用 puppeteer 模拟浏览器设置的屏幕宽度是 750,也就是说,得到的 transform 值中 translateX 和 translateY 两个值是以 750 为基准换算得到的一个数字,假如想要在下面描述到的将 DSL 渲染成图时(算法同学期望能模拟各种各样的屏幕尺寸去生成样本),就必须将获取到的 transform 值换算成相应屏幕设备时的值。


# 为了方便算法同学更好使用DSL渲染成图的工具,这里使用python来实现# screenshotShape是一个数组,代表屏幕宽高  [width, height]if 'transform' in style and 'matrix' in style['transform']:    matrix = style['transform'][7:-1].split(',')    translate = list(map(float, matrix[-2:]))    translateResult =  list(map(str, [distance*(screenshotShape[0]/750) for distance in translate]))    matrix[-2:] = translateResult
复制代码


通过以上 3 个步骤,最终得到的 DOM 节点样式属性个数一般维持在 20 个以内,能使输出的 DSL 精简非常多。

DSL 渲染成图片

同样的,我们能基于 puppeteer 去对页面做操作,也能使用它去把 DSL 渲染成目标模块页面,并截图。


首先,建立 DSL 与 HTML 标签的映射关系



其次,如果是 DSL 类型为 Group,就递归遍历里面的所有子元素,以此类推。完整的渲染流程图如下:


ViewModel 动态数据

一个模块,应用到 99 大促、双十一等各种会场,背后样式都是一致的,只有对应的数据不同,动态的数据一般是商品图片和商品信息。


闲鱼有一亿多的商品数据,如果把这商品数据拿过来与 View 一起渲染成模块,每个模块就有了成千上万种展现形态,且贴合算法模型实际识别过程中的输入,既能满足样本数量的要求,也能符合模型实际识别的场景,使模型准确率获得更大地提升。

效果

通过这样一条生成样本的通道,每个模块都能够提供给算法同学几万张质量很高的样本截图,使模型的准确率达到 98%以上。

展望

上述文章描述了如何批量生成样本来帮助解决算法模型对 99 大促和双十一会场中各个模块的识别。


目前,对模块 DSL 的动态调整依赖算法同学对模块的理解,eg.改变圆角 borderRadius 生成更多正向样本,或者增加噪声,eg.删除商品内容节点等生成负向样本,这些操作都需要算法同学对 DSL 进行定制化配置。在未来,我们希望尝试把这部分的工作也交给模型去处理,让模型对样本生成做决策,调整 DSL 的局部,并生成样式更加丰富和可靠的样本。


本文转载自公众号闲鱼技术(ID:XYtech_Alibaba)


原文链接


https://mp.weixin.qq.com/s/CvS4y73Q7hgIAfSzhxEuNg


2019-09-29 08:001324

评论

发布
暂无评论
发现更多内容

关于人才的招聘的一些看法(31/100)

hackstoic

团队管理 招聘

2021最强面试笔记非它莫属:3000字Java面试核心手册(大厂必备

爱好编程进阶

Java 程序员 后端开发

nginx配置系列(三)日志配置

乌龟哥哥

4月月更

GitOps指南

俞凡

DevOps gitops

7点建议助您写出优雅的Java代码

爱好编程进阶

Java 程序员 后端开发

linux之秘钥登录

入门小站

Linux

阿里架构师耗时 176 天整理出来的 Java 独家面试题(10 万字面试总结)

Java架构追梦

程序员 java面试 后端开发

架构实战营作业四

库尔斯

#架构实战营

网站开发进阶(一)Tomcat域名或IP地址访问配置详解

No Silver Bullet

tomcat 网站建设 5月月更

在线Excel转JSON工具

入门小站

工具

[Day32]-[二叉树]二叉树中的最大路径和

方勇(gopher)

LeetCode 二叉树 数据结构和算法

2020年底跳槽面试5家大厂,最后收获拼多多Java岗offer,分享三面总结!

爱好编程进阶

Java 程序员 后端开发

手撕阿里 Spring 框架:AOP、IOC、注解、事务,带你统统拿下

Java架构追梦

Java spring 程序员

2020最新版Java学习路线图--妈妈再也不用担心我误删数据库被开除了

爱好编程进阶

Java 程序员 后端开发

2020面试官会经常问到的三个并发工具类,你都知道吗?

爱好编程进阶

程序员 后端开发

2021年九月最新Java面试必背八股文,338道最新大厂架构面试题

爱好编程进阶

Java 程序员 后端开发

高精度在线计时器(秒表)

入门小站

工具

架构训练 模块4作业

小马

「架构实战营」

2021最新分享字节四面成功拿Offer!

爱好编程进阶

Java 程序员 后端开发

pinpoint插件开发之二:从零开始新建一个插件

程序员欣宸

Java 分布式 4月月更

4000字,详解Python操作MySQL数据库

爱好编程进阶

程序员 后端开发

Gitea 的简单介绍

HoneyMoose

Java 从一个 List 中删除 null 元素

HoneyMoose

在 ABAP 技术栈里实施 Continuous Integration 的一些挑战

汪子熙

DevOps 持续集成 abap 5月月更 持续优化

决战摸鱼之巅:将vscode撸成可局域网联机对战的moba平台

gamedilong

前端 vscode nodejs Node 摸鱼

C++类设计和实现的十大最佳实践

俞凡

c++ 最佳实践

11-SpringSecurity:Session共享

爱好编程进阶

Java 程序员 后端开发

2021最新一次Java面试,快手三面一轮游,如今已拿意向书

爱好编程进阶

Java 程序员 后端开发

2021金三银四必备:“基础-中级-高级

爱好编程进阶

Java 程序员 后端开发

32 岁的我裸辞了,八年 Java 老鸟,只因薪水被应届生倒挂

爱好编程进阶

Java 程序员 后端开发

7-52 两个有序链表序列的交集 (20 分)(思路加详解尾插法)come Boby!

爱好编程进阶

程序员 后端开发

阿里99大促模型识别背后的样本生成_文化 & 方法_云听_InfoQ精选文章