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

【机器翻译】基于术语词典干预的机器翻译挑战赛

文章目录

    • 一、赛题链接
    • 二、安装库
      • 1.spacy
      • 2.torch_text
    • 三、数据预处理
        • 赛题数据
        • 类定义 `TranslationDataset`
        • 批量处理函数 `collate_fn`
    • 四、编码器和解码器
        • Encoder 类
        • Decoder 类
        • Seq2Seq 类
        • 注意事项
    • 五、主函数
        • 1. `load_terminology_dictionary(dict_file)`
        • 2. `train(model, iterator, optimizer, criterion, clip)`
    • 六、验证集的模型评价和测试集的模型推理

一、赛题链接

赛题链接:https://challenge.xfyun.cn/topic/info?type=machine-translation-2024

二、安装库

1.spacy

查看本地spacy版本

pip show spacy

我安装3.6.0

pip install en_core_web_sm-3.6.0.tar.gz

en_core_web_sm下载链接:https://github.com/explosion/spacy-models/releases

2.torch_text

!pip install torchtext

命令 !pip install torchtext 是一个在支持Jupyter Notebook或类似环境的Python解释器中使用的命令,用于安装或更新torchtext库。这个命令通过Python的包管理工具pip来执行。

!:这个符号在Jupyter Notebook、Google Colab等环境中用作前缀,允许你在代码单元中执行shell命令。这意呀着,紧跟在这个符号后面的命令将会作为shell命令执行,而不是Python代码。

torchtext是PyTorch生态系统中的一个库,它提供了一套用于处理自然语言和其他文本数据的工具,包括数据加载、预处理、词汇表构建和简单的文本分类等。

三、数据预处理

赛题数据
  • 训练集:双语数据 - 中英14万余双语句对
  • 开发集:英中1000双语句对
  • 测试集:英中1000双语句对
  • 术语词典:英中2226条
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader
from torchtext.data.utils import get_tokenizer
from collections import Counter
import random
from torch.utils.data import Subset, DataLoader
import time# 定义数据集类
# 修改TranslationDataset类以处理术语
class TranslationDataset(Dataset):def __init__(self, filename, terminology):self.data = []with open(filename, 'r', encoding='utf-8') as f:for line in f:en, zh = line.strip().split('\t')self.data.append((en, zh))self.terminology = terminology# 创建词汇表,注意这里需要确保术语词典中的词也被包含在词汇表中self.en_tokenizer = get_tokenizer('basic_english')self.zh_tokenizer = list  # 使用字符级分词en_vocab = Counter(self.terminology.keys())  # 确保术语在词汇表中zh_vocab = Counter()for en, zh in self.data:en_vocab.update(self.en_tokenizer(en))zh_vocab.update(self.zh_tokenizer(zh))# 添加术语到词汇表self.en_vocab = ['<pad>', '<sos>', '<eos>'] + list(self.terminology.keys()) + [word for word, _ in en_vocab.most_common(10000)]self.zh_vocab = ['<pad>', '<sos>', '<eos>'] + [word for word, _ in zh_vocab.most_common(10000)]self.en_word2idx = {word: idx for idx, word in enumerate(self.en_vocab)}self.zh_word2idx = {word: idx for idx, word in enumerate(self.zh_vocab)}def __len__(self):return len(self.data)def __getitem__(self, idx):en, zh = self.data[idx]en_tensor = torch.tensor([self.en_word2idx.get(word, self.en_word2idx['<sos>']) for word in self.en_tokenizer(en)] + [self.en_word2idx['<eos>']])zh_tensor = torch.tensor([self.zh_word2idx.get(word, self.zh_word2idx['<sos>']) for word in self.zh_tokenizer(zh)] + [self.zh_word2idx['<eos>']])return en_tensor, zh_tensordef collate_fn(batch):en_batch, zh_batch = [], []for en_item, zh_item in batch:en_batch.append(en_item)zh_batch.append(zh_item)# 对英文和中文序列分别进行填充en_batch = nn.utils.rnn.pad_sequence(en_batch, padding_value=0, batch_first=True)zh_batch = nn.utils.rnn.pad_sequence(zh_batch, padding_value=0, batch_first=True)return en_batch, zh_batch

这段代码定义了一个用于机器翻译任务的数据集类 TranslationDataset,它继承自 PyTorch 的 Dataset 类。这个类特别设计来处理包含英文和中文翻译对的文本文件,并且它还支持一个术语词典(terminology),以确保这些术语在构建词汇表时被优先考虑。下

类定义 TranslationDataset
  • 初始化方法 __init__:

    • 读取翻译文件(每行包含一个英文句子和一个中文句子,由制表符分隔)。
    • 初始化术语词典(terminology),这是一个字典。
    • 使用 get_tokenizer('basic_english') 获取英文的基本分词器。对于中文,这里简单地将整个句子视为一个字符序列(使用 list 作为分词器,实际上并不是真正的分词,但在这个示例中为了简化处理)。
    • 使用 Counter 计数英文术语、英文句子分词结果和中文句子分词结果(尽管中文这里按字符处理,但仍进行计数以便后续筛选高频词)。
    • 构建英文和中文的词汇表。首先添加特殊标记(<pad>, <sos>, <eos>),然后添加术语词典中的词,最后添加最常见的10000个英文和中文词(通过 most_common(10000) 获取)。
    • 创建词汇表到索引的映射(word2idx)。
  • 长度方法 __len__:

    • 返回数据集中翻译对的数量。
  • 获取项方法 __getitem__:

    • 根据索引 idx 获取数据集中的一个翻译对(英文和中文)。
    • 使用分词器将英文句子分词,并将每个词转换为索引。
    • 对于中文句子,由于这里按字符处理,直接将每个字符转换为索引。
    • 序列开始和结束标记:在序列两端添加<sos> (Sequence Start)和<eos> (Sequence End)标记,帮助模型识别序列的起始和结束。
    • 在英文和中文句子的末尾添加 <eos> 索引表示句子结束。
    • 返回英文和中文句子的索引张量。
批量处理函数 collate_fn
  • 这个函数用于在 DataLoader 中将多个样本组合成一个批次。
  • 它遍历批次中的每个英文和中文句子索引张量,并将它们分别收集到 en_batchzh_batch 中。
  • 使用 nn.utils.rnn.pad_sequence 对英文和中文句子批次进行填充,以确保批次中的每个句子都有相同的长度(较短的句子用0填充,即 <pad> 的索引)。这里设置 batch_first=True 表示批次维度是第一维。
  • 返回填充后的英文和中文句子批次。

四、编码器和解码器

class Encoder(nn.Module):def __init__(self, input_dim, emb_dim, hid_dim, n_layers, dropout):super().__init__()self.embedding = nn.Embedding(input_dim, emb_dim)self.rnn = nn.GRU(emb_dim, hid_dim, n_layers, dropout=dropout, batch_first=True)self.dropout = nn.Dropout(dropout)def forward(self, src):# src shape: [batch_size, src_len]embedded = self.dropout(self.embedding(src))# embedded shape: [batch_size, src_len, emb_dim]outputs, hidden = self.rnn(embedded)# outputs shape: [batch_size, src_len, hid_dim]# hidden shape: [n_layers, batch_size, hid_dim]return outputs, hiddenclass Decoder(nn.Module):def __init__(self, output_dim, emb_dim, hid_dim, n_layers, dropout):super().__init__()self.output_dim = output_dimself.embedding = nn.Embedding(output_dim, emb_dim)self.rnn = nn.GRU(emb_dim, hid_dim, n_layers, dropout=dropout, batch_first=True)self.fc_out = nn.Linear(hid_dim, output_dim)self.dropout = nn.Dropout(dropout)def forward(self, input, hidden):# input shape: [batch_size, 1]# hidden shape: [n_layers, batch_size, hid_dim]embedded = self.dropout(self.embedding(input))# embedded shape: [batch_size, 1, emb_dim]output, hidden = self.rnn(embedded, hidden)# output shape: [batch_size, 1, hid_dim]# hidden shape: [n_layers, batch_size, hid_dim]prediction = self.fc_out(output.squeeze(1))# prediction shape: [batch_size, output_dim]return prediction, hiddenclass Seq2Seq(nn.Module):def __init__(self, encoder, decoder, device):super().__init__()self.encoder = encoderself.decoder = decoderself.device = devicedef forward(self, src, trg, teacher_forcing_ratio=0.5):# src shape: [batch_size, src_len]# trg shape: [batch_size, trg_len]batch_size = src.shape[0]trg_len = trg.shape[1]trg_vocab_size = self.decoder.output_dimoutputs = torch.zeros(batch_size, trg_len, trg_vocab_size).to(self.device)_, hidden = self.encoder(src)input = trg[:, 0].unsqueeze(1)  # Start tokenfor t in range(1, trg_len):output, hidden = self.decoder(input, hidden)outputs[:, t, :] = outputteacher_force = random.random() < teacher_forcing_ratiotop1 = output.argmax(1)input = trg[:, t].unsqueeze(1) if teacher_force else top1.unsqueeze(1)return outputs

上述代码实现了基于GRU(门控循环单元)的序列到序列(Seq2Seq)模型,该模型通常用于机器翻译、文本摘要等任务。代码由三个主要部分组成:Encoder 类、Decoder 类和 Seq2Seq 类。下面是对每个部分的详细解释:

Encoder 类
  • 初始化 (__init__): 接收输入维度(input_dim)、嵌入维度(emb_dim)、隐藏层维度(hid_dim)、层数(n_layers)和dropout比率(dropout)作为参数。构建了一个嵌入层(nn.Embedding)用于将输入转换为嵌入向量,一个GRU层(nn.GRU)用于处理序列数据,以及一个dropout层(nn.Dropout)用于减少过拟合。
  • 前向传播 (forward): 接收源序列(src)作为输入,首先通过嵌入层和dropout层,然后通过GRU层。返回GRU的输出和最终的隐藏状态。
Decoder 类
  • 初始化 (__init__): 类似于Encoder,但增加了一个全连接层(nn.Linear)用于将GRU的输出转换为预测的输出维度。
  • 前向传播 (forward): 接收目标序列的当前输入(input)和隐藏状态(hidden)作为输入。首先将输入通过嵌入层和dropout层,然后通过GRU层。最后,使用全连接层将GRU的输出转换为预测,并返回预测和更新后的隐藏状态。
Seq2Seq 类
  • 初始化 (__init__): 接收Encoder和Decoder实例以及设备(device)作为参数。这些实例和设备将用于模型的训练和推理。
  • 前向传播 (forward): 接收源序列(src)和目标序列(trg)作为输入,以及一个可选的教师强制比率(teacher_forcing_ratio)。首先,通过Encoder处理源序列以获取初始隐藏状态。然后,使用目标序列的第一个元素(通常是开始标记)作为Decoder的初始输入。在接下来的时间步中,Decoder根据当前输入和隐藏状态生成输出。根据教师强制比率,Decoder的下一个输入可以是目标序列的实际下一个元素(教师强制)或当前时间步的预测(非教师强制)。最后,返回所有时间步的预测输出。
注意事项
  • teacher_forcing_ratio用于在训练过程中平衡教师强制和非教师强制的比例。教师强制有助于模型更快地学习,因为它总是提供正确的下一个输入;然而,非教师强制有助于模型学习在测试时如何自己生成序列。
  • 模型的输出outputs是一个三维张量,其中包含了每个时间步每个样本在每个词汇上的预测概率。

五、主函数

# 新增术语词典加载部分
def load_terminology_dictionary(dict_file):terminology = {}with open(dict_file, 'r', encoding='utf-8') as f:for line in f:en_term, ch_term = line.strip().split('\t')terminology[en_term] = ch_termreturn terminologydef train(model, iterator, optimizer, criterion, clip):model.train()epoch_loss = 0for i, (src, trg) in enumerate(iterator):src, trg = src.to(device), trg.to(device)optimizer.zero_grad()output = model(src, trg)output_dim = output.shape[-1]output = output[:, 1:].contiguous().view(-1, output_dim)trg = trg[:, 1:].contiguous().view(-1)loss = criterion(output, trg)loss.backward()torch.nn.utils.clip_grad_norm_(model.parameters(), clip)optimizer.step()epoch_loss += loss.item()return epoch_loss / len(iterator)

这段代码包含两个主要的函数,用于处理术语词典的加载和模型训练的流程。下面是对这两个函数的详细解释:

1. load_terminology_dictionary(dict_file)

这个函数用于加载一个术语词典文件,并将文件中的内容转换为一个Python字典。这个字典的键(key)是英文术语,值(value)是对应的中文术语。

  • 参数:

    • dict_file: 术语词典文件的路径,该文件每行包含一个英文术语和一个中文术语,两者之间用制表符(\t)分隔。
  • 过程:

    1. 初始化一个空字典terminology来存储术语对。
    2. 使用with open(...)语句以只读模式('r')和UTF-8编码打开术语词典文件。这样做可以确保文件正确关闭,即使在读取文件时发生异常也是如此。
    3. 遍历文件的每一行,使用strip()方法去除每行末尾的换行符等空白字符,然后使用split('\t')方法将每行按制表符分割成英文术语和中文术语。
    4. 将英文术语作为键,中文术语作为值,存入terminology字典中。
    5. 遍历完成后,返回terminology字典。
2. train(model, iterator, optimizer, criterion, clip)

这个函数定义了模型训练的一个完整周期(epoch)的流程。它接收一个模型、一个数据迭代器、一个优化器、一个损失函数和一个梯度裁剪值作为参数。

  • 参数:

    • model: 待训练的模型。
    • iterator: 数据迭代器,用于遍历训练数据。
    • optimizer: 优化器,用于更新模型的参数以最小化损失函数。
    • criterion: 损失函数,用于评估模型预测和真实标签之间的差异。
    • clip: 梯度裁剪的阈值,用于防止梯度爆炸。
  • 过程:

    1. 将模型设置为训练模式(model.train())。
    2. 初始化epoch_loss为0,用于记录整个训练周期的总损失。
    3. 遍历迭代器中的每一批数据(src, trg),其中src是源语言数据,trg是目标语言数据。
    4. 将源数据和目标数据移动到指定的设备(如GPU)上。
    5. 清零优化器的梯度。
    6. 通过模型进行前向传播,得到预测结果output
    7. 由于模型通常输出的是整个序列的预测(包括起始标记),而损失计算通常不包括起始标记,因此需要调整outputtrg的形状,以排除起始标记。
    8. 计算损失值loss
    9. 通过反向传播计算梯度。
    10. 使用梯度裁剪来防止梯度爆炸。
    11. 更新模型的参数。
    12. 累加当前批次的损失值到epoch_loss
    13. 遍历完成后,计算并返回整个训练周期的平均损失值。
# 主函数
if __name__ == '__main__':start_time = time.time()  # 开始计时device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')#terminology = load_terminology_dictionary('../dataset/en-zh.dic')terminology = load_terminology_dictionary('../dataset/en-zh.dic')# 加载数据dataset = TranslationDataset('../dataset/train.txt',terminology = terminology)# 选择数据集的前N个样本进行训练N = 1000  #int(len(dataset) * 1)  # 或者你可以设置为数据集大小的一定比例,如 int(len(dataset) * 0.1)subset_indices = list(range(N))subset_dataset = Subset(dataset, subset_indices)train_loader = DataLoader(subset_dataset, batch_size=32, shuffle=True, collate_fn=collate_fn)# 定义模型参数INPUT_DIM = len(dataset.en_vocab)OUTPUT_DIM = len(dataset.zh_vocab)ENC_EMB_DIM = 256DEC_EMB_DIM = 256HID_DIM = 512N_LAYERS = 2ENC_DROPOUT = 0.5DEC_DROPOUT = 0.5# 初始化模型enc = Encoder(INPUT_DIM, ENC_EMB_DIM, HID_DIM, N_LAYERS, ENC_DROPOUT)dec = Decoder(OUTPUT_DIM, DEC_EMB_DIM, HID_DIM, N_LAYERS, DEC_DROPOUT)model = Seq2Seq(enc, dec, device).to(device)# 定义优化器和损失函数optimizer = optim.Adam(model.parameters())criterion = nn.CrossEntropyLoss(ignore_index=dataset.zh_word2idx['<pad>'])# 训练模型N_EPOCHS = 10CLIP = 1for epoch in range(N_EPOCHS):train_loss = train(model, train_loader, optimizer, criterion, CLIP)print(f'Epoch: {epoch+1:02} | Train Loss: {train_loss:.3f}')# 在训练循环结束后保存模型torch.save(model.state_dict(), './translation_model_GRU.pth')end_time = time.time()  # 结束计时# 计算并打印运行时间elapsed_time_minute = (end_time - start_time)/60print(f"Total running time: {elapsed_time_minute:.2f} minutes")

在这里插入图片描述
下面是对代码主要部分的详细解释:

  1. 环境设置与设备选择

    • 使用torch.device来检查CUDA是否可用,并据此选择使用GPU还是CPU进行模型训练。
  2. 术语词典加载

    • 调用load_terminology_dictionary函数加载一个术语词典文件(如en-zh.dic),该文件包含英文术语及其对应的中文翻译。加载了术语词典到terminology变量中。
  3. 数据加载与预处理

    • 使用TranslationDataset类(加载训练数据集(如train.txt),并传入术语词典。
    • 从数据集中选择前N个样本(这里是1000个)进行训练,通过SubsetDataLoader进行批量处理和打乱数据。
  4. 模型参数定义

    • 根据数据集的词汇表大小等设置模型的输入维度、输出维度、嵌入维度、隐藏层维度、层数及dropout率等参数。
  5. 模型初始化

    • 分别初始化编码器(Encoder)和解码器(Decoder),然后将它们组合成Seq2Seq模型,并将模型移至选定的设备上(GPU或CPU)。
  6. 优化器和损失函数

    • 使用Adam优化器来优化模型参数。
    • 使用交叉熵损失函数(忽略填充索引)来计算预测和真实标签之间的差异。
  7. 模型训练

    • 通过一个训练循环,进行多个epoch的训练。在每个epoch中,调用train函数来训练模型。
    • 使用梯度裁剪(CLIP)来防止梯度爆炸。
    • 打印每个epoch的训练损失。
  8. 模型保存

    • 在所有epoch完成后,保存模型的参数到文件中(如translation_model_GRU.pth)。
  9. 运行时间计算

    • 计算并打印从程序开始到结束的总运行时间(以分钟为单位)。

六、验证集的模型评价和测试集的模型推理

见教程
https://datawhaler.feishu.cn/wiki/FVs2wAVN5iqHMqk5lW2ckfhAncb

相关文章:

【机器翻译】基于术语词典干预的机器翻译挑战赛

文章目录 一、赛题链接二、安装库1.spacy2.torch_text 三、数据预处理赛题数据类定义 TranslationDataset批量处理函数 collate_fn 四、编码器和解码器Encoder 类Decoder 类Seq2Seq 类注意事项 五、主函数1. load_terminology_dictionary(dict_file)2. train(model, iterator, …...

推荐系统:从协同过滤到深度学习

目录 一、协同过滤&#xff08;Collaborative Filtering, CF&#xff09;1. 基于用户的协同过滤2. 基于物品的协同过滤 二、深度学习在推荐系统中的应用1. 深度学习模型的优势2. 深度学习在推荐系统中的应用实例 三、总结与展望 推荐系统是现代信息处理和传播中不可或缺的技术&…...

记录些Spring+题集(1)

接口防刷机制 接口被刷指的是同一接口被频繁调用&#xff0c;可能是由于以下原因导致&#xff1a; 恶意攻击&#xff1a;攻击者利用自动化脚本或工具对接口进行大量请求&#xff0c;以消耗系统资源、拖慢系统响应速度或达到其他恶意目的。误操作或程序错误&#xff1a;某些情…...

SpringBoot 解决 getSession().getAttribute() 在负载均衡环境下无法获取session的问题

在Spring Boot中&#xff0c;使用getSession().getAttribute()方法时遇到在负载均衡环境下无法正确获取session属性的问题&#xff0c;通常是由于session属性存储在单个服务器的内存中&#xff0c;而负载均衡会导致用户的请求被分配到不同的服务器上&#xff0c;因此无法找到在…...

Jmeter常用组件及执行顺序

一 常用组件 1.线程组 Thread Group 线程组是一系列线程的集合&#xff0c;每一个线程代表着一个正在使用应用程序的用户。在 jmeter 中&#xff0c;每个线程意味着模拟一个真实用户向服务器发起请求。 在 jmeter 中&#xff0c;线程组组件运行用户设置线程数量、初始化方式等…...

PTrade常见问题系列10

get_ashares获取list为空。 get_Ashares函数目前都是向行情服务器进行获取的 如果请求数过多&#xff0c;应答返回偶现为空现象&#xff0c; 后续版本内进行优化从服务器缓存内取&#xff0c;需求单号&#xff1a;202303213922&#xff0c;于PTradeQT1.0V202202.01.023内发布…...

数据结构(4.4)——求next数组

next数组的作用:当模式串的第j个字符失配时&#xff0c;从模式串的第next[j]的继续往后匹配 求模式串的next数组(手算) next[1] 任何模式串都一样&#xff0c;第一个字符不匹配时&#xff0c;只能匹配下一个子串&#xff0c;因此&#xff0c;往后&#xff0c;next[1]都无脑写…...

《mysql篇》--JDBC编程

JDBC是什么 JDBC就是Java DataBase Connectivity的缩写&#xff0c;翻译过来就很好理解了&#xff0c;就是java连接数据库。所以顾名思义&#xff0c;JDBC就是一种用于执行SQL语句的JavaApl&#xff0c;是Java中的数据库连接规范。为了可以方便的用Java连接各种数据库&#xff…...

android studio 怎么下载 buildTool

在Android Studio中下载Build Tools&#xff0c;通常可以通过Android Studio内置的SDK Manager来完成。以下是详细的步骤&#xff1a; 一、通过Android Studio的SDK Manager下载Build Tools 启动Android Studio&#xff1a;首先&#xff0c;确保你已经安装了Android Studio&am…...

copy 和 mutableCopy 有点乱

字符串的拷贝操作 对 string literal (字符串字面量) 执行 copy 要打印指针指向对象的地址和指针本身的地址&#xff0c;可以使用 %p 格式符来输出指针地址。以下代码&#xff0c;展示了 originalString 和 copiedString 的指针地址和指向对象的地址&#xff1a; NSString *…...

sqlalchemy通过查询参数生成query

sqlalchemy通过查询参数生成query 在SQLAlchemy中,可以使用查询参数来动态生成查询。这通常通过使用.filter()方法和Python的比较运算符来实现。以下是一个简单的示例,展示如何使用查询参数生成查询: 假设我们有一个名为User的模型(表),它具有id、username和email字段。…...

【JavaScript 算法】二分查找:快速定位目标元素

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、算法原理二、算法实现三、应用场景四、优化与扩展五、总结 二分查找&#xff08;Binary Search&#xff09;是一种高效的查找算法&#xff0c;适用于在有序数组中快速定位目标元素。相比于线性查找&#xff0c;二分查找…...

论文研读:ViT-V-Net—用于无监督3D医学图像配准的Vision Transformer

目录 摘要 介绍 方法 VIT-V-Net体系结构 损失函数 图像相似性度量 变形场正则化 结果与讨论 摘要 在过去的十年里&#xff0c;卷积神经网络(ConvNets)在各种医学成像应用中占据了主导地位并取得了最先进的性能。然而&#xff0c;由于缺乏对图像中远程空间关系的理解&a…...

C++入门到进阶(图文详解,持续更新中)

C入门到进阶&#xff08;图文详解&#xff0c;持续更新中&#xff09; 详解C入门知识到进阶&#xff0c;配合图观看易于理解记录 文章目录 目录 C入门到进阶&#xff08;图文详解&#xff0c;持续更新中&#xff09; 文章目录 前言 一、数据 &#xff08;一&#xff09;数据类…...

【React Hooks原理 - useRef】

概述 在Function Component项目中当我们需要操作dom的时候&#xff0c;第一时间想到的就是使用useRef这个Hook来绑定dom。但是这个仅仅是使用这个Hook而已&#xff0c;为了更好的学习React Hooks内部实现原理&#xff0c;知其所以然。所以本文根据源码从useRef的基础使用场景一…...

MVC之 IHttpModule管道模型《二》

》》》注意&#xff1a;在http请求的处理过程中&#xff0c;只能调用一个HttpHandler&#xff0c;但可以调用多个HttpModule。 HTTP Modules ASP.NET请求处理过程是基于管道模型的&#xff0c;这个管道模型是由多个HttpModule和HttpHandler组成&#xff0c;当请求到达HttpMod…...

2025上海纺织助剂展会+上海织物整理剂展

2025上海纺织助剂展会上海织物整理剂展 2025第十二届中国&#xff08;上海&#xff09;纺织助剂及织物整理剂展览会 时间: 2025年4月23-25日 地点:上海跨国采购会展中心&#xff08;光复西路2739号&#xff09; 展会简介&#xff1a; 2025第12届中国&#xff08;上海&#…...

中科亿海微亮相慕尼黑上海电子展

7月8-10日&#xff0c;备受瞩目的全球电子行业盛会“慕尼黑上海电子展”以空前规模启幕&#xff0c;汇聚了超过1600家参展企业&#xff0c;涵盖了从终端产品制造商到元器件供应商、组装/系统供应商、EMS、ODM/OEM、材料供应商及生产设备供应商的完整产业链。中科亿海微电子科技…...

Spring boot 2.0 升级到 3.3.1 的相关问题 (一)

文章目录 Spring boot 2.0 升级到 3.3.1 的相关问题 &#xff08;一&#xff09;拦截器Interceptor的变动问题介绍解决方案 WebMvcConfigurerAdapter 自定义Mvc配置问题介绍解决方案 Spring boot 2.0 升级到 3.3.1 的相关问题 &#xff08;一&#xff09; 拦截器Interceptor的…...

数据分析——Python网络爬虫(四){爬虫库的使用}

爬虫库 爬虫的步骤urllib库发送请求两种方法案例 爬虫的步骤 #mermaid-svg-h5azjtPInpsU2ZpP {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-h5azjtPInpsU2ZpP .error-icon{fill:#552222;}#mermaid-svg-h5azjtPInps…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

Frozen-Flask :将 Flask 应用“冻结”为静态文件

Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是&#xff1a;将一个 Flask Web 应用生成成纯静态 HTML 文件&#xff0c;从而可以部署到静态网站托管服务上&#xff0c;如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...

uniapp微信小程序视频实时流+pc端预览方案

方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度​WebSocket图片帧​定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐​RTMP推流​TRTC/即构SDK推流❌ 付费方案 &#xff08;部分有免费额度&#x…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战

“&#x1f916;手搓TuyaAI语音指令 &#x1f60d;秒变表情包大师&#xff0c;让萌系Otto机器人&#x1f525;玩出智能新花样&#xff01;开整&#xff01;” &#x1f916; Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制&#xff08;TuyaAI…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 &#x1f4dd; 在上一篇文章中&#xff0c;我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源&#xff0c;方便后续将资源打包到一个可执行文件中。 2.embed介绍 &#x1f3af; Go 1.16 引入了革命性的 embed 包&#xff0c;彻底改变了静态资源管理的…...

【堆垛策略】设计方法

堆垛策略的设计是积木堆叠系统的核心&#xff0c;直接影响堆叠的稳定性、效率和容错能力。以下是分层次的堆垛策略设计方法&#xff0c;涵盖基础规则、优化算法和容错机制&#xff1a; 1. 基础堆垛规则 (1) 物理稳定性优先 重心原则&#xff1a; 大尺寸/重量积木在下&#xf…...

第八部分:阶段项目 6:构建 React 前端应用

现在&#xff0c;是时候将你学到的 React 基础知识付诸实践&#xff0c;构建一个简单的前端应用来模拟与后端 API 的交互了。在这个阶段&#xff0c;你可以先使用模拟数据&#xff0c;或者如果你的后端 API&#xff08;阶段项目 5&#xff09;已经搭建好&#xff0c;可以直接连…...

算术操作符与类型转换:从基础到精通

目录 前言&#xff1a;从基础到实践——探索运算符与类型转换的奥秘 算术操作符超级详解 算术操作符&#xff1a;、-、*、/、% 赋值操作符&#xff1a;和复合赋值 单⽬操作符&#xff1a;、--、、- 前言&#xff1a;从基础到实践——探索运算符与类型转换的奥秘 在先前的文…...

C# winform教程(二)----checkbox

一、作用 提供一个用户选择或者不选的状态&#xff0c;这是一个可以多选的控件。 二、属性 其实功能大差不差&#xff0c;除了特殊的几个外&#xff0c;与button基本相同&#xff0c;所有说几个独有的 checkbox属性 名称内容含义appearance控件外观可以变成按钮形状checkali…...