使用langchain与你自己的数据对话(一):文档加载与切割

news2024/11/27 14:45:11

LangChain是一个基于大语言模型(如ChatGPT)用于构建端到端语言模型应用的 Python 框架。它提供了一套工具、组件和接口,可简化创建由大型语言模型 (LLM) 和聊天模型提供支持的应用程序的过程。LangChain 可以轻松管理与语言模型的交互,将多个组件链接在一起,以便在不同的应用程序中使用。LangChain可以让LLM来学习您自己的结构化或者非结构化的数据,这些数据包括pdf,text,youtbe,database等,这样就可以很方便的打造一个个性化的智能AI机器人。下面是LangChain可以学习的数据的种类和类型:

 Langchain在实现与外部数据对话的功能时需要经历下面的5个阶段,它们分别是:Document Loading->Splitting->Storage->Retrieval->Output,如下图所示:

Document Loading

在检索增强生成(Retrieval augmented generation,RAG)中,Langchain可以让LLM检索外部数据集中内容:

要实现对外部数据的检索,首先需要对各种外部数据的加载且对于不同类型的数据时Langchain提供了不同类型的数据加载器, 不过在实现加载外部数据之前,首先我们还是要做一些基础性工作,比如设置openai的api key:

import os
import openai
import sys
sys.path.append('../..')

from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file

openai.api_key  = os.environ['OPENAI_API_KEY']

PDFs

下面我们让langchain加载吴恩达老师的著名课程《机器学习》的课程讲义的pdf文档:

#! pip install pypdf 

from langchain.document_loaders import PyPDFLoader
loader = PyPDFLoader("docs/cs229_lectures/MachineLearning-Lecture01.pdf")
pages = loader.load()

 下面我们查看一下文档的页数:

len(pages)

接下来我们查看该文档第一页的部分内容,由于文本内容太长,所以我们只展示前500个字符的内容:

page = pages[0]

print(page.page_content[0:500])

 与实际内容做比对:

下面查看该页的元数据

page.metadata

 YouTube

langchain的另外一个重要的功能就是它可以读取youtube视频里的内容,langchain可以读取youtube视频内的音频数据,并将其转换成文本:

# ! pip install yt_dlp
# ! pip install pydub

from langchain.document_loaders.generic import GenericLoader
from langchain.document_loaders.parsers import OpenAIWhisperParser
from langchain.document_loaders.blob_loaders.youtube_audio import YoutubeAudioLoader

#视频链接
url="https://www.youtube.com/shorts/13c99EsNt4M"
#视频保存路径
save_dir="docs/youtube/"

loader = GenericLoader(
    YoutubeAudioLoader([url],save_dir),
    OpenAIWhisperParser()
)
docs = loader.load()

上面我们已经完成了对youtube视频的加载,并且将其中的音频转换成了文本,下面我们查看一下转换好的文本:

docs[0].page_content[0:500]

 URLs

除了从youtube中加载数据,Langchain还可以加载web网页的内容,下面我们看一个例子:

from langchain.document_loaders import WebBaseLoader

url="https://mp.weixin.qq.com/s/RhzHa1oMd0WHk0JamdfVRA"

#创建webLoader
loader = WebBaseLoader(url)

#获取文档
docs = loader.load()
#查看文档内容
text=docs[0].page_content
text=text.replace("\n",'')
print(text)

 我们对照一下实际网页的内容:

 文档分割(Document Splitting)

前面我们简单介绍了通过Langchain来加载和读取各种类型外部数据的方法,当数据被加载以后,接下来就来到了Splitting, 由于外部数据的数据量可能比较大,如pdf、text文档,youtube视频等产生的文档的数量或者说体积比较大,因此需要对外部数据文档进行分割(Splitting),文档被分割成块(chunks)后才能保存到向量数据库中:

 Langchain提供了很多文本切割的工具,其中langchain默认使用RecursiveCharacterTextSplitter:

  • CharacterTextSplitter():按字符来分割文本。
  • MarkdownHeaderTextSplitter():基于指定的标题来分割markdown 文件。
  • TokenTextSplitter():按token来分割文本。
  • SentenceTransformersTokenTextSplitter() : 按token来分割文本
  • RecursiveCharacterTextSplitter():按字符串分割文本,递归地尝试按不同的分隔符进行分割文本。
  • Language() - 用于 CPP、Python、Ruby、Markdown 等。
  • NLTKTextSplitter():使用 NLTK(自然语言工具包)按句子分割文本。
  • SpacyTextSplitter() - 使用 Spacy按句子的切割文本。

RecursiveCharacterTextSplitter

RecursiveCharacterTextSplitter是Langchain的默认文本分割器,它按不同的字符递归地分割文档,同时要兼顾被分割文本的长度和重叠字符,RecursiveCharacterTextSplitter默认使用[“\n\n” ,"\n" ," ",""] 这四个特殊符号作为分割文本的标记,下面对RecursiveCharacterTextSplitter()方法的参数说明如下:

  • chunk_size:被切割的字符串的最大长度
  • chunk_overlap:如果仅仅使用chunk_size来切割时,前后两段字符串重叠的字符数量。

这里需要说明一下chunk_overlap参数,为了保持字符串中语义的连贯性,就需要保持前后两段被分割的字符串有部分重叠,这就好比老师在上课的时候先回顾一下上一节课的内容,这样可以做到温故而知新,这就是设置重叠字符川的意义,下面我们看个例子:

from langchain.text_splitter import RecursiveCharacterTextSplitter, CharacterTextSplitter

r_splitter = RecursiveCharacterTextSplitter(
    chunk_size=26, #块长度
    chunk_overlap=4 #重叠字符串长度
)


text1 = 'abcdefghijklmnopqrstuvwxyz'
r_splitter.split_text(text1)

 这里我们使用RecursiveCharacterTextSplitter方法来切割字符串a-z,由于我们设置chunk_size的值为26,也就是每26个字符会被切块,但是因为a到z的字符串正好是26个字符,所以没有被切开下面我们在26个字母的后面再加上a到g试一下:

text2 = 'abcdefghijklmnopqrstuvwxyzabcdefg'
r_splitter.split_text(text2)

 

这里我们看到由于我们在a到z的后面又增加了a到g 8个字符所以现在字符串总长变成了34,但是RecursiveCharacterTextSpliterr还是会在每26个字符串的位置进行切割,所以原字符串被切割成了两段,同时由于我们还设置了chunk_overlap参数为4,所以前一个字符串的最后4个字符串会被加到后一个字符串的开头,这样做的目的是为了增强语义的连贯性。下面我们再看一个例子,这次我们在原来a到z的字符串中间,在字母和字母中间加入空格,所以字符串长度由原来的26变成了51:

text3 = "a b c d e f g h i j k l m n o p q r s t u v w x y z"
r_splitter.split_text(text3)

 这里我们发现字符串被切割成了3段,前2段每段都只有25个字母,这是因为前两段字符串其实还有一个空格,我们设置的chunk_size参数是26,所以它只会在每26个字符的位置进行切割,所以当第26个字符是空格的时候,该空格会被扔掉,不会被保留下来,所以造成前两个字符串都只有25个字母,但是在计算重叠字符时改空格仍然会保留下来,这就造成后一个字符串的开头包含了前一个字符串的最后四个字符(包括空格在内)。

CharacterTextSplitter

上面我们解释了RecursiveCharacterTextSplitter文档切割器,它是Langchain默认的文档切割器,接下来我们还可以来尝试另外一款文档切割器CharacterTextSplitter,这是一款比较的简单的按字符数来切割文档的文档切割组件,下面我们看一个例子,在下面的例子中我们任然设置了chunk_size为26和chunk_overlap为4这两个参数:

c_splitter = CharacterTextSplitter(
    chunk_size=26,
    chunk_overlap=4
)

text3 = "a b c d e f g h i j k l m n o p q r s t u v w x y z"
c_splitter.split_text(text3)

我们看到,默认情况下CharacterTextSplitter是忽略空格的,也就是说在默认情况下CharacterTextSplitter不会把空格当初字符,所以没有切割原来的字符串,任然输出包含空格在内的26个字母。我们再看下面的例子:

c_splitter = CharacterTextSplitter(
    chunk_size=26,
    chunk_overlap=4,
    separator = ' '
)
text3 = "a b c d e f g h i j k l m n o p q r s t u v w x y z"
c_splitter.split_text(text3)

 当我们在CharacterTextSplitter的参数中增加一个separator = ' '的参数,此时空格将不会被忽略,空格会被当成字符来对待,所以原字符串最后被切割成个3段,这类似于RecursiveCharacterTextSplitter。

递归分割细节

前面我们介绍了RecursiveCharacterTextSplitter,它是Langchain默认使用的文本切割器,也是Langchain推荐使用的文本切割器,它可以根据特定的标记,如双换行符(\n\n),单换行符(\n)等来分割文本,因此它可以将完整的语义保留在一个段落中,同时设置了重叠字符确保了语义的连贯性。下面我们来看一个例子,在这段文本中存在一个双换行符\n\n:

some_text = """When writing documents, writers will use document structure to group content. \
This can convey to the reader, which idea's are related. For example, closely related ideas \
are in sentances. Similar ideas are in paragraphs. Paragraphs form a document. \n\n  \
Paragraphs are often delimited with a carriage return or two carriage returns. \
Carriage returns are the "backslash n" you see embedded in this string. \
Sentences have a period at the end, but also, have a space.\
and words are separated by space."""

下面我们看一下文本的总长度:

 该段文本的中长度为496个字符。下面我们分别用CharacterTextSplitter和RecursiveCharacterTextSplitter来切割该段文本:

c_splitter = CharacterTextSplitter(
    chunk_size=450,
    chunk_overlap=0,
    separator = ' '
)
r_splitter = RecursiveCharacterTextSplitter(
    chunk_size=450,
    chunk_overlap=0, 
    separators=["\n\n", "\n", " ", ""] #默认
)

 这里需要说明的是CharacterTextSplitter默认的字分割符是双换行符即\n\n, 这里我们将分隔符改成了空格,而RecursiveCharacterTextSplitter的默认字分割符是一个列表即["\n\n", "\n", " ", ""],因此它会用分割符列表中从左至右的顺序的分割符依次去搜索目标文档中的分割符,然后再分割文档,比如先搜索目标文档中的双换行符\n\n,如果存在,则切割文档,然后依次搜索单分隔符\n,空格等,下面我们首先尝试用CharacterTextSplitter来切割文档,这里我们CharacterTextSplitter的chunk_overlap值设置为0,也就是不设置重叠字符的意思:

c_splitter.split_text(some_text)

 

 这里我们看到,CharacterTextSplitter按字符串长度将切割成了2段,因为我们设置了separator 为空格,所以它一定是在空格处来切割文本,并且长度要尽量满足我们设置的chunk_size=450的长度,所以第一段的长度应该是<=450的最大值:

ds=c_splitter.split_text(some_text)
len(ds[0])

 这里我们看到第一段的长度是448,满足不大于450的要求。下面我们用RecursiveCharacterTextSplitter来切割文本:

r_splitter.split_text(some_text)

这里我们看到RecursiveCharacterTextSplitter也将文本分割成了两段,只不过它是在原文本中的双换行符处切割的,这是因为RecursiveCharacterTextSplitter的分割符是一个列表,其中的双换行符\n\n优先级最大,因此凡事在文本中出现双换行符的位置都会被分割,并且被分割的文本长度不能大于chunk_size的设定值。接下来我们在RecursiveCharacterTextSplitter的分隔符列表中增加一个句号作为分隔符,我们再来看看分割的结果。

r_splitter = RecursiveCharacterTextSplitter(
    chunk_size=150,
    chunk_overlap=0,
    separators=["\n\n", "\n", "\. ", " ", ""]
)
r_splitter.split_text(some_text)

 

 这里我们看到文本被分割成了5段,并且是按双换行符\n\n和句号这两个分割符来分割的,只是句号出现在了各段的句首位置,这明显是错误的,句号应该是出现在上一段的句尾才对。下面我们调整一下分隔符列表中的正则表达式:

r_splitter = RecursiveCharacterTextSplitter(
    chunk_size=150,
    chunk_overlap=0,
    separators=["\n\n", "\n", "(?<=\. )", " ", ""]
)
r_splitter.split_text(some_text)

我们在分隔符列表中增加了正则表达式"(?<=\. )",它的意思是保证句号前面一定会存在字符,这样就避免了句号被保留在句首的情况。

接下来我们使用一个现实的pdf文件来实际测试一下文档分割功能:

from langchain.document_loaders import PyPDFLoader
loader = PyPDFLoader("docs/cs229_lectures/MachineLearning-Lecture01.pdf")
pages = loader.load()

这里我们使用langchain的PyPDFLoader文档加载器来加载pdf文件,它是按页来加载pdf文件的,也就是说如果原来pdf文件中一共有10页,那么在执行load()后生成的pages也包含了这10页:

len(pages)

 这里我们看到原pdf文档里一共有22页,我们加载好以后生成的pages对象的长度也是22。下面我们用CharacterTextSplitter来分割这个文档并设置如下参数:

  • separator="\n" : 设置单换行符作为分隔符
  • chunk_size=1000:设置块的大小为1000个字符
  • chunk_overlap=150:设置重叠字符为150个字符
  • length_function=len :长度函数设置为python的len函数
from langchain.text_splitter import CharacterTextSplitter

#创建分割器
text_splitter = CharacterTextSplitter(
    separator="\n",
    chunk_size=1000,
    chunk_overlap=150,
    length_function=len
)

#分割文档
docs = text_splitter.split_documents(pages)

下面我们看看分割好的文档docs包含多少段文档:

len(docs)

 我们看到原来22页的pdf文档经过分割后变成了77段的文档。

Token 分割

除了按字符分割以为,Langchain还提供了按token来分割文本的方法,所谓token可以理解为含义简单的最小词语单位,这里一个token大约由4个字符组成。因为大型语言模型(LLM),通常是以token的数量作为其计量(或收费)的依据。所以采用token分割也有助于我们在使用像chatGPT这样的LLM的同时更好的控制成本。下面我们看一个例子:

from langchain.text_splitter import TokenTextSplitter

text_splitter = TokenTextSplitter(chunk_size=1, chunk_overlap=0)

text1 = "foo bar bazzyfoo"

text_splitter.split_text(text1)

在使用token分割文本时英语中的一些非常用单词如这里的bazzyfoo会被分割成多个token,如这里将bazzyfoo分割成了4个token,它们分别是b, az, zy, foo。再看一个例子:

text2="what can I do for you ?"
text_splitter.split_text(text2)

 

 基本上常用的英语单词都会被分割成单独的token.下面我们将之前的pdf文档进行token分割:

text_splitter = TokenTextSplitter(chunk_size=10, chunk_overlap=0)

docs = text_splitter.split_documents(pages)

len(docs)

 这里我们将chunk_size设置为10,也就是说每一段里最多只保留10个token, 最后docs中包含了1557个chunk,且每个chunk中的token数量<=10. 下面我们查看一下docs中的内容:

docs[0]

docs[100]

这里我们看到docs里面的内容都很短,都不超过10个token。

 上下文感知分割(Context aware splitting)

对文本分割的目的旨在将具有共同语义的上下文的文本放在一起。文本分割通常使用句子或其他分隔符将相关文本保持在一起,但许多文档(例如 Markdown)具有可以在拆分中显式的结构(如标题)。我们可以使用 MarkdownHeaderTextSplitter 来保留块中的标题元数据:

from langchain.document_loaders import NotionDirectoryLoader
from langchain.text_splitter import MarkdownHeaderTextSplitter

markdown_document = """# Title\n\n \
## Chapter 1\n\n \
Hi this is Jim\n\n Hi this is Joe\n\n \
### Section \n\n \
Hi this is Lance \n\n 
## Chapter 2\n\n \
Hi this is Molly"""

headers_to_split_on = [
    ("#", "Header 1"),
    ("##", "Header 2"),
    ("###", "Header 3"),
]

markdown_splitter = MarkdownHeaderTextSplitter(
    headers_to_split_on=headers_to_split_on
)

md_header_splits = markdown_splitter.split_text(markdown_document)

这里我们设置了抽取指定标题(如标题1, 标题2,标题3) ,且同一标题内的的数据他们被放置在同一个块内.

md_header_splits[0]

md_header_splits[1]

 

这里我们可以看到MarkdownHeaderTextSplitter将同一标题下的文本放在了同一个块(chunk)中,而文本对应的标题信息则被存储在块的元数据中了。

总结

今天我们学习了文本的加载与分割,Langchain提供了丰富的外部数据加载器,这些外部数据可以是结构化的,也可以是非结构化的,其中我们还介绍了从网页和youtube视频中加载文本的方法,这个挺有意思的,大家可以尝试一下,由于外部数据量可能比较大,如pdf, text文档等,因此当我们加载了外部数据以后,我们还需要对数据进行分割处理,我们介绍了几种文本分割的方法,其中有按字符分割的CharacterTextSplitter分割器,和递归分割的RecursiveCharacterTextSplitter分割器。以及token分割器和markdown分割器,这里langchain默认使用RecursiveCharacterTextSplitter分割器,其中RecursiveCharacterTextSplitter默认使用一个分割符列表来分割数据,同时还要兼顾块的大小和重叠字符。

参考资料

PDF | 🦜️🔗 Langchain

Markdown | 🦜️🔗 Langchain

Recursively split by character | 🦜️🔗 Langchain

 Split by character | 🦜️🔗 Langchain

 Split by tokens | 🦜️🔗 Langchain

 MarkdownHeaderTextSplitter | 🦜️🔗 Langchain

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

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

相关文章

简单理解TCP,UDP,HTTP

我们都知道TCP、UDP、HTTP内部有很复杂的过程&#xff0c;很多人没办法理解的那么深&#xff0c;只想知道这是个什么鬼。 1、TCP、UDP、HTTP 是什么? TCP/IP是个协议组&#xff0c;可分为三个层次&#xff1a;网络层、传输层和应用层。在网络层有IP协议、ICMP协议、ARP协议、…

50 Matplotlib Visualizations, Python实现,源码可复现

详情请参考博客: Top 50 matplotlib Visualizations 因编译更新问题&#xff0c;本文将稍作更改&#xff0c;以便能够顺利运行。 0 Introduction 新建项目文件夹为matplotlib_visualizations&#xff0c;以下所有的.py文件均默认在该位置。 0.2 Setup Setup.py文件内容如下&…

(双指针) 剑指 Offer 57 - II. 和为s的连续正数序列 ——【Leetcode每日一题】

❓ 剑指 Offer 57 - II. 和为s的连续正数序列 难度&#xff1a;简单 输入一个正整数 target &#xff0c;输出所有和为 target 的连续正整数序列&#xff08;至少含有两个数&#xff09;。 序列内的数字由小到大排列&#xff0c;不同序列按照首个数字从小到大排列。 示例 1…

zookeeper的应用

Zookeeper的配置文件解析: Zookeeper内部原理: 选举机制 半数机制:在集群环境中半数以上的机器存活,这个集群可用,所以在设计Zookeeper集群系统时&#xff0c;通常会选择 奇数台服务器来搭建Zookeeper的集群 虽然在配置文件中并没有指定Master和Slave。但是&#xff0c;Zookeep…

【安全狗】linux免费服务器防护软件安全狗详细安装教程

在费用有限的基础上&#xff0c;复杂密码云服务器基础防护常见端口替换安全软件&#xff0c;可以防护绝大多数攻击 第一步&#xff1a;下载服务器安全狗Linux版&#xff08;下文以64位版本为例&#xff09; 官方提供了两个下载方式&#xff0c;本文采用的是 方式2 wget安装 方…

09.计算机网络——套接字编程

文章目录 网络字节序socket编程socket 常见APIsockaddr结构 UDP编程创建socket绑定socketsendto发送数据recvform接收数据关闭socket TCP编程创建socket绑定socketlisten监听套接字accept服务端接收连接套接字connect客户端连接套接字send发送数据recv接收数据关闭socket 工具n…

算法训练营第四十六天||● 139.单词拆分 ● 关于多重背包,你该了解这些! ● 背包问题总结篇!

● 139.单词拆分 这道题和完全背包一样&#xff0c;求排列数相当于 字符串相当于背包&#xff0c;字串相当于物品 注意find方法的使用 find&#xff08;s.begin(),s.end(),"zichuan") 还有s.substr的使用s.substr(起始位置&#xff0c;截取长度&#xff09; clas…

Stable Diffusion服务环境搭建(远程服务版)

Stable Diffusion服务环境搭建&#xff08;远程服务版&#xff09; Stable Diffusion是什么 Stable diffusion是一个基于Latent Diffusion Models&#xff08;潜在扩散模型&#xff0c;LDMs&#xff09;的文图生成&#xff08;text-to-image&#xff09;模型。具体来说&#…

ES6基础知识一:说说var、let、const之间的区别

一、var 在ES5中&#xff0c;顶层对象的属性和全局变量是等价的&#xff0c;用var声明的变量既是全局变量&#xff0c;也是顶层变量 注意&#xff1a;顶层对象&#xff0c;在浏览器环境指的是window对象&#xff0c;在 Node 指的是global对象 var a 10; console.log(window.…

VUE3---->基础入门

目录 vue 基础入门 1、解读核心关键词&#xff1a;框架 2、vue 的版本 3、vue 的调试工具 vue 基础入门 vite 的基本使用 1. 创建 vite 的项目 2. 梳理项目的结构 3. vite 项目的运行流程 组件的基本使用 1. 组件的注册 2. 组件之间的样式冲突问题 3. 组件的 props …

穿透内网群晖NAS实现远程访问【无公网IP】

穿透内网群晖NAS实现远程访问【无公网IP】 现代科技日新月异&#xff0c;我们身边的电子设备也在不断更新&#xff0c;日积月累之下&#xff0c;被淘汰的电子设备越来越多&#xff0c;难道就让这些性能不算差的电子设备从此闲置么&#xff0c;这明显不符合我们物尽其用的原则&a…

记录安装stable diffusion webui时,出现的gfpgan安装卡住的问题

参考链接&#xff1a;(145条消息) 使用stable diffusion webui时&#xff0c;安装gfpgan失败的解决方案&#xff08;windows下的操作&#xff09;_新时代原始人的博客-CSDN博客

[書籍]思考的框架

圖片來源:博客來書店 《思考的框架》是一本極具啟發性和實用性的書籍&#xff0c;它以系統性和綜合性的方式引導讀者運用跨學科思維來解決問題和拓展思維視野。作者巧妙地整合了來自不同領域的思想家和學者的觀點&#xff0c;從心理學到經濟學&#xff0c;從哲學到科學等&#…

docker安装jdk

文章目录 1.安装镜像2.查看已安装的镜像4.运行容器5.进入JDK 容器6.查看JDK版本 1.安装镜像 找到所要安装的镜像版本&#xff0c;复制命令 输入命令&#xff0c;下载openjdk8镜像 命令作用docker pull openjdk:8拉取版本号为8的镜像 2.查看已安装的镜像 命令作用docker ima…

指针大厂笔试真题讲解(c语言篇)

大家好&#xff0c;我是c语言boom家宝&#xff0c;今天为大家带来的是c语言指针内容在大厂笔试中的真题讲解&#xff0c;希望能让初学者对指针有更深入的理解。 ps&#xff1a;如有侵权&#xff0c;请私信联系&#xff0c;立刻删除。 真题一&#xff1a; 答案&#xff1a;2 &…

SpringCloud分布式项目下feign的使用

新建一个feign的微服务&#xff08;后面统称为A&#xff09;&#xff0c;其他项目要使用利用maven导入该服务模块的依赖就行了 导入依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</…

【C++】STL——list的使用和介绍、list的构造函数及其使用、list迭代器及其使用

文章目录 1.list的介绍和使用2.list的构造函数&#xff08;1&#xff09;list (size_type n, const value_type& val value_type()) &#xff08;2&#xff09;list() 构造空的list&#xff08;3&#xff09;list (const list& x) 拷贝构造函数&#xff08;4&#xff…

Spring Boot创建与运行

Spring Boot创建与运行 ​ 经过之前 Spring 文章的铺垫&#xff0c;终于来到了基于 Spring &#xff0c;并且也是 Spring 最火的框架之一 Spring Boot &#xff0c;在企业或者个人项目中&#xff0c;基本都是使用 Spring Boot &#xff0c;所以 Spring Boot 在 Spring 的学习阶…

Spring Boot 源码学习之@EnableAutoConfiguration注解

EnableAutoConfiguration 注解 引言主要内容1. EnableAutoConfiguration 功能解析1.1 常见的自动配置示例1.2 源码介绍 2. Import 注解介绍3. AutoConfigurationPackage 注解介绍 总结 引言 在 Huazie 的上篇博文中&#xff0c;我们详细了解了关于 SpringBootApplication 注解…

【论文阅读 03】机器学习算法在颈动脉斑块影像学分类中的研究进展

读完之后就是&#xff0c;总结 机器学习&#xff08;SVM、小波&#xff09;和深度学习&#xff08;CNN&#xff09;在 颈动脉斑块影像学中的 分类效果。只讨论了超声、磁共振两种成像 Chin J Clin Neurosci 临床神经科学杂志 复旦大学 颈动脉斑块( carotid plaques) 是一种…