666|2

169

帖子

1

TA的资源

纯净的硅(初级)

楼主
 

《动手学深度学习PyTorch版》阅读分享五 自然语言处理 [复制链接]

本帖最后由 cc1989summer 于 2024-10-12 21:02 编辑
前面分享了卷积神经网络,这也是机器学习中最基础的工具和模型。
在前面的介绍中,我们试着用卷积神经网络跑了手写识别案例,本次来到自然语言处理。
 
自然语言处理(NLP) 是指研究使用自然语言的计算机和人类之间的交互。 在实践中,使用自然语言处理技术来处理和分析文本数据是非常常见的,比如语义识别和机器翻译。
人类语言是抽象的信息符号,其中蕴含着丰富的语义信息,人类可以很轻松地理解其中的含义。而计算机只能处理数值化的信息,无法直接理解人类语言,所以需要将人类语言进行数值化转换。
 
NLP 通过将计算语言学(基于规则的人类语言建模)与统计建模、机器学习 (ML) 和深度学习相结合,使计算机和数字设备能够识别、理解和生成文本和语音。
NLP 研究开启了生成式 AI 时代,这涵盖了从大型语言模型 (LLM) 的沟通技巧到图像生成模型理解请求的能力。NLP 已经成为许多人日常生活的一部分,其应用场景包括为搜索引擎提供支持,通过语音命令提示聊天机器人以进行客户服务、语音操作的 GPS 系统和智能手机上的数字助理。
 
 
自然语言处理的架构如图,首先需经过预训练,再经由神经网络深度学习,最后完成预期的应用功能(情感分析or 自然语言推断)。
针对预训练,首要的是对自然语言处理,将其转化为机器学习可处理的向量。
自然语言是用来表达人脑思维的复杂系统。 在这个系统中,词是意义的基本单元。顾名思义, 词向量是用于表示单词意义的向量, 并且还可以被认为是单词的特征向量或表示。 将单词映射到实向量的技术称为词嵌入(WORD2VEC。 
 
 
为什么要对词进行编码(词向量化)?
任何数学模型,其输入都需要是数值型的,因为计算机只能理解数字,词语是人类语言的抽象总结,计算机时无法理解的,而在自然语言处理中,我们面对的是文字,而文字是无法直接被数学模型所直接利用的。所以我们需要将文字进行编码,将每一个字符用一个向量进行表示。
 
如何更好的表示单词呢?首先需要了解NLP领域的一个基本假设 —— 分布式假说(distributional hypothesis)。分布式假说是指上下文类似的单词具有相似的意义。或者说一个单词的含义由其上下文决定。例如,“苹果”如果与“香蕉”,“梨子”,“一斤”等词语同时出现时,它大概率表示一种水果;如果“苹果”与“手机”, “小米”,“ipad”等词语同时出现时,它大概率表示科技产品或者科技公司,此时它与水果的概念就相去甚远了。
 
比如把单词转化为50维的词向量:man和boy这两个相似的词就比较相似。
word2vec模式下的两个模型:CBOW和SkipGram
CBOW模型:是通过一个或多个单词的上下文来进行这个词语的预测
Skip Gram模型:是通过一个或多个单词来进行上下文的预测。
这里重点介绍CBOW(连续词袋模型),以上下文词汇预测当前词。
即用 去预测 
CBOW模型中,输入是上下文中的词语向量,再乘以输入权重矩阵,所得的向量求平均,作为隐藏层向量,再乘以输出权重矩阵,输出是目标词语的向量,在这个过程中不断最小化目标loss。在Skip-gram模型中,输入是目标词语的向量,输出是上下文中的词语向量。(输入层一般使用 one-hot将文字 -> 向量)。
one-hot是什么呢?独热编码(One-Hot Encoding),又称一位有效编码,是表示离散变量(categorical data)的一种方法。
 
例如我们有一句话为:I drink coffee everyday”,我们分词后对其进行one-hot编码,结果为:
  • I:[1, 0, 0, 0]
  • drink:[0, 1, 0, 0]
  • coffee:[0, 0, 1, 0]
  • everyday:[0, 0, 0, 1]
我们选coffee作为中心词,window size设为2,也就是说,我们要根据单词"I","drink""everyday"来预测一个单词,并且我们希望这个单词是coffee
下图就是word2vec的过程。
无论是CBOW 模型还是skip-gram 模型,word2vec 一般而言都能提供较高质量的词向量表达,下图是以 50000 个单词训练得到的 128 维的 skip-gram 词向量压缩到 2 维空间中的可视化展示图:
可以看到,意思相近的词基本上被聚到了一起,也证明了 word2vec 是一种可靠的词向量表征方式。
 
 
 
下面来跑基于CBOW 的Word2vec模型

1定义一个句子列表,后面会用这些句子来训练 CBOW模型 

import numpy as np
from torch import nn
from torch.nn import functional as F


# 定义一个句子列表,后面会用这些句子来训练 CBOW Skip-Gram 模型
sentences = ["Kage is Teacher", "Mazong is Boss", "Niuzong is Boss",
"Xiaobing is Student", "Xiaoxue is Student",]
# 将所有句子连接在一起,然后用空格分隔成多个单词
words = ' '.join(sentences).split()
# 构建词汇表,去除重复的词
word_list = list(set(words))
# 创建一个字典,将每个词映射到一个唯一的索引
word_to_idx = {word: idx for idx, word in enumerate(word_list)}
# 创建一个字典,将每个索引映射到对应的词
idx_to_word = {idx: word for idx, word in enumerate(word_list)}
voc_size = len(word_list) # 计算词汇表的大小
print(" 词汇表:", word_list) # 输出词汇表
print(" 词汇到索引的字典:", word_to_idx) # 输出词汇到索引的字典
print(" 索引到词汇的字典:", idx_to_word) # 输出索引到词汇的字典
print(" 词汇表大小:", voc_size) # 输出词汇表大小
运行结果:

2 生成 CBOW 训练数据 

代码:
# 生成 CBOW 训练数据
def create_cbow_dataset(sentences, window_size=2):
data = []# 初始化数据
for sentence in sentences:
sentence = sentence.split() # 将句子分割成单词列表
for idx, word in enumerate(sentence): # 遍历单词及其索引
# 获取上下文词汇,将当前单词前后各 window_size 单词作为周围词
context_words = sentence[max(idx - window_size, 0):idx] \
+ sentence[idx + 1:min(idx + window_size + 1, len(sentence))]
# 将当前单词与上下文词汇作为一组训练数据
data.append((word, context_words))
return data
# 使用函数创建 CBOW 训练数据
cbow_data = create_cbow_dataset(sentences)
# 打印未编码的 CBOW 数据样例(前三个)
print("CBOW 数据样例(未编码):", cbow_data[:3])
运行结果:

3 定义 One-Hot 编码函数 


def one_hot_encoding(word, word_to_idx):
tensor = torch.zeros(len(word_to_idx)) # 创建一个长度与词汇表相同的全 0 张量
tensor[word_to_idx[word]] = 1 # 将对应词的索引设为 1
return tensor # 返回生成的 One-Hot 向量

 

4 定义 CBOW 模型

 

# 定义 CBOW 模型
import torch.nn as nn # 导入 neural network
class CBOW(nn.Module):
    def __init__(self, voc_size, embedding_size):
        super(CBOW, self).__init__()
        # 从词汇表大小到嵌入大小的线性层(权重矩阵)
        self.input_to_hidden = nn.Linear(voc_size,
                                         embedding_size, bias=False)
        # 从嵌入大小到词汇表大小的线性层(权重矩阵)
        self.hidden_to_output = nn.Linear(embedding_size,
                                          voc_size, bias=False)
    def forward(self, X): # X: [num_context_words, voc_size]
        # 生成嵌入:[num_context_words, embedding_size]
        embeddings = self.input_to_hidden(X)
        # 计算隐藏层,求嵌入的均值:[embedding_size]
        hidden_layer = torch.mean(embeddings, dim=0)
        # 生成输出层:[1, voc_size]
        output_layer = self.hidden_to_output(hidden_layer.unsqueeze(0))
        return output_layer
embedding_size = 2 # 设定嵌入层的大小,这里选择 2 是为了方便展示
cbow_model = CBOW(voc_size,embedding_size)  # 实例化 CBOW 模型
print("CBOW 模型:", cbow_model)

 

 

 

 

 

5 训练 cbow 模型 

# 训练 cbow
learning_rate = 0.001 # 设置学习速率
epochs = 1000 # 设置训练轮次
criterion = nn.CrossEntropyLoss() # 定义交叉损失函数
import torch.optim as optim # 导入随机梯度下降优化器
optimizer = optim.SGD(cbow_model.parameters(), lr=learning_rate)
# 开始训练循环
loss_values = [] # 用于存储每轮的平均损失值
for epoch in range(epochs):
loss_sum = 0 # 初始化损失值
for target, context_words in cbow_data:
# 将上下文词转换为 One-Hot 向量并堆叠
X = torch.stack([one_hot_encoding(word, word_to_idx) for word in context_words]).float()
# 将目标词转换为索引值
y_true = torch.tensor([word_to_idx[target]], dtype=torch.long)
y_pred = cbow_model(X) # 计算预测值
loss = criterion(y_pred, y_true) # 计算损失
loss_sum += loss.item() # 累积损失
optimizer.zero_grad() # 清空梯度
loss.backward() # 反向传播
optimizer.step() # 更新参数
if (epoch+1) % 100 == 0: # 输出每 100 轮的损失,并记录损失
print(f"Epoch: {epoch+1}, Loss: {loss_sum/len(cbow_data)}")
loss_values.append(loss_sum / len(cbow_data))
# 绘制训练损失曲线
import matplotlib.pyplot as plt # 导入 matplotlib
# 绘制二维词向量
plt.rcParams["font.family"]=['SimHei'] # 用来设定字体样式
plt.rcParams['font.sans-serif']=['SimHei'] # 用来设定无衬线字体样式
plt.rcParams['axes.unicode_minus']=False # 用来正常显示负号
plt.plot(range(1, epochs//100 + 1), loss_values) # 绘图
plt.title(' 训练损失曲线 ') # 图题
plt.xlabel(' 轮次 ') # X Label
plt.ylabel(' 损失 ') # Y Label
plt.show() # 显示图

6 输出 cbow 习得的词嵌入

# 输出 cbow 习得的词嵌入
print("CBOW 词嵌入:")
for word, idx in word_to_idx.items(): # 输出每个词的嵌入向量
print(f"{word}: {cbow_model.input_to_hidden.weight[:,idx].detach().numpy()}")
运行结果为:
CBOW 词嵌入:
Niuzong: [0.46508402 0.55232465]
Teacher: [0.24856524 0.62238467]
is: [-0.6280461 -0.5844824]
Mazong: [0.15402862 0.36817124]
Xiaobing: [0.67069155 0.09598981]
Boss: [1.1241493 0.4596834]
Student: [0.44188187 0.6775399 ]
Kage: [0.5566621 0.48963603]
Xiaoxue: [0.8823291 0.12908652]

7 向量可视化看一下

fig, ax = plt.subplots()
for word, idx in word_to_idx.items():
# 获取每个单词的嵌入向量
vec = cbow_model.input_to_hidden.weight[:,idx].detach().numpy()
ax.scatter(vec[0], vec[1]) # 在图中绘制嵌入向量的点
ax.annotate(word, (vec[0], vec[1]), fontsize=12) # 点旁添加单词标签
plt.title(' 二维词嵌入 ') # 图题
plt.xlabel(' 向量维度 1') # X 轴 Label
plt.ylabel(' 向量维度 2') # Y 轴 Label
plt.show() # 显示图
运行结果为:
可以看到意思相近的词被划到了相近的位置。
本次的分享就到这里。
 
 
 
 
全部代码详见:
import numpy as np
import torch
from torch import nn
from torch.nn import functional as F

import torch
import torch.optim as optim

# 定义一个句子列表,后面会用这些句子来训练 CBOW 和 Skip-Gram 模型
sentences = ["Kage is Teacher", "Mazong is Boss", "Niuzong is Boss",
             "Xiaobing is Student", "Xiaoxue is Student",]
# 将所有句子连接在一起,然后用空格分隔成多个单词
words = ' '.join(sentences).split()
# 构建词汇表,去除重复的词
word_list = list(set(words))
# 创建一个字典,将每个词映射到一个唯一的索引
word_to_idx = {word: idx for idx, word in enumerate(word_list)}
# 创建一个字典,将每个索引映射到对应的词
idx_to_word = {idx: word for idx, word in enumerate(word_list)}
voc_size = len(word_list) # 计算词汇表的大小



# 生成 CBOW 训练数据
def create_cbow_dataset(sentences, window_size=2):
    data = []# 初始化数据
    for sentence in sentences:
        sentence = sentence.split()  # 将句子分割成单词列表
        for idx, word in enumerate(sentence):  # 遍历单词及其索引
            # 获取上下文词汇,将当前单词前后各 window_size 个单词作为周围词
            context_words = sentence[max(idx - window_size, 0):idx] \
                + sentence[idx + 1:min(idx + window_size + 1, len(sentence))]
            # 将当前单词与上下文词汇作为一组训练数据
            data.append((word, context_words))
    return data
# 使用函数创建 CBOW 训练数据
cbow_data = create_cbow_dataset(sentences)
# 打印未编码的 CBOW 数据样例(前三个)


def one_hot_encoding(word, word_to_idx):
    tensor = torch.zeros(len(word_to_idx))  # 创建一个长度与词汇表相同的全 0 张量
    tensor[word_to_idx[word]] = 1  # 将对应词的索引设为 1
    return tensor  # 返回生成的 One-Hot 向量


# 展示 One-Hot 编码前后的数据
word_example = "Teacher"
print("One-Hot 编码前的单词:", word_example)
print("One-Hot 编码后的向量:", one_hot_encoding(word_example, word_to_idx))


# 定义 CBOW 模型
import torch.nn as nn # 导入 neural network
class CBOW(nn.Module):
    def __init__(self, voc_size, embedding_size):
        super(CBOW, self).__init__()
        # 从词汇表大小到嵌入大小的线性层(权重矩阵)
        self.input_to_hidden = nn.Linear(voc_size,
                                         embedding_size, bias=False)
        # 从嵌入大小到词汇表大小的线性层(权重矩阵)
        self.hidden_to_output = nn.Linear(embedding_size,
                                          voc_size, bias=False)
    def forward(self, X): # X: [num_context_words, voc_size]
        # 生成嵌入:[num_context_words, embedding_size]
        embeddings = self.input_to_hidden(X)
        # 计算隐藏层,求嵌入的均值:[embedding_size]
        hidden_layer = torch.mean(embeddings, dim=0)
        # 生成输出层:[1, voc_size]
        output_layer = self.hidden_to_output(hidden_layer.unsqueeze(0))
        return output_layer
embedding_size = 2 # 设定嵌入层的大小,这里选择 2 是为了方便展示
cbow_model = CBOW(voc_size,embedding_size)  # 实例化 CBOW 模型
print("CBOW 模型:", cbow_model)


# 训练 cbow 类
learning_rate = 0.001 # 设置学习速率
epochs = 1000 # 设置训练轮次
criterion = nn.CrossEntropyLoss()  # 定义交叉熵损失函数
import torch.optim as optim # 导入随机梯度下降优化器
optimizer = optim.SGD(cbow_model.parameters(), lr=learning_rate)
# 开始训练循环
loss_values = []  # 用于存储每轮的平均损失值
for epoch in range(epochs):
    loss_sum = 0 # 初始化损失值
    for target, context_words in cbow_data:
        # 将上下文词转换为 One-Hot 向量并堆叠
        X = torch.stack([one_hot_encoding(word, word_to_idx) for word in context_words]).float()
        # 将目标词转换为索引值
        y_true = torch.tensor([word_to_idx[target]], dtype=torch.long)
        y_pred = cbow_model(X)  # 计算预测值
        loss = criterion(y_pred, y_true)  # 计算损失
        loss_sum += loss.item() # 累积损失
        optimizer.zero_grad()  # 清空梯度
        loss.backward()  # 反向传播
        optimizer.step()  # 更新参数
    if (epoch+1) % 100 == 0: # 输出每 100 轮的损失,并记录损失
      print(f"Epoch: {epoch+1}, Loss: {loss_sum/len(cbow_data)}")
      loss_values.append(loss_sum / len(cbow_data))


import matplotlib.pyplot as plt
# 输出 cbow 习得的词嵌入
print("CBOW 词嵌入:")
for word, idx in word_to_idx.items(): # 输出每个词的嵌入向量
    print(f"{word}: {cbow_model.input_to_hidden.weight[:,idx].detach().numpy()}")

    fig, ax = plt.subplots()
    for word, idx in word_to_idx.items():
        # 获取每个单词的嵌入向量
        vec = cbow_model.input_to_hidden.weight[:, idx].detach().numpy()
        ax.scatter(vec[0], vec[1])  # 在图中绘制嵌入向量的点
        ax.annotate(word, (vec[0], vec[1]), fontsize=12)  # 点旁添加单词标签
    plt.title(' 二维词嵌入 ')  # 图题
    plt.xlabel(' 向量维度 1')  # X 轴 Label
    plt.ylabel(' 向量维度 2')  # Y 轴 Label
    plt.show()  # 显示图

 

 
 

此帖出自编程基础论坛

最新回复

语义识别是不是就是机器翻译呢   详情 回复 发表于 2024-10-13 09:08
点赞 关注
 

回复
举报

6802

帖子

0

TA的资源

五彩晶圆(高级)

沙发
 

语义识别是不是就是机器翻译呢

此帖出自编程基础论坛

点评

语义识别是NLP(自然语言处理)中的一个重要技术,它可以使计算机更好地理解人类语言的含义和意图。 他的主要应用方向有:智能客服、搜索引擎、情感分析(舆论监控)、机器翻译。 说这么多,其实就是说,机器翻译只是  详情 回复 发表于 2024-10-13 11:59
 
 
 

回复

169

帖子

1

TA的资源

纯净的硅(初级)

板凳
 
Jacktang 发表于 2024-10-13 09:08 语义识别是不是就是机器翻译呢

语义识别是NLP(自然语言处理)中的一个重要技术,它可以使计算机更好地理解人类语言的含义和意图。

他的主要应用方向有:智能客服、搜索引擎、情感分析(舆论监控)、机器翻译。

说这么多,其实就是说,机器翻译只是语义识别的一个典型应用情景。

此帖出自编程基础论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表