嵌入层(Embedding Layer)将输入数据转换为高维向量表示的详细解释(附有嵌入矩阵W的生成过程)

嵌入层(Embedding Layer)将输入数据转换为高维向量表示的详细解释(附有嵌入矩阵W的生成过程)

嵌入层(Embedding Layer)是一种将输入数据映射到高维向量空间的技术。它在自然语言处理和时间序列分析等任务中非常常见。下面是嵌入层如何工作的详细解释:

1. 嵌入层的定义

嵌入层是一种查找表,将离散的输入数据(如词或时间序列中的特征)映射到一个连续的高维向量空间中。这个过程可以看作是将每个离散的输入映射为一个向量。

2. 嵌入矩阵

嵌入矩阵 W W W 是嵌入层的核心。假设嵌入矩阵的维度为 V × D V \times D V×D

  • V V V 是输入数据的词汇量或特征的数量。
  • D D D 是嵌入向量的维度。

每个输入索引 i i i 都对应嵌入矩阵中的一个向量 W [ i ] W[i] W[i],这个向量的维度为 D D D

3. 嵌入过程

嵌入过程包括以下几个步骤:

  1. 输入数据的索引化

    • 输入数据通常以索引的形式表示,例如时间序列中的每个时间点可以用一个索引表示。
  2. 查找嵌入向量

    • 对于每个输入索引,从嵌入矩阵 W W W 中查找对应的嵌入向量。
    • 例如,假设输入数据的索引为 i i i,则对应的嵌入向量为 W [ i ] W[i] W[i]
  3. 输出嵌入向量

    • 每个输入索引都被映射为一个高维向量,这些向量构成嵌入层的输出。
具体例子

假设有一个简单的时间序列输入数据,表示为索引 [ 1 , 2 , 3 ] [1, 2, 3] [1,2,3],嵌入矩阵 W W W 的维度为 4 × 512 4 \times 512 4×512

W = ( W [ 0 ] W [ 1 ] W [ 2 ] W [ 3 ] ) W = \begin{pmatrix} W[0] \\ W[1] \\ W[2] \\ W[3] \\ \end{pmatrix} W= W[0]W[1]W[2]W[3]

其中,每个 W [ i ] W[i] W[i] 是一个512维的向量。

  1. 输入数据的索引化

    • 输入数据为 [ 1 , 2 , 3 ] [1, 2, 3] [1,2,3]
  2. 查找嵌入向量

    • 对应的嵌入向量为:
      • 输入索引 1 对应的嵌入向量为 W [ 1 ] W[1] W[1]
      • 输入索引 2 对应的嵌入向量为 W [ 2 ] W[2] W[2]
      • 输入索引 3 对应的嵌入向量为 W [ 3 ] W[3] W[3]
  3. 输出嵌入向量

    • 嵌入层的输出为这些高维向量的集合:
      ( W [ 1 ] W [ 2 ] W [ 3 ] ) \begin{pmatrix} W[1] \\ W[2] \\ W[3] \\ \end{pmatrix} W[1]W[2]W[3]
数学表示

假设输入索引为 x i x_i xi,嵌入矩阵为 W W W,则嵌入向量 e i e_i ei 表示为:

e i = W [ x i ] e_i = W[x_i] ei=W[xi]

其中, e i e_i ei 是对应的嵌入向量,维度为 D D D

嵌入矩阵 ( W ) 的生成过程举例说明

假设我们有一个用于时间序列预测的模型,其输入是过去30天的销售数据,每天的销售数据用一个数值表示。为了让模型更好地理解这些数据,我们使用一个嵌入层将这些数值转换为高维向量表示。

初始嵌入矩阵
  1. 初始化

    • 假设我们的销售数据在0到1000之间变化,因此我们需要一个词汇表大小为1001(包括0)。
    • 我们设定嵌入维度为4,这意味着每个销售数据将被映射为一个4维向量。

    初始嵌入矩阵可以表示为一个随机的1001行4列的矩阵,例如:

    W = [
        [0.01, -0.02, 0.03, -0.01],  # 表示销售值0的嵌入向量
        [-0.01, 0.02, -0.03, 0.04],  # 表示销售值1的嵌入向量
        ...,
        [0.03, -0.04, 0.05, -0.06]   # 表示销售值1000的嵌入向量
    ]
    
嵌入矩阵的训练过程
  1. 模型训练前

    • 我们开始训练模型。初始的嵌入矩阵 ( W ) 只是一些随机数,尚未反映任何有用的模式或关系。
  2. 前向传播

    • 在每次训练中,输入数据会通过嵌入层。假设我们输入的一段销售数据是:

      [123, 456, 789, 321, 654, ...]
      
    • 模型会查找对应的嵌入向量。例如,销售值123对应的嵌入向量是:

      W[123] = [0.02, -0.01, 0.03, 0.04]
      
    • 输入数据转换为嵌入向量矩阵:

      [
          [0.02, -0.01, 0.03, 0.04],  # 对应销售值123
          [-0.03, 0.05, -0.02, 0.01],  # 对应销售值456
          ...
      ]
      
  3. 计算损失

    • 通过模型的前向传播得到预测结果,与真实的销售数据进行比较,计算损失。

    • 假设真实的销售数据是:

      [130, 460, 800, 330, 660, ...]
      
    • 计算预测结果与真实值之间的差异,例如使用均方误差(MSE)损失函数。

  4. 反向传播和梯度更新

    • 通过反向传播算法,计算损失对嵌入矩阵 ( W ) 中每个参数的梯度。

    • 使用优化算法(如梯度下降或Adam),根据计算得到的梯度更新嵌入矩阵中的参数。

      例如,如果在某次训练中发现销售值123的嵌入向量对损失的贡献较大,模型会调整这个嵌入向量的参数,使其在下一次预测中表现得更好:

      W[123] = [0.02, -0.01, 0.03, 0.04] -> [0.025, -0.015, 0.035, 0.045]
      
优化后的嵌入矩阵
  1. 训练后

    • 经过多次迭代,嵌入矩阵 ( W ) 中的向量逐步优化,每个销售值的嵌入向量能够更好地反映其在时间序列中的模式和关系。

    例如,经过训练后的嵌入矩阵可能变为:

    W = [
        [0.02, -0.03, 0.05, -0.02],  # 表示销售值0的嵌入向量
        [-0.02, 0.03, -0.04, 0.05],  # 表示销售值1的嵌入向量
        ...,
        [0.04, -0.05, 0.06, -0.07]   # 表示销售值1000的嵌入向量
    ]
    

通过这种方式,嵌入矩阵 ( W ) 在训练过程中从随机初始化的状态逐渐优化,最终能够提供有意义的高维向量表示,这些向量能够帮助模型更准确地进行预测和分类。

小结

嵌入层通过嵌入矩阵将输入数据从离散的索引空间映射到连续的高维向量空间。这种表示方法能够捕捉输入数据中的语义和特征信息,使得模型可以更有效地处理复杂的输入数据。这一过程在自然语言处理和时间序列分析等领域被广泛应用,通过查找表的方式将输入数据转换为高维向量,使得后续的深度学习模型可以更好地学习和泛化数据中的模式和依赖关系。

  • 21
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为您提供Python实现将Neo4j的知识图谱利用TransH嵌入方法转换成嵌入向量的代码,并附有详细注释。在提供代码之前,需要先安装PyTorch和py2neo模块。 ```python import torch from torch.utils.data import DataLoader from py2neo import Graph, Node, Relationship # 定义TransH模型 class TransH(torch.nn.Module): def __init__(self, ent_num, rel_num, dim, margin): super(TransH, self).__init__() self.ent_num = ent_num self.rel_num = rel_num self.dim = dim self.margin = margin self.ent_embedding = torch.nn.Embedding(self.ent_num, self.dim) self.rel_embedding = torch.nn.Embedding(self.rel_num, self.dim) self.norm_vector = torch.nn.Embedding(self.rel_num, self.dim) def _calc(self, h, t, r): h = h.view(-1, self.dim, 1) t = t.view(-1, self.dim, 1) r = r.view(-1, self.dim, 1) norm = torch.norm(r, p=2, dim=1, keepdim=True) norm_r = r / norm norm_h = torch.matmul(h, norm_r.transpose(1,2)) norm_t = torch.matmul(t, norm_r.transpose(1,2)) score = torch.norm(norm_h + r - norm_t, p=2, dim=1) return score def forward(self, pos_h, pos_t, pos_r, neg_h, neg_t, neg_r): pos_score = self._calc(pos_h, pos_t, pos_r) neg_score = self._calc(neg_h, neg_t, neg_r) loss_func = torch.nn.MarginRankingLoss(margin=self.margin) y = torch.Tensor([-1]) loss = loss_func(pos_score, neg_score, y) return loss def ent_embeddings(self): return self.ent_embedding.weight.detach().cpu().numpy() # 加载知识图谱数据 class KnowledgeGraphDataLoader(DataLoader): def __init__(self, graph, batch_size, num_workers): self.graph = graph self.batch_size = batch_size self.num_workers = num_workers self.ent2id = {} self.rel2id = {} self.id2ent = {} self.id2rel = {} self.train_triples = [] self.dev_triples = [] self.test_triples = [] self.load_data() # 加载数据 def load_data(self): query = "MATCH (h)-[r]->(t) RETURN id(h), id(t), type(r)" result = self.graph.run(query) for row in result: h, t, r = row if h not in self.ent2id: self.ent2id[h] = len(self.ent2id) self.id2ent[self.ent2id[h]] = h if t not in self.ent2id: self.ent2id[t] = len(self.ent2id) self.id2ent[self.ent2id[t]] = t if r not in self.rel2id: self.rel2id[r] = len(self.rel2id) self.id2rel[self.rel2id[r]] = r self.train_triples.append((self.ent2id[h], self.ent2id[t], self.rel2id[r])) # 获取训练数据 def get_train_data(self): return self.train_triples # 获取实体数量 def get_ent_num(self): return len(self.ent2id) # 获取关系数量 def get_rel_num(self): return len(self.rel2id) # 获取实体ID def get_ent_id(self, ent): return self.ent2id[ent] # 获取关系ID def get_rel_id(self, rel): return self.rel2id[rel] # 获取实体 def get_ent(self, ent_id): return self.id2ent[ent_id] # 获取关系 def get_rel(self, rel_id): return self.id2rel[rel_id] # 训练TransH模型 def train_transh(graph, dim=50, margin=1.0, lr=0.01, batch_size=1000, epochs=500, num_workers=8): data_loader = KnowledgeGraphDataLoader(graph, batch_size, num_workers) ent_num = data_loader.get_ent_num() rel_num = data_loader.get_rel_num() transh = TransH(ent_num, rel_num, dim, margin) optimizer = torch.optim.SGD(transh.parameters(), lr=lr) transh.train() for epoch in range(epochs): data_iter = DataLoader(data_loader, batch_size=batch_size, shuffle=True, num_workers=num_workers) for batch in data_iter: pos_h, pos_t, pos_r = torch.LongTensor(batch[:, 0]), torch.LongTensor(batch[:, 1]), torch.LongTensor(batch[:, 2]) neg_h, neg_t, neg_r = data_loader.get_corrupted_triples(pos_h, pos_t, pos_r) loss = transh(pos_h, pos_t, pos_r, neg_h, neg_t, neg_r) optimizer.zero_grad() loss.backward() optimizer.step() print('Epoch [{}/{}], Loss: {:.4f}'.format(epoch+1, epochs, loss.item())) return transh.ent_embeddings() # 连接Neo4j数据库 graph = Graph("bolt://localhost:7687", auth=('neo4j', 'password')) # 训练TransH模型 ent_embeddings = train_transh(graph, dim=50, margin=1.0, lr=0.01, batch_size=1000, epochs=500, num_workers=8) # 保存实体嵌入向量 for ent_id in range(len(ent_embeddings)): ent = data_loader.get_ent(ent_id) node = Node("Entity", name=ent, embedding=ent_embeddings[ent_id]) graph.create(node) ``` 以上代码实现了将Neo4j的知识图谱利用TransH嵌入方法转换成嵌入向量,并将实体嵌入向量保存到Neo4j数据库中。其中,TransH模型的训练过程采用随机梯度下降算法,优化器使用SGD,损失函数采用MarginRankingLoss,训练过程中使用了多线程加载数据。由于每个实体的嵌入向量是一个向量,因此使用了Neo4j的属性来保存实体嵌入向量

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值