大模型基础——从零实现一个Transformer(1)

一、Transformer模型架构图

主要模块:

   embedding层:

  • Input/Output Embedding: 将每个标记(token)转换为对应的向量表示。

  • Positional Encoding:由于没有时序信息,需要额外加入位置编码。

   

    N个 block堆叠:

  • Multi-Head Attention: 利用注意力机制对输入进行交互,得到具有上下文信息的表示。根据其所处的位置有不同的变种:邻接解码器嵌入位置是掩码多头注意力,特点是当前位置只能注意本身以及之前位置的信息;掩码多头注意力紧接的多头注意力特点是Key和Value来自编码器的输出,而Query来自底层的输出,目的是在计算输出时考虑输入信息。

  • Layer Normalization: 作用于Transformer块内部子层的输出表示上,对表示序列进行层归一化。

  • Residual connection :作用于Transformer块内部子层输入和输出上,对其输入和输出进行求和。

  • Position-wise Feedforward Network: 通过多层全连接网络对表示序列进行非线性变换,提升模型的表达能力。

二、分词器BPE 

2.1 原理

字节对编码(BPE, Byte Pair Encoder),又称 digram coding 双字母组合编码,是一种数据压缩 算法,用来在固定大小的词表中实现可变⻓度的子词。

BPE 首先将词分成单个字符,然后依次用另一个字符替换频率最高的一对字符 ,直到循环次数结束。

BPE训练算法的步骤如下:

  1. 初始化语料库

  2. 将语料库中每个单词拆分成字符作为子词,并在单词结尾增加一个</w>字符

  3. 将拆分后的子词构成初始子词词表

  4. 在语料库中统计单词内相邻子词对的频次

  5. 合并频次最高的子词对,合并成新的子词,并将新的子词加入到子词词表

  6. 重复步骤4和5直到进行了设定的合并次数或达到了设定的子词词表大小

2.2 tokenize实现

from collections import defaultdict
import jieba
from  typing import *class BPETokenizer:def __init__(self,special_tokens=[]) -> None:''':param sepcial_tokens: 额外添加的特殊token,'''self.word_freqs = defaultdict(int)self.merges = {}self.token_to_id =  {}self.id_to_token = {}if special_tokens is None:special_tokens = []special_tokens = ['<PAD>', '<UNK>', '<BOS>', '<EOS>'] +  special_tokensfor token in special_tokens:self._add_token(token)self.unk_token = "<UNK>"self.unk_token_id = self.token_to_id.get(self.unk_token)def _add_token(self,token:str) -> None:'''将token添加到词表中:param token::return:'''# 新添加的token添加到最后,所以idx默认是当前词表的长度if token not in self.token_to_id:idx = len(self.token_to_id)self.token_to_id[token] = idxself.id_to_token[idx] = token@propertydef vobcab_size(self) -> int:return len(self.token_to_id)## 以下是训练bpe相关函数 startdef _learn_vocab(self,corpus: list[str]) -> None:'''统计词频:param corpus::return:'''for sentence in corpus:sentence = sentence.lower()# 分词统计词频words = [w for w in jieba.cut(sentence) if w != " "]for word in words:self.word_freqs[word] += 1def _compute_pair_freqs(self,splits) -> dict[Tuple, int]:'''统计相邻字符的共现频率:param splits::return:'''pair_freqs = defaultdict(int)## 遍历word里面的相关的子字符,统计共现频率for word,freq in self.word_freqs.items():split = splits[word]if len(split) == 1:continuefor i in range(len(split) - 1):pair = (split[i], split[i + 1])pair_freqs[pair] += freqreturn pair_freqsdef _merge_pair(self,a:str,b:str,splits):'''合并字符并跟新split里面word对应的字符组成比如 splits里面有个单词是 “hello”:['h','e','l','l','o']如果合并了字符h和字符e,那么就要变成“hello”:['he','l','l','o']:param a::param b::param splits::return:'''for word in self.word_freqs:split = splits[word]if len(split) == 1:continuei = 0while i < len(split) -1:if split[i] == a and split[i+1] == b:split = split[:i] + [a + b] + split[i+2:]else:i += 1splits[word] = splitreturn  splitsdef _merge_vocab(self,vocab_size,splits):''':param vocab_size: 预期的词表的大小,当达到词表大小,bpe算法就结束:param splits::return:'''merges = {}while self.vobcab_size < vocab_size:# 先统计共现频率pari_freqs = self._compute_pair_freqs(splits)best_pair = Nonemax_freq = 0for pair,freq in pari_freqs.items():if max_freq < freq:best_pair = pairmax_freq = freq# 合并新词splits = self._merge_pair(*best_pair,splits)# 将新词加入词表merges[best_pair] = best_pair[0] + best_pair[1]self._add_token(best_pair[0] + best_pair[1])return mergesdef train(self,corpus,vocab_size):'''bpe训练代码:param corpus: 文本语料:param vocab_size: 期望的词表大小:return:'''self._learn_vocab(corpus)splits = {word: [c for c in word] for word in self.word_freqs.keys()}for split in splits.values():for c in split:self._add_token(c)self.merges = self._merge_vocab(vocab_size, splits)## 训练bpe相关函数 enddef tokenize(self,text):'''bpe分词:param text::return:'''text = text.lower()words = [w for w in jieba.cut(text) if w != " "]splits = [[c for c in word] for word in words]for pair,merge in self.merges.items():for idx,split in enumerate(splits):i = 0while i < len(split) -1:if split[i] == pair[0] and split[i+1] == pair[1]:split = split[:i] + [merge] + split[i + 2:]else:i += 1splits[idx] = splitreturn sum(splits,[])def _convert_token_to_id(self,token:str):'''将token转换为具体的id:param token::return:'''return self.token_to_id.get(token,self.unk_token_id)def _convert_id_to_token(self,index:int) -> str:return self.id_to_token.get(index,self.unk_token)def _convert_ids_to_tokens(self,token_ids: list[int]) -> list[str]:return [self._convert_id_to_token(index) for index in token_ids]def _convert_tokens_to_ids(self, tokens: list[str]) -> list[int]:return [self._convert_token_to_id(token) for token in tokens]def encode(self, text: str) -> list[int]:tokens = self.tokenize(text)return self._convert_tokens_to_ids(tokens)def clean_up_tokenization(self, out_string: str) -> str:out_string = (out_string.replace(" .", ".").replace(" ?", "?").replace(" !", "!").replace(" ,", ",").replace(" ' ", "'").replace(" n't", "n't").replace(" 'm", "'m").replace(" 's", "'s").replace(" 've", "'ve").replace(" 're", "'re"))return out_stringdef decode(self, token_ids: list[int]) -> str:tokens = self._convert_ids_to_tokens(token_ids)return self.clean_up_tokenization(" ".join(tokens))if __name__ == '__main__':corpus = ["This is the Hugging Face Course.","This chapter is about tokenization.","This section shows several tokenizer algorithms.","Hopefully, you will be able to understand how they are trained and generate tokens.",]tokenizer = BPETokenizer()tokenizer.train(corpus, 50)print(tokenizer.tokenize("This is not a token."))print(tokenizer.vobcab_size)token_ids = tokenizer.encode("This is not a token.")print(token_ids)# this is not a token.#由于分词的时候没有 对单词的尾部/w处理,导致decode的时候不知道单词是否结束print(tokenizer.decode(token_ids))

三. Embedding层

import math
from torch import  nn,Tensor
class Embedding(nn.Module):def __init__(self,vocab_size:int, d_model:int) -> None:''':param vocab_size: 词库大小:param d_model: embedding的向量维度'''super().__init__()self.embed = nn.Embedding(vocab_size,d_model)self.sqrt_d_model = math.sqrt(d_model)def forward(self,x:Tensor) -> Tensor:''':param x: 输入的Tensor,(batch_size,seq_length):return: Tensor,shape为:(batch_size,seq_length,d_model)'''## 论文里面,初始化以后要乘以 d_model的平方根return self.embed(x) * self.sqrt_d_model

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

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

相关文章

【QT5】<总览四> QT常见绘图、图表及动画

文章目录 前言 一、QFile类读写文件 二、QPainter绘简单图形 三、QChart图表 四、QPropertyAnimation属性动画 五、Q_PROPERTY宏简介 六、自定义属性动画 前言 承接【QT5】&#xff1c;总览三&#xff1e; QT常用控件。若存在版权问题&#xff0c;请联系作者删除&#…

UE5 Mod Support 思路——纯蓝图

原创作者&#xff1a;Chatouille 核心功能 “Get Blueprint Assets”节点&#xff0c;用于加载未来的mod。用基础类BP_Base扩展即可。打包成补丁&#xff0c;放到Content\Paks目录下&#xff0c;即可让游戏访问到内容。 与文中所写不同的地方 5.1或者5.2开始&#xff0c;打…

uniapp封装picker选择器组件,支持关键字查询

CommonPicker.vue组件 路径在 components\CommonPicker.vue <template><view><uni-easyinput v-model"searchQuery" :placeholder"placeholder" /><picker :range"filteredOptions" :range-key"text" v-model&…

从零开始:疾控中心实验室装修攻略,让你的实验室一步到位!

在当今充满挑战和变化的世界中&#xff0c;疾病的控制和预防成为了人类生存与发展的重要课题。而疾控中心作为防控疾病的核心机构&#xff0c;其疾控中心实验室设计建设显得尤为重要。下面广州实验室装修公司小编将分享疾控中心实验室设计建设方案&#xff0c;为疾病防控工作提…

玩转STM32-通信协议SPI(详细-慢工出细活)

文章目录 一、SPI的基础知识1.1 接口定义1.2 单机和多机通信 二、STM32的SPI工作过程2.1 从选择&#xff08;NSS&#xff09;脚管理2.2 时钟相位与极性2.3 SPI主模式2.4 SPI从模式 三、应用实例 一、SPI的基础知识 1.1 接口定义 SPI系统可直接与各个厂家生产的多种标准外围器…

ChatGPT-4o独家揭秘:全国一卷高考语文作文如何轻松斩获满分?

​一、2024年全国一卷高考 二、2018年全国一卷高考 三、2016年全国一卷高考 一、2024年全国一卷高考 技术进步的悖论&#xff1a;我们的问题真的在减少吗&#xff1f; 引言 随着互联网的普及和人工智能的应用&#xff0c;越来越多的问题能够快速得到解答。然而&#xff0c;这引…

网络空间安全数学基础·同余式

6.1 剩余系&#xff08;掌握&#xff09; 6.2 同余式概念与一次同余式&#xff08;熟练&#xff09; 6.3 中国剩余定理&#xff08;熟练&#xff09; 6.1 剩余系 设m是正整数&#xff0c;模m同余的全体整数是一个模m剩余类&#xff0c;即可表示为a qmr&#xff0c; 0≤r<…

牛客练习赛126(O(n)求取任意大小区间最值)

牛客练习赛126(O(n)求取任意大小区间最值) 牛客练习赛126 A.雾粉与签到题 题意&#xff1a;给出长度为n的数组, 顺序选出任意三个元素&#xff0c;最小化第二个元素 思路&#xff1a; 遍历除了第一个和最后一个元素取最小值即可 AC code&#xff1a; void solve() {int…

使用 tc (Traffic Control)控制网络延时

设置网络延时 1500ms 800ms tc qdisc add dev eth0 root netem delay 1500ms 800msping 测试 ping www.baidu.com取消设置网络延时 sudo tc qdisc del dev eth0 root

inflight 守恒和带宽资源守恒的有效性

接着昨天的问题&#xff0c;inflight 守恒的模型一定存在稳定点吗&#xff1f;并不是。如果相互抑制强度大于自我抑制强度&#xff0c;系统也会跑飞&#xff1a; 模拟结果如下&#xff1a; 所以一定要记得 a < b。 比对前两个图和后两个图的 a&#xff0c;b 参数关系&am…

PS初级|写在纸上的字怎么抠成透明背景?

前言 上一次咱们讲了很多很多很多的抠图教程&#xff0c;这次继续。。。最近有小伙伴问我&#xff1a;如果是写在纸上的字&#xff0c;要怎么把它抠成透明背景。 这个其实很简单&#xff0c;直接来说就是选择通道来抠。但有一点要注意的是&#xff0c;写在纸上的字&#xff0…

鸿蒙开发的南向开发和北向开发

鸿蒙开发主要分为设备开发和应用开发两个方向&#xff0c;也叫南向开发和北向开发&#xff1a; 鸿蒙设备开发(南向开发&#xff09;&#xff0c;要侧重于硬件层面的开发&#xff0c;涉及硬件接口控制、设备驱动开发、鸿蒙系统内核开发等&#xff0c;目的是使硬件设备能够兼容并…

android antirollback verno 获取方法

ReadRollbackIndex.exe 获取 调查avbVBMeta结构体 typedef struct AvbVBMetaImageHeader { /* 0: Four bytes equal to "AVB0" (AVB_MAGIC). */ uint8_t magic[AVB_MAGIC_LEN]; /* 4: The major version of libavb required for this header. */ uint32_t…

美团面试:百亿级分片,如何设计基因算法?

尼恩说在前面 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试资格&#xff0c;遇到很多很重要的架构类/设计类的场景题&#xff1a; 1.说说分库分表的基因算法&#xff1f…

react native中内容占位效果

react native中内容占位效果 效果实例图实例代码skeleton.jsx 效果实例图 实例代码skeleton.jsx import React, { useEffect, useRef } from "react"; import { Animated, StyleSheet, View } from "react-native"; import { pxToPd } from "../../.…

寻找python库的安装路径

以pip库为例 要找到并修改 pip 库中的 __pip-runner__.py 文件&#xff0c;您可以按照以下步骤操作&#xff1a; 找到 pip 库的安装路径&#xff1a; 通常&#xff0c;Python 库会安装在您的虚拟环境或全局 Python 包目录中。您可以通过以下命令来找到 pip 库的路径&#xff1…

代码随想录算法训练营day31|455.分发饼干、376.摆动序列、53.最大子序和

分发饼干 455. 分发饼干 - 力扣&#xff08;LeetCode&#xff09; 贪心算法&#xff0c;让每个饼干给到能够满足的孩子&#xff0c;所以需要对饼干尺寸和孩子的满足值先进行排序&#xff0c;然后针对每一个饼干的尺寸&#xff0c;挑选恰好能够满足的孩子&#xff08;这里表述…

期末成绩怎么单独发给家长

想知道如何让成绩查询变得简单又安全吗&#xff1f;跟着我&#xff0c;带你发现一个让家长和老师都省心的神器&#xff01; 传统的成绩发布方式&#xff0c;一张张成绩单&#xff0c;一封封邮件&#xff0c;或是一条条短信&#xff0c;这些方法虽然有效&#xff0c;但效率不高&…

[论文笔记]AIOS: LLM Agent Operating System

引言 这是一篇有意思的论文AIOS: LLM Agent Operating System&#xff0c;把LLM智能体(代理)看成是操作系统。 基于大语言模型(LLMs)的智能代理的集成和部署过程中存在着许多挑战&#xff0c;其中问题包括代理请求在LLM上的次优调度和资源分配&#xff0c;代理和LLM之间在交互…

C#上位机开发

目录 一、上位机简介二、C#语法三、新建VS工程四、WinForm控件4.1 属性4.2 事件4.3 窗体方法4.4 常用控件4.5 布局 五、Serial上位机5.1 UI界面设计5.2 功能设计 六、项目打包成安装包6.1 前提准备6.2 打包步骤 一、上位机简介 在单片机项目开发中&#xff0c;上位机也是一个很…