机器翻译与数据集_by《李沐:动手学深度学习v2》pytorch版

系列文章目录


文章目录

  • 系列文章目录
  • 介绍机器翻译
  • 下载和预处理数据集
    • 词元化
    • 词表
    • 加载数据集
    • 训练模型
      • 对上述代码中出现的Vocab进行总体解释和逐行解释
      • 使用场景
    • 小结
    • 练习
    • 答案
      • 1. `num_examples` 参数对词表大小的影响
      • 2. 对于没有单词边界的语言,单词级词元化的有效性


介绍机器翻译

语言模型是自然语言处理的关键, 而机器翻译是语言模型最成功的基准测试。 因为机器翻译正是将输入序列转换成输出序列的序列转换模型(sequence transduction)的核心问题。 序列转换模型在各类现代人工智能应用中发挥着至关重要的作用, 为此,本节将介绍机器翻译问题及其后文需要使用的数据集。
机器翻译(machine translation)指的是将序列从一种语言自动翻译成另一种语言。 事实上,这个研究领域可以追溯到数字计算机发明后不久的20世纪40年代, 特别是在第二次世界大战中使用计算机破解语言编码。 几十年来,在使用神经网络进行端到端学习的兴起之前, 统计学方法在这一领域一直占据主导地位。因为统计机器翻译(statistical machine translation)涉及了 翻译模型和语言模型等组成部分的统计分析, 因此基于神经网络的方法通常被称为 神经机器翻译(neural machine translation), 用于将两种翻译模型区分开来。
本书的关注点是神经网络机器翻译方法,强调的是端到端的学习。下面,我们看一下如何将预处理后的数据加载到小批量中用于之后的训练。

import os
import torch
from d2l import torch as d2l

下载和预处理数据集

首先,下载一个由Tatoeba项目的双语句子对
组成的“英-法”数据集,数据集中的每一行都是制表符分隔的文本序列对,序列对由英文文本序列和翻译后的法语文本序列组成。
请注意,每个文本序列可以是一个句子,也可以是包含多个句子的一个段落。
在这个将英语翻译成法语的机器翻译问题中,英语是源语言(source language),法语是目标语言(target language)。

# 注册数据集到数据中心,指定数据集名称和下载链接及其校验和
d2l.DATA_HUB['fra-eng'] = (d2l.DATA_URL + 'fra-eng.zip','94646ad1522d915e7b0f9296181140edcf86a4f5')# 定义一个函数,用于加载“英语-法语”数据集
def read_data_nmt():"""载入“英语-法语”数据集"""# 下载并解压数据集,返回数据目录data_dir = d2l.download_extract('fra-eng')# 打开解压后的文本文件,读取其内容with open(os.path.join(data_dir, 'fra.txt'), 'r', encoding='utf-8') as f:return f.read()  # 返回文件的全部内容# 调用函数,获取原始文本数据
raw_text = read_data_nmt()# 打印原始文本的前50个字符
print(raw_text[:50])
Go.	Va !
Hi.	Salut !
Run!	Cours !
Run!	Courez !
Wh

下载数据集后,原始文本数据需要经过[几个预处理步骤]。
例如,我们用空格代替不间断空格(non-breaking space),使用小写字母替换大写字母,并在单词和标点符号之间插入空格。

def preprocess_nmt(text):"""预处理“英语-法语”数据集"""# 定义一个辅助函数,用于判断是否在单词和标点之间插入空格def no_space(char, prev_char):return char in set(',.!?') and prev_char != ' '# 将文本中的不间断空格和某些特殊空格替换为普通空格# 将文本转换为小写字母text = text.replace('\u202f', ' ').replace('\xa0', ' ').lower()# 在单词和标点符号之间插入空格out = [' ' + char if i > 0 and no_space(char, text[i - 1]) else charfor i, char in enumerate(text)]# 将处理后的字符列表连接成一个字符串并返回return ''.join(out)# 调用预处理函数,处理原始文本数据
text = preprocess_nmt(raw_text)# 打印处理后的文本前80个字符
print(text[:80])
go .	va !
hi .	salut !
run !	cours !
run !	courez !
who ?	qui ?
wow !	ça alors !

词元化

与字符级词元化不同,在机器翻译中,我们更喜欢单词级词元化(最先进的模型可能使用更高级的词元化技术)。下面的tokenize_nmt函数对前num_examples个文本序列对进行词元,其中每个词元要么是一个词,要么是一个标点符号。
此函数返回两个词元列表:sourcetargetsource[i]是源语言(这里是英语)第 i i i个文本序列的词元列表,target[i]是目标语言(这里是法语)第 i i i个文本序列的词元列表。

# 定义一个函数,用于将“英语-法语”数据集进行词元化
def tokenize_nmt(text, num_examples=None):"""词元化“英语-法语”数据集"""# 初始化源语言(英语)和目标语言(法语)的列表source, target = [], []# 遍历文本中的每一行for i, line in enumerate(text.split('\n')):# 如果指定了样本数量,且已处理的行数超过该数量,则停止处理if num_examples and i > num_examples:break# 将当前行按制表符分割,得到源语言和目标语言的部分parts = line.split('\t')# 如果当前行包含源语言和目标语言(即分割后有两个部分)if len(parts) == 2:# 将源语言部分按空格分割并添加到源语言列表中source.append(parts[0].split(' '))# 将目标语言部分按空格分割并添加到目标语言列表中target.append(parts[1].split(' '))# 返回源语言和目标语言的列表return source, target# 调用词元化函数,处理文本数据
source, target = tokenize_nmt(text)# 打印源语言和目标语言的前6个样本
source[:6], target[:6]
([['go', '.'],['hi', '.'],['run', '!'],['run', '!'],['who', '?'],['wow', '!']],[['va', '!'],['salut', '!'],['cours', '!'],['courez', '!'],['qui', '?'],['ça', 'alors', '!']])

让我们[绘制每个文本序列所包含的词元数量的直方图]。
在这个简单的“英-法”数据集中,大多数文本序列的词元数量少于 20 20 20个。

# 定义一个函数,用于绘制列表长度对的直方图
def show_list_len_pair_hist(legend, xlabel, ylabel, xlist, ylist):"""绘制列表长度对的直方图"""# 设置图形的大小d2l.set_figsize()# 绘制直方图,计算 xlist 和 ylist 中每个列表的长度_, _, patches = d2l.plt.hist([[len(l) for l in xlist], [len(l) for l in ylist]])# 设置 x 轴标签d2l.plt.xlabel(xlabel)# 设置 y 轴标签d2l.plt.ylabel(ylabel)# 为第二个数据集的直方图的每个条形设置斜线填充for patch in patches[1].patches:patch.set_hatch('/')# 添加图例d2l.plt.legend(legend)# 调用函数,绘制源语言和目标语言的长度直方图
show_list_len_pair_hist(['source', 'target'], '# tokens per sequence','count', source, target);

在这里插入图片描述

词表

由于机器翻译数据集由语言对组成,因此我们可以分别为源语言和目标语言构建两个词表。
使用单词级词元化时,词表大小将明显大于使用字符级词元化时的词表大小。
为了缓解这一问题,这里我们将出现次数少于2次的低频率词元视为相同的未知(“<unk>”)词元。
除此之外,我们还指定了额外的特定词元,例如在小批量时用于将序列填充到相同长度的填充词元(“<pad>”),以及序列的开始词元(“<bos>”)和结束词元(“<eos>”)。这些特殊词元在自然语言处理任务中比较常用。

# 创建源语言(英语)词汇表,指定最小频率和保留的特殊标记
src_vocab = d2l.Vocab(source, min_freq=2,reserved_tokens=['<pad>', '<bos>', '<eos>'])# 获取词汇表中的词汇数量
len(src_vocab)
10012
# 访问源语言列表中的第一个句子,并获取该句子的第二个词元
source[0][1]
'.'

加载数据集

回想一下,语言模型中的[序列样本都有一个固定的长度],无论这个样本是一个句子的一部分还是跨越了多个句子的一个片断。
这个固定长度是由语言模型中的num_steps(时间步数或词元数量)参数指定的。
在机器翻译中,每个样本都是由源和目标组成的文本序列对,其中的每个文本序列可能具有不同的长度。
为了提高计算效率,我们仍然可以通过截断(truncation)和填充(padding)方式实现一次只处理一个小批量的文本序列。
假设同一个小批量中的每个序列都应该具有相同的长度num_steps,那么如果文本序列的词元数目少于num_steps时,我们将继续在其末尾添加特定的“<pad>”词元,直到其长度达到num_steps;反之,我们将截断文本序列时,只取其前num_steps 个词元,并且丢弃剩余的词元。这样,每个文本序列将具有相同的长度,以便以相同形状的小批量进行加载。如前所述,下面的truncate_pad函数将(截断或填充文本序列)。

# 定义一个函数,用于截断或填充文本序列
def truncate_pad(line, num_steps, padding_token):"""截断或填充文本序列"""# 如果序列长度超过指定的步数,则进行截断if len(line) > num_steps:return line[:num_steps]  # 截断到 num_steps 长度# 否则,进行填充,直到达到指定的步数return line + [padding_token] * (num_steps - len(line))  # 填充# 调用函数,处理源语言的第一个句子,目标长度为 10,填充标记为词汇表中的 <pad>
truncate_pad(src_vocab[source[0]], 10, src_vocab['<pad>'])
[47, 4, 1, 1, 1, 1, 1, 1, 1, 1]

现在我们定义一个函数,可以将文本序列[转换成小批量数据集用于训练]。
我们将特定的“<eos>”词元添加到所有序列的末尾,用于表示序列的结束。
当模型通过一个词元接一个词元地生成序列进行预测时,生成的“<eos>”词元说明完成了序列输出工作。
此外,我们还记录了每个文本序列的长度,统计长度时排除了填充词元,在稍后将要介绍的一些模型会需要这个长度信息。

# 定义一个函数,将机器翻译的文本序列转换成小批量
def build_array_nmt(lines, vocab, num_steps):"""将机器翻译的文本序列转换成小批量"""# 将每个文本行转换为对应的词汇表索引lines = [vocab[l] for l in lines]# 在每个序列末尾添加结束标记 <eos>lines = [l + [vocab['<eos>']] for l in lines]# 使用 truncate_pad 函数填充或截断每个序列,并转换为张量array = torch.tensor([truncate_pad(l, num_steps, vocab['<pad>']) for l in lines])# 计算每个序列的有效长度(不包括填充部分)valid_len = (array != vocab['<pad>']).type(torch.int32).sum(1)# 返回填充后的张量和有效长度return array, valid_len

训练模型

最后,我们定义load_data_nmt函数来返回数据迭代器,以及源语言和目标语言的两种词表。

# 定义一个函数,用于加载翻译数据集并返回迭代器和词表
def load_data_nmt(batch_size, num_steps, num_examples=600):"""返回翻译数据集的迭代器和词表"""# 读取和预处理数据text = preprocess_nmt(read_data_nmt())# 对文本进行词元化,得到源语言和目标语言source, target = tokenize_nmt(text, num_examples)# 创建源语言的词汇表,指定最小频率和保留的特殊标记src_vocab = d2l.Vocab(source, min_freq=2,reserved_tokens=['<pad>', '<bos>', '<eos>'])# 创建目标语言的词汇表,指定最小频率和保留的特殊标记tgt_vocab = d2l.Vocab(target, min_freq=2,reserved_tokens=['<pad>', '<bos>', '<eos>'])# 将源语言序列转换为数组,并计算有效长度src_array, src_valid_len = build_array_nmt(source, src_vocab, num_steps)# 将目标语言序列转换为数组,并计算有效长度tgt_array, tgt_valid_len = build_array_nmt(target, tgt_vocab, num_steps)# 将所有数据数组组合成一个元组data_arrays = (src_array, src_valid_len, tgt_array, tgt_valid_len)# 创建数据迭代器,支持批量处理data_iter = d2l.load_array(data_arrays, batch_size)# 返回数据迭代器和源、目标语言的词汇表return data_iter, src_vocab, tgt_vocab

当然可以!以下是对 Vocab 类的逐行解释,以及对整个类的总结。

class Vocab:"""Vocabulary for text."""def __init__(self, tokens=None, min_freq=0, reserved_tokens=None):"""初始化词汇表"""if tokens is None:tokens = []  # 如果没有提供 tokens,则初始化为空列表if reserved_tokens is None:reserved_tokens = []  # 如果没有提供保留的特殊标记,则初始化为空列表# 统计词频并按频率排序counter = count_corpus(tokens)  # 统计每个词的出现频率self._token_freqs = sorted(counter.items(), key=lambda x: x[1], reverse=True)  # 按频率降序排序# 未知标记的索引为 0self.idx_to_token = ['<unk>'] + reserved_tokens  # 初始化索引到词的映射,包含未知标记和保留标记self.token_to_idx = {token: idx for idx, token in enumerate(self.idx_to_token)}  # 创建词到索引的映射# 添加频率大于 min_freq 的词到词汇表for token, freq in self._token_freqs:if freq < min_freq:break  # 如果频率小于 min_freq,则停止添加if token not in self.token_to_idx:self.idx_to_token.append(token)  # 将词添加到索引到词的列表self.token_to_idx[token] = len(self.idx_to_token) - 1  # 更新词到索引的映射def __len__(self):return len(self.idx_to_token)  # 返回词汇表的大小def __getitem__(self, tokens):# 支持通过索引获取词或词列表if not isinstance(tokens, (list, tuple)):return self.token_to_idx.get(tokens, self.unk)  # 返回词的索引,如果不存在则返回未知标记的索引return [self.__getitem__(token) for token in tokens]  # 返回词列表的索引def to_tokens(self, indices):# 将索引转换为词if not isinstance(indices, (list, tuple)):return self.idx_to_token[indices]  # 返回单个索引对应的词return [self.idx_to_token[index] for index in indices]  # 返回索引列表对应的词@propertydef unk(self):  # 返回未知标记的索引return 0@propertydef token_freqs(self):  # 返回词频列表return self._token_freqs

对上述代码中出现的Vocab进行总体解释和逐行解释

Vocab 类用于管理文本数据的词汇表,提供词与索引之间的映射、词频统计等功能。其主要功能包括:

  1. 初始化词汇表

    • 接受一组词元(tokens),最小频率(min_freq),以及保留的特殊标记(reserved_tokens)。
    • 统计词频,并按频率排序。
    • 将频率大于指定最小频率的词添加到词汇表中,并建立词到索引的映射。
  2. 支持索引操作

    • 可以通过 __getitem__ 方法根据词获取其索引,支持单个词和词列表的查询。
    • 可以通过 to_tokens 方法根据索引获取对应的词,支持单个索引和索引列表的查询。
  3. 属性方法

    • unk 返回未知标记的索引(通常为0)。
    • token_freqs 返回词频列表,便于分析。

使用场景

  • 文本处理:在自然语言处理任务中,Vocab 类可用于构建词汇表,帮助模型理解输入文本的结构。
  • 数据预处理:在训练模型之前,使用 Vocab 类可以有效地将文本数据转换为数值格式,以便于后续的模型训练和评估。
class Vocab:"""Vocabulary for text."""def __init__(self, tokens=None, min_freq=0, reserved_tokens=None):"""初始化词汇表"""if tokens is None:tokens = []  # 如果没有提供 tokens,则初始化为空列表if reserved_tokens is None:reserved_tokens = []  # 如果没有提供保留的特殊标记,则初始化为空列表# 统计词频并按频率排序counter = count_corpus(tokens)  # 统计每个词的出现频率self._token_freqs = sorted(counter.items(), key=lambda x: x[1], reverse=True)  # 按频率降序排序# 未知标记的索引为 0self.idx_to_token = ['<unk>'] + reserved_tokens  # 初始化索引到词的映射,包含未知标记和保留标记self.token_to_idx = {token: idx for idx, token in enumerate(self.idx_to_token)}  # 创建词到索引的映射# 添加频率大于 min_freq 的词到词汇表for token, freq in self._token_freqs:if freq < min_freq:break  # 如果频率小于 min_freq,则停止添加if token not in self.token_to_idx:self.idx_to_token.append(token)  # 将词添加到索引到词的列表self.token_to_idx[token] = len(self.idx_to_token) - 1  # 更新词到索引的映射def __len__(self):return len(self.idx_to_token)  # 返回词汇表的大小def __getitem__(self, tokens):# 支持通过索引获取词或词列表if not isinstance(tokens, (list, tuple)):return self.token_to_idx.get(tokens, self.unk)  # 返回词的索引,如果不存在则返回未知标记的索引return [self.__getitem__(token) for token in tokens]  # 返回词列表的索引def to_tokens(self, indices):# 将索引转换为词if not isinstance(indices, (list, tuple)):return self.idx_to_token[indices]  # 返回单个索引对应的词return [self.idx_to_token[index] for index in indices]  # 返回索引列表对应的词@propertydef unk(self):  # 返回未知标记的索引return 0@propertydef token_freqs(self):  # 返回词频列表return self._token_freqs

下面我们[读出“英语-法语”数据集中的第一个小批量数据]。

train_iter, src_vocab, tgt_vocab = load_data_nmt(batch_size=2, num_steps=8)
for X, X_valid_len, Y, Y_valid_len in train_iter:print('X:', X.type(torch.int32))print('X的有效长度:', X_valid_len)print('Y:', Y.type(torch.int32))print('Y的有效长度:', Y_valid_len)break
X: tensor([[134,  12,   4,   3,   1,   1,   1,   1],[ 13, 178,   4,   3,   1,   1,   1,   1]], dtype=torch.int32)
X的有效长度: tensor([4, 4])
Y: tensor([[0, 5, 3, 1, 1, 1, 1, 1],[0, 4, 3, 1, 1, 1, 1, 1]], dtype=torch.int32)
Y的有效长度: tensor([3, 3])
for X, X_valid_len, Y, Y_valid_len in train_iter:print(Y[0][0].type(torch.int32))Z = Y[0][0].type(torch.int32)print(Z)break
tensor(0, dtype=torch.int32)
tensor(0, dtype=torch.int32)

小结

  • 机器翻译指的是将文本序列从一种语言自动翻译成另一种语言。
  • 使用单词级词元化时的词表大小,将明显大于使用字符级词元化时的词表大小。为了缓解这一问题,我们可以将低频词元视为相同的未知词元。
  • 通过截断和填充文本序列,可以保证所有的文本序列都具有相同的长度,以便以小批量的方式加载。

练习

  1. load_data_nmt函数中尝试不同的num_examples参数值。这对源语言和目标语言的词表大小有何影响?
  2. 某些语言(例如中文和日语)的文本没有单词边界指示符(例如空格)。对于这种情况,单词级词元化仍然是个好主意吗?为什么?

答案

1. num_examples 参数对词表大小的影响

load_data_nmt 函数中,num_examples 参数决定了用于构建词表的示例数量。尝试不同的 num_examples 值会对源语言和目标语言的词表大小产生以下影响:

  • 较小的 num_examples

    • 词表可能会更小,因为只考虑了有限数量的示例,导致一些频率较低的词被忽略。
    • 可能无法捕捉到语言的多样性,尤其是在处理复杂或多样化的文本时。
  • 较大的 num_examples

    • 词表通常会更大,因为包含了更多的词汇和短语,能够更好地反映语言的丰富性。
    • 可能会包含更多的低频词,增加词表的复杂性,导致模型在训练时需要处理更多的词。

总结来说,num_examples 的选择直接影响词表的覆盖范围和复杂性,较大的示例数量通常能更好地捕捉语言的特性。

2. 对于没有单词边界的语言,单词级词元化的有效性

在处理没有单词边界的语言(如中文和日语)时,单词级词元化可能面临挑战。以下是一些考虑因素:

  • 问题

    • 由于缺乏明确的单词边界,单词级词元化可能会导致错误的词分割,无法准确捕捉到语言的结构和意思。
    • 词汇表可能会变得非常庞大,因为每个字符或字可能被视为一个单独的“单词”。
  • 替代方案

    • 对于这些语言,更常用的做法是使用字符级或子词级(如 BPE,Byte Pair Encoding)词元化。
    • 这种方法可以更好地处理语言的特性,减少词汇表的大小,同时保留语义信息。

总结
单词级词元化在没有单词边界的语言中并不总是有效,使用字符级或子词级词元化通常是更好的选择,因为它们能够更好地适应这些语言的结构特点。

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

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

相关文章

[ IDE ] SEGGER Embedded Studio for RISC-V

一、FILE 二、Edit 三、View 四、Search 五、Navigate 六、Project 七、Build 7.1 编译 先选择一个目标类型&#xff0c;再选择编译。 八、Debug 九、Target 十、Tools 10.1 自定义快捷键 点击菜单项&#xff0c;通过Tools –> Options –> Keyboard&#xff0c;实现自…

2024年《Python基础语法大全及知识点总结》小白入门必备!(高清PDF下载)

一、引言 在 2024 年&#xff0c;Python 依然是编程领域的闪耀之星。无论是数据分析、人工智能、Web 开发还是自动化任务&#xff0c;Python 都以其简洁高效的语法和强大的功能发挥着重要作用。本文将为你呈现超级完整的 Python 基础语法和知识点总结&#xff0c;助你轻松掌握…

JVM面试知识点手册

第一部分&#xff1a;JVM 概述 1.1 JVM 简介 Java Virtual Machine&#xff08;JVM&#xff09; 是 Java 语言的核心组件&#xff0c;负责将 Java 程序编译后的字节码&#xff08;bytecode&#xff09;转换为机器指令&#xff0c;并在目标机器上执行。JVM 提供了硬件和操作系…

Java 集合详解

目录 一. 概述 二. Collection接口实现类 三. Map接口实现类 四. 线程安全集合 五. List接口下集合实现原理 1. ArrayList实现原理 1.1. 基于动态数组 1.2. 随机访问 1.3. 添加元素 1.4. 删除元素 1.5. 迭代器 1.6. 克隆和序列化 1.7. ArrayList简单使用 2. Link…

重磅发布:OpenAI o1全新推理模型系列

2024年9月12日&#xff0c;OpenAI正式推出全新的推理模型系列——OpenAI o1。这款全新AI模型系列专为解决复杂问题而设计&#xff0c;能够在响应前花费更多时间进行思考&#xff0c;并通过深入推理应对比以往模型更具挑战性的科学、编程和数学问题。 1. 开发背景与首发版本 今…

安装Kali Linux后8件需要马上安排的事

目录 一、更新升级 二、 编辑器 三、用户与权限 四、 下载TOR 五、下载终端 一、更新升级 sudo apt update -y && sudo apt upgrade -y && sudo apt autoremove 二、 编辑器 VScode或者vim&#xff1b;点击.deb就会下载了 一般都会下载到Downloads文件夹中…

读论文-使用潜在扩散模型进行高分辨率图像合成

论文名称&#xff1a;High-Resolution Image Synthesis with Latent Diffusion Models 论文地址&#xff1a;arxiv.org/pdf/2112.10752v2 项目地址&#xff1a;GitHub - CompVis/stable-diffusion: A latent text-to-image diffusion model 潜在扩散模型&#xff08;LDMs&…

Mac使用技巧-来自苹果专人在线辅导服务2

好记性不如烂笔头&#xff01; 其实高效的学习途径还是尽量跟着苹果工作人员在线进行学习&#xff0c;这样一对一&#xff0c;有来有往&#xff0c;学习有反馈&#xff0c;并且很高效&#xff0c;很多东西演示一遍就学会了&#xff0c;自己看还是会花更长的时间。 苹果专人在线…

AI测试|利用OpenAI的文本生成模型,自动生成测试用例的几个场景示例

将人工智能 (AI) 融入软件测试将彻底改变游戏规则&#xff0c;可以显著提高效率和有效性。本文利用 OpenAI 的文本生成模型&#xff08;text generation model&#xff09;&#xff0c;特别是 GPT-3.5-turbo 和 GPT-4-turbo-preview&#xff0c;在 Google Colab 中构建文本生成…

102.SAPUI5 sap.ndc.BarcodeScannerButton调用摄像头时,localhost访问正常,使用IP访问失败

目录 原因 解决办法 1.修改谷歌浏览器的setting 2.在tomcat中配置https访问 参考 使用SAPUI5的sap.ndc.BarcodeScannerButton调用摄像头时&#xff0c;localhost访问正常&#xff0c;使用IP访问时&#xff0c;一直打不开摄像头&#xff0c;提示getUserMedia()问题。 原因…

有关JS下隐藏的敏感信息

免责声明&#xff1a;本文仅做分享&#xff01; 目录 JavaScript 介绍 核心组成 工具 FindSomething ** 浏览器检查 ** LinkFinder URLfinder ** SuperSearchPlus ** ffuf ParasCollector waymore Packer Fuzzer JS逆向 应用&#xff1a; 小结&#xff1a; Ja…

简明linux系统编程--互斥锁--TCP--UDP初识

目录 1.互斥锁 2.信号 2.1介绍 2.2信号的内核机制 3.linux网络编程概述 3.1一览七层协议 3.2一览数据传输过程 3.3四层网络模型 3.4服务端和客户端的数据交互 4.TCP服务端编程 5.TCP客户端编程 6.UDP服务端编程 7.UDP客户端编程 1.互斥锁 互斥锁也是和信号量一样&a…

【C++】——优先级队列和容器适配器

文章目录 优先级队列容器适配器 优先级队列 优先级队列是一种特殊的队列&#xff0c;他的元素出队列顺序并不按照先进先出原则&#xff0c;而是根据元素的优先级来。优先级高的先出&#xff0c;优先级低的后出。(类似于堆) 优先级队列常用成员函数&#xff1a; empty()&#x…

6.C++程序中的基本数据类型

数据类型是指在C中用于声明不同类型变量或函数的一个系统或抽象或者是一个分类&#xff0c;它决定了变量存储占用的内存空间以及解析存储的位模式。其实数据类型可以理解为固定内存大小的别名&#xff0c;是创建变量的模具&#xff0c;具体使用哪种模具&#xff08;包括自定义&…

ai写作软件排行榜前十名,5个软件帮助你快速使用ai写作

ai写作软件排行榜前十名&#xff0c;5个软件帮助你快速使用ai写作 AI写作软件已经成为许多人工作和创作中的重要工具&#xff0c;尤其是在快速生成内容、提高写作效率以及优化文本方面。以下是五款优秀的AI写作软件&#xff0c;它们能够帮助你轻松完成各种写作任务&#xff0c…

芯片级配件产品研发的小众企业生存之路

在半导体行业中&#xff0c;芯片级配件产品的研发一直是一个充满挑战的领域&#xff0c;尤其是对于小众企业而言&#xff0c;如何在技术壁垒高、资金需求大的市场中生存并发展&#xff0c;成为了业界普遍关注的问题。芯片级配件产品涉及到晶圆制造、封装、测试等多个复杂工艺环…

计算机人工智能前沿进展-大语言模型方向-2024-09-20

计算机人工智能前沿进展-大语言模型方向-2024-09-20 1. Multimodal Fusion with LLMs for Engagement Prediction in Natural Conversation Authors: Cheng Charles Ma, Kevin Hyekang Joo, Alexandria K. Vail, Sunreeta Bhattacharya, Alvaro Fern’andez Garc’ia, Kailan…

码头童话,“丈量”行业数智化转型

作者 | 曾响铃 文 | 响铃说 一箱车厘子从地球正对的另一边远渡重洋来到中国&#xff0c;而一旦到达&#xff0c;5个小时内它就能变成北京、天津、河北、河南等区域老百姓果盘里的美味。 这一幕&#xff0c;来自央视联合华为制作发布的《新智中国说-谈智一会间》第一期“码头…

win10下使用docker、k8s部署java应用

在上一篇文章 Windows10上Docker和Kubernetes的安装 中&#xff0c;已经介绍了在 Windows10上安装Docker和Kubernetes &#xff0c;有了这个环境基础之后&#xff0c;就可以用来部署服务了 在项目目录下新建Dockfile文件&#xff0c;内容如下&#xff08;请根据实际情况调整&am…

鸿蒙开发之ArkUI 界面篇 十五 交叉轴对其方式

鸿蒙界面有两个容器一个是Colum、一个是Row&#xff0c;Colum主轴是垂直方向&#xff0c;交叉轴是水平方向&#xff0c;Row的主轴是水平方向&#xff0c;交叉轴是垂直方向&#xff0c;对应方向调整子控件的话&#xff0c;justifyContent调整的是主轴方向的子控件距离&#xff0…