前端智能化漫谈 (4) - pix2code结果编辑距离分析
Levenshtein距离分析
从实用的角度,我们先采用莱文斯坦距离,也就是编辑距离来分析一下pix2code的结果。因为Levenshtein距离是从DSL角度来看,需要人工修改时的最小编辑次数,所以从这个角度来分析是有其意义的。
我们分别用greedy和beam 3两种方法对于datasets/android/eval_set下面的png都生成一遍gui,分别存放于../android_greedy和../android_beam3目录。
可以用这样的命令:
python3 ./generate.py ../bin pix2code ../datasets/android/eval_set/ ../android_greedy/ greedy
python3 ./generate.py ../bin pix2code ../datasets/android/eval_set/ ../android_beam3/ 3
然后我们就可以写一个pix2code_levenshtein函数来比较它们之间的差别,记得安装python_levenshtein库:
def pix2code_levenshtein(path1, path2):
count = 0
score = 0
average_score = 0
for f in os.listdir(path2):
if f.find(".gui") != -1:
f1 = os.path.join(path1,f)
f2 = os.path.join(path2,f)
print(f)
if os.path.exists(f1) and os.path.exists(f2):
print(f1)
txt1 = open(f1).read()
txt1 = txt1.replace(" ","")
print(txt1)
print(f2)
txt2 = open(f2).read()
txt2 = txt2.replace(" ","")
print(txt2)
this_score = Levenshtein.distance(txt1,txt2)
print('This score:',this_score)
print(Levenshtein.ratio(txt1,txt2))
count = count + 1
score = score + this_score
average_score = score / count
print('Current score:',average_score)
样例分析
我们随机挑选10个文件分析一下
greedy和beam 3都能100%正确识别
例子:
完全正确的例子就不分析了。
以greedy获取的结果为例:
stack{
row{
switch
}
row{
switch
}
row{
radio
}
row{
label,slider,label
}
}
footer{
btn-home,btn-dashboard,btn-home
}
greedy和beam 3同样识别错误
10个样例中有4例是这样的情况。
102D9F19-4FAB-4144-9996-589C22991D61
标准答案如下:
../datasets/android/eval_set/102D9F19-4FAB-4144-9996-589C22991D61.gui
stack{
row{
switch
}
row{
label,btn
}
row{
switch,switch
}
}
footer{
btn-search,btn-dashboard,btn-notifications
}
不管是greedy还是beam 3,都错了两处,将footer中间的btn-dashboard和右边的btn-notifications给识别成了btn-home。
../android_greedy/102D9F19-4FAB-4144-9996-589C22991D61.gui
stack{
row{
switch
}
row{
label,btn
}
row{
switch,switch
}
}
footer{
btn-search,btn-home,btn-home
}
48CCC704-865B-48FC-B64C-C9DA057E5F61
这个case两种算法都只错了一处,与上例第二处错误一样,将btn-notifications给识别成了btn-home。
stack{
row{
switch
}
row{
label,btn,btn
}
}
footer{
btn-dashboard,btn-notifications
}
../android_greedy/48CCC704-865B-48FC-B64C-C9DA057E5F61.gui
stack{
row{
switch
}
row{
label,btn,btn
}
}
footer{
btn-dashboard,btn-home
}
54BC253F-DA31-4904-BC18-233CC0083E2F
这个比较复杂,不管greedy还是beam 3下都不能正确认别。标准答案如下:
stack{
row{
radio
}
row{
label,btn
}
row{
radio
}
row{
check
}
row{
label,slider,label
}
row{
switch
}
row{
check
}
row{
label,btn
}
}
footer{
btn-dashboard,btn-home,btn-dashboard
}
不管是在greedy识别中还是beam 3识别中,第三行和第四行的check和radio识别反了。
第6行和第7行没识别出来,在第8行后多识别出一行。
另外,footer上的三个都识别错了。
stack{
row{
radio
}
row{
label,btn
}
row{
check
}
row{
radio
}
row{
label,slider,label
}
row{
label,btn
}
row{
radio
}
}
footer{
btn-home,btn-dashboard,btn-notifications
}
CCF7369F-FCE4-4801-8936-E251EE90038C
这个case也相对简单,标准答案如下:
stack{
row{
switch
}
row{
switch
}
row{
check
}
row{
switch
}
}
footer{
btn-notifications,btn-home,btn-home
}
greedy和beam 3都是两处错误,一处是switch识别成了radio;另一处是footer上最左边的的btn-notifications被识别成了btn-home。
stack{
row{
switch
}
row{
switch
}
row{
radio
}
row{
switch
}
}
footer{
btn-home,btn-home,btn-home
}
greedy模式与beam 3模式下表现不同的
DBC890B4-0490-4A9B-88F6-8625F518F269
这个case中,greedy错了6处,beam 3错了4处。
stack{
row{
switch
}
row{
radio
}
row{
label,slider,label
}
row{
switch
}
row{
switch
}
}
footer{
btn-home,btn-dashboard,btn-dashboard
}
greedy下对第三行的识别基本失败。
第四行和第五行的switch,greedy下只识别成一个radio。
另外,footer上错了两个。
stack{
row{
switch
}
row{
radio
}
row{
switch,switch,btn,btn
}
row{
radio
}
}
footer{
btn-dashboard,btn-notifications,btn-dashboard
}
beam 3搜索对于第三行的支持很好。第4行第5行的switch还是没识别出来。
最后,footer的错误与greedy时一样。
stack{
row{
switch
}
row{
radio
}
row{
label,slider,label
}
row{
radio
}
}
footer{
btn-dashboard,btn-notifications,btn-dashboard
}
68F022A8-0C01-4684-A9B2-27E586C2D918
stack{
row{
switch
}
row{
check
}
row{
label,slider,label
}
row{
check
}
}
footer{
btn-search,btn-search,btn-notifications
}
在greedy模式下,check被识别成了radio
stack{
row{
switch
}
row{
check
}
row{
label,slider,label
}
row{
radio
}
}
footer{
btn-search,btn-search,btn-notifications
}
而在beam 3模式下,有3处识别错误,第2行没识别出来,另外footer上错了两个:
stack{
row{
switch
}
row{
}
row{
label,slider,label
}
row{
radio
}
}
footer{
btn-notifications,btn-search,btn-notifications
}
7C656D6E-0402-4D53-9450-CC948F07A8D4
stack{
row{
switch
}
row{
switch
}
row{
btn,btn,switch,switch
}
row{
label,btn
}
row{
label,slider,label
}
row{
switch
}
row{
label,btn,btn,btn
}
row{
switch,btn,btn
}
}
footer{
btn-home,btn-search,btn-search,btn-search
}
到这么复杂的情况下,不管是greedy和beam 3都乱了套,各有十几处错误。
greedy的情况:
stack{
row{
switch
}
row{
switch
}
row{
btn,switch,switch
}
row{
label,btn,btn,btn
}
row{
switch
}
row{
label,slider,label
}
row{
label,btn
}
row{
switch
}
row{
label,btn
}
}
footer{
btn-home,btn-search,btn-search,btn-search
}
beam 3的情况:
stack{
row{
switch
}
row{
switch
}
row{
btn,switch,}
row{
label,btn,btn,btn
}
row{
label,slider,label
}
row{
switch
}
row{
label,btn
}
row{
label,slider,btn,btn
}
}
footer{
btn-search,btn-search,btn-search,btn-home
}
8B5AF397-CBD8-4B2C-B8A6-3E9D036B4F2F
我们再来看一个复杂点的例子,标准答案如下:
stack{
row{
btn,switch,btn
}
row{
switch
}
row{
btn,btn,btn,btn
}
row{
label,slider,label
}
row{
radio
}
row{
check
}
row{
check
}
}
footer{
btn-notifications,btn-home,btn-notifications,btn-notifications
}
greedy算法在第一行识别就把中间的switch识别成了btn。
stack{
row{
btn,btn,btn
}
row{
switch
}
row{
label,slider,label
}
row{
check
}
row{
label,slider,label
}
row{
btn
}
row{
radio
}
}
footer{
btn-home,btn-home,btn-home,btn-home
}
beam 3的表现要好一些,但是在row中识别出了row,,,,是个败笔:
stack{
row{
btn,btn,btn
}
row{
switch
}
row{
row,,,,
row{
label,slider,label
}
row{
check
}
row{
check
}
}
footer{
btn-search,btn-notifications,btn-home,btn-home
}
beam 3可正确识别而greedy不能正确识别的case
9DB2E273-687B-4C00-952C-354C1AE1BF99
greedy对于同一行较多控件情况下的识别能力不如beam 3,在第1行第4个控件识别上出了问题,标准答案如下:
stack{
row{
btn,switch,switch,btn
}
row{
check
}
row{
switch
}
}
footer{
btn-dashboard,btn-home
}
greedy时最后一个btn识别成了switch
stack{
row{
btn,switch,switch,switch
}
row{
check
}
row{
switch
}
}
footer{
btn-dashboard,btn-home
}
样例总结
这10个case中,greedy模式下的平均Levenshtein距离32.1,beam 3模式下为28.
250张Android测试集,greedy平均编辑距离为27.9,beam 3模式下32.