XDRush

CNN在计算广告中的应用-物料优化之以图找图

1 背景说明

我们知道,在信息流广告中,广告的展现形式通常分为三种:

  • 大图:点击率最高,对图文相关性要求也最高
  • 小图:点击率相对偏低,不占用屏幕
  • 三图:介于大图和小图之间

以上三种广告展现形式已经被证明能够很好的融入到信息流广告中,在保证用户体验的情况下,恰当的让广告得到展示。

最近在做物料优化时,接触到这样的一个场景:大图样式中,基本上每个关键词对应一张图;小图样式中,同样如此;三图样式和小图样式共用一套图集;那么问题来了,当请求的样式的三图时,由于平均每个关键词只有一张小图,导致在我们的三图样式中,对大部分关键词,另外的两张图采用行业打底形式(也就是给关键词所对应的行业配几张通用的图片),这就导致了这些关键词的点击率不高,有些场景下甚至会影响用户体验。那么,如何在仅有一张图片的境况下,快速给这个关键词配上另外的几张图呢?

2 CNN以图找图原理及实现

2.1 以图找图原理

既然一个关键词已经有一张图了,那么根据这张图在几万图片集合中能否找出跟这个图片最接近的几张图呢?答案是肯定的。

这样我想到了在NLP中计算词和词的相关性上,通过词的vector计算词与词之间的余弦距离,就能计算词与词之间的距离,也就能找出近似词。寻着这个启发,只需要得到一个图片的vector表示即可!就比较简单了,直接用现成的模型VGG,Inception,ResNet等等就可以,抽取其中的高阶特征,即可得到图片的向量表示,再计算整个图片集中的图片与给定图片的cosine举例,取相关性top的图,就是内容最接近的图。实验证明,这种以图找图的方式,可靠度接近95%,大大节省了人工找图成本。

2.2 以图找图tensorflow实现

这里我就以现有的VGG为例,直接抽取vgg的第七个全连接层的向量作为图片的表示,然后再计算余弦距离,再排序取topN即可。部分实现代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
model_path = './models/tensorflow'
vgg_path = './data/vgg16-20160129.tfmodel'
def cal_sim(array1, array2):
size = len(array1)
result = 0.0
sum_array1 = 0.0
sum_array2 = 0.0
for i in range(size):
result += array1[i] * array2[i]
sum_array1 += array1[i] * array1[i]
sum_array2 += array2[i] * array2[i]
sum_array1 = math.sqrt(sum_array1)
sum_array2 = math.sqrt(sum_array2)
return result * 1.0 / (sum_array1 * sum_array2)
def get_pic_array_dict():
images_dir = "data/material_opt/images_220_140"
image_list = os.listdir(images_dir)
pic_dict = {}
index = 0;
for i in range(0, len(image_list)):
index += 1
#if index > 10:
# break
key = image_list[i].strip().split(".")
key = key[0]
path = os.path.join(images_dir, image_list[i])
if os.path.isfile(path):
try:
feat = read_image(path)
c_fc7 = sess.run(graph.get_tensor_by_name("import/Relu_1:0"), feed_dict={images:feat})
if key not in pic_dict:
pic_dict[key] = []
pic_dict[key].append(c_fc7[0])
except AttributeError as err:
print "index: ", index
print err
return pic_dict
def get_sim_pic(sess, input_file):
pic_dict = get_pic_array_dict()
print "load pic_dict DONE"
fp = open(input_file)
fp_result = open("final_result.dat", "w")
for line in fp.readlines():
rst = line.strip().split("\t")
if len(rst) != 2:
continue
kwd = rst[0]
url = rst[1]
try:
tmp_pic_file = "images/temp/tmp.jpg"
urllib.urlretrieve(url, tmp_pic_file)
## 获取目标图像表示
feat = read_image(tmp_pic_file)
fc7 = sess.run(graph.get_tensor_by_name("import/Relu_1:0"), feed_dict={images:feat})
result_dict = {}
for key, value in pic_dict.items():
sim_val = cal_sim(fc7[0], value[0])
#print "sim_val: ", sim_val
if key not in result_dict:
if sim_val > 0.5:
result_dict[key] = sim_val
#result_dict[key].append(sim_val)
print "cal done"
## 排序,去top5相关性的图像
items = sorted(result_dict.items(), lambda x, y: cmp(x[1], y[1]), reverse=True)
print "sort done"
num = 0
for key, value in items:
## 排除自己
if value > 0.99:
continue
fp_result.write(kwd + "\t" + key + "\t" + str(value) + "\n")
num += 1
if num > 4:
break
except IOError as err:
print err
fp.close()
fp_result.close()