阿里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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章