GPT2从放弃到入门(四)

引言

体验地址:https://huggingface.co/spaces/greyfoss/gpt2-chatbot

上篇文章我们通过Gradio作为前端轻松地连接到训练好的Chatbot,本文介绍如何分享你创建好的模型给你的朋友。

image-20240322110947010

当你训练好的模型推送到Huggingface Hub上后,其实还可以进一步部署给朋友使用的,见上图。

image-20240322111326152

点进去后,会看到可以通过Gradio部署我们的聊天机器人,选择配置时被FREE深深吸引住了,再定睛一看原来是CPU,但是免费的还是挺香。2C16G应该对于这个模型来说也够用了。

为了在CPU上有良好的体验,我们需要在部署时进行一些优化,下面主要介绍通过ONNX来部署。

ONNX

本节的内容参考了Pytorch和HuggingFace官方教程,见参考1和2。

Open Neural Network eXchange (ONNX) 是表示机器学习模型格式的一种开放标准,定义了一套公共的运算符和一种公共的文件格式,以在各种框架中表示深度学习模型,包括PyTorch和TensorFlow。当将模型导出为ONNX格式时,这些运算符被用于构建一个计算图(通常称为中间表示),表示数据在神经网络中的流动。torch.onnx模块提供了从本地PyTorch torch.nn.Module模型中捕获计算图并将其转换为ONNX图的API。

通过公开具有标准化运算符和数据类型的图形,ONNX使得在不同框架之间轻松切换变得很容易。例如,可以将在PyTorch中训练的模型导出为ONNX格式,然后在TensorFlow中导入(反之亦然)。

导出的模型可以被许多支持ONNX的运行时所使用,包括微软的ONNX Runtime。

需要确保Pytorch的版本是2.1.0及以上,需要安装的库是:

!pip install --upgrade onnx onnxscript onnxruntime

验证一下:

import torch
print(torch.__version__)import onnxscript
print(onnxscript.__version__)from onnxscript import opset18  import onnxruntime
print(onnxruntime.__version__)
2.2.1+cu121
0.1.0.dev20240315
1.17.1

导出Pytorch模型到ONNX

截至PyTorch 2.1版本,ONNX Exporter有两个版本。

torch.onnx.dynamo_export是最新的(仍处于beta阶段)导出器,基于TorchDynamo技术,自PyTorch 2.0版本。

torch.onnx.export基于TorchScript后端,自PyTorch 1.2.0版本。

本节我们会看到如何将Pytorch模型使用TorchDynamo导出成ONNX格式。

ONNX是一种灵活的开放标准格式,用于表示机器学习模型。标准化的机器学习表示使得这些模型可以在各种硬件平台和运行环境中执行,从大规模云计算超级计算机到资源受限的边缘设备,如网络浏览器和手机。

定义一个简单的图像分类器

import torch
import torch.nn as nn
import torch.nn.functional as Fclass MyModel(nn.Module):def __init__(self):super(MyModel, self).__init__()self.conv1 = nn.Conv2d(1, 6, 5)self.conv2 = nn.Conv2d(6, 16, 5)self.fc1 = nn.Linear(16 * 5 * 5, 120)self.fc2 = nn.Linear(120, 84)self.fc3 = nn.Linear(84, 10)def forward(self, x):x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))x = F.max_pool2d(F.relu(self.conv2(x)), 2)x = torch.flatten(x, 1)x = F.relu(self.fc1(x))x = F.relu(self.fc2(x))x = self.fc3(x)return x

导出成ONNX格式

我们已经定义了我们的模型,需要实例化它并创建一个随机的32x32输入。接下来,我们可以将模型导出为ONNX格式:

torch_model = MyModel()
torch_input = torch.randn(1, 1, 32, 32)
onnx_program = torch.onnx.dynamo_export(torch_model, torch_input)

可以看到,我们没有修改任何模型的代码,生成的ONNX模型以二进制protobuf文件的形式存储在torch.onnx.ONNXProgram中。

保存ONNX模型到文件中

我们可以进一步地使用以下代码将ONNX模型保存到磁盘上:

onnx_program.save("my_image_classifier.onnx")

这会在当前目录下保存这个文件。

我们可以使用以下代码将ONNX文件重新加载到内存中,并检查它的格式是否正确:

import onnx
onnx_model = onnx.load("my_image_classifier.onnx")
onnx.checker.check_model(onnx_model)

没报错说明没问题。

使用Netron可视化ONNX模型图

还可以使用Netron进行可视化。Netron可以安装在macOS、Linux或Windows计算机上,也可以直接在浏览器中运行。我们尝试使用Web版本,打开以下链接:https://netron.app/。

image-20240322115114941

打开链接后,我们可以点击Open Model...按钮加载刚才保存好的ONNX模型。

image-20240322115212403

使用ONNX运行时执行ONNX模型

我们转换成ONNX格式当然是想执行它。下面看如何使用ONNX Runtime执行ONNX模型。

ONNX标准并不支持PyTorch支持的所有数据结构和类型,因此在将输入传递给ONNX Runtime之前,我们需要将PyTorch输入适配为ONNX格式。在我们的示例中,输入恰好与原始的PyTorch模型相同,但在更复杂的模型中,输入可能比原始的PyTorch模型更多。

ONNX Runtime需要额外的步骤,这涉及将所有PyTorch张量转换为Numpy(在CPU上),并将它们封装到一个字典中,键是一个输入名称的字符串,值是Numpy张量。

现在,我们可以创建一个ONNX Runtime推理会话,使用处理后的输入执行ONNX模型,并获取输出。在本文中,ONNX Runtime在CPU上执行,但也可以在GPU上执行。

import onnxruntime
# torch_input = torch.randn(1, 1, 32, 32)
# 将PyTorch输入适配为ONNX格式
onnx_input = onnx_program.adapt_torch_inputs_to_onnx(torch_input)
print(f"Input length: {len(onnx_input)}")
print(f"Sample input: {onnx_input}")ort_session = onnxruntime.InferenceSession("./my_image_classifier.onnx", providers=['CPUExecutionProvider']) # CPU# 转换为Numpy
def to_numpy(tensor):return tensor.detach().cpu().numpy() if tensor.requires_grad else tensor.cpu().numpy()onnxruntime_input = {k.name: to_numpy(v) for k, v in zip(ort_session.get_inputs(), onnx_input)}onnxruntime_outputs = ort_session.run(None, onnxruntime_input)
Input length: 1
Sample input: (tensor([[[[-0.7220, -0.5403,  2.4361,  ..., -0.7169, -1.8715,  1.0804],[ 1.4021, -1.4058,  2.1243,  ..., -0.3179,  1.0338, -0.7995],[-0.4521, -0.7909, -0.5292,  ..., -1.4944, -0.5231,  0.1697],...,[-0.0386,  0.5920, -1.5468,  ...,  0.3635, -1.0620, -1.6128],[ 0.5296, -1.3540, -0.3576,  ..., -0.6198,  2.6026, -0.3067],[-1.7563,  2.0526, -0.4164,  ..., -0.2538,  0.0301, -0.1198]]]]),)

比较Pytorch和ONNX运行时的结果

torch_outputs = torch_model(torch_input)
torch_outputs = onnx_program.adapt_torch_outputs_to_onnx(torch_outputs)assert len(torch_outputs) == len(onnxruntime_outputs)
for torch_output, onnxruntime_output in zip(torch_outputs, onnxruntime_outputs):torch.testing.assert_close(torch_output, torch.tensor(onnxruntime_output))print("PyTorch and ONNX Runtime output matched!")
print(f"Output length: {len(onnxruntime_outputs)}")
print(f"Sample output: {onnxruntime_outputs}")
PyTorch and ONNX Runtime output matched!
Output length: 1
Sample output: [array([[ 0.07159428, -0.05138571,  0.04295354, -0.12783284,  0.06733166,0.09275323, -0.00052077,  0.04322926, -0.00434714, -0.10994226]],dtype=float32)]

导出🤗 Transformers模型到ONNX

在生产环境中部署🤗 Transformers模型通常需要将模型导出为序列化格式,以便在专用运行时和硬件上加载和执行。

🤗 Optimum是Transformers的扩展,通过其exporters模块,可以将模型从PyTorch导出为ONNX序列化格式。🤗 Optimum还提供了一组性能优化工具,以在目标硬件上以最大效率训练和运行模型。

本节演示了如何使用🤗 Optimum将🤗 Transformers模型导出为ONNX格式。

一旦导出成ONNX格式,模型可以:

  • 通过类似图量化和量化等技术为推理进行量化;
  • 通过ORTModelForXXX类运行在ONNX Runtime中,和🤗 Transformers中的AutoModel有同样的API;
  • 运行在量化推理pipelines中, 和🤗 Transformers中的 pipeline() 有同样的API;

🤗 Optimum通过利用配置对象来支持ONNX导出。

有两种方法可以将🤗 Transformers模型导出为ONNX格式,下面我们将展示这两种方法:

  • 通过🤗 Optimum的CLI导出。
  • 通过🤗 Optimum和optimum.onnxruntime导出。

通过🤗 Optimum的CLI导出

首先需要安装额外的依赖:

pip install optimum[exporters]

下面的命令将把🤗 Hub的检查点distilbert/distilbert-base-uncased-distilled-squad导出为ONNX格式:

!optimum-cli export onnx --model distilbert/distilbert-base-uncased-distilled-squad distilbert_base_uncased_squad_onnx/

到当前目录的distilbert_base_uncased_squad_onnx文件下。

Framework not specified. Using pt to export the model.
config.json: 100% 451/451 [00:00<00:00, 1.93MB/s]
model.safetensors: 100% 265M/265M [00:01<00:00, 166MB/s]
Automatic task detection to question-answering.
tokenizer_config.json: 100% 28.0/28.0 [00:00<00:00, 78.8kB/s]
vocab.txt: 100% 232k/232k [00:00<00:00, 3.53MB/s]
tokenizer.json: 100% 466k/466k [00:00<00:00, 2.40MB/s]
Using the export variant default. Available variants are:- default: The default ONNX variant.
Using framework PyTorch: 2.2.1+cu121
/usr/local/lib/python3.10/dist-packages/transformers/models/distilbert/modeling_distilbert.py:246: TracerWarning: torch.tensor results are registered as constants in the trace. You can safely ignore this warning if you use this function to create tensors out of constant variables that would be the same every time you call this function. In any other case, this might cause the trace to be incorrect.mask, torch.tensor(torch.finfo(scores.dtype).min)
Post-processing the exported models...
Weight deduplication check in the ONNX export requires accelerate. Please install accelerate to run it.
Validating ONNX model distilbert_base_uncased_squad_onnx/model.onnx...-[✓] ONNX model output names match reference model (start_logits, end_logits)- Validating ONNX Model output "start_logits":-[✓] (2, 16) matches (2, 16)-[✓] all values close (atol: 0.0001)- Validating ONNX Model output "end_logits":-[✓] (2, 16) matches (2, 16)-[✓] all values close (atol: 0.0001)
The ONNX export succeeded and the exported model was saved at: distilbert_base_uncased_squad_onnx

上面的例子展示了如何从🤗 Hub中导出检查点,如果你想导出本地模型到ONNX,首先确保你把模型权重和分词器文件保存到同一个目录(local_path)。当使用CLI时,将local_path作为模型参数传递,并提供--task参数:

optimum-cli export onnx --model local_path --task question-answering distilbert_base_uncased_squad_onnx/

得到的model.onnx文件可以被运行在很多支持ONNX的加速器中,比如可以使用ONNX运行时加载并运行模型:

from transformers import AutoTokenizer
from optimum.onnxruntime import ORTModelForQuestionAnsweringtokenizer = AutoTokenizer.from_pretrained("distilbert_base_uncased_squad_onnx")
model = ORTModelForQuestionAnswering.from_pretrained("distilbert_base_uncased_squad_onnx")
inputs = tokenizer("What am I using?", "Using DistilBERT with ONNX Runtime!", return_tensors="pt")
outputs = model(**inputs)
print(outputs)
QuestionAnsweringModelOutput(loss=None, start_logits=tensor([[-4.7652, -1.0452, -7.0409, -4.6864, -4.0277, -6.2021, -4.9473,  2.6287,7.6111, -1.2488, -2.0551, -0.9350,  4.9758, -0.7707,  2.1493, -2.0703,-4.3232, -4.9472]]), end_logits=tensor([[ 0.4382, -1.6502, -6.3654, -6.0661, -4.1482, -3.5779, -0.0774, -3.6168,-1.8750, -2.8910,  6.2582,  0.5425, -3.7699,  3.8232, -1.5073,  6.2311,3.3604, -0.0772]]), hidden_states=None, attentions=None)

通过🤗 Optimum和optimum.onnxruntime导出

除了使用CLI,还可以使用代码导出🤗 Transformers模型:

from optimum.onnxruntime import ORTModelForSequenceClassification
from transformers import AutoTokenizermodel_checkpoint = "bert-base-chinese"
save_directory = "onnx/"# 加载模型并导出成ONNX
ort_model = ORTModelForSequenceClassification.from_pretrained(model_checkpoint, export=True)
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)# 保存ONNX的模型和分词器
ort_model.save_pretrained(save_directory)
tokenizer.save_pretrained(save_directory)

使用🤗 Transformers生成内容

在上篇文章中我们自己实现了generate方法,仅为了学习知识,实际中我们应该使用官方的generate方法:

def response(user_input,chat_history,top_k,top_p,temperature,repetition_penalty,no_repeat_ngram_size,):history = list(itertools.chain(*chat_history))history.append(user_input)prompt = format(history)input_ids = tokenizer.encode(prompt,return_tensors="pt",add_special_tokens=False,).to(device)prompt_length = input_ids.shape[1]beam_output = model.generate(input_ids,pad_token_id=tokenizer.pad_token_id,max_new_tokens=255,num_beams=3,top_k=top_k,top_p=top_p,no_repeat_ngram_size=no_repeat_ngram_size,temperature=temperature,repetition_penalty=repetition_penalty,early_stopping=True,do_sample=True,)# 不然会重复输出prompt内容output = beam_output[0][prompt_length:]tokens = tokenizer.convert_ids_to_tokens(output)for i, token in enumerate(tokens[:-1]):if is_english_word(token) and is_english_word(tokens[i + 1]):tokens[i] = token + " "text = "".join(tokens).replace("##", "").strip()

在HF Spaces部署Gradio项目

本节我们看如何上传训练好的模型到HF Spaces上,并以ONNX的格式通过Gradio进行演示。

首先要将训练好的模型上传到HF上,当然你得有一个HF账号,并且已经登录:

model.push_to_hub("gpt2-chatbot-chinese")
tokenizer.push_to_hub("gpt2-chatbot-chinese")

这里会默认上传到你账户下的gpt2-chatbot-chinese项目中,这个名称可以随意更改。

然后可以通过 https://huggingface.co/spaces/onnx/export 自动将🤗 Transformers模型导出成ONNX格式,并上传到ONNX model zero中。但是很遗憾没成功:

image-20240322152846357

一直在排队。但是我发现HF Spaces中的应用是以Docker容器运行的,我们可以编写任何代码,包括将模型加载成ONNX!

核心代码是:

from optimum.onnxruntime import ORTModelForCausalLMmodel = ORTModelForCausalLM.from_pretrained("greyfoss/gpt2-chatbot-chinese", export=True)

结束了!

创建Space时它会有一个代码仓库,我们可以修改app.py文件以及增加requirements.txt文件。除了没有Dockerfile其他和Docker项目用起来差不多。

requirements.txt(么有仔细看,应该写多了):

torch
numpy==1.25.2
pandas==2.1.0
tqdm==4.66.1
transformers==4.30.2
datasets==2.14.4
sentencepiece==0.1.99
huggingface_hub
optimum[exporters]
onnxruntime
accelerate

app.py改成:

from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
from collections import defaultdict
import gradio as gr
from optimum.onnxruntime import ORTModelForCausalLMimport itertools
import regex as re
import logginguser_token = "<User>"
eos_token = "<EOS>"
bos_token = "<BOS>"
bot_token = "<Assistant>"logger = logging.getLogger()
handler = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.INFO)max_context_length = 750def format(history):prompt = bos_tokenfor idx, txt in enumerate(history):if idx % 2 == 0:prompt += f"{user_token}{txt}{eos_token}"else:prompt += f"{bot_token}{txt}"prompt += bot_tokenreturn promptdef remove_spaces_between_chinese(text):rex = r"(?<![a-zA-Z]{2})(?<=[a-zA-Z]{1})[ ]+(?=[a-zA-Z] |.$)|(?<=\p{Han}) +"return re.sub(rex, "", text, 0, re.MULTILINE | re.UNICODE)def gradio(model, tokenizer):def response(user_input,chat_history,top_k,top_p,temperature,repetition_penalty,no_repeat_ngram_size,):history = list(itertools.chain(*chat_history))history.append(user_input)prompt = format(history)input_ids = tokenizer.encode(prompt,return_tensors="pt",add_special_tokens=False,)[:, -max_context_length:]prompt_length = input_ids.shape[1]beam_output = model.generate(input_ids,pad_token_id=tokenizer.pad_token_id,max_new_tokens=250,num_beams=1, # with cputop_k=top_k,top_p=top_p,no_repeat_ngram_size=no_repeat_ngram_size,temperature=temperature,repetition_penalty=repetition_penalty,early_stopping=True,do_sample=True)output = beam_output[0][prompt_length:]generated = remove_spaces_between_chinese(tokenizer.decode(output, skip_special_tokens=True, clean_up_tokenization_spaces=True))logger.info(prompt+generated)return generatedbot = gr.Chatbot(show_copy_button=True, show_share_button=True, height="2000")with gr.Blocks() as demo:gr.Markdown("GPT2 chatbot | Powered by nlp-greyfoss")with gr.Accordion("Parameters in generation", open=False):with gr.Row():top_k = gr.Slider(2.0,100.0,label="top_k",step=1,value=50,info="Limit the number of candidate tokens considered during decoding.",)top_p = gr.Slider(0.1,1.0,label="top_p",value=0.9,info="Control the diversity of the output by selecting tokens with cumulative probabilities up to the Top-P threshold.",)temperature = gr.Slider(0.1,2.0,label="temperature",value=0.9,info="Control the randomness of the generated text. A higher temperature results in more diverse and unpredictable outputs, while a lower temperature produces more conservative and coherent text.",)repetition_penalty = gr.Slider(0.1,2.0,label="repetition_penalty",value=1.2,info="Discourage the model from generating repetitive tokens in a sequence.",)no_repeat_ngram_size = gr.Slider(0,100,label="no_repeat_ngram_size",step=1,value=5,info="Prevent the model from generating sequences of n consecutive tokens that have already been generated in the context. ",)gr.ChatInterface(response,chatbot=bot,additional_inputs=[top_k,top_p,temperature,repetition_penalty,no_repeat_ngram_size,],retry_btn = "🔄 Regenerate",undo_btn = "↩️ Remove last turn",clear_btn = "➕ New conversation",examples=[["写一篇介绍人工智能的文章。", 30, 0.9, 0.95, 1.2, 5],["给我讲一个笑话。", 50, 0.8, 0.9, 1.2, 6],["Can you describe spring in English?", 50, 0.9, 1.0, 1, 5]])demo.queue().launch()tokenizer = AutoTokenizer.from_pretrained("greyfoss/gpt2-chatbot-chinese")model = ORTModelForCausalLM.from_pretrained("greyfoss/gpt2-chatbot-chinese", export=True)gradio(model, tokenizer)

完整代码如上所示,同时还增加了打印print(prompt)的代码进行调试。在该过程中发现前面的format写错了( ⚠️以下是有Bug的代码):

def format(history):prompt = train_args.bos_tokenfor idx, txt in enumerate(history):if idx % 2 == 0:prompt += f"{train_args.user_token}{txt}{train_args.eos_token}"else:prompt += f"{train_args.bos_token}{txt}{train_args.eos_token}"prompt += train_args.bot_tokenreturn prompt

真的不仔细看发现不了:

def format(history):prompt = train_args.bos_tokenfor idx, txt in enumerate(history):if idx % 2 == 0:prompt += f"{train_args.user_token}{txt}{train_args.eos_token}"else:prompt += f"{train_args.bot_token}{txt}"prompt += train_args.bot_tokenreturn prompt

有两处修改,都是在else内:

  • bos_token改成bot_token,这个影响非常大,比如你好啊的回复会有问题;
  • 移除了eos_token,使用🤗 Transformers的generate方法会自己增加<EOS>标记;

image-20240322165037470

这次发送你好啊这种没有问题了。

这个Space在一定时间(两天内)没人访问后会进入休眠,毕竟是免费的。要等它激活,查看日志可以看到如下内容:

Framework not specified. Using pt to export the model.
Using the export variant default. Available variants are:- default: The default ONNX variant.
Using framework PyTorch: 2.2.1+cu121
Overriding 1 configuration item(s)- use_cache -> True
/usr/local/lib/python3.10/site-packages/transformers/models/gpt2/modeling_gpt2.py:810: TracerWarning: Converting a tensor to a Python boolean might cause the trace to be incorrect. We can't record the data flow of Python values, so this value will be treated as a constant in the future. This means that the trace might not generalize to other inputs!if batch_size <= 0:
Post-processing the exported models...
Deduplicating shared (tied) weights...
Found different candidate ONNX initializers (likely duplicate) for the tied weights:lm_head.weight: {'onnx::MatMul_3809'}transformer.wte.weight: {'transformer.wte.weight'}
Removing duplicate initializer onnx::MatMul_3809...
Running on local URL:  http://0.0.0.0:7860To create a public link, set `share=True` in `launch()`.
<BOS><User>你好啊<EOS><Assistant>
<BOS><User>你好啊<EOS><Assistant>你好,有什么我可以帮助你的吗?<EOS><User>你好<EOS><Assistant>

当看到Running on local URL: http://0.0.0.0:7860才表示启动成功。但是你们可能看不到日志,不过前几次有问题多试几次就好了。

<BOS><User>你好啊<EOS><Assistant>
<BOS><User>你好啊<EOS><Assistant>你好,有什么我可以帮助你的吗?<EOS><User>你好<EOS><Assistant>

是格式化后的输入,这次没问题了。下面我们正常聊个天,看下效果如何。

image-20240326222418888

首先我们可以调整生成参数。

image-20240326223042426

这里通过代码写死了最多生成250个token,因此如果发现内容不够可以尝试输入继续让模型继续输出。这个例子展示了它可以继续进行创作。

然后可以点击New conversation进行新的会话:

image-20240326224747592

最后,欢迎大家去体验: https://huggingface.co/spaces/greyfoss/gpt2-chatbot

参考

  1. https://pytorch.org/tutorials/beginner/onnx/intro_onnx.html

  2. https://huggingface.co/docs/transformers/en/serialization

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

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

相关文章

大数据Hadoop生态圈体系视频课程

课程介绍 熟悉大数据概念&#xff0c;明确大数据职位都有哪些&#xff1b;熟悉Hadoop生态系统都有哪些组件&#xff1b;学习Hadoop生态环境架构&#xff0c;了解分布式集群优势&#xff1b;动手操作Hbase的例子&#xff0c;成功部署伪分布式集群&#xff1b;动手Hadoop安装和配…

codeforces div4 Double Strings

#include<iostream> #include<algorithm> #include<cstring> #include<map> using namespace std; int T, n; string s[900005]; map<string, int>mm;//存放每一个字符串是否出现过 int main() {cin >> T;while (T--){mm.clear();//每次清…

服务端测试开发必备技能:Mock测试

什么是mock测试 Mock 测试就是在测试活动中&#xff0c;对于某些不容易构造或者不容易获取的数据/场景&#xff0c;用一个Mock对象来创建以便测试的测试方法。 Mock测试常见场景 无法控制第三方系统接口的返回&#xff0c;返回的数据不满足要求依赖的接口还未开发完成&#…

linux 离线安装 dotnet tool

1. 在官网下载对应的nuget包,比如: dotnet-dump NuGet Gallery | dotnet-dump 3.1.57502 注意文件名称: dotnet-dump.3.1.57502.nupkg 我犯了一个错误,下载比较慢,然后通过迅雷来下载,结果没有后缀名称. 2. 然后拷贝到linux上,比如: 拷贝到dp文件夹下, 在dp文件夹上级执行命…

mfc140.dll丢失的解决方法,快速修复win10系统dll问题

在Windows 10操作系统环境下&#xff0c;如果发现系统中关键的动态链接库文件mfc140.dll丢失&#xff0c;可能会引发一系列运行问题。mfc140.dll是Microsoft Foundation Class Library&#xff08;微软基础类库&#xff09;的重要组成部分&#xff0c;对于许多基于该库开发的应…

代码随想录算法训练营第三十五天|860. 柠檬水找零,406. 根据身高重建队列,452. 用最少数量的箭引爆气球

860. 柠檬水找零 题目 在柠檬水摊上&#xff0c;每一杯柠檬水的售价为 5 美元。顾客排队购买你的产品&#xff0c;&#xff08;按账单 bills 支付的顺序&#xff09;一次购买一杯。 每位顾客只买一杯柠檬水&#xff0c;然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾…

【干货】无源滤波器设计讲解,工作原理+设计步骤

今天给大家分享的是&#xff1a;无源模拟滤波器针对很多入门小白不懂滤波器设计&#xff0c;一些老工程师上班很多年有的也不懂得总结知识点&#xff0c;以及想学习不知道怎么系统学习的这一类人群&#xff0c;前方知识点来袭&#xff0c;请君放心食用~ 在信号处理领域&#x…

java的一些内部小知识,类与对象的关系

目录 1. java2. 类与对象的关系 1. java test.java ---- javac --> Test.class ---- java-----> 内存 ----> cpu 源文件 二进制代码 所有正在运行的软件都在内存中有自己的内存空间 jvm —>运行java程序的&#xff0c;java虚拟机 main(); // 内部调用run()run(i…

苍穹外卖项目笔记

软件开发流程 需求分析&#xff1a;说明书和原型 设计&#xff1a;UI&#xff0c;数据库&#xff0c;接口设计 编码&#xff1a;项目代码&#xff0c;单元测试 测试&#xff1a;测试用例&#xff0c;测试报告 上线运维&#xff1a;软件环境安装&#xff0c;配置 软件环境…

Mybatis中条件传入多个参数时,如何处理

entity&#xff1a; Data AllArgsConstructor NoArgsConstructor public class User {private Integer id;private String username;private String password;private String phone;private String address; }dao接口&#xff1a; public interface UserDAO {List<User>…

基于vue+element+springboot+uniapp开发的智慧城管源码,java智慧城市管理综合执法系统源码

智慧城管源码&#xff0c;智慧执法&#xff0c;数字化城市管理综合执法系统源码 智慧城管系统充分利用物联网、云计算、信息融合、网络通讯、数据分析与挖掘等技术&#xff0c;对城市管理进行全方位覆盖。它通过建立城市综合管理平台&#xff0c;将城市的信息和管理资源有机结合…

错误 LNK1104 无法打开文件“mfc140.lib”

如图&#xff0c;编译一个别人已有的项目&#xff0c;我的编译报错为&#xff1a; 但是我所有文件夹全局搜索了一下&#xff0c;这个文件是存在的。但是当前项目访问不到。 更改方法&#xff1a;项目->属性->配置属性->VC目录->库目录 全局搜索找到mfc140.lib的…

【LeetCode 算法专题突破】定长滑动窗口

文章目录 前言[1456. 定长子串中元音的最大数目](https://leetcode.cn/problems/maximum-number-of-vowels-in-a-substring-of-given-length/)题目描述&#xff1a;难度分1263代码与解题思路代码复盘 [2269. 找到一个数字的 K 美丽值](https://leetcode.cn/problems/find-the-k…

NAT---网络地址转换技术

Network Address Translation 1、起源&#xff1a;ip地址不够用 2、作用&#xff1a;让私网地址映射成公网地址&#xff0c;进而访问网络。 3、私网Ip地址的范围&#xff1a; A类&#xff1a;10.0.0.0-10.255.255.255 B类&#xff1a;172.16.0.0-172.31.255.255 C类&…

码垛机与人工搬运:效率与安全性的比较分析

在现代包装行业中&#xff0c;泡沫箱因其轻便和保温特性被广泛用于商品的包装与运输。随着自动化技术的不断发展&#xff0c;码垛机成为提升泡沫箱生产效率、降低劳动强度的关键技术。本文旨在比较码垛机与人工码垛在泡沫箱生产中的优势&#xff0c;并探讨自动化码垛的未来发展…

Springboot快速整合bootstrap-table使用,接口对接

这个表格加持还是不错了&#xff0c;自带了全局搜索&#xff0c;分页&#xff0c;数据导出&#xff0c;卡片视图&#xff0c;等&#xff0c;本次整合添加了数据添加弹窗和编辑数据回显弹窗&#xff0c;附完整页面代码&#xff0c;只需要拿过来替换自己实际的接口即可。 效果图 …

鸿蒙实战开发-如何通过拖动滑块调节应用内字体大小

介绍 本篇Codelab将介绍如何使用基础组件Slider&#xff0c;通过拖动滑块调节应用内字体大小。要求完成以下功能&#xff1a; 实现两个页面的UX&#xff1a;主页面和字体大小调节页面。拖动滑块改变字体大小系数&#xff0c;列表页和调节页面字体大小同步变化。往右拖动滑块字…

ppp验证实验

实际操作图 1&#xff0c;IP划分分配 [r1]interface Serial 4/0/0 [r1-Serial4/0/0]ip add 192.168.1.1 24 [r2]interface Serial 4/0/0 [r2-Serial4/0/0]ip address 192.168.1.2 24 [r2]int Mp-group 0/0/0 [r2-Mp-group0/0/0]ip add 192.168.2.1 24 [r3]int Mp-group 0/…

Xcode Launching “XXX“ is taking longer than expected

文章目录 1.问题2.如何进入iOS DeviceSupport目录3.解决方法4.参考博客 1.问题 LLDB is likely reading from device memory to resolve symbols 2.如何进入iOS DeviceSupport目录 3.解决方法 进入iOS DeviceSupport目录&#xff0c;删除该真机对应的架构文件&#xff08;比如…

QT作业day3

1、使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数 将登录按钮使用qt5版本的连接到自定义的槽函数中&#xff0c;在槽函数中判断ui界面上输入的账号是否为"admin"&#xff0c;密码是…