【NLP 60、实践 ⑭ 使用bpe构建词表】
目录
一、BPE(Byte Pair Encoding)算法详解
1.基本概念
2.核心思想
3.算法步骤详解
Ⅰ、预处理
Ⅱ、统计字符对频率
Ⅲ、合并高频字符对
Ⅳ、编码与解码
① 编码(文本→子词序列)
② 解码(子词序列→文本)
二、使用BPE算法构建词表 实现方式 ①
1.数据预处理模块
2. 统计模块 get_stats()
3.合并模块 merge()
4. 词表构建模块
5. 解码模块 encode
6.编码模块 encode
7.运行示例
8.完整代码
人们总是在无能为力的时候喜欢说顺其自然
—— 25.4.15
一、BPE(Byte Pair Encoding)算法详解
1.基本概念
BPE(Byte Pair Encoding)是一种子词分词(Subword Tokenization)算法,最初用于数据压缩,后被引入自然语言处理(NLP)领域,解决传统分词方法(如按空格分割)的以下问题:
未登录词(OOV):无法处理词典外的罕见词(如专业术语、新词)。
数据稀疏性:低频词导致模型泛化能力差。
多语言支持:统一处理不同语言(如中文、英文、德语的混合文本)。
2.核心思想
通过迭代合并高频字符对,将单词拆分为更小的子词单元(Subword Units),平衡词汇表大小与语义粒度。
示例:单词 "unhappy"
→ 拆分为 ["un", "happy"]
(若 "un"
和 "happy"
均为高频子词)
3.算法步骤详解
Ⅰ、预处理
输入:原始文本(如英文句子、代码片段)。
操作:
① 将文本按空格分割为单词,统计词频。
② 将每个单词拆分为字符序列,末尾添加特殊符号(如 </w>
)标记单词结束。
③ 初始化词汇表为所有基础字符(如ASCII字符、Unicode符号)。
Ⅱ、统计字符对频率
遍历所有单词拆分后的字符序列,统计相邻字符对的共现频率。
Ⅲ、合并高频字符对
选择频率最高的字符对,将其合并为新符号,并更新词汇表。
重复此过程,直到达到预设的合并次数(或词汇表大小)。
Ⅳ、编码与解码
① 编码(文本→子词序列)
对输入文本按最长匹配原则,递归拆分单词为已合并的子词。
贪心策略:优先匹配最长子词。
② 解码(子词序列→文本)
拼接子词并去除特殊符号(如 </w>
)
二、使用BPE算法构建词表 代码实现
1.数据预处理模块
text:输入的多语言字符串
tokens:整数列表,每个整数表示一个UTF-8字节
text.encode("utf-8"):将字符串编码为字节序列(默认使用UTF-8)。
参数名 | 类型 | 默认值 | 说明 |
---|---|---|---|
encoding | str | "utf-8" | 编码格式(可省略) |
list():将可迭代对象(如元组、字符串、集合)转换为列表。
参数名 | 类型 | 说明 |
---|---|---|
iterable | 可迭代对象 | 如字符串、元组、集合等 |
map():将函数 func
应用到可迭代对象的每个元素,返回迭代器。
参数名 | 类型 | 说明 |
---|---|---|
func | function | 要应用的函数 |
iterable | 可迭代对象 | 如列表、元组等 |
text = '''...''' # 多语言文本
tokens = text.encode("utf-8")
tokens = list(map(int, tokens))
2. 统计模块 get_stats()
ids:可迭代对象(如列表、元组等),基于这个可迭代对象来统计相邻元素组成的元素对出现的次数
counts:字典(dict
),用于存储元素对及其出现次数的字典。
pair:元组(tuple
),在 for
循环中,pair
表示由 ids
中相邻的两个元素组成的元组。
字典.get():获取字典中指定键的值,若键不存在则返回默认值。
参数名 | 类型 | 默认值 | 说明 |
---|---|---|---|
key | 任意类型 | 无 | 要查找的键 |
default | 任意类型 | None | 键不存在时返回的值 |
zip():将多个可迭代对象按位置打包成元组的列表。
参数名 | 类型 | 说明 |
---|---|---|
*iterables | 多个可迭代对象 | 如 zip([1,2], ["a","b"]) |
def get_stats(ids):counts = {}for pair in zip(ids, ids[1:]):counts[pair] = counts.get(pair, 0) + 1return counts
3.合并模块 merge()
ids:可迭代对象(如列表、元组等),当前字节序列
pair:待合并的字节对,一个由两个元素组成的元组。
idx:新子词的唯一标识符,当在 ids
中找到与 pair
匹配的相邻元素对时,会用 idx
这个元素来替换该元素对,实现合并的效果
newids:列表(list
),用于存储处理后的结果。
列表.append(): 向列表末尾添加元素。
参数名 | 类型 | 说明 |
---|---|---|
item | 任意类型 | 待添加的元素 |
def merge(ids, pair, idx):newids = []i = 0while i < len(ids):if i < len(ids) - 1 and ids[i] == pair[0] and ids[i + 1] == pair[1]:newids.append(idx)i += 2else:newids.append(ids[i])i += 1return newids
4. 词表构建模块
vocab_size:表示初始的词汇表大小。
num_merges:通过 vocab_size - 256
计算得出,表示需要进行合并操作的次数。
ids:列表(list
),初始时被赋值为 list(tokens),ids
用于存储这些元素,并在后续的合并操作中不断被更新。每次合并操作后,ids
中的元素会根据合并规则发生变化。
tokens:一个包含词汇表中所有元素(可以是单词、字符等)的可迭代对象。
list():将可迭代对象(如元组、字符串、集合)转换为列表。
参数名 | 类型 | 说明 |
---|---|---|
iterable | 可迭代对象 | 如字符串、元组、集合等 |
merges:字典(dict
),记录合并操作的结果。字典的键是由两个元素组成的元组(表示被合并的元素对),值是合并后生成的新元素的索引(从 256
开始依次递增)。
stats:字典(dict
),记录 ids
中相邻元素对出现次数的字典。字典的键是元素对(以元组形式表示),值是该元素对出现的次数。
get_stats():统计列表中两个相邻元素出现的次数
pair:元组(tuple
), 从 stats
字典中获取,它表示在当前的 ids
中出现次数最多的相邻元素对,这个元素对将在本次合并操作中被合并为一个新的元素。
max():返回可迭代对象中的最大值,或者多个参数中的最大值。
max(iterable, *, key=None, default=default):
从给定的可迭代对象(如列表、元组、集合等)中返回最大的元素。如果提供了 key
函数,则会根据 key
函数的返回值来比较元素的大小,而不是直接比较元素本身;如果提供了 default
参数,当可迭代对象为空时,返回 default
的值,否则当可迭代对象为空时会抛出 ValueError
异常。
参数名 | 类型 | 是否必填 | 默认值 | 描述 |
---|---|---|---|---|
iterable | 可迭代对象(如列表、元组、集合等) | 是 | 无 | 要从中找出最大值的可迭代对象 |
key | 函数 | 否 | None | 一个接收单个参数的函数,用于指定比较元素的方式。函数的返回值将用于比较元素的大小 |
default | 任意类型 | 否 | 无(在可迭代对象为空时会引发异常) | 当 iterable 为空时返回的值 |
max(arg1, arg2, *args, *, key=None):
返回多个参数中的最大值。如果提供了 key
函数,则会根据 key
函数的返回值来比较参数的大小,而不是直接比较参数本身。
参数名 | 类型 | 是否必填 | 默认值 | 描述 |
---|---|---|---|---|
arg1, arg2, *args | 任意类型(要求所有参数类型兼容比较) | 至少一个参数 | 无 | 要从中找出最大值的多个参数 |
key | 函数 | 否 | None | 一个接收单个参数的函数,用于指定比较参数的方式。函数的返回值将用于比较参数的大小 |
idx:整数(int
),通过 256 + i
计算得出,用于表示合并后生成的新元素的索引。
merge():将统计得到的两个最高频字符对合并为一个新字符
len():返回对象的长度或元素个数。
参数名 | 类型 | 说明 |
---|---|---|
obj | 任意可迭代对象 | 如列表、字符串、字典等 |
表示初始的词汇表大小。
5. 解码模块 encode
vocab:字典(dict
),初始时,通过字典推导式 {idx: bytes([idx]) for idx in range(256)}
创建,将整数索引 idx
(范围是 0 到 255)映射为对应的单字节 bytes
对象(bytes([idx])
)。后续通过循环 for (p0, p1), idx in merges.items():
,根据 merges
中记录的合并信息,将合并后的索引 idx
映射为合并后的字节序列(即 vocab[p0] + vocab[p1]
)。vocab
最终用于将整数索引转换为字节序列,是解码过程的关键数据结构。
(p0, p1):merges
字典的键(是一个元组),表示在之前的合并操作中被合并的两个元素对应的索引。
idx:整数(int
),在字典推导式 {idx: bytes([idx]) for idx in range(256)}
中,idx
是循环变量,用于生成初始的 vocab
字典。在循环 for (p0, p1), idx in merges.items():
中,idx
是 merges
字典的值,表示合并后新的索引,并且在 vocab
中用于存储合并后的字节序列。在 decode
函数中,idx
作为 vocab
的键,用于从 vocab
中获取对应的字节序列。
merges:字典(dict
),存储合并操作的结果。
text:在 decode
函数中,通过 tokens.decode("utf-8", errors="replace")
生成。它是将 tokens
字节串按照 UTF-8 编码进行解码得到的文本内容。errors="replace"
表示在解码过程中如果遇到无法解码的字节,将用替换字符(通常是 ?
)来替代,以避免解码错误。text
是最终解码得到的字符串结果,是 decode
函数的返回值。
ids:列表(list
),作为 decode
函数的参数,ids
是一个包含一系列整数索引的列表。这些索引将用于从 vocab
字典中获取对应的字节序列,进而通过连接和解码操作得到原始的文本内容。
items():返回字典的键值对视图(dict_items
对象)。
str.join():将可迭代对象的元素用 str
连接成新字符串。
参数名 | 类型 | 说明 |
---|---|---|
iterable | 可迭代对象 | 元素必须为字符串类型 |
tokens.decode():将字节序列解码为字符串。
参数名 | 类型 | 是否必填 | 默认值 | 描述 |
---|---|---|---|---|
encoding | 字符串(str ) | 是 | 无 | 指定用于解码字节串的编码格式,这里设置为 "utf-8" ,表示使用 UTF - 8 编码进行解码。UTF - 8 是一种广泛使用的可变长度字符编码,能够表示世界上大部分的字符。 |
errors | 字符串(str ) | 否 | "strict" | 指定在解码过程中遇到无法解码的字节时的处理方式。这里设置为 "replace" ,表示使用替换字符(通常是 ? )来替代无法解码的字节;默认值 "strict" 表示当遇到无法解码的字节时会抛出 UnicodeDecodeError 异常。此外,还有其他可选值,如 "ignore" 表示忽略无法解码的字节,直接跳过它们进行解码。 |
# decoding:print("————————————————————————————————————————————————————————————————————")
vocab = {idx: bytes([idx]) for idx in range(256)}
for (p0, p1), idx in merges.items():vocab[idx] = vocab[p0] + vocab[p1]def decode(ids):tokens = b"".join(vocab[idx] for idx in ids)text = tokens.decode("utf-8", errors="replace")return textprint("decode示例:",decode([65, 32, 80, 114, 111, 103, 114, 97, 109, 109, 260, 263, 153, 258, 73, 110, 116, 114, 111, 100, 117, 99, 116, 105,111, 110, 32, 116, 111, 32, 85, 110, 105, 271, 101, ]))
# print(decode(ids))print("————————————————————————————————————————————————————————————————————")
6.编码模块 encode
merges:字典(dict
),存储了合并操作的结果。字典的键是由两个元素组成的元组(表示被合并的元素对),值是合并后生成的新元素的索引。
text:作为 encode
函数的输入参数,text
是要进行编码处理的原始文本内容。函数会将其先转换为 UTF-8 编码的字节序列,然后根据 merges
中记录的合并规则进行处理。
tokens:列表(list
),一个包含原始文本 UTF-8 编码后每个字节对应的整数值的列表。
text.encode():将字符串编码为UTF-8格式的字节序列。
参数名 | 类型 | 默认值 | 说明 |
---|---|---|---|
text | str | 无 | 待编码的原始字符串 |
encoding | str | "utf-8" | 编码格式(可指定其他编码如"gbk") |
len():返回对象的长度或元素个数。
参数名 | 类型 | 说明 |
---|---|---|
obj | 任意可迭代对象 | 如列表、字符串、字典等 |
starts:字典(dict
),一个记录 tokens
中相邻元素对出现次数的字典。字典的键是元素对(以元组形式表示),值是该元素对出现的次数。
get_stats():统计列表中两个相邻元素出现的次数
pair:元组(tuple
),在当前的 tokens
中,根据 merges
字典的映射关系,能找到的最合适进行合并的相邻元素对
min():用于返回可迭代对象中的最小值,或者在多个参数中返回最小的那个值。
参数名 | 类型 | 是否必填 | 默认值 | 描述 |
---|---|---|---|---|
*args | 可迭代对象或多个参数 | 是 | 无 | 如果传入一个可迭代对象,如列表、元组等,min() 函数会返回该可迭代对象中的最小值;如果传入多个参数,min() 函数会返回这些参数中的最小值。 |
key | 函数 | 否 | 无 | 用于指定一个函数,该函数会被应用到可迭代对象的每个元素上,以确定比较的键。例如,如果可迭代对象是一个包含字典的列表,通过 key 函数可以指定按照字典的某个键来比较大小。 |
default | 任意类型 | 否 | 无 | 当可迭代对象为空时,返回指定的默认值。如果没有指定 default 且可迭代对象为空,min() 函数将引发 ValueError 异常。 |
字典.get():获取字典中指定键的值,若键不存在则返回默认值。
参数名 | 类型 | 默认值 | 说明 |
---|---|---|---|
key | 任意类型 | 无 | 要查找的键 |
default | 任意类型 | None | 键不存在时返回的值 |
lambda:创建匿名函数(无函数名)。
参数名 | 类型 | 说明 |
---|---|---|
arguments | 参数列表 | 如 x, y |
expression | 表达式 | 函数体(单行表达式) |
float():将数值或字符串转换为浮点数。
参数名 | 类型 | 说明 |
---|---|---|
value | int/str | 要转换的数值或字符串 |
# encoding:print(merges)print("————————————————————————————————————————————————————————————————————")def encode(text):tokens = list(text.encode("utf-8"))while len(tokens) >= 2:stats = get_stats(tokens)pair = min(stats, key=lambda p: merges.get(p, float("inf")))if pair not in merges:break # nothing else can be mergedidx = merges[pair]tokens = merge(tokens, pair, idx)return tokens
7.运行示例
str:例子中演示编解码和bpe算法用到的字符串
str = "一切都会好的,我一直相信"
print("encode示例:",encode("一切都会好的,我一直相信"))
for i in str:print(i,encode(i))
print(str == decode(encode(str)))
8.完整代码
text = ('''学习语言是一件十分有趣的事情。学习英语能打开通往世界的大门,学习中文能感受悠久文化的魅力,学习日语能沉浸在独特的动漫与文学氛围中,学习韩语能追热门的韩剧、听动感的韩流音乐。语言,语言,它承载着文化,传递着情感。学习,学习,不断学习不同的语言,会发现世界变得更加丰富多彩。每一种语言都有其独特之处,有趣,有趣,真的太有趣了。无论是英语的语法,中文的诗词,日语的助词,韩语的字母,都值得我们深入学习,去探索其中的奥秘。学习语言,学习语言,这是一场永无止境且充满乐趣的旅程 。Learn languages, it's really fascinating. Learning English can open the door to the world, learning Chinese can let you feel the charm of a long - standing culture, learning Japanese can immerse you in the unique atmosphere of anime and literature, learning Korean can enable you to follow popular Korean dramas and listen to dynamic K - pop music. Language, language, it bears culture and conveys emotions. Learn, learn, keep learning different languages and you will find the world becomes more colorful. Each language has its uniqueness. Interesting, interesting, it's really so interesting. Whether it's the grammar of English, the poetry of Chinese, the particles of Japanese, or the letters of Korean, they are all worthy of our in - depth learning to explore the mysteries within. Learning languages, learning languages, this is an endless and fun - filled journey. 日本語を学ぶことはとても面白いことです。英語を学ぶことで世界の扉が開けます、中国語を学ぶことで悠久の文化の魅力を感じることができます、日本語を学ぶことで独特なアニメや文学の雰囲気に浸ることができます、韓国語を学ぶことで人気のある韓国ドラマを追い、ダイナミックなK - pop音楽を聴くことができます。言語、言語、それは文化を担ぎ、感情を伝えます。学び、学び、異なる言語をずっと学ぶと、世界がもっと多彩になることに気づきます。どの言語もその独自性があります。面白い、面白い、本当にとても面白いです。英語の文法也好,中国語の詩也好,日本語の助詞也好,韓国語の文字也好,すべて私たちが深く学び、その中の神秘を探る価値があります。言語を学ぶ、言語を学ぶ、これは果てしなく楽しみに満ちた旅です。한국어를 배우는 것은 정말 재미있는 일입니다. 영어를 배우면 세계의 문을 열 수 있고, 중국어를 배우면 오랜 역사의 문화 매력을 느낄 수 있으며, 일본어를 배우면 독특한 애니메이션과 문학 분위기에 몰입할 수 있고, 한국어를 배우면 인기 있는 한국 드라마를 따라보고 다이나믹한 K - 팝 음악을 들을 수 있습니다. 언어, 언어, 문화를 지탱하고 감정을 전달합니다. 배우고, 배우고, 계속 다른 언어를 배우다 보면 세계가 더욱 풍요롭게 변하는 것을 발견하게 됩니다. 각 언어마다 독특한 특징이 있습니다. 재미있어, 재미있어, 정말 너무 재미있어요. 영어의 문법也好,중국어의 시也好,일본어의 조사也好,한국어의 글자也好,모두 우리가 깊이 배우고 그 속의 비밀을 탐구할 가치가 있습니다. 언어를 배우고, 언어를 배우고, 이는 끝없이 재미와 즐거움이 가득 찬 여정입니다 。 ''')tokens = text.encode("utf-8")
tokens = list(map(int, tokens))def get_stats(ids):counts = {}for pair in zip(ids, ids[1:]):counts[pair] = counts.get(pair, 0) + 1return countsdef merge(ids, pair, idx):newids = []i = 0while i < len(ids):if i < len(ids) - 1 and ids[i] == pair[0] and ids[i + 1] == pair[1]:newids.append(idx)i += 2else:newids.append(ids[i])i += 1return newidsvocab_size = 276num_merges = vocab_size - 256
ids = list(tokens)merges = {}
for i in range(num_merges):stats = get_stats(ids)pair = max(stats, key=stats.get)idx = 256 + iprint(f"merging {pair} into a new token {idx}")ids = merge(ids, pair, idx)merges[pair] = idxprint("tokens length:", len(tokens))
print("ids length:", len(ids))
print(f"compression ratio: {len(tokens) / len(ids):.2f}X")# decoding:print("————————————————————————————————————————————————————————————————————")
vocab = {idx: bytes([idx]) for idx in range(256)}
for (p0, p1), idx in merges.items():vocab[idx] = vocab[p0] + vocab[p1]def decode(ids):tokens = b"".join(vocab[idx] for idx in ids)text = tokens.decode("utf-8", errors="replace")return textprint("decode示例:",decode([65, 32, 80, 114, 111, 103, 114, 97, 109, 109, 260, 263, 153, 258, 73, 110, 116, 114, 111, 100, 117, 99, 116, 105,111, 110, 32, 116, 111, 32, 85, 110, 105, 271, 101, ]))
# print(decode(ids))print("————————————————————————————————————————————————————————————————————")# encoding:print(merges)print("————————————————————————————————————————————————————————————————————")def encode(text):tokens = list(text.encode("utf-8"))while len(tokens) >= 2:stats = get_stats(tokens)pair = min(stats, key=lambda p: merges.get(p, float("inf")))if pair not in merges:break # nothing else can be mergedidx = merges[pair]tokens = merge(tokens, pair, idx)return tokensstr = "一切都会好的,我一直相信"
print("encode示例:",encode("一切都会好的,我一直相信"))
for i in str:print(i,encode(i))
print(str == decode(encode(str)))
相关文章:
【NLP 60、实践 ⑭ 使用bpe构建词表】
目录 一、BPE(Byte Pair Encoding)算法详解 1.基本概念 2.核心思想 3.算法步骤详解 Ⅰ、预处理 Ⅱ、统计字符对频率 Ⅲ、合并高频字符对 Ⅳ、编码与解码 ① 编码(文本→子词序列) ② 解码(子词序列→文本) …...
String +memset字符串类题型【C++】
tips: 1、寻找最大公共子串时,如果字符串可以旋转但是不能反转,考虑在每个字符串后重复一次自身,如 "abcd" 变为 "abcdabcd",这样在用dp就可以了。 如何变环拆环为链: cin>>n&…...
06 GE Modifier
看看这个 问题。怪!究竟下一个modifier能不能访问到上一个?刚才还可以啊现在怎么不行了。 这里捕获了Owner的属性,Source不知道在哪捕获的 CalculationType: 1.使用计算后的值 2.使用基础值 3.使用计算后的值-基础值。 BackingAttributes Sou…...
30元一公斤的樱桃甜不甜
2025年4月20日,13~27℃,还好 待办: 综合教研室——会议记录3份(截止年4月18日) 备课冶金《物理》 备课理工《高数》 备课理工《物理》 教学技能大赛教案(2025年4月24日,校赛,小组合作…...
App-Controller - 通过自然语言操控应用程序的智能框架
本文翻译整理自:https://github.com/alibaba/app-controller 一、关于 App-Controller App-Controller 是基于大语言模型(LLMs)和智能体(Agents)构建的创新性API编排框架,旨在利用LLMs的高级推理能力来集成和同步各类应用程序提供的API。 上图展示了App…...
Deepseek输出的内容如何直接转化为word文件?
我们有时候会直接利用deepseek翻译别人的文章或者想将deepseek输出的内容直接复制到word文档里。但是文本格式和word是不对应的。这时候需要输入如下命令: 以上翻译内容的格式和排版要求如下: 1、一级标题 字体为黑体(三号)&…...
深入剖析 Java Web 项目序列化:方案选型与最佳实践
在 Java Web 开发中,“序列化”是一个你无法绕过的概念。无论是缓存数据、共享 Session,还是进行远程过程调用(RPC)或消息传递,序列化都扮演着底层数据搬运工的角色。它负责将内存中的 Java 对象转换成可传输或可存储的…...
第36讲:作物生长预测中的时间序列建模(LSTM等)
目录 🧠 为什么用时间序列模型来预测作物生长? ⛓️ 什么是 LSTM? 📊 示例案例:预测小麦NDVI变化趋势 1️⃣ 模拟数据构建(或使用真实遥感数据) 2️⃣ 构建 LSTM 所需数据格式 3️⃣ 构建并训练 LSTM 模型 4️⃣ 模型预测与效果可视化 🧠 除了 LSTM,还有哪…...
LeetCode 每日一题 2563. 统计公平数对的数目
2563. 统计公平数对的数目 给你一个下标从 0 开始、长度为 n 的整数数组 nums ,和两个整数 lower 和 upper ,返回 公平数对的数目 。 如果 (i, j) 数对满足以下情况,则认为它是一个 公平数对 : 0 < i < j < n,…...
Redis 哨兵与集群脑裂问题详解及解决方案
Redis 哨兵与集群脑裂问题详解及解决方案 本文将深入探讨Redis在哨兵模式和集群模式下可能出现的脑裂问题,包括其发生场景、原因以及有效的解决策略。同时,我们还将提供相应的代码示例和配置方案来帮助读者理解和实施。 一、脑裂问题概述 脑裂&#x…...
Laravel-vite+vue开发前端模板
开始这篇文章的时候,你已经安装了laravel!你已经安装了laravel!你已经安装了laravel! 然后你的laravel服务器环境已经搭建好,应用可以正常访问 laravel vite plugin 官方原文 laravel默认已经集成vitejs,单纯使用vi…...
springboot+vue3+mysql+websocket实现的即时通讯软件
项目演示 即时通讯软件项目演示 业务架构 技术栈 后端 选用编程语言 Javaweb框架SpringBootdb MySQL 持久存储nosql 缓存 Redis全双工通信框架 WebSocket 前端 前端框架Vue3TypescriptUI样式 Css、ElementPlus网页路由 vue-router全双工通信框架Websocket 功能完成情况 已实…...
HTMLCSS实现网页轮播图
网页中轮播图区域的实现与解析 在现代网页设计中,轮播图是一种常见且实用的元素,能够在有限的空间内展示多个内容,吸引用户的注意力。下面将对上述代码中轮播图区域的实现方式进行详细介绍。 一、HTML 结构 <div class"carousel-c…...
HTML表单与数据验证设计
HTML 表单与数据验证设计:构建可靠的用户数据采集系统 引言 互联网的核心是数据交互,而HTML表单是这一交互的主要入口。作为前端工程师,设计高质量的表单不仅关乎用户体验,更直接影响数据收集的准确性和系统安全。 在我的学习实…...
[Windows] 星光桌面精灵 V0.5
[Windows] 星光桌面精灵 链接:https://pan.xunlei.com/s/VOOI9NCNDB0iBONt5gz7zUb9A1?pwdgxa6# [Windows] 星光桌面精灵 V0.5 这款桌面精灵是动态的,而且还可以做快捷启动...
Java 网络编程性能优化:高吞吐量的实现方法
Java 网络编程性能优化:高吞吐量的实现方法 在当今的互联网时代,网络应用的性能优化是开发人员面临的重要挑战之一。Java 作为一门广泛使用的编程语言,提供了强大的网络编程支持,但如何通过优化实现高吞吐量,是每个 J…...
【去哪儿网】登录滑块逆向算法AES加密分析(逆天滑块轨迹)
目标:aHR0cHM6Ly91c2VyLnF1bmFyLmNvbS9wYXNzcG9ydC9sb2dpbi5qc3A 验证接口: https://vercode.qunar.com/inner/captcha/snapshot 可以发现是encryption方法生成,进入encryption里面,发现是AES加密的轨迹 track就是轨迹 直接…...
Redis ④-通用命令
Redis 是一个 客户端-服务器 结构的程序,这与 MySQL 是类似的,这点需要牢记!!! Redis 固然好,但也不是任何场景都适合使用 Redis,一定要根据当前的业务需求来选择是否使用 Redis Redis 通用命令…...
机制的作用
“机制”是一个广泛使用的概念,其含义和应用范围因领域而异。在不同的学科和实际应用中,机制有着不同的定义和功能。以下从几个主要领域对“机制”进行详细解释: 一、自然科学中的机制 (一)物理学 定义 在物理学中&…...
Pandas:数据处理与分析的核心操作
Pandas:数据处理与分析的核心操作 Pandas 是 Python 数据分析的核心库,它提供了高性能、易用的数据结构和数据分析工具。本文将详细介绍 Pandas 的核心操作,帮助你高效进行数据处理和分析。 1. Pandas 基础数据结构 Pandas 有两个主要的数…...
Kotlin实现Android应用保活方案
Kotlin实现Android应用保活优化方案 以下的Android应用保活实现方案,更加符合现代Android开发规范,同时平衡系统限制和用户体验。 1. 前台服务方案 class OptimizedForegroundService : Service() {private val notificationId 1private val channel…...
硬件电路(25)-过温保护器件ksd9700温控开关
一、概述 KSD9700系列温控开关是一种双金属作为感温元件的温控器,具有动作迅速、控温精确、控制电流大、使用寿命长的特点,被广泛应用于各类微型电机、电磁炉、空调电机、小家电等做温度保护控制。 二、应用 KSD9700系列产品是一种双金属作为感温元件的…...
vuex实现同一页面radio-group点击不同按钮显示不同表单
本文实现的是点击单一规格和多规格两个按钮会在页面显示不同的表单 方法一 <!-- 单规格和多规格的切换 --> <el-form label-width"80px" class"text-align-left"><el-form-item label"商品规格"><!-- 监听skus_type的改…...
代码随想录训练营第36天 ||1049. 最后一块石头的重量 II 494. 目标和 474. 一和零
1049. 最后一块石头的重量 II 讲解:代码随想录 思路: 01背包问题:题意说要求粉碎石头后留下的最小石头重量,石头粉碎的规则是两个石头如果重量相等,同时粉碎,如果重量不相等,粉碎后的重量是大…...
[Spring]SSM整合
第一步 整合任何框架,首先都是导入相关的jar包: <dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.18</version></dependency><!--mybatis依…...
【HDFS】HDFS数据迁移与备份全攻略:从日常备份到灾难恢复
目录 1 HDFS数据迁移与备份概述 2 集群间数据迁移:DistCp工具详解 2.1 DistCp工作原理架构 2.2 DistCp标准工作流程 2.3 DistCp性能优化方案 3 离线备份实施策略 3.1 HDFS到本地备份架构 4 灾难恢复方案设计 4.1 基于快照的恢复流程 4.2 数据一致性校验方…...
动态规划入门:背包问题求具体方案(以0-1背包问题为例)
本质:有向图最短(长)路问题 字典序最小方案?--贪心思路?(本题未使用) 分析第一个物品: 写代码时tip:要考虑“边读边做”还是“先读后做” #include<iostream> #i…...
git学习日志
你看到的是 Vim 文本编辑器的界面,并非 git 的窗口。这是你通过 vim hello.txt 命令打开的新文件。以下是分步操作指南: 1. 进入编辑模式 按下键盘上的 i 键(进入 “INSERT” 模式),此时左下角会显示 -- INSERT --。现…...
数字孪生废气处理工艺流程
图扑数字孪生废气处理工艺流程系统。通过精准 3D 建模,对废气收集、预处理、净化、排放等全流程进行 1:1 数字化复刻,实时呈现设备运行参数、污染物浓度变化等关键数据。 借助图扑可视化界面,管理者可直观掌握废气处理各环节状态,…...
iPhone 13P 换超容电池,一年实记的“电池循环次数-容量“柱状图
继上一篇 iPhone 13P 更换"移植电芯"和"超容电池"🔋体验,详细记录了如何更换这两种电池,以及各自的优略势对比。 一晃一年过去,时间真快,这次分享下记录了使用超容电池的 “循环次数 - 容量(mAh)…...
豆瓣图书数据采集与可视化分析(二)- 豆瓣图书数据清洗与处理
文章目录 前言一、查看数据基本信息二、拆分pub列三、日期列处理四、价格列处理五、出版社列处理六、评价人数列处理七、缺失值处理八、重复数据处理九、异常值处理十、完整代码十一、清洗与处理后的数据集展示 前言 豆瓣作为国内知名的文化社区,拥有庞大且丰富的图…...
【Sa-Token】学习笔记05 - 踢人下线源码解析
目录 前言 强制注销 踢人下线 源码解析 前言 所谓踢人下线,核心操作就是找到指定 loginId 对应的 Token,并设置其失效。 上图为踢人下线后,前端应该用图像给出来让用户重新登录,而不是让前端收到一个描述着被下线 的JSON 强…...
Linux | I.MX6ULL 文件系统
01 本节所有的测试程序需要开发板有 Qt 环境来运行。我们提供的文件系统是由 yocto 裁剪整理得来的。之后我们会整理一份单独移植的 qt 系统。方便用户移植第三方软件。如果用户的文件系统非我们的出厂版本,请参考之前烧写章节重新烧写出厂文件系统。开发板启动需要输入登录…...
Python3基础语法
一:注释 Python中用#表示单行注释,#之后的同行的内容都会被注释掉。 使用三个连续的双引号表示多行注释,两个多行注释标识之间内容会被视作是注释。 二:基础变量类型与操作符 1. 除法 * 除法 / python3中就算是两个整数相除&a…...
QEMU源码全解析 —— 块设备虚拟化(20)
接前一篇文章:QEMU源码全解析 —— 块设备虚拟化(19) 本文内容参考: 《趣谈Linux操作系统》 —— 刘超,极客时间 《QEMU/KVM源码解析与应用》 —— 李强,机械工业出版社 特此致谢! 上一回大致解析了drive_new函数,本回重点对于drive_new函数中调用的blockdev_init函…...
JavaScript 笔记 --- part 4 --- Web API (part 2)
(webAPI part2) DOM 基本操作 事件流 定义: 指的是事件完整执行过程中的流动路径 捕获阶段: 事件从最外层的窗口对象开始,逐层向内传播到目标元素,并触发相应的事件处理程序。 冒泡阶段: 事件从目标元素开始,逐层向外传播到最外层的窗口对象…...
从入门到精通汇编语言 第六章(中断及外部设备操作)
参考教程:通俗易懂的汇编语言(王爽老师的书)_哔哩哔哩_bilibili 一、移位指令 1、8个移位指令 (1)逻辑左移指令SHL:SHL OPR, CNT。 ①OPR为操作数,CNT为左移位数,该指令将OPR视作…...
PySide6 GUI 学习笔记——常用类及控件使用方法(常用类尺寸QSizeF)
QSizeF 类(浮点尺寸类) 文章目录 QSizeF 类(浮点尺寸类)概述主要方法列表详细说明及应用举例注意事项 概述 QSizeF 类使用浮点精度定义二维对象的尺寸。官方文档在这里。 主要方法列表 __init__(self) …...
操作系统中的虚拟化技术深度对话
操作系统中的虚拟化技术深度对话 参与者:系统工程师(Engineer)、开发者(Developer)、学生(Student) 1. 虚拟化的基本概念 Student:虚拟化到底是什么?为什么操作系统需要…...
第35讲:构建属于自己的遥感大模型平台,并接入地理数据工作流
目录 🌍 写在前面 一、为什么要构建属于自己的遥感大模型平台? 二、核心技术选型推荐 ✅ 前端部分 ✅ 后端部分 ✅ 部署平台 三、平台架构设计思路 四、案例实战:构建一个在线遥感分割平台 📌 第一步:模型服务封装(FastAPI) 📌 第二步:前端上传与展示(L…...
langchain-nextjs-template 模板安装与配置
前提条件: node安装yarn 安装:npm install -g yarn 目录 1. 克隆项目2. 安装依赖3. 配置环境变量4. 修改模型配置5. 启动开发服务器6. 项目结构说明7. 功能说明8. 自定义提示模板部分过程文件截图 1. 克隆项目 首先,从 GitHub 克隆 LangCha…...
安卓单机斗地主,具备休闲挑战等多模式
软件介绍 斗地主单机版是一款超适合在安卓设备上玩的游戏。当你周末玩网游玩累了的时候,它就是个很不错的选择哦。 多种模式可选 这个斗地主单机版有不同的模式呢,有休闲模式、挑战模式、炸弹场和大师赛。你可以根据自己的喜好随意挑选模式,…...
电解电容失效分析过程、失效分析报告
参考: 深度剖析关键电子元器件电解电容内部故障隐患 电解电容的参数指标 电路板中电解电容是存在寿命的,电解电容中的电解液随着时间会慢慢减少导致电容容值降低,最终导致电源出现问题。相信大家都见过电解电容鼓包的情况。 所以做设计的时…...
Ubuntu修改Swap交换空间大小
前言: 安装Ubuntu系统时,选择了默认空间分配方案,Swap空间仅1G,而实际的物理内存有32G,分给Swap空间至少为内存的1倍,最好是内存值的2倍,系统相当卡顿,重做系统后,费力部…...
SpringBoot 知识图谱
预警:本文非常长,建议先 mark 后看,也许是最后一次写这么长的文章说明:前面有 4 个小节关于 Spring 的基础知识,分别是:IOC 容器、JavaConfig、事件监听、SpringFactoriesLoader 详解,它们占据了本文的大部分内容,虽然它们之间可能没有太多的联系,但这些知识对于理解 …...
智谱开源新一代GLM模型,全面布局AI智能体生态
2024年4月15日,智谱在中关村论坛上正式发布了全球首个集深度研究与实际操作能力于一体的AI智能体——AutoGLM沉思。这一革命性技术的发布标志着智谱在AGI(通用人工智能)领域的又一次重要突破。智谱的最新模型不仅推动了AI智能体技术的升级&am…...
一文读懂Python之numpy模块(34)
一、模块简介 numpy是Python语言中做科学计算的基础库,重在于数值计算,有一个强大的N维数组对象Array,同时NumPy 提供了大量的库函数和操作,可以帮助程序员轻松地进行Array数值计算。 numpy在数据分析和机器学习领域被广泛使用。…...
Lora 微调自定义device_map
Lora 微调自定义device_map 首先查看模型权重参数配置model.safetensors.index.json 查看多少解码器 这里的layer可以理解为解码器层,后面有qkv,bais,layernomal等 # 显卡数量 num_gpus = 5 # 总层数 num_layers = 28layers_per_gpu = num_layers // num...
二叉树的顺序结构及实现
一.二叉树的顺序结构 二.堆的概念及结构 三.堆的实现 一.二叉树的顺序结构 普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。现实中我们通常把堆 ( 一种二叉树 ) 使用顺序结构的数组来存储。 二.堆的概念…...
python生成项目依赖文件requirements.txt
文章目录 通过pip freeze去生成通过pipreqs去生成 通过pip freeze去生成 pip freeze > requirements.txt会将整个python的Interceptor的环境下lib包下所有的依赖都生成到这个文件当中,取决于我们使用的python的版本下所有的安装包。不建议使用这种方式ÿ…...