LLM之RAG实战(二十九)| 探索RAG PDF解析

       对于RAG来说,从文档中提取信息是一种不可避免的场景,确保从源文件中提取出有效的内容对于提高最终输出的质量至关重要。

       文件解析过程在RAG中的位置如图1所示:

       在实际工作中,非结构化数据比结构化数据丰富得多。如果这些海量数据无法解析,它们的巨大价值将无法实现。在非结构化数据中,PDF文档占大多数。有效地处理PDF文档还可以极大地帮助管理其他类型的非结构化文档。

       本文主要介绍解析PDF文件的方法,为有效解析PDF文档和提取尽可能多的有用信息提供了算法和参考。

一、解析PDF的挑战

       PDF文档是非结构化文档的代表,然而,从PDF文档中提取信息是一个具有挑战性的过程。

       将PDF描述为输出指令的集合更准确,而不是数据格式。PDF文件由一系列指令组成,这些指令指示PDF阅读器或打印机在屏幕或纸张上显示符号的位置和方式,这与HTML和docx等文件格式形成对比,后者使用<p>、<w:p>、<table>和<w:tbl>等标记来组织不同的逻辑结构,如图2所示:

       解析PDF文档的挑战在于准确提取整个页面的布局,并将包括表格、标题、段落和图像在内的内容翻译成文档的文本表示。这个过程涉及到处理文本提取、图像识别中的不准确之处,以及表中行-列关系的混乱。

二、如何解析PDF文档

一般来说,解析PDF有三种方法:

  • 基于规则的方法:根据文档的组织特征确定每个部分的风格和内容。然而,这种方法不是很通用,因为PDF有很多类型和布局,不可能用预定义的规则覆盖所有类型和布局。
  • 基于深度学习模型的方法:例如将目标检测OCR模型相结合的流行解决方案。
  • 基于多模态大模型对复杂结构进行Pasing或提取PDF中的关键信息。

2.1 基于规则的方法

       pypdf[1]就是一种基于规则广泛使用的解析器,也是LangChainLlamaIndex中解析PDF文件的标准方法。

      以下是使用pypdf解析“Attention Is All You Need”[2]论文的第6页。原始页面如图3所示:

代码如下:

import PyPDF2filename = "/Users/Florian/Downloads/1706.03762.pdf"pdf_file = open(filename, 'rb')reader = PyPDF2.PdfReader(pdf_file)page_num = 5page = reader.pages[page_num]text = page.extract_text()print('--------------------------------------------------')print(text)pdf_file.close()

执行的结果是(为了简洁起见,省略了其余部分):

(py) Florian:~ Florian$ pip list | grep pypdfpypdf                    3.17.4pypdfium2                4.26.0(py) Florian:~ Florian$ python /Users/Florian/Downloads/pypdf_test.py--------------------------------------------------Table 1: Maximum path lengths, per-layer complexity and minimum number of sequential operationsfor different layer types. nis the sequence length, dis the representation dimension, kis the kernelsize of convolutions and rthe size of the neighborhood in restricted self-attention.Layer Type Complexity per Layer Sequential Maximum Path LengthOperationsSelf-Attention O(n2·d) O(1) O(1)Recurrent O(n·d2) O(n) O(n)Convolutional O(k·n·d2) O(1) O(logk(n))Self-Attention (restricted) O(r·n·d) O(1) O(n/r)3.5 Positional EncodingSince our model contains no recurrence and no convolution, in order for the model to make use of theorder of the sequence, we must inject some information about the relative or absolute position of thetokens in the sequence. To this end, we add "positional encodings" to the input embeddings at thebottoms of the encoder and decoder stacks. The positional encodings have the same dimension dmodelas the embeddings, so that the two can be summed. There are many choices of positional encodings,learned and fixed [9].In this work, we use sine and cosine functions of different frequencies:PE(pos,2i)=sin(pos/100002i/d model)PE(pos,2i+1)=cos(pos/100002i/d model)where posis the position and iis the dimension. That is, each dimension of the positional encodingcorresponds to a sinusoid. The wavelengths form a geometric progression from 2πto10000 ·2π. Wechose this function because we hypothesized it would allow the model to easily learn to attend byrelative positions, since for any fixed offset k,PEpos+kcan be represented as a linear function ofPEpos..........

       从上述基于PyPDF检测的结果来看,可以观察到它在不保留结构信息的情况下将PDF中的字符序列序列化为单个长序列。换句话说,它将文档的每一行都视为一个由换行符“\n”分隔的序列,这会妨碍段落或表格的准确识别。

       这种限制是基于规则的方法的固有特征。

2.2 基于深度学习模型的方法

       这种方法的优点是能够准确识别整个文档的布局,包括表格和段落。它甚至可以理解表中的结构。这意味着它可以将文档划分为定义明确、完整的信息单元,同时保留预期的含义和结构。

       然而,这种方法也有一些局限性,目标检测和OCR阶段可能很耗时。因此,建议使用GPU或其他加速设备,并使用多个进程和线程进行处理。

       这种方法涉及目标检测和OCR模型,我测试了几个有代表性的开源框架:

  • Unstructured[3]:它已集成到langchain中[4]。使用hi_res策略设置infer_table_structure=True可以很好的识别表格信息。然而,fast策略因为不使用目标检测模型,在识别图像和表格方面表现较差。
  • Layout-parser[5]:如果需要识别复杂的结构化PDF,建议使用最大的模型以获得更高的精度,尽管它可能会稍微慢一些。此外,Layout解析器的模型[6]在过去两年中似乎没有更新。
  • PP-StructureV2[7]:可以组合各种模型用于文档分析,性能高于平均水平。体系结构如图4所示:

      除了开源工具,还有像ChatDOC这样的付费工具,它们利用基于布局的识别+OCR方法来解析PDF文档。

      接下来,我们将使用开源unstructured[3]解析PDF,解决三个关键挑战。

挑战1:如何从表格和图像中提取数据

      在这里,我们将使用unstructured[3]框架作为示例,检测到的表数据可以直接导出为HTML。其代码如下:

from unstructured.partition.pdf import partition_pdffilename = "/Users/Florian/Downloads/Attention_Is_All_You_Need.pdf"# infer_table_structure=True automatically selects hi_res strategyelements = partition_pdf(filename=filename, infer_table_structure=True)tables = [el for el in elements if el.category == "Table"]print(tables[0].text)print('--------------------------------------------------')print(tables[0].metadata.text_as_html)

         partition_pdf函数的内部流程如下图5所示:

         代码的运行结果如下:

Layer Type Self-Attention Recurrent Convolutional Self-Attention (restricted) Complexity per Layer O(n2 · d) O(n · d2) O(k · n · d2) O(r · n · d) Sequential Maximum Path Length Operations O(1) O(n) O(1) O(1) O(1) O(n) O(logk(n)) O(n/r)--------------------------------------------------<table><thead><th>Layer Type</th><th>Complexity per Layer</th><th>Sequential Operations</th><th>Maximum Path Length</th></thead><tr><td>Self-Attention</td><td>O(n? - d)</td><td>O(1)</td><td>O(1)</td></tr><tr><td>Recurrent</td><td>O(n- d?)</td><td>O(n)</td><td>O(n)</td></tr><tr><td>Convolutional</td><td>O(k-n-d?)</td><td>O(1)</td><td>O(logy(n))</td></tr><tr><td>Self-Attention (restricted)</td><td>O(r-n-d)</td><td>ol)</td><td>O(n/r)</td></tr></table>

       复制HTML标记并将其另存为HTML文件。然后,使用Chrome打开它,如图6所示:

        可以观察到,非结构化的算法在很大程度上恢复了整个表。

挑战2:如何重新排列检测到的块?特别是对于双列PDF

       在处理双列PDF时,让我们以论文“BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding”[8]为例,读取顺序由红色箭头所示:

       在确定布局后,unstructured[3]框架会将每个页面划分为几个矩形块,如图8所示:

         每个矩形块的详细信息可以通过以下格式获得:

[LayoutElement(bbox=Rectangle(x1=851.1539916992188, y1=181.15073777777613, x2=1467.844970703125, y2=587.8204599999975), text='These approaches have been generalized to coarser granularities, such as sentence embed- dings (Kiros et al., 2015; Logeswaran and Lee, 2018) or paragraph embeddings (Le and Mikolov, 2014). To train sentence representations, prior work has used objectives to rank candidate next sentences (Jernite et al., 2017; Logeswaran and Lee, 2018), left-to-right generation of next sen- tence words given a representation of the previous sentence (Kiros et al., 2015), or denoising auto- encoder derived objectives (Hill et al., 2016). ', source=<Source.YOLOX: 'yolox'>, type='Text', prob=0.9519357085227966, image_path=None, parent=None), LayoutElement(bbox=Rectangle(x1=196.5296173095703, y1=181.1507377777777, x2=815.468994140625, y2=512.548237777777), text='word based only on its context. Unlike left-to- right language model pre-training, the MLM ob- jective enables the representation to fuse the left and the right context, which allows us to pre- In addi- train a deep bidirectional Transformer. tion to the masked language model, we also use a “next sentence prediction” task that jointly pre- trains text-pair representations. The contributions of our paper are as follows: ', source=<Source.YOLOX: 'yolox'>, type='Text', prob=0.9517233967781067, image_path=None, parent=None), LayoutElement(bbox=Rectangle(x1=200.22352600097656, y1=539.1451822222216, x2=825.0242919921875, y2=870.542682222221), text='• We demonstrate the importance of bidirectional pre-training for language representations. Un- like Radford et al. (2018), which uses unidirec- tional language models for pre-training, BERT uses masked language models to enable pre- trained deep bidirectional representations. This is also in contrast to Peters et al. (2018a), which uses a shallow concatenation of independently trained left-to-right and right-to-left LMs. ', source=<Source.YOLOX: 'yolox'>, type='List-item', prob=0.9414362907409668, image_path=None, parent=None), LayoutElement(bbox=Rectangle(x1=851.8727416992188, y1=599.8257377777753, x2=1468.0499267578125, y2=1420.4982377777742), text='ELMo and its predecessor (Peters et al., 2017, 2018a) generalize traditional word embedding re- search along a different dimension. They extract context-sensitive features from a left-to-right and a right-to-left language model. The contextual rep- resentation of each token is the concatenation of the left-to-right and right-to-left representations. When integrating contextual word embeddings with existing task-specific architectures, ELMo advances the state of the art for several major NLP benchmarks (Peters et al., 2018a) including ques- tion answering (Rajpurkar et al., 2016), sentiment analysis (Socher et al., 2013), and named entity recognition (Tjong Kim Sang and De Meulder, 2003). Melamud et al. (2016) proposed learning contextual representations through a task to pre- dict a single word from both left and right context using LSTMs. Similar to ELMo, their model is feature-based and not deeply bidirectional. Fedus et al. (2018) shows that the cloze task can be used to improve the robustness of text generation mod- els. ', source=<Source.YOLOX: 'yolox'>, type='Text', prob=0.938507616519928, image_path=None, parent=None), LayoutElement(bbox=Rectangle(x1=199.3734130859375, y1=900.5257377777765, x2=824.69873046875, y2=1156.648237777776), text='• We show that pre-trained representations reduce the need for many heavily-engineered task- specific architectures. BERT is the first fine- tuning based representation model that achieves state-of-the-art performance on a large suite of sentence-level and token-level tasks, outper- forming many task-specific architectures. ', source=<Source.YOLOX: 'yolox'>, type='List-item', prob=0.9461237788200378, image_path=None, parent=None), LayoutElement(bbox=Rectangle(x1=195.5695343017578, y1=1185.526123046875, x2=815.9393920898438, y2=1330.3272705078125), text='• BERT advances the state of the art for eleven NLP tasks. The code and pre-trained mod- els are available at https://github.com/ google-research/bert. ', source=<Source.YOLOX: 'yolox'>, type='List-item', prob=0.9213815927505493, image_path=None, parent=None), LayoutElement(bbox=Rectangle(x1=195.33956909179688, y1=1360.7886962890625, x2=447.47264000000007, y2=1397.038330078125), text='2 Related Work ', source=<Source.YOLOX: 'yolox'>, type='Section-header', prob=0.8663332462310791, image_path=None, parent=None), LayoutElement(bbox=Rectangle(x1=197.7477264404297, y1=1419.3353271484375, x2=817.3308715820312, y2=1527.54443359375), text='There is a long history of pre-training general lan- guage representations, and we briefly review the most widely-used approaches in this section. ', source=<Source.YOLOX: 'yolox'>, type='Text', prob=0.928022563457489, image_path=None, parent=None), LayoutElement(bbox=Rectangle(x1=851.0028686523438, y1=1468.341394166663, x2=1420.4693603515625, y2=1498.6444497222187), text='2.2 Unsupervised Fine-tuning Approaches ', source=<Source.YOLOX: 'yolox'>, type='Section-header', prob=0.8346447348594666, image_path=None, parent=None), LayoutElement(bbox=Rectangle(x1=853.5444444444446, y1=1526.3701822222185, x2=1470.989990234375, y2=1669.5843488888852), text='As with the feature-based approaches, the first works in this direction only pre-trained word em- (Col- bedding parameters from unlabeled text lobert and Weston, 2008). ', source=<Source.YOLOX: 'yolox'>, type='Text', prob=0.9344717860221863, image_path=None, parent=None), LayoutElement(bbox=Rectangle(x1=200.00000000000009, y1=1556.2037353515625, x2=799.1743774414062, y2=1588.031982421875), text='2.1 Unsupervised Feature-based Approaches ', source=<Source.YOLOX: 'yolox'>, type='Section-header', prob=0.8317819237709045, image_path=None, parent=None), LayoutElement(bbox=Rectangle(x1=198.64227294921875, y1=1606.3146266666645, x2=815.2886352539062, y2=2125.895459999998), text='Learning widely applicable representations of words has been an active area of research for decades, including non-neural (Brown et al., 1992; Ando and Zhang, 2005; Blitzer et al., 2006) and neural (Mikolov et al., 2013; Pennington et al., 2014) methods. Pre-trained word embeddings are an integral part of modern NLP systems, of- fering significant improvements over embeddings learned from scratch (Turian et al., 2010). To pre- train word embedding vectors, left-to-right lan- guage modeling objectives have been used (Mnih and Hinton, 2009), as well as objectives to dis- criminate correct from incorrect words in left and right context (Mikolov et al., 2013). ', source=<Source.YOLOX: 'yolox'>, type='Text', prob=0.9450697302818298, image_path=None, parent=None), LayoutElement(bbox=Rectangle(x1=853.4905395507812, y1=1681.5868488888855, x2=1467.8729248046875, y2=2125.8954599999965), text='More recently, sentence or document encoders which produce contextual token representations have been pre-trained from unlabeled text and fine-tuned for a supervised downstream task (Dai and Le, 2015; Howard and Ruder, 2018; Radford et al., 2018). The advantage of these approaches is that few parameters need to be learned from scratch. At least partly due to this advantage, OpenAI GPT (Radford et al., 2018) achieved pre- viously state-of-the-art results on many sentence- level tasks from the GLUE benchmark (Wang language model- Left-to-right et al., 2018a). ', source=<Source.YOLOX: 'yolox'>, type='Text', prob=0.9476840496063232, image_path=None, parent=None)]

        其中(x1,y1)是左上顶点的坐标,(x2,y2)是右下顶点的坐标:

        (x_1, y_1) --------            |             |            |             |            |             |            ---------- (x_2, y_2)

       此时,可以选择重新调整页面的阅读顺序。Unstructured[3]有一个内置的排序算法,但我发现在处理双列情况时,排序结果不是很令人满意。

       因此,有必要设计一种算法。最简单的方法是先按左上角顶点的水平坐标排序,如果水平坐标相同,则按垂直坐标排序。其伪代码如下所示:

layout.sort(key=lambda z: (z.bbox.x1, z.bbox.y1, z.bbox.x2, z.bbox.y2))

       然而,我们发现,即使是同一列中的块,其水平坐标也可能发生变化。如图9所示,紫色线条块的水平坐标bbox.x1实际上更靠左。排序时,它将位于绿线块之前,这显然违反了读取顺序。

在这种情况下使用的一种可能的算法如下:

  • 首先,对左上角的所有x坐标x1进行排序,我们可以得到x1_min
  • 然后,对所有右下角的x坐标x2进行排序,我们可以得到x2_max
  • 接下来,将页面中心线的x坐标确定为:
x1_min = min([el.bbox.x1 for el in layout])x2_max = max([el.bbox.x2 for el in layout])mid_line_x_coordinate = (x2_max + x1_min) /  2

       接下来,如果bbox.x1<mid_line_x_cordinate,则块被分类为左列的一部分。否则,它将被视为右列的一部分。

       分类完成后,根据列中的y坐标对每个块进行排序。最后,将右侧列连接到左侧列的右侧。

left_column = []right_column = []for el in layout:    if el.bbox.x1 < mid_line_x_coordinate:        left_column.append(el)    else:        right_column.append(el)left_column.sort(key = lambda z: z.bbox.y1)right_column.sort(key = lambda z: z.bbox.y1)sorted_layout = left_column + right_column

       值得一提的是,这种改进也与单列PDF兼容。

挑战3:如何提取多级标题

       提取标题(包括多级标题)的目的是提高LLM答案的准确性。

       例如,如果用户想知道图9中2.1节的主要内容,通过准确提取2.1节的标题,并将其与相关内容一起作为上下文发送给LLM,最终答案的准确性将显著提高。

       该算法仍然依赖于图9所示的布局块。我们可以提取type=’Section-header’的块,并计算高度差(bbox.y2--bbox.y1)。高度差最大的块对应第一级标题,其次是第二级标题,然后是第三级标题。

2.3 基于多模态大模型解析复杂结构的PDF

       在多模态模型爆炸之后,也可以使用多模式模型来解析表。Llamalndex有几个例子[9]:

  • 检索相关图像(PDF页面)并将其发送到GPT4-V以响应查询。
  • 将每个PDF页面视为一个图像,让GPT4-V对每个页面进行图像推理,为图像推理构建文本矢量存储索引,根据图像推理矢量存储查询答案。
  • 使用Table Transformer从检索到的图像中裁剪表信息,然后将这些裁剪的图像发送到GPT4-V以进行查询响应。
  • 对裁剪的表图像应用OCR,并将数据发送到GPT4/GGP-3.5以回答查询。

       经过测试,确定第三种方法是最有效的。

       此外,我们可以使用多模态模型从图像中提取或总结关键信息(PDF文件可以很容易地转换为图像),如图10所示:

三、结论

       一般来说,非结构化文档提供了高度的灵活性,并且需要各种解析技术。然而,目前还没有达成共识的最佳实践。

       在这种情况下,建议选择最适合您项目需求的方法。建议根据不同类型的PDF应用特定的应对方法。例如,论文、书籍和财务报表可能会根据其特点进行独特的设计。

       然而,如果可以的话,建议选择基于深度学习或基于多模态的方法。这些方法可以有效地将文档分割成定义明确、完整的信息单元,从而最大限度地保留文档的预期含义和结构。

参考文献:

[1] https://github.com/py-pdf/pypdf

[2] https://arxiv.org/pdf/1706.03762.pdf

[3] http://unstructured-io.github.io/unstructured/

[4] https://github.com/langchain-ai/langchain/blob/master/libs/langchain/langchain/document_loaders/pdf.py

[5] http://github.com/Layout-Parser/layout-parser

[6] https://layout-parser.github.io/platform/

[7] https://arxiv.org/pdf/2210.05391.pdf

[8] https://arxiv.org/pdf/1810.04805.pdf

[9] https://docs.llamaindex.ai/en/stable/examples/multi_modal/multi_modal_pdf_tables.html

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

记录西门子:SCL设置不同顺序

一台搅拌的设备&#xff0c;需要控制三种料的进料顺序和进料重量&#xff0c;顺序和重量可以随便设定&#xff0c;也可以是几十种料。触摸屏上面有A、B、C三种液体原料&#xff0c;需要设定三种液体原料重量&#xff0c;并设定序号。 假设如下面所示设定&#xff1a;那将先打开…

java数据结构与算法刷题-----LeetCode90. 子集 II

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 解题思路:时间复杂度O( n 2 ∗ n n^2*n n2∗n),空间复杂度O(n) 7…

开箱机自动化装箱技术:原理、应用与未来趋势

在物流、电商等行业中&#xff0c;开箱机作为自动化装箱技术的核心设备&#xff0c;正逐渐改变着传统的包装方式&#xff0c;为企业带来了效率和成本的双重优化。星派将从开箱机的原理出发&#xff0c;详细解析其应用领域&#xff0c;并展望未来的发展趋势。 一、开箱机的工作原…

《高效便捷,探索快递柜系统架构的智慧之路》

随着电商业务的蓬勃发展&#xff0c;快递柜系统作为一种高效、便捷的最后一公里配送解决方案&#xff0c;正在受到越来越多企业和消费者的青睐。本篇博客将深入探讨快递柜系统的架构设计理念、优势和实践&#xff0c;帮助读者了解如何构建智能化的快递柜系统&#xff0c;提升物…

【UE5】非持枪状态蹲姿移动的动画混合空间

项目资源文末百度网盘自取 在BlendSpace文件夹中单击右键选择动画(Animation)中的混合空间(Blend Space) &#xff0c;选择SK_Female_Skeleton&#xff0c;命名为BS_NormalCrouch 打开BS_NormalCrouch 水平轴表示角色的方向&#xff0c;命名为Direction&#xff0c;方向的最…

教师如何搭建学生查询考试分数的平台?

随着信息技术的快速发展&#xff0c;搭建一个学生查询考试分数的平台已经成为现代教育管理的重要组成部分。这样的平台不仅可以提高成绩管理的效率&#xff0c;还能为学生提供便捷、及时的成绩查询服务。那么&#xff0c;作为教师&#xff0c;我们应该如何搭建这样一个平台呢&a…

低代码开发平台,快速搭建开源MES系统

MS低代码云MES作为一家专注于提供生产制造数字化方案的服务商&#xff0c;“以客户为中心”、以“数据驱动、智能化、互联化”为企业的核心标签&#xff0c;以低代码平台为切入点&#xff0c;帮助企业构建以人为本的未来供应链生态系统&#xff0c;实现制造企业的智能化转型。 …

Simple Admin:基于Go Zero的大型项目分布式微服务后端管理系统

Simple Admin 是一个开箱即用的分布式微服务后端管理系统&#xff0c;基于go-zero开发&#xff0c;为开发中大型后台提供了丰富的功能&#xff0c;支持三端代码生成。 官方自带多种扩展&#xff0c;助力中小企业快速上云&#xff0c;快速迭代。适合用于微服务学习和商用&#x…

如何拆解技术瓶颈的难点

以大化小的思路 解决一个一个小问题从而解决最终问题 三段论&#xff1a; 抽象能力 职责领域划分 分层构建解决方案 案例&#xff1a;全局分布式事务的解决方案 抽象能力&#xff1a;全局分布式 是由一个个小的事务组合而成的&#xff0c;其中一个分布式事务出现问题&#xff…

VsCode免密登录

创建本地密匙 按下WinR输入cmd&#xff0c;输入 ssh-keygen -t rsa然后连续回车直到结束 找到Your public key has been saved in C:\Users\Administrator/.ssh/id_rsa.pub&#xff0c;每个人都不一样找到密匙所在地 打开id_rsa.pub这个文件&#xff0c;可以用记事本打开&am…

wayland(xdg_wm_base) + egl + opengles 渲染使用纹理贴图的旋转 3D 立方体实例(十三)

文章目录 前言一、使用 stb_image 库加载纹理图片1. 获取 stb_image.h 头文件2. 使用 stb_image.h 中的相关接口加载纹理图片3. 纹理图片——cordeBouee4.jpg二、渲染使用纹理贴图的旋转 3D 立方体1. egl_wayland_texture_cube.c2. Matrix.h 和 Matrix.c3. xdg-shell-client-pr…

Nacos 集群搭建

1 . 集群结构图 : 其中包括3个nacos结点&#xff0c;然后一个负载均衡器代理3个Nacos。这里负载均衡器可以使用nginx ; 我们计划的集群结构 : 三个nacos结点的地址 : 节点ipportnacos1192.168.150.18845nacos2192.168.150.18846nacos3192.168.150.18847 2 . 搭建集群 搭…

LeetCode 2864. 最大二进制奇数

文章目录 LeetCode 2864. 最大二进制奇数思路1AC CODE思路2AC CODE LeetCode 2864. 最大二进制奇数 题目链接&#xff1a;https://leetcode.cn/problems/maximum-odd-binary-number/description/ 思路1 由于二进制基数的最后一位必须是1&#xff0c;而其他位越大越好&#xf…

激活函数Mish

paper&#xff1a;Mish: A Self Regularized Non-Monotonic Activation Function official implementation&#xff1a;https://github.com/digantamisra98/Mish 背景 在早期文献中&#xff0c;Sigmoid和TanH激活函数被广泛使用&#xff0c;随后在深度神经网络中失效。相比于…

【小沐学C#】C#文件读写方式汇总

文章目录 1、简介2、相关类介绍3、代码示例3.1 FileStream&#xff08;流文件&#xff09;3.2 StreamReader / StreamWriter &#xff08;文本文件&#xff09;3.2.1 StreamReader3.2.2 StreamWriter 3.3 BinaryReader / BinaryWriter &#xff08;二进制文件&#xff09;3.3.1…

2024.03.13作业

要求&#xff1a;设计一个Per类&#xff0c;类中包含私有成员:姓名、年龄、指针成员身高、体重&#xff0c;再设计一个Stu类&#xff0c;类中包含私有成员:成绩、Per类对象p1&#xff0c;设计这两个类的构造函数、析构函数和拷贝构造函数。 #include <iostream> #includ…

初学MyBatis小结

0 简介 MyBatis官网介绍 MyBatis 是一款优秀的持久层框架&#xff0c;它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO&#xff08;P…

C语言分析基础排序算法——归并排序

目录 归并排序 递归版本 非递归版本 非递归版本的问题 归并排序小优化 归并排序 归并排序&#xff0c;分为分治以及合并&#xff0c;分治部分可以使用递归或者非递归完成&#xff0c;归并排序的基本思路是&#xff1a;将已有序的子序列合并&#xff0c;得到完全有序的序列…

qiankun:vite/webpack项目配置

相关博文&#xff1a; https://juejin.cn/post/7216536069285429285?searchId202403091501088BACFF113F980BA3B5F3 https://www.bilibili.com/video/BV12T411q7dq/?spm_id_from333.337.search-card.all.click qiankun结构&#xff1a; 主应用base&#xff1a;vue3historyv…

基于SpringCache实现数据缓存

SpringCache SpringCache是一个框架实现了基本注解的缓存功能,只需要简单的添加一个EnableCaching 注解就能实现缓存功能 SpringCache框架只是提供了一层抽象,底层可以切换CacheManager接口的不同实现类即使用不同的缓存技术,默认的实现是ConcurrentMapCacheManagerConcurren…