做不锈钢管网站,建筑工程机械人才培训网的证书,下载新版app免费下载安装,域名备案企业网站内容目录
一.引言
二.实现思路
1.样本构建
2.Word2vec 架构
3.EGES 架构
4.基于 NEG 的 Word2vec 架构
三.Keras 实现 Word2vec
1.样本构建
2.模型构建
3.向量获取
四.keras 实现 EGES
1.样本构建
2.模型构建
3.Dot Layer 详解
3.1 init 方法
3.2 call 方法
3.3 完…目录
一.引言
二.实现思路
1.样本构建
2.Word2vec 架构
3.EGES 架构
4.基于 NEG 的 Word2vec 架构
三.Keras 实现 Word2vec
1.样本构建
2.模型构建
3.向量获取
四.keras 实现 EGES
1.样本构建
2.模型构建
3.Dot Layer 详解
3.1 init 方法
3.2 call 方法
3.3 完整代码
4.向量获取
4.1 计算 sku 相似度
4.2 商品 sku 冷启动
4.3 侧信息重要性分析
4.4 引入预训练模型
五.总结 一.引言
前面介绍了基于 Gensim 的 Word2vec 实现以及 EGES 的理论与样本准备由于 EGES 是在 Word2vec 的基础上为 (Target, Context) 中的 Target 增加 SideInfo 侧信息增加表达能力所以这里先实现 Word2vec再加入侧信息实现 EGES二者实现思路相近。
Tips
本文实现方式为 Skip-GramCBOW 同学们可以基于下面思路自己实现。 二.实现思路
1.样本构建 由于实现形式为 Skip-Gram所以是 (Target, Context) 即 (中心词, 上下文) 的形式通过 window_size 可以控制我们从序列 Seq 样本中获取的样本对数量。 2.Word2vec 架构 样本为 (Target, Context)输入为仅 Target 对应位置为 1 的 one-hot 向量通过 Hidden-Layer 获取 Target 对应的 K 维向量随后与 SoftMax 输出层的 KxN 的参数矩阵相乘的到 N 维向量对 N 维向量取 Softmax 并与仅 Target 为 1 的 one-hot label 进行 Loss 的计算并梯度回传。
Tips
由于 Target 中心词所在词库大小 N 通常很大所以最后一步的 Softmax 计算相对比较耗时论文中提出了两种优化方法
• 层次 Softmax
层次 softmax 基于霍夫曼树生成的词库优化了 dot 计算的数量与高频词的计算数量。
• 负采样
Negative Sample 这个方法非常简单粗暴但是好用每次为 Target 生成 ns 个非 Context 的词作为负样本这样计算量直接从 N 缩减至 ns一般推荐 ns 为 5-20
由于层次 softmax 构造相对复杂这里我们采用更好实现的 Negative Sample 即负采样。 3.EGES 架构 这里 SI 0 代表 Item 即 (Target, Context) 里的 ContextS1 1 - S1 n 为 n 类 SideInfo 侧信息针对每一个 SI 0 都有一个 Alpha 权重向量通过 ∑ α * Emb 的形式得到加权平均的 Embedding后面的计算同 Word2vec 一致。 N 和 P 代表随机采样的 Negative Sample 和 Context 对应的 Positive Sample。
Tips
这里把图歪过来架构就很相似了简单分下下 Word2vec 与 EGES 的区别 • 样本构造
EGES 采用 Session 截取用户历史行为Word2vec 基于用户完整历史行为游走。
• Hidden 层输入
EGES 加入 SideInfo 加权得到隐层的输入Word2vec 直接 lookup 得到 Target Embedding 输入隐层。 4.基于 NEG 的 Word2vec 架构 直接通过 Embedding 层 lookup 获取 (Target, Context) 对应的 K 维度 Embedding随后执行 Dot 计算并通过 Sigmoid 得到 0-1 的值将多分类的 Category_Crossentropy 转换为了二分类 Binary_Crossentropy 的问题。其样本构造也很简单针对正样本 (Target, Context) 其 Label 为 1再基于 Target 生成 ns 个 (Target, Negative Word) 的负样本其 Label 为 0。最后获取 Embedding 的向量作为词向量即可如果是 EGES 则是增加 Weight Merge 即加权求和操作即可。 三.Keras 实现 Word2vec
1.样本构建 word_target, word_context zip(*all_pairs)word_target np.array(word_target, dtypeint32)word_context np.array(word_context, dtypeint32) 上篇数据预处理的文章中我们已经基于编码后的 sku 商品序列游走获取了如上图的样本形式后续将基于该样本与 NEG 的架构实现 Word2vec 与 EGES。
Tips
注意数据类型的 dtype否则会报错因为我们处理完的为字符类型训练需要 int32 or int64。 2.模型构建
- Embedding 层 input_target Input((1,))input_context Input((1,))embedding Embedding(sku_num, args.emb_dim, input_length1, nameembedding)# 获取 Embtarget embedding(input_target)target Reshape((args.emb_dim, 1))(target)context embedding(input_context)context Reshape((args.emb_dim, 1))(context)
直接构建 Embedding 层获取 (Target, Context) 的 K 维向量。 - Dot 层 # now perform the dot product operation to get a similarity measuredot_product Dot(axes1)([target, context])dot_product Reshape((1,))(dot_product)# add the sigmoid output layeroutput Dense(1, activationsigmoid)(dot_product)
直接 Dot 计算内积。 - Model 层 # create the primary training modelmodel Model([input_target, input_context], output)model.summary()model.compile(lossbinary_crossentropy, optimizerrmsprop, metrics[accuracy])
选择 binary_crossentroy 进行模型编译 Tips
同样需要注意把 labels 用 np.array 包装起来否则训练无法进行。 3.向量获取 model.fit((word_target, word_context), np.array(labels), epochs10, batch_size128)# 获取训练后的 Embeddingemb np.array(embedding.get_weights()[0])print(商品数量 %d 词向量数量: %s % (sku_num, emb.shape))print(emb[:10])
跑 10 个 epoch 看看 最后查看商品数量和 Emb 数量是否一致随后将 Emb 按索引反映射到 word 即 sku 商品上即实现了每个 sku 对应一个 Embedding 四.keras 实现 EGES
1.样本构建
(Target, Context) 与上面 Word2vec 一致这里需要给 Target 增加 SideInfo将样本修改为 ([Target, SI 1, SI 2, SI N], Context) 的形式其中 SI N 代表第 N 个 SideInfo。本例中 sku 商品共包含 3 个 SideInfo 分别为 brand-品牌、shop_id-店铺、cate-标签。 word_target np.array(word_target, dtypeint32)word_context np.array(word_context, dtypeint32)word_target_with_side_info []for word in word_target:# 获取侧信息并追加side_info sku_side_info[sku_side_info[sku_id] word].values[0]word_target_with_side_info.append(np.array(side_info, dtypeint32))word_target_with_side_info np.array(word_target_with_side_info, dtypeint32)
sku_side_info 是上文数据预处理中生成的 Sku 信息的 DataFrame这里获取 values 并添加到新的样本集合中 sku、brand、shop_id 与 cate 对应的 Dim 数为样本中对应特征 Unique 去重后的数量。 2.模型构建
- 输入层 # 添加 SideInfo: brand,shop_id,cateinput_target Input((4,))input_context Input((1,)) 由于添加了 3 类 SideInfo所以 Input 增加 3 维。 - Dot 层 dot_layer EGES_model(feat_num_list, args.emb_dim)([input_target, input_context])
这里 dot_layer 需要实现 EGES 加权求和获取 Merge 合并后 Embedding 的工作篇幅较长我们放在后面统一分析。 - Model 层 # add the sigmoid output layeroutput Dense(1, activationsigmoid)(dot_layer)# create the primary training modelmodel Model([input_target, input_context], output)model.summary()model.compile(lossbinary_crossentropy, optimizerrmsprop, metrics[accuracy]) 3.Dot Layer 详解
dot_layer 实现继承 tensorflow.python.keras.models.Model 实现主要包含 init 初始化与 call 调用两个方法的实现。其中 call 方法如下图红框所示基本包含了 EGES 前置的全部逻辑。 3.1 init 方法
根据上图我们分析模型需要如下参数
• SI 0 参数矩阵
SI 0 为 sku 对应的 Embedding 层其维度为 len(unique(sku)) x K
• SI 1-N 参数矩阵
SI 1-N 为 Side Info 对应的 Embedding 层其维度分别为 len(unique(SI I)) x K
• Alpha 权重矩阵
针对每个 sku 有 1s 个 alpha 权重所以共需要 len(unique(sku)) x (1s) 个参数 A.参数准备 这里 embedding_list 存储 SI 0-N 的 Embedding 层参数feat_num 1 s 即总特征数dim K 代表 Embedding 维度sku_num len(unique(sku_id)) 为全部商品的数量。 B.参数初始化
Sku Num: 34048
Feat Dim: [[sku_id, 34048], [brand, 3663], [shop_id, 4786], [cate, 80]]
根据每个 Feat 的维度构建其 Embedding 层参数最后构建 sku_num x feat_num 的 alpha 权重层参数。 3.2 call 方法
根据上图我们再分析下如何实现 call 方法
• 依次获取 Embedding
按照样本书序从对应 embedding_list 中 lookup 即可获取对应向量
• 拼接 Embedding
tf.stack 直接将获取的向量拼接在一起
• 加权求和 Embedding
lookup 获取 alpha 向量与 stack 拼接的向量对位相乘再 reduce_sum 求和即可 A.Target Side 向量获取 原始样本为 None x 4lookup 后 stack 在一起得到 None x 4 x 128。 B.Alpha 权重向量获取 获取对应 sku 的 1s 维 Alpha 权重向量为了保证每个权重的非负性这里采用 exp 转正并通过 Softmax 的形式对每个权重参数进行了归一化。 C.reduce_sum 加权求和
直接对位相乘再除以求和后的 α 即可。 D.Dot 获取内积
加权求和 merge 后的 embedding 与 lookup 得到的 1xK 的 context 即目标词的 embedding 进行内积最终得到 None x 1 输出到下一层。 3.3 完整代码
from abc import ABCimport tensorflow as tf
from tensorflow.python.keras.models import *
from tensorflow.python.keras.layers import *class EGES_model(Model, ABC):def __init__(self, feat_num_list, emb_dim):super(EGES_model, self).__init__()# Embedding 矩阵self.embedding_list []self.feat_num len(feat_num_list)self.dim emb_dimself.sku_num feat_num_list[0][1]print(Sku Num:, self.sku_num)print(Feat Dim:, feat_num_list)# word embeddingfor i in range(self.feat_num):feat_name feat_num_list[i][0]feat_num feat_num_list[i][1]self.embedding_list.append(self.add_weight(namefeat_name,shape(feat_num, emb_dim),initializerhe_normal,trainableTrue))# alpha weight embedding [id x 4]self.alpha_weight self.add_weight(nameweight,shape(self.sku_num, self.feat_num),initializerhe_normal,trainableTrue)def call(self, pairs):(word_with_side_info, context_info) pairs# 获取侧信息 Embedding 用户3个侧信息 None x 4 x 128embed_list []for i in range(self.feat_num):# [N x Emb] 10x128index tf.cast(word_with_side_info[:, i], dtypeint32)emb_var tf.nn.embedding_lookup(self.embedding_list[i], index)[:, :self.dim]embed_list.append(emb_var)# (None, 128, 4)combine_emb tf.stack(embed_list, axis-1)# (None, 4, 128)combine_emb tf.reshape(combine_emb, shape(-1, self.feat_num, self.dim))# 加权求和# (None, ) (None, 4) (None, )sku_index tf.cast(word_with_side_info[:, 0], dtypeint32)sku_alpha_emb tf.nn.embedding_lookup(self.alpha_weight, sku_index)[:, :]alpha_sum tf.expand_dims(tf.reduce_sum(tf.exp(sku_alpha_emb), axis-1), axis1)# (None, 4, 128)add_weight_emb combine_emb * tf.exp(tf.expand_dims(sku_alpha_emb, axis-1))# (None, 128)merge_emb tf.reduce_sum(add_weight_emb, axis1) / alpha_sum# 上下文变量# (None, 1, 128)context_emb tf.nn.embedding_lookup(self.embedding_list[0], tf.cast(context_info, dtypeint32))[:, :self.dim]# (None, 128)context_emb tf.reshape(context_emb, shape(-1, self.dim))# None x 1dot_product Dot(axes1)([merge_emb, context_emb])return dot_product 4.向量获取 model.fit([word_target_with_side_info, word_context], np.array(labels), epochs10, batch_size128)跑 10 个 epoch同样注意把 labels 用 np.array 包起来 训练完我们从 EGES_model 对应的 dot 层获取向量即可 # 获取训练后的 Embeddingweight_list model.layers[2].get_weights()weight_map {}for i in range(len(feat_num_list)):feat_name feat_num_list[i][0]feat_emb weight_list[i]weight_map[feat_name] feat_emb
针对 SI 0 - sku 和 SI 1-3 三个侧信息我们可以获取 4 个向量矩阵根据后续任务的不同我们可以做如下事情
4.1 计算 sku 相似度 使用 sku Embedding 计算内积寻找不同 sku 的相似度也可以降维观察不同 sku 的分布 4.2 商品 sku 冷启动
在冷启动时引入商品对应侧信息优化冷启动商品的初始 Embedding 4.3 侧信息重要性分析 print(np.array(weight_list[-1]))通过 alpha 参数矩阵我们使用 exp 归一化可以分析不同 sku 的向量偏好根据色阶图看以分析不同特征对结果的重要程度 4.4 引入预训练模型
可以将不同特征的 Embedding 用于后续 Deep 任务的参数初始化例如 FNN 使用 FM 预训练的向量一样 五.总结
当年还未深度接触 DeepLearning 时总觉得 word2vec 很复杂但是通过前面的分析、再到框架最后到具体实现我们发现其思路清晰实现也很简洁如果把 dot 层的计算更换为其他相似度计算例如 Cos 余弦相似度那上面的架构就和 DSSM 很类似。
word2vec 是 Google 于 2013 年开源的获取 word vector 的算法包距今已经10年、EGES 是 2018 年由阿里巴巴算法团队提出距今也已经5年在算法日新月异的今天已经算的是很古老的知识了但是其 Embedding 的思想一直影响着后面深度学习的发展因此把它搞清楚对于很多 DeepLearning 的知识理解也很有帮助。
上面利用负采样的方法实现了 Skip-gram除了负采样的优化方法外源码中还有很多实现的细节
• σ(x) 的近似计算
sigmoid 函数在 x -6 或者 x -6 时变化已经微乎其微实际计算中除了 Softmax 计算量巨大外sigmoid 函数计算也很多可以通过细分区间缓存 σ(x) 的近似值从而将计算切换为查表优化计算速度。
• 向量相似度检索
由于词库的大小 N 通常很大每次计算都匹配所有向量并内积计算相似度会非常耗时线上无法接受可以通过缓存 item-item 之间的相似度做的快速查找常用的方法有 LSH局部敏感哈希算法。
• 低频词与高频词
利用语料构建词库时开发者可以通过 min_count 控制每个词出现过多少次才能收到到词库中。低频词出现次数较少但其独一无二的性质有时可以精准描述某些特定场景而高频词虽然出现很多但却意义不大例如 的、是 这些因此实际场景中除了过滤停用词外还需要分析低频词的代表性以及高频词的实际意义。可以通过 SubSampleing 的技巧对高频词做处理其思想是有一定概率不计算当前高频词从而优化计算速度就像是 Dropout 一样。当然使用层次 Softmax 也可以很好地解决高频词的效率问题。
• 窗口与上下文
根于 Target 与 window_size 我们会生成 [-window_sizewindow_size] -1 个样本源码中采取先对 [1, window_size] 随机一个整数 c然后再生成 [-cc] -1 个样本相当于 window_size 其实也是随机变化的。
参考
Word2vec 的一些思考word2vec的一些遗留思考
Word2vec 的一些理论word2vec 中的数学原理详解
Word2cec 的一些代码基于keras实现word2vec