paddle——站在巨人肩膀上及背刺二三事

 飞桨AI Studio - 人工智能学习与实训社区     

飞桨PaddlePaddle-源于产业实践的开源深度学习平台

        先抛结论,对于想要快速了解某一领域有哪些比较适合落地的算法的从业人员来说,是一个很好的参考系统。从中可以知道从哪些模型里选型、如何轻量化、如何加速、一些非常细节的FAQ。但是,这个框架维护上还是存在欠缺,比如很多人反馈的教程调不通,盘子铺得较大但维护没跟上;遇到一些报错的时候,相比pytorch这种大量使用的框架,能查到的解决方案较少。                 我遇到的三个坑是:

1、P100开发环境效果验证OK——UWSGI+NGINX搭好项目后——多进程报错,勉强单进程跑跑,网上的说法是paddle有多进程的问题,需要把import放到多进程里,但是试了一番没成功。

2、同一个镜像,相同的代码,换个服务器上测试环境V100直接卡死,没有报错提示,就是卡住了,后来倒腾了几天试版本,又是降低paddle版本,又是换显卡类型,终于搞定。这一点网上很多人也提到了,报错信息不完善。所以,如果是新手,并需要在短期内上线服务的场景,慎重。

3、cpu推理正常,即加参数use_gpu=False,但gpu推理乱码,这里需要基于box输出判断是识别乱码还是整个流程乱码了,如果box数量正常和cpu一致,那就是识别乱码,大概率是词典的问题。如果确定是gpu乱码,会比较麻烦,和显卡型号、驱动版本、cuda、paddle-paddle-gpu版本有关,可以搜索关键词(paddle gpu 乱码),遇到该问题的人也挺多,解决方法一般是各种升级降级,只能试出来,个人认为这属于paddle框架的兼容性问题。

        上面吐槽了一番,但值得肯定的是,paddle在轻量化及速度上还是不错的。

        如果后面的读者成功解决了UWSGI+NGINX多进程部署的问题,请分享一下你的经验。报错信息如下:

[Hint: 'cudaErrorInitializationError'. The API call failed because the CUDA driver and runtime could not be initialized. ] (at /paddle/paddle/phi/backends/gpu/cuda/cuda_info.cc:172)

一、paddleocr

1.1 简介

GitHub - PaddlePaddle/PaddleOCR: Awesome multilingual OCR toolkits based on PaddlePaddle (practical ultra lightweight OCR system, support 80+ languages recognition, provide data annotation and synthesis tools, support training and deployment among server, mobile, embedded and IoT devices)在README_ch.md里可以看到ppocr最新加入的一些算法 

FAQ(doc/doc_ch/FAQ.md)里可以看到一些常见的问题

1.2 ppocr支持的算法

查看tools/program.py。

注:pp会不断更新,最新最全的还是要看源码,这里只是示例说明

ssert alg in ['EAST', 'DB', 'SAST', 'Rosetta', 'CRNN', 'STARNet', 'RARE', 'SRN','CLS', 'PGNet', 'Distillation', 'NRTR', 'TableAttn', 'SAR', 'PSE','SEED', 'SDMGR', 'LayoutXLM', 'LayoutLM', 'LayoutLMv2', 'PREN', 'FCE','SVTR', 'ViTSTR', 'ABINet', 'DB++', 'TableMaster', 'SPIN', 'VisionLAN','Gestalt', 'SLANet', 'RobustScanner', 'CT', 'RFL', 'DRRG', 'CAN','Telescope']

检测:sast、psenet、db

识别:百度自研结合语义基于Transformer的srn、基于ctc的CRNN、StarNet和Rosetta,基于attention的RARE。80种语言

端到端识别:PGnet

Kie:sdmgr

sdmgr利用双模态信息(文本及坐标+视觉)进行图节点分类。图像特征通过UNet提取特征图,并通过ROI Pooling获取切片的图像特征。对每个字符进行one-hot编码,投影到低维空间,并输入Bi-LSTM获取文本特征。

特征融合尝试了三种方法(CONCAT、线性求和、克罗内克积),克罗内克积最优

sdmgr属于mmocr工作

GitHub - open-mmlab/mmocr at 4882c8a317cc0f59c96624ce14c8c10d05fa6dbc

原理:

带你读AI论文:SDMG-R结构化提取—无限版式小票场景应用 - 华为云开发者联盟 - 博客园

sdmgr_cc_moe的博客-CSDN博客

DocVQALayoutLM、LayoutLMv2,LayoutXLM, ser和re由LayoutXLM实现

语义实体识别SER

关系抽取RE:

Style-Text

    基于论文《Editing Text in the Wild》中的SRNet

PaddleOCR/data_synthesis.md at release/2.4 · PaddlePaddle/PaddleOCR · GitHub

其他数据合成工具

SynthText_Chinese_version,TextRecognitionDataGenerator、text_renderer

SynthText3D、UnrealText、StyleText

PP-Structure之版面分析: 文字、标题、图片、列表和表格5类,基于yolov2

PP-Structure之表格解析:基于RARE算法,后面又出了个SLANet

轻量化移动端部署:EasyEdge、Paddle-Lite

1.3一张图的OCR

    过程分为:文本检测——切子图,并根据长宽比旋转90度,主要是为了处理竖排文字(0、90度)——文本方向分类(0、180度)——文本识别。

检测:DBNet 

分类:每个切片的方向分类,在pp中将切片方向分类放在检测后面,而不是方向分类——检测——识别。这样做的好处有:1)可以处理竖排文字 2)支持对同一张图中多个不同文档图像的处理。缺陷1)实测经常会发生在第一步旋转90度就转错了 2)耗时比对整张图像进行方向分类慢一点。

        在paddleocr的方向分类模块中,不仅仅依赖模型的分类输出,还会参考softmax的值,当方向分类为180且置信度大于0.9时才会将图片进行旋转180度操作。如果定位时有上下行都切出来的现象,就容易造成置信度0.5左右的分类错误。猜想是因为模型不太确定这个几个字是上下结构或左右结构。

        而且我不理解,为什么模型判断方向这一步只做二分类,不做四分类。很多单字的定位最后因为方向搞错了,无法识别正确。

识别:CRNN

        pp做了很多速度和显存上的优化,其中动态宽度对速度的提升非常有效果,实测自己训练的大训练模型(基于Restnet,200M左右)修改动态宽度和其他一些点后和pp的速度也很接近了,考虑到字数和时间比,甚至更快一点。关于pp的轻量化,知乎有一篇很好的介绍:PaddleOCR为何这么轻?

        普通的图片走完ocr流程的时间在0.3s左右,如果文字较多,时间会相对增加。可以下载开源模型,然后根据场景更改一下调用流程、阈值、前处理后处理。

1.4 半自动标注工具PPOCRLabel

        要解析一些证件,自研和百度的都不能定位得特别好,想试一下半自动标注能不能偷懒一点。

        安装:过程参考PPOCRLable下的README即可,不再赘述,一种不行就换一种,我最后是通过python脚本运行成功的,报需要啥安装包就装啥,有安装包冲突就搜索一下,安装别人推荐的版本,包括什么“Class RunLoopModeTracker is implemented in both”报错闪退。内网环境下不了模型就手动操作,改改代码的download部分,加个if os.path.exists。

        平时都是labelme标,这个界面用起来有点别扭,为啥要这么搞呢?堪比单个脚踏板的汽车。包括:

1、图片后缀要是正常的图片后缀,不能没后缀

2、不接受指定文件夹下的循环嵌套文件夹,只能是对应文件夹下的图片

3、不能设置标签路径,和图片放一起了

4、多个文件的标签放到了一个标注文件中,如果我想把数据放在几个文件夹中标,就很难受

5、进入标注状态后不能esc,必须让我标注

6、自动标注后的标签是矩形,进行矩形标注会显示4个点,我想改成4点的标注都不知道从哪改,Label.txt里没有显式形状的说明。

7、有旋转90方向,但太隐蔽,要用3个jia4组成快捷键,不好用。

        这个工具目前最大价值在于半自动标注了,其他真的不咋好用。

1.5训练

        用自己的数据更新定位识别模型

1.5.1训练定位模型

python tools/train.py -x config/det/***/***.yml

      yml文件需指定:预训练模型路径pretrained_model、数据集图片路径data_dir、标签文件路径label_file_list。如果没有共享内存,在loadel中增加use_shared_memory: False。

        这里需要关注的是标签格式,paddle自定义了一个怪怪的标签文件格式,从yml中的label_file_list可以看出标签文件label.txt是个txt文件。每一行对应一张图片及其所有定位框的标签。定位和识别yml的dataset的name都为SimpleDataset,不同的是使用了不同的dataset的transforms。

        关注SimpleDataset、transformers中的DetLabelEncode,

# ppocr/data/simple_dataset.py
class SimpleDataSet(Dataset):...def get_ext_data(self):ext_data_num = 0for op in self.ops:if hasattr(op, 'ext_data_num'):ext_data_num = getattr(op, 'ext_data_num')breakload_data_ops = self.ops[:self.ext_op_transform_idx]ext_data = []while len(ext_data) < ext_data_num:file_idx = self.data_idx_order_list[np.random.randint(self.__len__())]data_line = self.data_lines[file_idx]data_line = data_line.decode('utf-8')#  self.delimiter = dataset_config.get('delimiter', '\t') 分割符是\t# 每行是一个标签substr = data_line.strip("\n").split(self.delimiter)file_name = substr[0]file_name = self._try_parse_filename_list(file_name)label = substr[1]img_path = os.path.join(self.data_dir, file_name)data = {'img_path': img_path, 'label': label}if not os.path.exists(img_path):continuewith open(data['img_path'], 'rb') as f:img = f.read()data['image'] = img# transform将 label 进行了转化,所以后面才有polysdata = transform(data, load_data_ops)if data is None:continueif 'polys' in data.keys():if data['polys'].shape[1] != 4:continueext_data.append(data)return ext_data
# ppocr/data/imaug/label_ops.pyclass DetLabelEncode(object):def __init__(self, **kwargs):passdef __call__(self, data):label = data['label']label = json.loads(label)nBox = len(label)boxes, txts, txt_tags = [], [], []for bno in range(0, nBox):box = label[bno]['points']   # 点坐标txt = label[bno]['transcription']   # 文本boxes.append(box)txts.append(txt)if txt in ['*', '###']:   # 这2种是要ignore的txt_tags.append(True)else:txt_tags.append(False)if len(boxes) == 0:return Noneboxes = self.expand_points_num(boxes)   # 不断复制最后一个box至最大点数一致boxes = np.array(boxes, dtype=np.float32)txt_tags = np.array(txt_tags, dtype=np.bool_)data['polys'] = boxesdata['texts'] = txtsdata['ignore_tags'] = txt_tagsreturn data

再参考labelme标注的json文件转为paddleOCR提供的标注文件格式_labelme标注文件转为 paddleocr训练文件格式_月夜竹清的博客-CSDN博客

可知,标签文件格式为

aaa.jpg    [{"transcription":"xxx","points":[[x0,y0],[x1,y1],[x2,y2],[x3,y3]],...}]

问题1: 在读取文件的时候老是报错"Expecting property name enclosed in double quotes",查了下说是因为json.loads必须是双引号,老改不对,在ppocr中查了一下,正确写法如下,原来[{},{}]这种数据也能json.dumps成字符串!

# ppocr/utils/gen_label.py
out_file.write(img_path+'\t'+json.dumps(label, ensure_ascii=False)+'\n')

问题2:自训练的模型转infer模型后效果不好,这么小的模型,这么大的数据,而且主要是图像中最后一个长切片不好,为什么呢?一开始怀疑是crop的问题,数据增强的时候是否容易把下面的切掉,实验固定crop(0,0,w,h)后还是不行,推翻了这个推测。后来怀疑是参数的问题,网上很多人自训练检测模型转inference模式后,效果不行,需要指定det_limit_side_len=736、det_limit_type='min',默认的参数和训练时eval的不一致。这个解决方案很行!效果差距巨大,为何paddleocr要这样!而且还很隐蔽不易发现。深入研究后,发现,开源模型指不指定这2个参数差距不大,甚至不一定是正效果(某个场景,v2指定是正效果,v3v4是负效果),但是自训练模型会影响很大,整体影响1%,某个字段影响6%。

        官方说法是训练时为了进行评估,resize到XXX,推理时为了速度又将长边限制在YYY。见以下FAQ。

https://github.com/PaddlePaddle/PaddleOCR/blob/dygraph/doc/doc_ch/detection.md#5-faq

        简单来说,原来默认infer时把输入默认为,最长边960(det_limit_side_len=960、det_limit_type='max'),但训练时默认又是最短边736(见DetResizeForTest类的默认处理方法)。

        如果不确定自己是否修改到位,可以分别试一下 tools/infer/predict_det.py和tools/infer_det.py的效果。以下2个函数都会生成可视化结果及box的text。

# 基于训练模型,加载checkpoint模型
python tools/infer_det.py -c config/*** -o Global.infer_img='xxx.jpg'# 基于转成的推理模型
python tools/infer/predict_det.py --miage_dir='xxx.jpg'  --det_model_dir="xxx" --det_limit_type=min --det_limit_side_len=736

训练检测模型,同样遭遇的人:

https://github.com/PaddlePaddle/PaddleOCR/issues/9116

https://github.com/PaddlePaddle/PaddleOCR/issues/2080

问题3:自训练的db模型,边框太贴字了,导致识别效果不好,尤其是第一个和最后一个字

这就要联系到db的原理,推理时自动扩大区域,查看yml中的PostProcess参数,里面有个unclip_ratio默认值1.5,增大该值可以扩大缩放程度,改成2.2还不错。

关于Paddle OCR检测器检测框偏小的解决方法_det_db_unclip_ratio_AI浩的博客-CSDN博客

问题4:训练v4的检测模型时,有cml、teacher、student3种yml文件,分别是什么意思?

cml是蒸馏后的小模型,约5M,用cml蒸馏方法训练,训出1个teacher2个student;teacher是用在server端的大模型,用dml方法训练,训出2个teacher,约110M;student我的理解是在小模型上finetine

v3开始引入了一堆互学习等的概念,具体参考https://zhuanlan.zhihu.com/p/511564666

大致概念如下

DML(Deep Mutual Learning):教师模型互学习策略、蒸馏策略。通过两个结构相同的模型互相学习,可以有效提升文本检测模型的精度。教师模型采用DML策略,同时训练2个Teacher出来
UDML(Unified-Deep Mutual Learning):联合互学习策略,。在PP-OCRv3中,针对两个不同的SVTR_LCNet和Attention结构,对他们之间的PP-LCNet的特征图、SVTR模块的输出和Attention模块的输出同时进行监督训练。
CML(Collaborative Mutual Learning) 协同互学习文本检测蒸馏策略,针对学生模型的训练方式,基于Teacher和2个student,同时训练2个Student出来

问题5:这么多花里胡哨的yml文件,那该如何训练呢?

先说结论,可以训练v2、v3,但训不了v4的det模型。

PP-OCRv3有官方训练教程,和教程稍微有点不同的是现在在模型已经有student模型了,不用从best_accuracy转出来

https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.6/doc/doc_ch/PP-OCRv3_det_train.md

自己瞎捣鼓v4 似乎训练过程有点问题,cml训练时PPLCNetNew找不到对应模型,改成PPLCNetv3报别的错,如下Question,也没有官方解决回复。student的训练下了配置文件中的预训练模型,又是找不到各种参数,私以为配置文件里的那个权重是不全的只有backbone没有neck和head,应该下载README.md里的文件,但是下不了没对应文件可下。teacher模型太大,不想用,没必要。

PPLCNetNew找不到對應模型 · Issue #10685 · PaddlePaddle/PaddleOCR · GitHub;

参考v3的finetune训练教程,尝试训练PP-OCRv4的检测模型,失败了,等官方吧。

a、首先从README.md中找到对应训练模型ch_PP-OCRv4_det_distill_train.tar,下载后提取Student参数。。

百度快修一修吧T_T

问题6:训练v4的student检测模型时,“The pretrained params backbone.xxx not in model”。

对应配置文件为ch_pp-ocrv4_det_student.yml,下载对应的预训练模型后训练,产生如题报错。

vim ppocr/utils/save_load.py 后发现待训练模型参数有905层,预训练模型参数只有836层,且还有5层不在待训练模型中。

强行训练后,缺失大量参数导致检测效果很不好。

这个人也有同样的问题在微调模型的时候,“ppocr WARNING: The pretrained params conv**** not in model”正常吗? · Issue #6684 · PaddlePaddle/PaddleOCR · GitHub

问题7:paddle中db如何调参

训练后,准召都在0.9附近,出现了很明显的漏检,而且有大切片的漏检。

db主要是调后处理参数,参数在配置文件yml的PostProcess中,除了上文unclip_ratio外,还有几个重要参数thresh=0.3、box_thresh=0.6、max_candidates=1000。查看DBPostProcess方法可知,thresh过滤了小于该值的map位置,box_thresh过滤了小于该得分的box、max_candidates限制了切片数量。打印中间过程后,我将box_thresh调小到了0.35。此外,在后处理类中,还限定了最小面积min_size=3

1.5.2训练识别模型

识别模型的标签文件比较简单,间隔符为\t,每一行为

aaa.jpg    text

除上述格式外,还有另一种格式用于处理相同标签的数据增强数据集,请参考如下链接。此外,该文章还提到在训练V3识别模型时“ 由于预训练模型提供的是蒸馏模型,需先将Student模型的参数提取出

”【官方】十分钟完成 PP-OCRv3 识别全流程实战_AI Studio的博客-CSDN博客

训练识别模型也可能遇到参数不对齐的问题,主要关注resize、字典

训练识别模型,同样遭遇的人:

https://github.com/PaddlePaddle/PaddleOCR/pull/2470

1.6 基于不同paddle的模型进行推理

想比较下v2、v3、v4在自己场景中的推理能力,同样的代码,v2推理有问题。经排查,推理老的模型需要指定ocr_version

经确认,v4>v3>v2

from paddleocr import PaddleOCR
import cv2ocr_engine = PaddleOCR(cls_model ='XXX_cls_infer',use_angel_cls=True,det_model_dir = 'XXX_det_infer',rec_model_dir='XXX_rec_infer',ocr_version="PP-OCRv2",# 检测模型重要参数det_limit_type="min",det_limit_side_len=736,)img_path='xxx.jpg'
res = ocr_engine.ocr(img=cv2.imread(img_path))

1.7 安装环境

        之所以在这里还要提一下paddle的安装,是因为,paddle安装总是常看常新,在不同环境下想要把paddlepaddle-gpu搭建起来,真是丰富多彩的奇妙之旅。

        首先要知道,paddlepaddle是cpu版本,paddlepaddle-gpu才即支持gpu又支持cpu。paddle框架比pytorch对cuda、cudnn更为敏感,换句话说,就是兼容性不好。所以一旦cuda不兼容,会有各种报错。

1.7.1 查看cuda版本

        这里可以分别查看nvidia-smi和nvcc -V显示的cuda版本,分别表示cuda的driver API和runtime API。目前我的安装都是基于nvcc -V显示的cuda版本,nvidia-smi尚未试验过(即尚未实验过没有单独安装cuda下,只有显卡驱动显示cuda的情况下安装gpu版本的paddle)。

【精选】cuda 的driver API 和 runtime API_driver api version: 12.2, runtime api version: 11._Be long的博客-CSDN博客

https://blog.csdn.net/weixin_44015965/article/details/122176244

1.7.2 方案一:基于nvcc-v 显示的cuda版本选择正确的paddlepaddle-gpu版本

这里习惯性地用pip进行安装,但是!pip显示的并不全,比较惨的时候恰好和你的cuda都不匹配。这时候需要自行下载whl进行安装,paddlepaddle-gpu==2.5.2.post117表示cuda版本为117,paddlepaddle-gpu版本为2.5.2

下载网址如下:

https://www.paddlepaddle.org.cn/whl/linux/mkl/avx/stable.html

以下官方教程还给了个 “包含 cuDNN 动态链接库的 PaddlePaddle”的下载地址,暂不知道具体含义

Linux 下的 PIP 安装-使用文档-PaddlePaddle深度学习平台

1.7.3 方案二:基于pip安装cuda驱动及paddle

    有时并没有单独安装的cuda及cudann,即nvcc -V无结果,/usr/local 也没cuda文件夹。实际上可以不单独安装cuda,pytorch安装时可以顺带安装cuda及cudann,paddle同理。不同的是paddle需要使用pip来安装cuda,而不是安装paddle时自带。在GPU服务器上安装步骤如下:

# 基于pip安装cuda及paddle
pip install nvidia-cuda-runtime-cu11
pip install nvidia-cublas-cu11
pip install nvidia-cuda-nvrtc-cu11
pip install nvidia-cudnn-cu11
pip install paddlepaddle-gpu=2.4.1.post112
# 软链接示例
ln -s /usr/local/lib/python3.7/site-packages/nvidia/cublas/lib/libcublas.so.11 /usr/local/lib/python3.7/site-packages/nvidia/cublas/lib/libcublas.so
# 动态链接库
export LD_LIBRARY_PATH =patha/lib:pathb/lib:pathc/lib

import paddle时,如提示缺失某个so文件,安装并添加到LD_LIBRARY_PATH 即可,例如提示缺失了libcudart.so.11.0,这个在cuda_runtime时会安装

1.7.4确认安装成功

import paddle
paddle.utils.run_check()

无需模型即可验证paddle是否安装成功,安装失败的表现包括:

  • 运行run_check提示cuda相关报错
  • 运行ocr模型识别文字乱码
  • 运行检测模型输出的box异常
  • segment错误
  • 程序卡死,需外部中断

1.8 超大尺寸图像推理

对于尺寸特别大的图,比如用户滑屏的截图,或者一些扫描软件的扫描结果,可以采用滑窗的方法解决,可以参考某网友的解决方案:

https://github.com/PaddlePaddle/PaddleOCR/issues/11888

或参考paddle的slice参数的网格化切图方案,看def __call__(self, img, cls=True, slice={}):函数

tools/infer/predict_system.py · PaddlePaddle/PaddleOCR - Gitee.com

注意paddle的处理代码,如果图片长度超过32767 会触发一个opencv的short类型的最大值上限,从而导致抛出异常。

二、paddle lite

       用于移动端部署,有完备的demo文件,训练好的文件转为nb格式即可。具体模型是否适合各种芯片,需要deploy、FastDeploy等处的说明。

https://github.com/PaddlePaddle/FastDeploy

2.1模型转换

训练模型——推理infer模型——nb模型

第一步:

python tools/export_model.py -c config/***/*.yml -o weight=***

转为pdmodel和pdiparams文件

第二步:

paddle_lite_opt --optimize_out=*** --optimize_out_type=naive_buffer --valid_targets=arm --model_file=***.pdmodel --param_file=***.pdiparams

转为nb文件

三、paddle其他组件

        除去paddleocr外,百度还有几个专用场景套件,如PaddleClas分类、PaddleDetection检测、PaddleSeg分割、PaddleGAN、PaddleVideo、ERNIEKit语义、PLSC海量分类、ElasticCTR推荐、Parakeet语音合成、PGL图学习、PARL强化学习、Paddle Quantum量桨、PaddleHelix生物计算。

        其中我今后比较会用到的组件有:paddlenlp、UIE、文心大模型。

2.1PaddleNLP

2.2文心大模型

        ERNIE 是百度基于transformer研发的,可视为一个比较强的中文transformer,backbone结构没什么特殊,主要是设计了一些特殊的预训练任务,有基于mask的预训练,也有迁移到不同任务上的预训练。

2.3UIE

        另一个文本方面的大统一思想是UIE,本质是基于ERNIE的双指针解码(仅谈paddle的实现)

UIE教程(搜索 五条标注数据搞定快递单信息抽取):

优点:教程给的是“北京市海淀区上地十街10号18888888888张三”,改成“北京市海淀区上地十街10号18888888888交款人:李白百”后还是能把名字抽出来。

from paddlenlp import Taskflowschema = ["姓名", "省份", "城市", "县区", "电话", "详细地址"]
ie = Taskflow("information_extraction", schema=schema)
res=ie("交款人:李白百 北京市海淀区上地十街10号18888888888")
print(res)
# [{'姓名': [{'text': '李白百', 'start': 4, 'end': 7, 'probability': 0.9335348137713595}], '县区': [{'text': '海淀区', 'start': 11, 'end': 14, 'probability': 0.9149133074831752}]}]

uie的其他信息:

《Unified Structure Generation for Universal Information Extraction》

    Yaojie Lu等人提出了开放域信息抽取的统一框架,这一框架在实体抽取、关系抽取、事件抽取、情感分析等任务上都有着良好的泛化效果。开放域信息抽取可以实现零样本(zero-shot)或者少样本(few-shot)抽取

(杂谈)关于UIE的一点感想_常鸿宇的博客-CSDN博客_uie原理

  

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

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

相关文章

【C语言】线程

目录 1. 什么是线程 1.1概念 1.2 进程和线程的区别 1.3 线程资源 2. 函数接口 2.1创建线程: pthread_create 2.2 退出线程: pthread_exit 2.3 回收线程资源 练习 1. 什么是线程 1.1概念 线程是一个轻量级的进程&#xff0c;为了提高系统的性能引入线程。 在同一个进…

【C语言】字符串函数详解

文章目录 Ⅰ. strcpy -- 字符串拷贝1、函数介绍2、模拟实现 Ⅱ. strcat -- 字符串追加1、函数介绍2、模拟实现 Ⅲ. strcmp -- 字符串比较1、函数介绍2、模拟实现 Ⅳ. strncpy、strncat、strncmp -- 可限制操作长度Ⅴ. strlen -- 求字符串长度1、函数介绍2、模拟实现&#xff08…

Windows部署NVM并下载多版本Node.js的方法(含删除原有Node的方法)

本文介绍在Windows电脑中&#xff0c;下载、部署NVM&#xff08;node.js version management&#xff09;环境&#xff0c;并基于其安装不同版本的Node.js的方法。 在之前的文章Windows系统下载、部署Node.js与npm环境的方法&#xff08;https://blog.csdn.net/zhebushibiaoshi…

centos 8 中安装Docker

注&#xff1a;本次样式安装使用的是centos8 操作系统。 1、镜像下载 具体的镜像下载地址各位可以去官网下载&#xff0c;选择适合你们的下载即可&#xff01; 1、CentOS官方下载地址&#xff1a;https://vault.centos.org/ 2、阿里云开源镜像站下载&#xff1a;centos安装包…

STM32-笔记40-BKP(备份寄存器)

一、什么是BKP&#xff08;备份寄存器&#xff09;&#xff1f; 备份寄存器是42个16位的寄存器&#xff0c;可用来存储84个字节的用户应用程序数据。他们处在备份域里&#xff0c;当VDD电源被切断&#xff0c;他们仍然由VBAT维持供电。当系统在待机模式下被唤醒&#xff0c;或…

vue-cli项目配置使用unocss

在了解使用了Unocss后&#xff0c;就完全被它迷住了。接手过的所有项目都配置使用了它&#xff0c;包括一些旧项目&#xff0c;也跟同事分享了使用Unocss的便捷性。 这里分享一下旧项目如何配置和使用Unocss的&#xff0c;项目是vue2vue-cli构建的&#xff0c;node<20平常开…

新增文章分类功能

总说 过程参考黑马程序员SpringBoot3Vue3全套视频教程&#xff0c;springbootvue企业级全栈开发从基础、实战到面试一套通关_哔哩哔哩_bilibili 目录 总说 一、功能实现 1.1 Controller层 1.2 Service层 1.3 Impl层 1.4 Mapper层 1.5 测试接口 二、优化 2.1 2.2 一、…

知识图谱常见的主流图数据库

在知识图谱中&#xff0c;主流使用的图数据库包括以下几种&#xff1a; Neo4j&#xff1a;这是目前全球部署最广泛的图数据库之一&#xff0c;具有强大的查询性能和灵活的数据模型&#xff0c;适用于复杂关系数据的存储和查询。 JanusGraph&#xff1a;JanusGraph是一个开源的…

JavaSE学习心得(多线程与网络编程篇)

多线程-网络编程 前言 多线程&JUC 多线程三种实现方式 第一种实现方式 第二种实现方式 第三种实现方式 常见成员方法 买票引发的安全问题 同步代码块 同步方法 Lock锁 生产者和消费者 常见方法 等待唤醒机制 练习 抢红包 抽奖 多线程统计并求最…

Pytorch基础教程:从零实现手写数字分类

文章目录 1.Pytorch简介2.理解tensor2.1 一维矩阵2.2 二维矩阵2.3 三维矩阵 3.创建tensor3.1 你可以直接从一个Python列表或NumPy数组创建一个tensor&#xff1a;3.2 创建特定形状的tensor3.3 创建三维tensor3.4 使用随机数填充tensor3.5 指定tensor的数据类型 4.tensor基本运算…

candb++ windows11运行报错,找不到mfc140.dll

解决问题记录 mfc140.dll下载 注意&#xff1a;放置位置别搞错了

​公专网一体5G工业路由器,智慧电网全链路加密监控管理

随着可再生能源的集成 电网调度策略复杂性增加 需更精细的并网管理以平衡供需 传统电力网络的通信基础落后 难以适应电力设施的广泛分布 和日益增长的管理维护需求 计讯物联5G公专网一体路由器 通过融合公网和专网的优势 有效解决了现代电网对于 高效、灵活和安全通信的需求 ↓…

【Linux】--- 进程的等待与替换

进程的等待与替换 一、进程等待1、进程等待的必要性2、获取子进程status3、进程等待的方法&#xff08;1&#xff09;wait&#xff08;&#xff09;函数&#xff08;2&#xff09;waitpid函数 4、多进程创建以及等待的代码模型5、非阻塞接口 轮询 二、进程替换1、替换原理2、替…

zerotier搭建虚拟局域网,自建planet

基于该开源项目 自建planet节点&#xff0c;更快速&#xff0c;更安全 本教程依据docker-zerotier-planet 项目文档书写&#xff0c;并以linux(centos 7)和windows作为示例&#xff0c;需要其他系统配置方法&#xff0c;可移步项目文档 一. 前置资源 具有外网ip的服务器 后面…

屏幕轻触间:触摸交互从 “感知” 到 “智算” 的隐秘路径

从用户点击屏幕到前端感知及数据处理全流程剖析 引言 在移动智能设备与触摸交互技术深度融合的当下&#xff0c;当我们的手指轻触手机屏幕&#xff0c;一系列复杂且精妙的技术流程便瞬间启动。这一过程涵盖硬件层、驱动层、操作系统层、应用层&#xff0c;甚至延伸到后端的数…

深入Node.js集群:原理、优势与搭建实战,如何应对高并发

文章目录 一、Node.js 集群简介二、Node.js 集群原理剖析2.1 主从模型2.2 负载均衡机制2.3 进程间通信&#xff08;IPC&#xff09; 三、Node.js 集群优势详解3.1 性能提升3.2 高可用性3.3 资源利用率优化 四、Node.js 集群搭建实战4.1 准备工作4.2 创建主控制节点4.3 工作节点…

数字普惠金融对新质生产力的影响研究(2015-2023年)

基于2015—2023年中国制造业上市公司数据&#xff0c;探讨了数字普惠金融对制造业企业新质生产力的影响及作用机理。研究发现&#xff0c;数字普惠金融有助于促进制造业企业新质生产力的发展&#xff0c;尤其是在数字普惠金融的使用深度较大的情况下&#xff0c;其对新质生产力…

数据仓库基础常见面试题

1.数据仓库是什么 ‌数据仓库&#xff08;Data Warehouse&#xff09;是一个面向主题的、集成的、非易失的、随时间变化的数据集合&#xff0c;用于支持企业的管理决策‌。它不同于传统的操作型数据库&#xff0c;后者主要用于处理日常业务交易和实时查询&#xff0c;而数据仓库…

记一次OpenEuler Linux磁盘分区表损坏的数据恢复

问题复现 原本有一台GIS地图服务器存放大量数据&#xff0c;突然有一天磁盘满了&#xff0c;于是运维人员照常进行磁盘扩容。但由于误操作&#xff0c;导致使用fdisk的时候把分区表损坏了&#xff0c;表现如下&#xff1a; 这里可以看到启动时能看到xvda被分为了xvda1和xvda2…

分布式数据存储基础与HDFS操作实践(副本)

以下为作者本人撰写的报告&#xff0c;步骤略有繁琐&#xff0c;不建议作为参考内容&#xff0c;可以适当浏览&#xff0c;进一步理解。 一、实验目的 1、理解分布式文件系统的基本概念和工作原理。 2、掌握Hadoop分布式文件系统&#xff08;HDFS&#xff09;的基本操作。 …