自己动手做chatgpt:解析gpt底层模型transformer的输入处理

news2024/11/18 9:49:18

前面我们完成了一些基本概念,如果你对深度学习的基本原理还不了解,你可以通过这里获得更多信息,由于深度学习的教程汗牛充栋,因此我在这里不会重复,而是集中精力到chatgpt模型原理的分析,实现和实践上。ChatGPT基于一种叫transformer的深度学习模型,它又由一系列组件组合而成,对称我们将逐个剖析。首先我们看看transformer模型的基本结构:
请添加图片描述

不知你是否感觉这个图有种赛博朋克的科幻感。两个大方块左边那个叫encoder,也叫编码器,在深度学习中一种很常见的模式是,将输入数据经过一系列运算后转换成一种特定向量,用术语说叫lantent vector,这个向量往往记录了输入数据的特定属性,右边方块叫decoder,它的作用是解析encoder生成的中间向量,然后生成某种特定的输出。举个具体例子,警察在侦查案件时,往往会让目击者描述嫌疑人的长相特征,此时目击者就相当于encoder,他描述的特征比如“圆脸,卷发,高额头”等就相当于上面encoder的输出向量,然后公安部分有特定的刑侦人员通过这些特征把嫌疑人的相貌绘制出来,通常绘制的画像跟真实嫌疑人相貌有不小差距,但是由于它能捕捉特定特征,因此这种画像对警方追查嫌疑人也有很大帮助。

首先我们看第一步请添加图片描述
inputs是模型的输入数据,对chatgpt来说输入就是一个单词或者句子,input embedding是对输入的一种预处理,它把输入的单词或句子转换成一个向量,这一步是NLP算法中一个重要的课题,前面我们描述过任何难以用传统数据结构描述的对象都可以用向量来表示,当一个词被转换成多维空间的向量时,我们就能通过研究向量在空间中的分布来了解它在语言中的特性,同时如果两个单词分别转换成向量后,如果他们对应的向量在空间上距离越接近,我们就认为他们之间的关系越紧密。

首先我们看看如何将单词转换为向量,这里我们使用BERT模型,它是谷歌大脑早期基础模型之一,通过它我们就能够直接将单词转换为向量。首先我们看一个句子:

The man is king and he loves dog, the woman is queen and she loves cat

在句子中有几个关键词,(man,woman), (king, queen), (dog, cat),可以看到每一组的两个词,它们在含义上互相接近,因此有理由预计如果将他们转换为向量,那么括号对里单词对应的向量在空间上的距离会相互接近,我们用代码检验一下:

from transformers import AutoTokenizer, AutoModel
import torch
from sklearn.metrics.pairwise import cosine_similarity

# Load the BERT tokenizer and model
tokenizer = AutoTokenizer.from_pretrained('bert-base-uncased')
model = AutoModel.from_pretrained('bert-base-uncased')

words = ["man", "woman", "king", "queen", "cat", "dog"]
#embeddings = np.array([word2Vector(word).detach().numpy().reshape(1, -1).flatten() for word in words])
sentence = "The man is king and he loves dog, the woman is queen and she loves cat"
word1 = "man"
word2 = "woman"
word3 = "king"
word4 = "queen"
word5 = "cat"
word6 = "dog"

# Tokenize the sentence and words
tokens = tokenizer(sentence, return_tensors='pt')
word1_tokens = tokenizer(word1, return_tensors='pt')
word2_tokens = tokenizer(word2, return_tensors='pt')
word3_tokens = tokenizer(word3, return_tensors='pt')
word4_tokens = tokenizer(word4, return_tensors='pt')
word5_tokens = tokenizer(word5, return_tensors='pt')
word6_tokens = tokenizer(word6, return_tensors='pt')

# Get the embeddings for the sentence and words
sentence_embedding = model(**tokens).last_hidden_state.mean(dim=1).squeeze()
word1_embedding = model(**word1_tokens).last_hidden_state.mean(dim=1).squeeze()
word2_embedding = model(**word2_tokens).last_hidden_state.mean(dim=1).squeeze()
word3_embedding = model(**word3_tokens).last_hidden_state.mean(dim=1).squeeze()
word4_embedding = model(**word4_tokens).last_hidden_state.mean(dim=1).squeeze()
word5_embedding = model(**word5_tokens).last_hidden_state.mean(dim=1).squeeze()
word6_embedding = model(**word6_tokens).last_hidden_state.mean(dim=1).squeeze()

embeddings = [word1_embedding.detach().numpy().reshape(1, -1).flatten(), word2_embedding.detach().numpy().reshape(1, -1).flatten(),
              word3_embedding.detach().numpy().reshape(1, -1).flatten(), word4_embedding.detach().numpy().reshape(1, -1).flatten(),
              word5_embedding.detach().numpy().reshape(1, -1).flatten(), word6_embedding.detach().numpy().reshape(1, -1).flatten()]

上面代码通过下载已经训练好的BERT模型,然后将给定句子进行分词,每个单词在模型训练的语料中都有对应编号,我们找到其编号也就是上面对应的word1_tokens等输入到模型中获得其对应向量word1_embedding,我们不用关心上面代码的逻辑,只需要知道代码把单词转换为向量即可,然后我们把向量打印出来看看:

import numpy as np
print(np.shape(word1_embedding.detach().numpy().reshape(1, -1).flatten()))
print(f"word embedding : {word1_embedding}")

上面代码运行后所得结果如下:
请添加图片描述
可以看到单词转换为向量后,对应的是一个包含有768个元素的一维向量,接下来我们把六个单词向量绘制出来看看其对应关系:

import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA

pca = PCA(n_components=2)
embeddings_2d = pca.fit_transform(embeddings)
fig, ax = plt.subplots()
ax.scatter(embeddings_2d[:, 0], embeddings_2d[:, 1])
for i, word in enumerate(words):
    ax.annotate(word, (embeddings_2d[i, 0], embeddings_2d[i, 1]))
plt.show()

上面代码运行后所得结果如下:
在这里插入图片描述
可以看到上面提到的每个括号里面的单词,相互之间距离接近,也就是说这些单词在语义上相互之间的关联性比较强,此外单词向量化后我们还能计算他们在语义上的相似性,从上图也可以看到,(man, women)在语义上相近,(queen, king)在语义上相近,(cat,dog)在语义上相近,在算法上我们通过计算两个向量夹角的余弦值来判断两个向量指向对象的相似度,我们看看相应代码实现:

man_king_sim = torch.cosine_similarity(word1_embedding, word3_embedding, dim=0)
print(f"sim for man and king: {man_king_sim}")

上面代码输出结果为:
sim for man and king: 0.861815869808197

woman_queen_sim = torch.cosine_similarity(word2_embedding, word4_embedding, dim=0)
print(f'sim for woman and queen: {woman_queen_sim}')

代码输出结果为:
sim for woman and queen: 0.8941507935523987

man_woman_sim = torch.cosine_similarity(word1_embedding, word2_embedding, dim=0)
print(f'sim for man and woman: {man_woman_sim}')

输出结果为:
im for man and woman: 0.9260298013687134

man_dog_sim = torch.cosine_similarity(word1_embedding, word6_embedding, dim=0)
print(f'sim for man and dog: {man_dog_sim}')

woman_dog_sim = torch.cosine_similarity(word2_embedding, word5_embedding, dim=0)
print(f'sim for woman and cat : {woman_dog_sim}')

dog_cat_sim = torch.cosine_similarity(word6_embedding, word5_embedding, dim=0)
print(f'sim for dog and cat: {dog_cat_sim}')

上面代码输出结果为:

sim for man and dog: 0.8304506540298462
sim for woman and cat : 0.876427948474884
sim for dog and cat: 0.900851309299469

从输出结果我们看到,dog和cat在语义上接近,man和woman在语义上接近。在具体的文本中,影响两个词意思相近性的因素还有他们在文本中的距离,假设man和women在一个句子中距离很近,那么就有可能他们指向的是一对夫妇或者情侣,但如果距离很远,那有可能文章的意思就是在说两个不相干的人,因此单词在文本中的距离也会影响他们在语义上的成分,因此chatgpt在识别文本时,也会把单词的距离纳入考量。

回到上面架构图,我们会看到在输入部分还有一个叫positional encoding的东西,如下图所示:
请添加图片描述
这个positional encoding 本质就是对单词在句子中的距离进行编码,这里位置的编码结果也是一维向量,而且向量的长度跟单词对应向量要一致,因为他们要进行加法运算后,其结果才能输入给chatgpt进行下一步处理,那么chatgpt是怎么去”编码“单词位置的呢,它用了如下方式进行计算:
请添加图片描述

公式中pos表示单词在句子中的位置,i表示向量中分量的下标,当i=0时PE(pos, 0)就是第0个分量的取值,PE(pos, 2*0+1) 就是第1个分量的取值,d_model表示的是向量的长度,由于上面我们对单词的编码向量长度是768,因此它这里的取值也是768,我们看看实现代码:

import numpy as np

def positional_encoding(max_len, d_model):
    """
    Generates positional encoding for a given sequence length and model dimension.
    
    Args:
        max_len (int): Maximum sequence length.
        d_model (int): Model dimension.
        
    Returns:
        np.array: Positional encoding matrix of shape (max_len, d_model).
    """
    pos_enc = np.zeros((max_len, d_model))
    for pos in range(max_len):
        for i in range(0, d_model, 2):
            # Compute positional encoding values
            div_term = np.power(10000, (2 * i) / d_model)
            pos_enc[pos, i] = np.sin(pos / div_term)
            pos_enc[pos, i + 1] = np.cos(pos / div_term)
    return pos_enc

max_len = len(sentence)
d_model = 768
pos_enc = positional_encoding(max_len, d_model)
print("Positional Encoding:\n", pos_enc)

上面代码执行后输出如下:

Positional Encoding:
 [[ 0.00000000e+00  1.00000000e+00  0.00000000e+00 ...  1.00000000e+00
   0.00000000e+00  1.00000000e+00]
 [ 8.41470985e-01  5.40302306e-01  8.15250650e-01 ...  1.00000000e+00
   1.04913973e-08  1.00000000e+00]
 [ 9.09297427e-01 -4.16146837e-01  9.44236772e-01 ...  1.00000000e+00
   2.09827946e-08  1.00000000e+00]
 ...
 [-8.55519979e-01 -5.17769800e-01  8.57295439e-01 ...  1.00000000e+00
   7.02923619e-07  1.00000000e+00]
 [-8.97927681e-01  4.40143022e-01  9.16178088e-01 ...  1.00000000e+00
   7.13415016e-07  1.00000000e+00]
 [-1.14784814e-01  9.93390380e-01  2.03837160e-01 ...  1.00000000e+00
   7.23906413e-07  1.00000000e+00]]

接下来我们按照上图把位置编码对应的向量跟单词向量相加:

pe_tensor = []
for tensor in pos_enc:
  pe_tensor.append(torch.from_numpy(tensor))

man_index = sentence.index("man")
man_pe_tensor = word1_embedding + pe_tensor[man_index]

woman_index = sentence.index("woman")
woman_pe_tensor = word2_embedding + pe_tensor[woman_index]

dog_index = sentence.index("dog")
dog_pe_tensor = word6_embedding + pe_tensor[dog_index]

cat_index = sentence.index("cat")
cat_pe_tensor = word5_embedding + pe_tensor[cat_index]

现在所得的最终向量不但包含了单词的语义,同时还包含了单词在句子中的位置信息,于是chatgpt就得综合这两种信息来对单词进行识别,那么单词向量加上位置信息后会有什么影响呢,一个可见的影响是,如果两个单词在位置中的距离越远,那么他们的语义相似度就会降低,也就是单词向量加上它对应的位置向量后,所得结果进行余弦计算时其对应的结果应该会有相应的降低,我们实验看看:

man_woman_pe = torch.cosine_similarity(man_pe_tensor, woman_pe_tensor, dim = 0)
print(f'man woman sim with pe: {man_woman_pe}')  #0.9260298013687134

man_dog_pe = torch.cosine_similarity(man_pe_tensor, dog_pe_tensor, dim = 0)
print(f'man dog sim with pe: {man_dog_pe}')  #0.8304506540298462

woman_cat_pe = torch.cosine_similarity(woman_pe_tensor, cat_pe_tensor, dim = 0)
print(f'woman cat sim with pe: {woman_cat_pe}') #0.876427948474884

dog_cat_pe = torch.cosine_similarity(dog_pe_tensor, cat_pe_tensor, dim = 0)
print(f'dog cat sim with pe: {dog_cat_pe}') #0.900851309299469

上面代码运行结果如下;

man woman sim with pe: 0.8062191669897198
man dog sim with pe: 0.8047418505220771
woman cat sim with pe: 0.7858729168616464
dog cat sim with pe: 0.7830654688550558

通过结果我们能看到,在考虑到距离因素后,对应两个词在语义上的相似度确实有相应的降低。至此我们就完成了chatgpt模型输入处理部分的分析,想一节我们分析开启大模型算法的理论基石:multi-attention,正是因为这个机制或算法的引进,chatgpt这种基于transfomer架构的语言生成能力才会如此强悍。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/441933.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

初识C语言————3

博主这篇文章浅谈一下自己对函数和数组的理解。之后会详细说明。 文章目录 一、函数 二、数组 1、数组定义 2、数组的下标 3、数组的使用 一、函数 函数可以理解为一个模块的代码&#xff0c;完成一个独立的功能。 #include <stdio.h> int main() {int num1 0;int num…

ASEMI代理ADM3051CRZ-REEL7原装ADI车规级ADM3051CRZ-REEL7

编辑&#xff1a;ll ASEMI代理ADM3051CRZ-REEL7原装ADI车规级ADM3051CRZ-REEL7 型号&#xff1a;ADM3051CRZ-REEL7 品牌&#xff1a;ADI/亚德诺 封装&#xff1a;SOIC-8 批号&#xff1a;2023 引脚数量&#xff1a;8 安装类型&#xff1a;表面贴装型 ADM3051CRZ-REEL7汽…

【Python】读取rdata类型数据转为csv excel格式文件, 无需安装r语言基于pyreadr+pandas实现数据分析(保姆级注释)

目录 环境配置取得数据名 datas.keys()取得pandas的DataFrame类型数据一些数据分析例程供入门同学学习转化为csv excel格式所有数据 转化为csv取前面100行数据 快速测试能否转化csv取前面100行数据 快速测试能否转化xlsx 完整例程总结 欢迎关注 『Python』 系列&#xff0c;持续…

简述AutoGPT原理(提示词)

启动时需要设置三个项目&#xff1a;机器人名字、设定给机器人的角色、要完成的目标。 根据你的设定利用ChatGPT进行下一步的抉择&#xff0c;具体的&#xff0c;实际上归功于提示词&#xff1a; 下面这段提示词在干什么呢&#xff1f; 将设定的名字、角色、目标告诉ChatGPT&…

【U8+】用友U8+对账不平案例及方法总结

【问题需求】 在使用用友U8软件过程中&#xff0c;由于软件涉及到多方面的对账。 所以经常会遇到期初或结账时对账不平。 【经验分享】 在众多对账中&#xff0c; 只有当【总账上下级】&#xff08;即&#xff1a;总账与明细账对账&#xff09;不平的时候&#xff0c; 软件才…

春秋云境:CVE-2022-26965(后台RCE)

目录 一、题目 二、 利用cms主题构造木马 一、题目 介绍&#xff1a; Pluck-CMS-Pluck-4.7.16 后台RCE 进入题目&#xff1a; cms页面 点击admin进行登录&#xff1a; 弱口令admin登录&#xff1a; 成功登录进去&#xff1a; 国产化一下&#xff1a; 选项---选择主题 点击…

漏洞分析丨cve20144113

一、漏洞简述 Microsoft Windows下的 win32k.sys是Windows子系统的内核部分&#xff0c;是一个内核模式设备驱动程序&#xff0c;它包含有窗口管理器、后者控制窗口显示和管理屏幕输出等。如果Windows内核模式驱动程序不正确地处理内存中的对象&#xff0c;则存在一个特权提升…

js对象案例练习

个人名片&#xff1a; &#x1f60a;作者简介&#xff1a;一名大一在校生&#xff0c;web前端开发专业 &#x1f921; 个人主页&#xff1a;python学不会123 &#x1f43c;座右铭&#xff1a;懒惰受到的惩罚不仅仅是自己的失败&#xff0c;还有别人的成功。 &#x1f385;**学习…

SQL Server的日志传送

日志传送和复制 一、前言二、相关术语和定义三、日志传送和复制3.1、在主数据库丢失时从辅助数据库进行复制的要求和过程3.2、使用事务复制进行日志传送3.3、使用合并复制进行日志传送 一、前言 日志传送允许您自动将事务日志备份从主服务器实例上的主数据库发送到单独辅助服务…

思维导图手撕MyBatis源码

文章目录 前置准备通过类加载器读取配置文件流创建sqlSessionFactory建造者模式的使用 打开SqlSession获取Mapper接口对象执行Mapper接口方法 前置准备 既然要读MyBatis的源码&#xff0c;那么我们就要先弄清楚MyBatis的入口在哪。这里我们直接写一个标准的MyBatis使用程序&am…

Node 【Buffer 与 Stream】

文章目录 &#x1f31f;前言&#x1f31f;Buffer&#x1f31f; Buffer结构&#x1f31f; 什么时候用Buffer&#x1f31f; Buffer的转换&#x1f31f; Buffer使用&#x1f31f; 创建Buffer&#x1f31f; 字符串转Buffer&#x1f31f; Buffer转字符串&#x1f31f; 拼接Buffer&am…

微信小程序登录注册页面

// login.js // 获取应用实例 var app getApp() var api require("../../utils/api.js")Page({data: {motto: zhenbei V1.0.0,userInfo: {},hasUserInfo: false,disabled: true,btnstate: default,username: ,password: ,canIUse: wx.canIUse(button.open-type.get…

UE4/5 C++网络服务器编程纪录【零】--准备篇

前言 之前利用业余时间重新复习UE4/5的C开发&#xff0c;闲来无事做了个基于独立服务器的多人在线&#xff08;目前限定客户数量是20人以内&#xff09;DEMO&#xff0c;核心功能在我之前发的B站视频里面有&#xff0c;战斗、动作、交互以及场景演示都有了&#xff0c;有朋友看…

Linux使用:环境变量指南和CPU和GPU利用情况查看

Linux使用&#xff1a;环境变量指南和CPU和GPU利用情况查看 Linux环境变量初始化与对应文件的生效顺序Linux的变量种类设置环境变量直接运行export命令定义变量修改系统环境变量修改用户环境变量修改环境变量配置文件 环境配置文件的区别profile、 bashrc、.bash_profile、 .ba…

函数(有点难,要注重实战)

目录 1. 函数是什么2. C语言中函数的分类2.1 库函数2.1.1 如何学会使用库函数&#xff1f; 2.2 自定义函数 3. 函数的参数3.1 实际参数&#xff08;实参&#xff09;&#xff1a;3.2 形式参数&#xff08;形参&#xff09;&#xff1a; 4. 函数的调用&#xff1a;4.1 传值调用4…

Spark SQL实战(08)-整合Hive

1 整合原理及使用 Apache Spark 是一个快速、可扩展的分布式计算引擎&#xff0c;而 Hive 则是一个数据仓库工具&#xff0c;它提供了数据存储和查询功能。在 Spark 中使用 Hive 可以提高数据处理和查询的效率。 场景 历史原因积累下来的&#xff0c;很多数据原先是采用Hive…

Node内置模块 【url模块与queryString】

文章目录 &#x1f31f;前言&#x1f31f;url 模块&#x1f31f; URL各部分说明&#x1f31f; 将URL字符串转换为对象&#x1f31f; 将对象格式化为URL字符串&#xff1a;url.format(urlObj)&#x1f31f; URL路径处理&#xff1a;url.resolve(from, to) &#x1f31f; querySt…

MySQL-四大类日志

目录 &#x1f341;MySQL日志分为4大类 &#x1f341;错误日志 &#x1f343;修改系统配置 &#x1f341;二进制日志 &#x1f343;查看二进制日志 &#x1f343;删除二进制日志 &#x1f343;暂时停止二进制日志的功能 &#x1f341;事务日志(或称redo日志) &#x1f341;慢查…

SSM整合、环境配置以及详细综合测试(单表查询、多表查询和数据分页、前后端分离、Vue3)

SSM整合、环境配置以及基础综合测试 准备&#xff1a;创建maven项目以及项目框架准备 SSM整合简介 介绍: SSM(SpringSpringMVCMyBatis) 整合&#xff0c;就是三个框架协同开发。Spring整合Mybatis就是将Mybatis核心配置文件当中数据源的配置、事务处理、以及工厂的配置&…

OpenGL入门教程之 深入三角形

一、引言 本教程使用GLEW和GLFW库。  通过本教程&#xff0c;你能轻松的、深入的理解OpenGL如何绘制一个三角形。  如果你不了解OpenGL是什么&#xff0c;可以阅读OpenGL深入理解。 二、基本函数和语句介绍 通过阅读以下的函数&#xff0c;你的大脑里能留下关于OpenGL基本函…