【LLM】DeepSpeed分布式训练框架

news2024/9/30 5:33:40

文章目录

  • 一、DeepSpeed介绍
    • 1. 分布式背景介绍
    • 2. deepspeed介绍
  • 二、deepspeed+transformer代码实战
    • 1. 预处理和Json文件
    • 2. 训练代码
  • 三、deepspeed加速Bloom lora微调
    • 1. 配置文件
    • 2. 训练代码
  • Reference

一、DeepSpeed介绍

1. 分布式背景介绍

  • 分布式计算环境中,主节点负责协调其他节点和进程的工作
  • pytorch官方提供的分布式训练工具Accelerate只支持nvlink,而T4,3090这类显卡是PIX ,检测方式:nvidia-smi topo -m;deepspeed支持更大规模的模型训练
  • 混合精度训练
  • ZeRO可以减少内存占用,优化大模型训练,将模型参数分成了三个部分:Optimizer States、Gradient 和 Model Parameter。在使用 ZeRO 进行分布式训练时,可以选择 ZeRO-Offload 和 ZeRO-Stage3 等不同的优化技术。

2. deepspeed介绍

  • 在 DeepSpeed 中,可以通过在配置文件中设置 “bf16.enabled”: true 来启用 BF16 混合精度训练,减少占用内存。
    • 混合精度训练是指在训练过程中同时使用FP16(半精度浮点数)和FP32(单精度浮点数)两种精度的技术。
  • deepspeed可以根据具体情况选择合适的通信库,例如在 CPU 集群上进行分布式训练,可以选择 mpi 和 gloo;如果是在 GPU 上进行分布式训练,可以选择 nccl。
    • mpi 是一种跨节点通信库,常用于 CPU 集群上的分布式训练;
    • gloo 是一种高性能的分布式训练框架,支持 CPU 和 GPU 上的分布式训练;
    • nccl 是 NVIDIA 提供的 GPU 专用通信库,被广泛应用于 GPU 上的分布式训练。
  • DeepSpeed的核心技术:
    • Zero(Zero Redundancy Optimizer,3D优化与卸载):在deepspeed中通过zero_optimization.stage=0/1/2/3 设置,卸载通过zero_optimization.offload_optimizer.device设置
  • DeepSpeed的推理优化技术:
    • Deep fusion:如下图,红色虚线框是以该单位为优化Kernel,对应的数字是优化的效率倍数
    • Inference-customized GeMM

在这里插入图片描述

二、deepspeed+transformer代码实战

1. 预处理和Json文件

  • 首先是利用huggingface的datasets.map对数据集的样本自定义操作;transformers可以通过trainer集成deepspeed功能,这种用法需要提供配置文件,如下面的deepspeed配置文件ds_config.json文件。关于这个config具体配置可参考文档。
  • 这里用的FLAN-T5模型;启动deepspeed:deepspeed --include=localhost:1,2 train.py,启动前两张显卡;注意使用ZeRO3需要有足够的内存
  • 如果不使用trianer来集成deepspeed,from_pretrained和 from_config这样的核心功能应该包含DeepSpeed中的重要部分,例如zero。初始化Zero的时候应该为stage3或者更高。参考文档。
{
  "bf16": {
    "enabled": "auto"
  },
  "optimizer": {
    "type": "AdamW",
    "params": {
      "lr": "auto",
      "betas": "auto",
      "eps": "auto",
      "weight_decay": "auto"
    }
  },
  "scheduler": {
    "type": "WarmupLR",
    "params": {
      "warmup_min_lr": "auto",
      "warmup_max_lr": "auto",
      "warmup_num_steps": "auto"
    }
  },
  "zero_optimization": {
    "stage": 3,
    "offload_optimizer": {
      "device": "cpu",
      "pin_memory": true
    },
    "offload_param": {
      "device": "cpu",
      "pin_memory": true
    },
    "overlap_comm": true,
    "contiguous_gradients": true,
    "sub_group_size": 1e9,
    "reduce_bucket_size": "auto",
    "stage3_prefetch_bucket_size": "auto",
    "stage3_param_persistence_threshold": "auto",
    "stage3_max_live_parameters": 1e9,
    "stage3_max_reuse_distance": 1e9,
    "stage3_gather_16bit_weights_on_model_save": false
  },
  "gradient_accumulation_steps": "auto",
  "gradient_clipping": "auto",
  "steps_per_print": 2000,
  "train_batch_size": "auto",
  "train_micro_batch_size_per_gpu": "auto",
  "wall_clock_breakdown": false
}

2. 训练代码

  • 数据:samsum数据集
  • 模型:google/flan-t5-xxl大模型
# !/usr/bin/python
# -*- coding: utf-8 -*-
"""
@Author    : guomiansheng
@Software  : Pycharm
@Contact   : 864934027@qq.com
@File      : deepspeed_test.py
"""
import nltk
import torch
import evaluate
import datasets
import numpy as np
from nltk.tokenize import sent_tokenize
from torch.utils.data import DataLoader
from torch.nn.utils.rnn import pad_sequence
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
from transformers import Seq2SeqTrainer, Seq2SeqTrainingArguments

nltk.download("punkt")

dataset_name = "samsum" # 数据集名称
model_name="google/flan-t5-xxl" # 模型名称
max_input_length = 512
max_gen_length = 128
output_dir = "checkpoints"
num_train_epochs = 5
learning_rate = 5e-5
deepspeed_config = "./ds_config.json" # deepspeed配置文件
per_device_train_batch_size=1 # batch size设置为1,因为太大导致OOM
per_device_eval_batch_size=1
gradient_accumulation_steps=2 # 由于单卡的batch size为1,为了扩展batch size,使用梯度累加

tokenizer = AutoTokenizer.from_pretrained(model_name)

# 加载数据
dataset = datasets.load_dataset(dataset_name)
print(dataset["train"][0])

# tokenize
def preprocess(examples):
    dialogues = ["summarize:" + dia for dia in examples["dialogue"]]
    # summaries = [summ for summ in examples["summary"]]
    model_inputs = tokenizer(dialogues, max_length=max_input_length, truncation=True)
    labels = tokenizer(text_target=examples["summary"], max_length=max_gen_length, truncation=True)
    model_inputs["labels"] = labels["input_ids"]
    return model_inputs

tokenized_dataset = dataset.map(preprocess, batched=True, remove_columns=["dialogue", "summary", "id"])
# print(tokenized_dataset["train"]["input_ids"][0]) # 打印结果


# 对batch进行padding
def collate_fn(features):
    batch_input_ids = [torch.LongTensor(feature["input_ids"]) for feature in features]
    batch_attention_mask = [torch.LongTensor(feature["attention_mask"]) for feature in features]
    batch_labels = [torch.LongTensor(feature["labels"]) for feature in features]

    batch_input_ids = pad_sequence(batch_input_ids, batch_first=True, padding_value=tokenizer.pad_token_id)
    batch_attention_mask = pad_sequence(batch_attention_mask, batch_first=True, padding_value=0)
    batch_labels = pad_sequence(batch_labels, batch_first=True, padding_value=-100)

    return {
        "input_ids": batch_input_ids,
        "attention_mask": batch_attention_mask,
        "labels": batch_labels
    }
# 用于测试的代码
# dataloader = DataLoader(tokenized_dataset["test"], shuffle=False, batch_size=4, collate_fn=collate_fn)
# batch = next(iter(dataloader))
# print(batch)


# 加载模型
model = AutoModelForSeq2SeqLM.from_pretrained(model_name)
# 用于测试的代码
# dataloader = DataLoader(tokenized_dataset["test"], shuffle=False, batch_size=4, collate_fn=collate_fn)
# batch = next(iter(dataloader))
# output = model(**batch)
# print(output)


# 定义评估函数
metric = evaluate.load("rouge")

def compute_metrics(eval_preds):
    preds, labels = eval_preds
    if isinstance(preds, tuple):
        preds = preds[0]
    decoded_preds = tokenizer.batch_decode(preds, skip_special_tokens=True)
    labels = np.where(labels != -100, labels, tokenizer.pad_token_id)
    decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True)
    decoded_preds = ["\n".join(sent_tokenize(pred.strip())) for pred in decoded_preds]
    decoded_labels = ["\n".join(sent_tokenize(label.strip())) for label in decoded_labels]
    result = metric.compute(predictions=decoded_preds, references=decoded_labels, use_stemmer=True)
    result = {k: round(v * 100, 4) for k, v in result.items()}
    prediction_lens = [np.count_nonzero(pred != tokenizer.pad_token_id) for pred in preds]
    result["gen_len"] = np.mean(prediction_lens)
    return result


# 设置训练参数
training_args = Seq2SeqTrainingArguments(
    output_dir=output_dir,
    per_device_train_batch_size=per_device_train_batch_size,
    per_device_eval_batch_size=per_device_eval_batch_size,
    gradient_accumulation_steps=gradient_accumulation_steps,
    eval_accumulation_steps=1, # 防止评估时导致OOM
    predict_with_generate=True,
    fp16=False,
    learning_rate=learning_rate,
    num_train_epochs=num_train_epochs,
    # logging & evaluation strategies
    logging_dir="logs",
    logging_strategy="steps",
    logging_steps=50, # 每50个step打印一次log
    evaluation_strategy="steps",
    eval_steps=500, # 每500个step进行一次评估
    save_steps=500,
    save_total_limit=2,
    load_best_model_at_end=True,
    deepspeed=deepspeed_config, # deepspeed配置文件的位置
    report_to="all"
)


# 模型训练
trainer = Seq2SeqTrainer(
    model=model,
    args=training_args,
    train_dataset=tokenized_dataset["train"],
    eval_dataset=tokenized_dataset["validation"],
    data_collator=collate_fn,
    compute_metrics=compute_metrics,
)

trainer.train()
# 打印验证集上的结果
print(trainer.evaluate(tokenized_dataset["validation"]))
# 打印测试集上的结果
print(trainer.evaluate(tokenized_dataset["test"]))
# 保存最优模型
trainer.save_model("best")

加速训练方法:量化工具包bitsandbytes、deepspeed(先读torch.distributed和ColossalAI在搞)、llama.cpp量化模型

三、deepspeed加速Bloom lora微调

1. 配置文件

{
  "train_micro_batch_size_per_gpu": "auto",
  "gradient_accumulation_steps": "auto",
  "steps_per_print": 50,
  "gradient_clipping": 1.0,
  "zero_optimization": {
    "stage": 2,
    "offload_optimizer": {
            "device": "cpu"
    },
    "contiguous_gradients": true,
    "overlap_comm": true
  },
  "zero_allow_untested_optimizer": true,
  "fp16": {
    "enabled": true,
    "loss_scale": 0,
    "loss_scale_window": 1000,
    "hysteresis": 2,
    "min_loss_scale": 1
  },
  "optimizer": {
    "type": "Adam",
    "params": {
      "lr": "auto",
      "betas": "auto",
      "eps": "auto",
      "weight_decay": "auto"
    }
  },
  "activation_checkpointing": {
    "partition_activations": true,
    "contiguous_memory_optimization": true
  },
  "wall_clock_breakdown": false
}

2. 训练代码

  • 数据:使用BELLE提供的100万条指令微调数据
  • 模型:bloomz-7b1-mt模型
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@Author : andy
@Date   : 2023/7/10 10:07
@Contact: 864934027@qq.com 
@File   : bloom_lora.py 
"""
import os
import torch
import random
import datasets
import numpy as np
from tqdm import tqdm
from typing import Dict
from torch.utils.data import DataLoader
from transformers import (
    AutoModelForCausalLM,
    AutoTokenizer,
    DataCollatorForSeq2Seq,
    TrainingArguments,
    Trainer
)
from peft import (
    LoraConfig,
    TaskType,
    get_peft_model,
    get_peft_model_state_dict,
    set_peft_model_state_dict
)

def set_random_seed(seed):
    if seed is not None and seed > 0:
        random.seed(seed)
        np.random.seed(seed)
        torch.manual_seed(seed)
        torch.random.manual_seed(seed)
        torch.cuda.manual_seed(seed)
        torch.cuda.manual_seed_all(seed)
        torch.backends.cudnn.deterministic = True

set_random_seed(1234)

# 1. 设置参数
# LoRA参数
LORA_R = 8
LORA_ALPHA = 32
LORA_DROPOUT = 0.1
# 训练参数
EPOCHS=3
LEARNING_RATE=5e-5
OUTPUT_DIR="./checkpoints"
BATCH_SIZE=4 # 2
GRADIENT_ACCUMULATION_STEPS=3
# 其他参数
MODEL_PATH = "bigscience/bloomz-7b1-mt"
DATA_PATH = "./data/belle_open_source_1M.train.json"
MAX_LENGTH = 512
PATTERN = "{}\n{}"
DS_CONFIG = "ds_zero2_config.json"
tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH) # 加载tokenizer
# 加载数据
dataset = datasets.load_dataset("json", data_files=DATA_PATH)
# print(dataset["train"][0])


# 2. tokenize
def tokenize(text: str, add_eos_token=True):
    result = tokenizer(
        text,
        truncation=True,
        max_length=MAX_LENGTH,
        padding=False,
        return_tensors=None)
    # 判断是否要添加eos_token
    if (result["input_ids"][-1] != tokenizer.eos_token_id
        and len(result["input_ids"]) < MAX_LENGTH
        and add_eos_token):
        result["input_ids"].append(tokenizer.eos_token_id)
        result["attention_mask"].append(1)
    result["labels"] = result["input_ids"].copy()
    return result


def preprocess(example: Dict, train_on_inputs: bool = False):
    prompt = example["input"]
    response = example["target"]
    text = PATTERN.format(prompt, response)
    tokenized_inp = tokenize(text)
    # 若train_on_inputs为False,则将label中与input相关的token替换为-100
    if not train_on_inputs:
        tokenized_prompt = tokenize(prompt,add_eos_token=False)
        prompt_tokens_len = len(tokenized_prompt["input_ids"])
        tokenized_inp["labels"] = [-100]*prompt_tokens_len + tokenized_inp["labels"][prompt_tokens_len:]
    return tokenized_inp


train_data = dataset["train"].shuffle().map(preprocess, remove_columns=["id", "input", "target"])
print(train_data[0])

# pad_to_multiple_of=8表示padding的长度是8的倍数
collate_fn = DataCollatorForSeq2Seq(tokenizer, pad_to_multiple_of=8, return_tensors="pt", padding=True)

# 2. 加载模型
evice_map = {"": int(os.environ.get("LOCAL_RANK") or 0)}
# device_map指定模型加载的GPU;troch_dtype=torch.float16表示半精度加载模型
model = AutoModelForCausalLM.from_pretrained(MODEL_PATH, torch_dtype=torch.float16, device_map=device_map)


# 3. LoRA相关
lora_config = LoraConfig(
    task_type=TaskType.CAUSAL_LM,
    inference_mode=False,
    r=LORA_R, # LoRA中低秩近似的秩
    lora_alpha=LORA_ALPHA, # 见上文中的低秩矩阵缩放超参数
    lora_dropout=LORA_DROPOUT, # LoRA层的dropout
)
# 转换模型
model = get_peft_model(model, lora_config)
model.config.use_cache = False
old_state_dict = model.state_dict
model.state_dict = (
    lambda self, *_, **__: get_peft_model_state_dict(self, old_state_dict())
).__get__(model, type(model))
# 打印模型中的可训练参数
model.print_trainable_parameters()


# 4. 训练参数
args = TrainingArguments(
    output_dir=OUTPUT_DIR, # checkpoint的存储目录
    per_device_train_batch_size=BATCH_SIZE, # 单设备上的batch size
    gradient_accumulation_steps=GRADIENT_ACCUMULATION_STEPS, # 梯度累加的step数
    warmup_steps=100,
    num_train_epochs=EPOCHS,
    learning_rate=LEARNING_RATE,
    fp16=True, # 使用混合精度训练
    logging_steps=50,
    evaluation_strategy="no", # 不进行评估
    save_strategy="steps",
    save_steps=2000, # 保存checkpoint的step数
    save_total_limit=5, # 最多保存5个checkpoint
    deepspeed=DS_CONFIG
)


# 5. 模型训练
trainer = Trainer(
    model=model,
    train_dataset=train_data,
    eval_dataset=None,
    args=args,
    data_collator=collate_fn
)
trainer.train()
model.save_pretrained("best_model")

deepspeed --include=localhost:0,1,2,3 train.py启动。

Reference

[1] 大模型训练之框架篇
[2] NLP大规模语言模型微调实践:DeepSpeed+Transformers实现简单快捷上手百亿参数模型微调
[3] 直白图解GPT2模型Self Attention注意力机制:实现过程及MTB语言模型核心代码阅读总结
[4] 语言模型分布式并行训练基础知识必备:Collective通信操作及Pytorch示例
[5] 大规模语言模型训练关键技术:混合精度训练、显存分析与DeepSpeed分布式训练实践
[6] 大模型训练中的张量并行工具必读:Megatron-DeepSpeed工具代码mpu详解与实践
[7] https://github.com/microsoft/DeepSpeed
[8] deepspeed官方教程:https://www.deepspeed.ai/getting-started/
[9] DeepSpeed 通过系统优化加速大模型推理
[10] DeepSpeed: Accelerating large-scale model inference and training via system optimizations and compression. Microsoft Research Blog
[11] 图解大模型训练之:流水线并行(Pipeline Parallelism),以Gpipe为例
[12] 深度学习attention机制中的Q,K,V分别是从哪来的
[13] 《ZeRO: Memory Optimizations Toward Training Trillion Parameter Models》
[14] 【分布式训练】DeepSpeed:AllReduce与ZeRO-DP
[15] How to generate text: using different decoding methods for language generation with Transformers
[16] Transformer模型详解(图解最完整版).初识CV
[17] 大(语言)模型推理原理及加速.金
[18] Transformers DeepSpeed官方文档解读
[19] 英伟达Megatron-LM:Megatron-LM: Training Multi-Billion Parameter Language Models Using Model Parallelism
[20] https://github.com/NVIDIA/Megatron-LM

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

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

相关文章

进程间通信方法——命名管道

命名管道 匿名管道应用的一个限制就是只能在具有共同祖先&#xff08;具有亲缘关系&#xff09;的进程间通信。如果我们想在不相关的进程之间交换数据&#xff0c;可以使用FIFO文件来做这项工作&#xff0c;它经常被称为命名管道。&#xff08;命名管道是有文件名的&#xff0…

Vs窗口布局移动窗口vs直接卡死2

(1条消息) Vs窗口布局移动窗口vs直接卡死_vs拖动窗口布局卡死_Ma_Hong_Kai的博客-CSDN博客 由于莫名其妙的更新导致又卡死了&#xff0c;导致最近一年多无法拖动vs的框挺折磨 前一段时间看到一个有意思的命令 搞了搞了 可以拖动了&#xff08;目测应该是微软自己发现这个问…

【图像识别】openCV基础知识

图像处理基础 一、使用OpenCV前要准备的工作1.先导入需要用到的库2.自定义&#xff0c;图片展示函数 二、开始学习常用函数1.生成随机整数①. 函数说明②.代码a. 二维灰度图b. 三维彩色图 ③.代码现象a. 二维灰度图b. 三维彩色图 2.通道的分离与合并①先导入一张图片② 将其RGB…

多元回归预测 | Matlab基于麻雀算法(SSA)优化高斯过程回归(SSA-GPR)的数据回归预测,matlab代码,多变量输入模型

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 多元回归预测 | Matlab基于麻雀算法(SSA)优化高斯过程回归(SSA-GPR)的数据回归预测,matlab代码,多变量输入模型 评价指标包括:MAE、RMSE和R2等,代码质量极高,方便学习和替换数据。要求2018版本及以上。 部分源…

合宙Air001震撼来袭!

Air001芯片特性 采用ARM 32位的M0内核&#xff0c;主频可达48MHz&#xff1b; 4K RAM32K Flash&#xff1b; 1.7&#xff5e;5.5V超宽范围供电&#xff0c;USB和电池都能直接供电&#xff1b; 内嵌可配4/8/16/22.12/24MHz的RC振荡器&#xff0c;无需外挂晶振就能48MHz运行…

你连存活到JDK8中著名的Bug都不知道,你怎么敢跳槽涨薪的?

在笔者研究 JDK 源码时&#xff0c;注意到在CopyOnWriteArrayList 和ArrayList 的构造器中都出现了如下 bug 字样 6260652 其实代表的JDK bug 列表中的编号 http://bugs.java.com/bugdatabase/view_bug.do?bug_id6260652 http://bugs.java.com/bugdatabase/view_bug.do?bug…

GBU808-ASEMI薄体整流桥GBU808

编辑&#xff1a;ll GBU808-ASEMI薄体整流桥GBU808 型号&#xff1a;GBU808 品牌&#xff1a;ASEMI 芯片个数&#xff1a;4 封装&#xff1a;GBU-4 恢复时间&#xff1a;≥2000ns 工作温度&#xff1a;-50C~150C 浪涌电流&#xff1a;200A 正向电流&#xff1a;8A 反…

Golang 命令源码文件

Go 语言标准库中专门用于接收和解析命令参数。这个代码包的名字叫 flag。 函数 flag.StringVar 接受 4 个参数。 第 1 个参数是用于存储该命令参数值的地址&#xff0c;具体到这里就是在前面声明的变量 name 的地 址了&#xff0c;由表达式 &name 表示。 第 2 个参数是为…

高级运维开发工程师带你处理linux木马(挖矿病毒)实战例子

一、事态描述 centos7测试服务器&#xff0c;突然密码登不上去了&#xff0c;然后CPU占100%。已经猜到&#xff0c;登录密码过于简单&#xff0c;密码被破解挂马了。大概率是CPU挖矿病毒。 二、重置centos7登录root密码 步骤1 启动Linux Centos7系统&#xff0c;当出现如下画…

JavaWeb JSP 内置对象

1.JSP 内置对象 在jsp自动转换成的java文件的service方法中&#xff0c;我们可以看到这九个内置对象&#xff1a; 具体如下&#xff1a; request&#xff08;HttpServletRequest&#xff09;&#xff1a;代表客户端的HTTP请求。通过该对象&#xff0c;可以获取请求参数、请求…

时序区间预测 | Matlab基于高斯过程回归(GPR)时间序列区间预测,matlab代码,单变量输入模型

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 时间序列预测 | Matlab基于高斯过程回归(GPR)时间序列区间预测,matlab代码,单变量输入模型 评价指标包括:MAE、MBE和R2等,代码质量极高,方便学习和替换数据。要求2018版本及以上。 部分源码 %% 清空环境变量…

【Spring Boot丨(十 )】日志

上文讲了 类型安全配置属性 本篇来讲一下 Spring boot 的默认日志相关 Logging &#x1f351; 概述&#x1f34f; 日志格式&#x1f350; 控制台输出&#x1f965; 文件输出&#x1f95d; 文件轮换&#x1f352; 文件级别 &#x1f351; 概述 Spring Boot在所有内部日志中使用C…

支持裸耳3D空间音频?7月12日发布,荣耀Magic系列喜迎新成员

荣耀在7月12日将举办全场景新品发布会&#xff0c;其中将正式推出荣耀新款平板 MagicPad。 荣耀官方今天上午开始预热荣耀平板 MagicPad&#xff0c;官方海报文案表明这将成为首款支持裸耳3D空间音频的平板&#xff0c;引领行业潮流。 “空间音频技术”并不陌生&#xff0c;简…

git merge 与 git rebase 的区别

文章目录 前言1、使用 merge2、使用 rebase总结 前言 首先我们要清楚&#xff0c;git merge 与 git rebase 处理的问题是一样的&#xff0c;这两个命令都用于把一个分支的变更整合进另一个分支&#xff0c;只不过他们达成同样目的的方式不同。 刚开始&#xff0c;已经存在一…

Jmeter 做接口自动化测试的这些技巧你都掌握了吗

前言 JMeter 最初被设计用于 Web 应用测试&#xff0c;但后来扩展到了其他测试领域&#xff0c;可用于测试静态和动态资源&#xff0c;如静态文件、Java 小服务程序、CGI 脚本、Java 对象、数据库和 FTP 服务器等等。JMeter 可对服务器、网络或对象模拟巨大的负载&#xff0c;…

DBF文件的解析介绍

1.基本介绍 DBF是Digital Beam Forming的缩写&#xff0c;“.dbf”文件扩展名代表据库处理系统所产生的数据库文件&#xff0c;起初意为保存数据的文件是一个简单的表&#xff0c;可以使用ASCII字符集添加、修改、删除或打印数据&#xff0c;随着产品变得越来越流行&#xff0…

SIN65 DM蓝牙5.2双模热插拔PCB

键盘使用说明索引&#xff08;均为出厂默认值&#xff09; 软件支持&#xff08;驱动的详细使用帮助&#xff09;一些常见问题解答&#xff08;FAQ&#xff09;首次使用步骤蓝牙配对规则&#xff08;重要&#xff09;蓝牙和USB切换键盘默认层默认触发层0的FN键配置的功能默认功…

idea连接远程MySQL数据库

填写URL&#xff0c;以mysql为例 格式 jdbc:mysql://ip地址:端口号/数据库名 jdbc:mysql://127.0.0.1:3306/ldentification _Information

在 Kubernetes 上体验 EMQX 5.0 的 MQTT over QUIC 特性

引言 作为全球领先的开源分布式 MQTT Broker&#xff0c;EMQX 在 5.0 版本中引入了 MQTT over QUIC&#xff0c;将 MQTT 协议的优势与 QUIC 的特性相结合。通过充分利用 QUIC 协议低连接开销和多路复用的特点&#xff0c;MQTT over QUIC 为弱网络环境和不规则网络中的用户提供…

lib/db 标准单元分类(Standard Cells in ASIC Design)、Track定义

文章目录 drain curruntThreshold Voltage (VTH)channel lengthtrack&#xff08;Classification according to the Density&#xff09;Standard Cell Layout drain currunt Drain current (Id) uCox(W/L)[(Vgs-Vth)Vds-(1/2)Vds^2] Coxepision/tox#饱和电流计算公式&#xf…