基于可训练加权融合多嵌入矩阵的简易情感分类器构建问题
实现每个单词独立加权的多嵌入融合情感分类器
嘿,这个需求很实用啊!本质上就是给每个单词学习一对专属的权重,把不同预训练嵌入的词向量加权融合后再做分类,我给你拆解下具体怎么在主流框架里实现~
核心思路回顾
你要的是对每个单词w,计算x[w] * E1[w] + y[w] * E2[w],其中x和y是每个词独有的可学习参数。这里要注意两个关键点:
- 确保两个嵌入矩阵的维度一致(如果不一样,得先做维度映射)
- 让
x和y能跟着输入的词索引动态取对应权重
PyTorch 实现步骤
假设你已经准备好了词汇表、预训练的Glove嵌入矩阵E1(形状[vocab_size, embed_dim1])和Word2vec嵌入矩阵E2(形状[vocab_size, embed_dim2]):
1. 初始化组件
import torch import torch.nn as nn # 加载预训练嵌入,转成张量 E1 = torch.tensor(glove_embeddings, dtype=torch.float32) E2 = torch.tensor(word2vec_embeddings, dtype=torch.float32) # 如果两个嵌入维度不同,加个线性层把E2映射到E1的维度 if E1.shape[1] != E2.shape[1]: dim_mapper = nn.Linear(E2.shape[1], E1.shape[1]) else: dim_mapper = nn.Identity() # 维度相同就用恒等层 # 定义每个词的可学习权重x和y,初始可以设为0.5(均等加权) X = nn.Parameter(torch.full((E1.shape[0],), 0.5, dtype=torch.float32)) Y = nn.Parameter(torch.full((E1.shape[0],), 0.5, dtype=torch.float32)) # 如果不想微调预训练嵌入,冻结它们的梯度 E1.requires_grad_(False) E2.requires_grad_(False)
2. 构建模型类
class WeightedEmbedClassifier(nn.Module): def __init__(self, vocab_size, embed_dim, num_classes): super().__init__() self.E1 = E1 self.E2 = E2 self.dim_mapper = dim_mapper self.X = X self.Y = Y # 分类头:先池化再全连接 self.pool = nn.AdaptiveAvgPool1d(1) self.classifier = nn.Linear(embed_dim, num_classes) def forward(self, input_ids): # input_ids形状:[batch_size, seq_len] # 取出对应词的嵌入向量 e1 = self.E1[input_ids] # [batch_size, seq_len, embed_dim1] e2 = self.dim_mapper(self.E2[input_ids]) # 映射后和e1维度一致 # 取出对应词的权重,增加维度以便和词向量相乘 x_weights = self.X[input_ids].unsqueeze(-1) # [batch_size, seq_len, 1] y_weights = self.Y[input_ids].unsqueeze(-1) # 加权融合 merged_embeds = x_weights * e1 + y_weights * e2 # 句子级池化:把序列维度压缩掉 sentence_embed = self.pool(merged_embeds.transpose(1,2)).squeeze(-1) # 分类预测 logits = self.classifier(sentence_embed) return logits
TensorFlow/Keras 实现步骤
同样先准备好预训练嵌入的numpy数组:
1. 构建模型
import tensorflow as tf vocab_size = len(vocab) embed_dim1 = E1.shape[1] embed_dim2 = E2.shape[1] num_classes = 2 # 假设是二分类情感任务 # 输入层:接收词索引序列 input_ids = tf.keras.layers.Input(shape=(seq_len,)) # 加载预训练嵌入层,默认冻结不微调 embedding1 = tf.keras.layers.Embedding( vocab_size, embed_dim1, weights=[E1], trainable=False )(input_ids) embedding2 = tf.keras.layers.Embedding( vocab_size, embed_dim2, weights=[E2], trainable=False )(input_ids) # 维度映射(如果需要) if embed_dim1 != embed_dim2: embedding2 = tf.keras.layers.Dense(embed_dim1)(embedding2) # 定义每个词的可学习权重:用Embedding层实现每个索引对应一个标量权重 x_weights = tf.keras.layers.Embedding( vocab_size, 1, embeddings_initializer=tf.keras.initializers.Constant(0.5) )(input_ids) y_weights = tf.keras.layers.Embedding( vocab_size, 1, embeddings_initializer=tf.keras.initializers.Constant(0.5) )(input_ids) # 加权融合 merged_embeds = tf.multiply(x_weights, embedding1) + tf.multiply(y_weights, embedding2) # 句子级池化 sentence_embed = tf.keras.layers.GlobalAveragePooling1D()(merged_embeds) # 分类头 logits = tf.keras.layers.Dense(num_classes, activation='softmax')(sentence_embed) # 组装模型 model = tf.keras.Model(inputs=input_ids, outputs=logits) model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
一些实用小贴士
- 正则化防过拟合:可以给
X和Y加L2正则化,比如PyTorch里在定义参数时加weight_decay=1e-4,Keras里在Embedding层加kernel_regularizer=tf.keras.regularizers.l2(1e-4) - 微调预训练嵌入:如果想让Glove/Word2vec的嵌入也跟着优化,只需要把
E1.requires_grad_(True)(PyTorch)或者trainable=True(Keras)即可 - 权重初始化:除了0.5,也可以用随机正态分布初始化,或者根据任务调整初始权重偏向某一个嵌入
内容的提问来源于stack exchange,提问作者yftah89
相关产品推荐
相关产品推荐

