当前位置: 首页 > article >正文

文本向量化

文本向量化表示的输出比较

import time

import torch
from transformers import AutoTokenizer, AutoModelForMaskedLM, AutoModel


# simcse相似度分数
def get_model_output(model, tokenizer, text_str):
    """
    验证文本向量化表示的输出
    :param model:       模型的名称
    :param tokenizer:   tokenizer
    :param text_str:    文本内容 可以只一个str, 也可以是一个str_list
    :return:            返回该文本向量表示形式
    """
    # 返回的类似一个字典类型
    # padding 表示填充max_len  CLS + text + [SEP] return_tensors="pt" 返回pytorch类型的张量
    # 如果不加这个return_tensors="pt"参数 input_ids等key的value就不是tensor而是list
    inputs_text = tokenizer(text_str, return_tensors="pt",  padding=True)
    print_inputs_source(**inputs_text)

    with torch.no_grad():
        outputs_source = model(**inputs_text)
        last_hidden_states = outputs_source.last_hidden_state                   # shape (b_s, max_len, 768)
        # 一般我们会使用的三个模型输出 建议使用 pooling_output
        last_cls_embedding = outputs_source.last_hidden_state[:, 0, :]          # shape (b_s, 768) 每个文本的CLS 表示 这个是固定的
        last_hidden_states_mean = outputs_source.last_hidden_state.mean(dim=1)  # shape (b_s, 768) 这个表示会有问题 对(b_s, max_len, 768) 进行平均池化得到的
        pooling_output = outputs_source.pooler_output                           # shape (b_s, 768) 每个文本的CLS之后在进入一次池化(全连接层)得到pool_output   这个表示也是固定的
        last_hidden_states_pooling = model.pooler(last_hidden_states)
        print("last_hidden_states shape {}".format(last_hidden_states.shape))
        print("last_CLS_embedding shape {}".format(last_cls_embedding.shape))
        print("last_hidden_states_pool shape {}".format(last_hidden_states_pooling.shape))
        print("last_hidden_states_mean shape {}".format(last_hidden_states_mean.shape))
        print("pool_output shape {}".format(pooling_output.shape))
        print("equal last_pool and pool_output: {}".format(torch.equal(pooling_output, last_hidden_states_pooling)))

        print("last_hidden_states embedding {}".format(last_hidden_states))
        print("last_hidden_states mead {}".format(last_hidden_states_mean))
        print("last_cls_embedding embedding {}".format(last_cls_embedding))
        print("pool_output {}".format(pooling_output))


def print_inputs_source(input_ids, token_type_ids, attention_mask):
    """
    打印模型tokenizer之后的内容
    :param input_ids:
    :param token_type_ids:
    :param attention_mask:
    :return:
    """
    print("input_ids: {}".format(input_ids))
    print("token_type_ids: {}".format(token_type_ids))
    print("attention_mask: {}".format(attention_mask))



if __name__ == '__main__':
    """字典的拆包"""
    # "D:\program\pretrained_model\ESimCSE-ext-chinese-bert-wwm"
    """
    Erlangshen-SimCSE-110M-Chinese
    ESimCSE-ext-chinese-bert-wwm        这里的tokenier_config文件用的是sup-simcse的
    sup-simcse-bert-base-uncased
    "bert-base-uncased"
    """
    start_run_time = time.time()
    prefix_path = "D:/program/pretrained_model/"        # 本地路径前缀
    model_path = prefix_path + "bert-base-uncased"
    model = AutoModel.from_pretrained(model_path)
    tokenizer = AutoTokenizer.from_pretrained(model_path)
    text_str = "中国"
    text_list = ["中国", "今天是个好日子"]
    get_model_output(model, tokenizer, text_list)

1. CLS表示整个文本

outputs_source.hidden_states[-1][:, 0, :]这行代码是用来从模型的输出中提取最后一层的所有单词的第一个位置(通常是 [CLS] 标记)的隐藏状态。

1.1 关键代码:

        outputs_source = model(**inputs_text) 
        last_hidden_states = outputs_source.last_hidden_state                   # shape (b_s, max_len, 768)
pooling_output
        sentence_embedding = outputs_source.last_hidden_state[:, 0, :]          # shape (b_s, 768) 每个文本的CLS 表示 这个是固定的

这里首先得到模型的最后一层隐藏状态的输出last_hidden_state,shape (b_s, max_len, 768)
然后选出CLS这个token的表示将其作为整个句子的表示

1.2 整体代码

import time

import torch
from transformers import AutoTokenizer, AutoModelForMaskedLM, AutoModel


# simcse相似度分数
def get_model_output(model, tokenizer, text_str):
    """
    验证文本向量化表示的输出
    :param model:       模型的名称
    :param tokenizer:   tokenizer
    :param text_str:    文本内容 可以只一个str, 也可以是一个str_list
    :return:            返回该文本向量表示形式
    """
    # 返回的类似一个字典类型
    # padding 表示填充max_len  CLS + text + [SEP] return_tensors="pt" 返回pytorch类型的张量
    inputs_text = tokenizer(text_str, return_tensors="pt",  padding=True)
    # print_inputs_source(**inputs_text)

    with torch.no_grad():
        outputs_source = model(**inputs_text)
        last_hidden_states = outputs_source.last_hidden_state                   # shape (b_s, max_len, 768)
        # 一般我们会使用的三个模型输出 建议使用 pooling_output
        sentence_embedding = outputs_source.last_hidden_state[:, 0, :]          # shape (b_s, 768) 每个文本的CLS 表示 这个是固定的

    print("last_hidden_state shape: {}".format(last_hidden_states.shape))
    print("cls_embedding shape: {}".format(sentence_embedding.shape))
    print("last_cls_embedding: {}".format(sentence_embedding))
    return sentence_embedding


def print_inputs_source(input_ids, token_type_ids, attention_mask):
    """
    打印模型tokenizer之后的内容  CLS + text + SEP
    :param input_ids:
    :param token_type_ids:
    :param attention_mask:
    :return:
    """
    print("input_ids: {}".format(input_ids))
    print("token_type_ids: {}".format(token_type_ids))
    print("attention_mask: {}".format(attention_mask))


if __name__ == '__main__':
    start_run_time = time.time()
    prefix_path = "D:/program/pretrained_model/"        # 本地路径前缀
    model_path = prefix_path + "bert-base-uncased"
    model = AutoModel.from_pretrained(model_path)
    tokenizer = AutoTokenizer.from_pretrained(model_path)
    text_str = "中国"
    text_list = ["中国", "今天是个好日子"]
    get_model_output(model, tokenizer, text_str)

    end_run_time = time.time()
    used_time = end_run_time-start_run_time
    print("消耗时间为: {}秒".format(used_time))

输出结果: 中国 的文本表示如下
在这里插入图片描述

2. pooler_output表示整个文本

outputs_source.pooler_output 表示从模型的输出中提取的池化器输出(pooler output)。

在BERT模型中,经过最后一层的所有隐藏状态被经过一些池化操作,得到一个被称为"pooler output"的表示。这个表示通常被用于下游任务的输入,因为它是整个句子/序列的一个紧凑的表示。

所以,outputs_source.pooler_output 就是源文本(或输入文本)通过池化器得到的表示。

2.1 关键代码

        outputs_source = model(**inputs_text)
        sentence_embedding = outputs_source.pooler_output                   # shape (b_s, max_len, 768)

这里相当于是把最后一层隐藏状态通过一个全连接层然后在进行输出表示整个句子

2.2 整体代码

import time

import torch
from transformers import AutoTokenizer, AutoModelForMaskedLM, AutoModel


# simcse相似度分数
def get_model_output(model, tokenizer, text_str):
    """
    验证文本向量化表示的输出
    :param model:       模型的名称
    :param tokenizer:   tokenizer
    :param text_str:    文本内容 可以只一个str, 也可以是一个str_list
    :return:            返回该文本向量表示形式
    """
    # 返回的类似一个字典类型
    # padding 表示填充max_len  CLS + text + [SEP] return_tensors="pt" 返回pytorch类型的张量
    inputs_text = tokenizer(text_str, return_tensors="pt",  padding=True)
    # print_inputs_source(**inputs_text)

    with torch.no_grad():
        outputs_source = model(**inputs_text)
        sentence_embedding = outputs_source.pooler_output                   # shape (b_s, max_len, 768)
        # 一般我们会使用的三个模型输出 建议使用 pooling_output
        # sentence_embedding = outputs_source.last_hidden_state[:, 0, :]          # shape (b_s, 768) 每个文本的CLS 表示 这个是固定的

    print("pooling_embedding shape: {}".format(sentence_embedding.shape))
    print("pooling_embedding: {}".format(sentence_embedding))
    return sentence_embedding


def print_inputs_source(input_ids, token_type_ids, attention_mask):
    """
    打印模型tokenizer之后的内容  CLS + text + SEP
    :param input_ids:
    :param token_type_ids:
    :param attention_mask:
    :return:
    """
    print("input_ids: {}".format(input_ids))
    print("token_type_ids: {}".format(token_type_ids))
    print("attention_mask: {}".format(attention_mask))


if __name__ == '__main__':
    start_run_time = time.time()
    prefix_path = "D:/program/pretrained_model/"        # 本地路径前缀
    model_path = prefix_path + "bert-base-uncased"
    model = AutoModel.from_pretrained(model_path)
    tokenizer = AutoTokenizer.from_pretrained(model_path)
    text_str = "中国"
    text_list = ["中国", "今天是个好日子"]
    get_model_output(model, tokenizer, text_str)

    end_run_time = time.time()
    used_time = end_run_time-start_run_time
    print("消耗时间为: {}秒".format(used_time))

输出结果: 中国 的文本表示如下
在这里插入图片描述

3. 利用最后隐藏状态的mean进行表示

3.1 关键代码

        outputs_source = model(**inputs_text)
        sentence_embedding = outputs_source.last_hidden_state.mean(dim=1)         # shape (b_s, max_len, 768)

这里是利用last_hidden_state的mean进行表示 但这个表示如果利用批量文本向量化的时候可能会出现问题,因为mean的时候会考虑padding, cls_embedding, 和pool_embedding就不会出现这种情况

3.2 整体代码

import time

import torch
from transformers import AutoTokenizer, AutoModelForMaskedLM, AutoModel


# simcse相似度分数
def get_model_output(model, tokenizer, text_str):
    """
    验证文本向量化表示的输出
    :param model:       模型的名称
    :param tokenizer:   tokenizer
    :param text_str:    文本内容 可以只一个str, 也可以是一个str_list
    :return:            返回该文本向量表示形式
    """
    # 返回的类似一个字典类型
    # padding 表示填充max_len  CLS + text + [SEP] return_tensors="pt" 返回pytorch类型的张量
    inputs_text = tokenizer(text_str, return_tensors="pt",  padding=True)
    # print_inputs_source(**inputs_text)

    with torch.no_grad():
        outputs_source = model(**inputs_text)
        sentence_embedding = outputs_source.last_hidden_state.mean(dim=1)         # shape (b_s, max_len, 768)
        # 一般我们会使用的三个模型输出 建议使用 pooling_output
        # sentence_embedding = outputs_source.last_hidden_state[:, 0, :]          # shape (b_s, 768) 每个文本的CLS 表示 这个是固定的

    print("last_mean_embedding shape: {}".format(sentence_embedding.shape))
    print("last_mean_embedding: {}".format(sentence_embedding))
    return sentence_embedding


def print_inputs_source(input_ids, token_type_ids, attention_mask):
    """
    打印模型tokenizer之后的内容  CLS + text + SEP
    :param input_ids:
    :param token_type_ids:
    :param attention_mask:
    :return:
    """
    print("input_ids: {}".format(input_ids))
    print("token_type_ids: {}".format(token_type_ids))
    print("attention_mask: {}".format(attention_mask))


if __name__ == '__main__':
    start_run_time = time.time()
    prefix_path = "D:/program/pretrained_model/"        # 本地路径前缀
    model_path = prefix_path + "bert-base-uncased"
    model = AutoModel.from_pretrained(model_path)
    tokenizer = AutoTokenizer.from_pretrained(model_path)
    text_str = "中国"
    text_list = ["中国", "今天是个好日子"]
    get_model_output(model, tokenizer, text_str)

    end_run_time = time.time()
    used_time = end_run_time-start_run_time
    print("消耗时间为: {}秒".format(used_time))

输出结果: 中国 的文本表示如下
在这里插入图片描述

输出结果: 如果输入文本为text_list(批量向量化)那么输出结果如下
在这里插入图片描述

这里可以发现中国的文本表示变化了 说明padding填充影响了mean的结果
所以这种方法慎重使用

4. 总结:

4.1 三种表示方法

        model(**inputs_text).last_hidden_state.mean(dim=1)
        model(**inputs_text).last_hidden_state[:, 0, :]
        model(**inputs_text).pooler_output

4.2 last_hidden_state 和 pooler_output的区别以及转化

参考博客: https://blog.csdn.net/ningyanggege/article/details/132206331

last_hidden_states = model(**inputs_text).last_hidden_state 
model.pooler(last_hidden_state) == model(**inputs_text).pooler_output
import time

import torch
from transformers import AutoTokenizer, AutoModelForMaskedLM, AutoModel


# simcse相似度分数
def get_model_output(model, tokenizer, text_str):
    """
    验证文本向量化表示的输出
    :param model:       模型的名称
    :param tokenizer:   tokenizer
    :param text_str:    文本内容 可以只一个str, 也可以是一个str_list
    :return:            返回该文本向量表示形式
    """
    # 返回的类似一个字典类型
    # padding 表示填充max_len  CLS + text + [SEP] return_tensors="pt" 返回pytorch类型的张量
    inputs_text = tokenizer(text_str, return_tensors="pt",  padding=True)
    # print_inputs_source(**inputs_text)

    with torch.no_grad():
        outputs_source = model(**inputs_text)
        pooling_embedding = outputs_source.pooler_output                   # shape (b_s, max_len, 768)

        last_pool_embedding = model.pooler(outputs_source.last_hidden_state)

        # 一般我们会使用的三个模型输出 建议使用 pooling_output
        # sentence_embedding = outputs_source.last_hidden_state[:, 0, :]          # shape (b_s, 768) 每个文本的CLS 表示 这个是固定的

    print("valid equals {}".format(torch.equal(pooling_embedding, last_pool_embedding)))

    return pooling_embedding


if __name__ == '__main__':
    start_run_time = time.time()
    prefix_path = "D:/program/pretrained_model/"        # 本地路径前缀
    model_path = prefix_path + "bert-base-uncased"
    model = AutoModel.from_pretrained(model_path)
    tokenizer = AutoTokenizer.from_pretrained(model_path)
    text_str = "中国"
    text_list = ["中国", "今天是个好日子"]
    get_model_output(model, tokenizer, text_str)

    end_run_time = time.time()
    used_time = end_run_time-start_run_time
    print("消耗时间为: {:.2f}秒".format(used_time))


水平有限 如有问题欢迎指正交流
参考博客: https://blog.csdn.net/ningyanggege/article/details/132206331


http://www.kler.cn/a/133727.html

相关文章:

  • 《MYSQL45讲》误删数据怎么办
  • 并发基础:(淘宝笔试题)三个线程分别打印 A,B,C,要求这三个线程一起运行,打印 n 次,输出形如“ABCABCABC....”的字符串【举一反三】
  • 《EasyQuotation 与MongoDB在股市信息的奇妙融合》
  • 推荐一款好用的postman替代工具2024
  • 弹性盒子布局(Flexbox)详细介绍
  • 网络安全-Linux基础(bash脚本)
  • PTA-6-42 设计门票(抽象类)
  • [C/C++] 数据结构 LeetCode:用队列实现栈
  • 【碰碰球】弹珠游戏-微信小程序项目开发流程详解
  • 【短文】【踩坑】可以在Qt Designer给QTableWidge添加右键菜单吗?
  • 最长回文子序列 递归与动态规划
  • 【精选】项目管理工具——Maven详解
  • STM32的启动流程
  • 数据双向 双向数据绑定
  • 【Promise12数据集】Promise12数据集介绍和预处理
  • odoo16前端框架源码阅读——env.js
  • 深度优化数据库性能:Linux 内核参数调整解析
  • ChatGPT 从零到一打造私人智能英语学习助手
  • 【JavaEE初阶】计算机是如何工作的
  • Leetcode经典题目之“双指针交换元素“类题目
  • 基于SSM的古董拍卖系统
  • 基础组件-流量回放平台设计
  • 单线程的JS中Vue导致的“线程安全”问题
  • 【FPGA】Verilog:实现 RS 触发器 | Flip-Flop | 使用 NOR 的 RS 触发器 | 使用 NAND 的 RS 触发器
  • VUE(一)
  • Chrome 浏览器经常卡死问题解决