医疗知识图谱的问答系统详解

news2025/1/14 23:27:14

一、项目介绍

该项目的数据来自垂直类医疗网站寻医问药,使用爬虫脚本data_spider.py,以结构化数据为主,构建了以疾病为中心的医疗知识图谱,实体规模4.4万,实体关系规模30万。schema的设计根据所采集的结构化数据生成,对网页的结构化数据进行xpath解析。

项目的数据存储采用Neo4j图数据库,问答系统采用了规则匹配方式完成,数据操作采用neo4j声明的cypher。

项目的不足之处在于疾病的引发原因、预防等以大段文字返回,这块可引入事件抽取,可将原因结构化表示出来。

项目主要文件目录如下:

├── QASystemOnMedicalKG
    ├── answer_search.py               # 问题查询及返回
    ├── build_medicalgraph.py          # 将结构化json数据导入neo4j
    ├── chatbot_graph.py               # 问答程序脚本
    ├── QASystemOnMedicalKG/data
        ├── hepatopathy.json           # 肝病知识数据
        ├── medical.json               # 全科知识数据
    ├── QASystemOnMedicalKG/dict
        ├── check.txt                  # 诊断检查项目实体库
        ├── deny.txt                   # 否定词库
        ├── department.txt             # 医疗科目实体库
        ├── disease.txt                # 疾病实体库
        ├── drug.txt                   # 药品实体库
        ├── food.txt                   # 食物实体库
        ├── producer.txt               # 在售药品库
        ├── symptom.txt                # 疾病症状实体库
    ├── QASystemOnMedicalKG/prepare_data
        ├── build_data.py              # 数据库操作脚本
        ├── data_spider.py             # 数据采集脚本
        ├── max_cut.py                 # 基于词典的最大前向/后向匹配
    ├── question_classifier.py         # 问句类型分类脚本
    ├── question_parser.py             # 问句解析脚本

二、爬虫部分

爬虫部分我没有实际操作,简单看了一下源码。

数据来源为寻医问药网的疾病百科 http://jib.xywy.com/ 。点入具体的疾病页面如下:

爬取疾病介绍页的简介、病因、预防、症状、检查、治疗、并发症、饮食保健等详情页的内容。

爬虫模块使用的是urllib库,数据存在MongoDB数据库中。

其中并发症使用了自己写的max_cut匹配脚本中的双向最大向前匹配max_biward_cut。

三、知识库部分

知识库包含7类规模为4.4万的知识实体,11类规模约30万实体关系,具体如下:

 

(注意:belongs_to包括 科室属于科室 和 疾病属于科室 两种关系)

(注意:疾病的属性还包括cure_department)

知识库的构建是通过build_medicalgraph.py脚本实现。

build_medicalgraph.py

该脚本构建了一个MedicalGraph类,定义了Graph类的成员变量g和json数据路径成员变量data_path。

class MedicalGraph:
    def __init__(self):
        cur_dir = '\\'.join(os.path.abspath(__file__).split('\\')[:-1])   # 获取当前绝对路径的上层目录 linux中应用'/'split和join
        self.data_path = os.path.join(cur_dir, 'data\hepatopathy.json')   # 获取json文件路径
        self.g = Graph(
            host="127.0.0.1",  # neo4j 搭载服务器的ip地址,ifconfig可获取到
            http_port=7474,  # neo4j 服务器监听的端口号
            user="neo4j",  # 数据库user name,如果没有更改过,应该是neo4j
            password="******")

类中的函数如下:

read_nodes函数: 读取数据文件
定义节点变量(list类型)
disease_infos包含了所有的疾病信息,为元素为disease_dict(dict类型)的list

定义节点实体关系变量(list类型)

逐行读取json数据,每行一个disease_dict(dict类型),包含疾病的各种属性(注意:除上述8种属性还有cure_department和symptom两种实体也列入疾病dict里)

对于json里的字典键,如果是疾病的属性,则加入disease_dict中:

disease_dict['desc'] = data_json['desc']

如果和疾病有关系,则加入对应的关系列表:

 for acompany in data_json['acompany']:
     rels_acompany.append([disease, acompany])

如果是某个其他实体,则加入对应的实体列表:

check = data_json['check']
checks += check

注意:

symptoms既是疾病的属性,又有疾病—症状的关系。

cure_department在json中有两种形式,除了添加cure_department属性到disease_dict实体字典里和departments实体列表里。还需要提取关系,如果只有一个科室则直接提取疾病—科室关系(rels_category),如果有两个科室,还需要提取科室—科室关系(rels_department)。

        if 'cure_department' in data_json:
            cure_department = data_json['cure_department']
            if len(cure_department) == 1:
                 rels_category.append([disease, cure_department[0]])
            if len(cure_department) == 2:
                big = cure_department[0]
                small = cure_department[1]
                rels_department.append([small, big])      # 提取科室——科室关系
                rels_category.append([disease, small])

            disease_dict['cure_department'] = cure_department
            departments += cure_department

drug_details的形式为"drug_detail" : [ "惠普森穿心莲内酯片(穿心莲内酯片)", "北京同仁堂百咳静糖浆(百咳静糖浆)"],即包括药品名和生产厂商,因为字符串和括号的原因,提取药品—在售药品的关系的方式略有不同:

        if 'drug_detail' in data_json:
            drug_detail = data_json['drug_detail']
            producer = [i.split('(')[0] for i in drug_detail]
            rels_drug_producer += [[i.split('(')[0], i.split('(')[-1].replace(')', '')] for i in drug_detail]
            producers += producer

函数返回set去重后的所有实体、疾病属性信息和实体间关系。

create_graphnodes函数:创建知识图谱实体节点类型schema

首先调用read_nodes函数得到存储实体和实体间关系的变量。

知识图谱中主要包含两类节点,一类为中心疾病节点,包含各种疾病属性;一类为普通实体节点,即药品、食物等,不包含属性,分别调用以下两个函数创建:

create_diseases_nodes函数:创建知识图谱中心疾病的节点

对每一条disease_infos,调用py2neo库中Graph类的create函数,在neo4j中创建label为"Disease"的Node,disease_dict中的属性即为节点中的属性。

node = Node("Disease", name=disease_dict['name'], desc=disease_dict['desc'],
                        prevent=disease_dict['prevent'] ,cause=disease_dict['cause'],
                        easy_get=disease_dict['easy_get'],cure_lasttime=disease_dict['cure_lasttime'],
                        cure_department=disease_dict['cure_department']
                        ,cure_way=disease_dict['cure_way'] , cured_prob=disease_dict['cured_prob'])
self.g.create(node)

create_node函数:创建普通实体节点模块

对每一类实体,在neo4j中创建label为实体类别,name为具体实体名称的节点。

        for node_name in nodes:
            node = Node(label, name=node_name)
            self.g.create(node)

create_graphrels函数:创建实体关系边

同样调用read_nodes函数得到存储实体和实体间关系的变量。

再对模块函数create_relationship传入不同的变量参数,创建11类实体关系边。

create_relationship函数:创建实体关联边模块

首先对存储实体关系的list变量进行去重,因为实体关系为形如[[“a”,“b”],[“c”,“d”]]的嵌套list,无法直接用set去重,所以先将嵌套内层的list转为字符串,再用set。

去重后调用py2neo库中Graph类的run函数,使用Cypher语言直接执行Neo4j CQL语句,对每一对实体关系在neo4j里创建边:

query = "match(p:%s),(q:%s) where p.name='%s'and q.name='%s' create (p)-[rel:%s{name:'%s'}]->(q)" % (
                start_node, end_node, p, q, rel_type, rel_name)
try:
    self.g.run(query)
    count += 1
    print(rel_type, count, all)
except Exception as e:
    print(e)

export_data函数:导出数据到txt

调用read_nodes函数得到存储实体和实体间关系的变量。
逐行写入各变量对应的txt。

四、问答部分

问答系统支持的问答类型

 本项目的问答系统完全基于规则匹配实现,通过关键词匹配,对问句进行分类,医疗问题本身属于封闭域类场景,对领域问题进行穷举并分类,然后使用cypher的match去匹配查找neo4j,根据返回数据组装问句回答,最后返回结果。

问答框架的构建是通过chatbot_graph.py、answer_search.py、question_classifier.py、question_parser.py等脚本实现。

chatbot_graph.py

首先从需要运行的chatbot_graph.py文件开始分析。

该脚本构造了一个问答类ChatBotGraph,定义了QuestionClassifier类型的成员变量classifier、QuestionPase类型的成员变量parser和AnswerSearcher类型的成员变量searcher。

class ChatBotGraph:
    def __init__(self):
        self.classifier = QuestionClassifier()
        self.parser = QuestionPaser()
        self.searcher = AnswerSearcher()

该问答类的成员函数仅有一个chat_main函数

chat_main函数

首先传入用户输入问题,调用self.classifier.classify进行问句分类,如果没有对应的分类结果,则输出模板句式。如果有分类结果,则调用self.parser.parser_main对问句进行解析,再调用self.searcher.search_main查找对应的答案,如果有则返回答案,如果没有则输出模板句式。

def chat_main(self, sent):
    answer = '您好,我是肝病问答小助手,希望可以帮到您。祝您身体棒棒!'
    res_classify = self.classifier.classify(sent)
    if not res_classify:
        return answer
    res_sql = self.parser.parser_main(res_classify)
    final_answers = self.searcher.search_main(res_sql)
    if not final_answers:
        return answer
    else:
        return '\n'.join(final_answers)

由此可以看出,问答框架包含问句分类、问句解析、查询结果三个步骤,具体一步步分析。

首先是问句分类,是通过question_classifier.py脚本实现的。

question_classifier.py

该脚本构造了一个问题分类的类QuestionClassifier,定义了特征词路径、特征词、领域actree、词典、问句疑问词等成员变量。

特征词除了7类实体还包括由全部7类实体词构成的领域词region_words、否定词库deny_words。

构建领域actree通过调用self.build_actree实现。

构建词典通过调用self.build_wdtype_dict()实现。

问句疑问词包含了疾病的属性和边相关的问题词,参考上文中问答系统支持的问答类型

build_actree函数

该函数构建领域actree,加速过滤。通过python的ahocorasick库实现。

ahocorasick是一种字符串匹配算法,由两种数据结构实现:trie和Aho-Corasick自动机。

Trie是一个字符串索引的词典,检索相关项时时间和字符串长度成正比。

AC自动机能够在一次运行中找到给定集合所有字符串。AC自动机其实就是在Trie树上实现KMP,可以完成多模式串的匹配。

具体ahocorasick用法非本文重点,可参考https://blog.csdn.net/pirage/article/details/51657178等博文。

    def build_actree(self, wordlist):
        actree = ahocorasick.Automaton()         # 初始化trie树
        for index, word in enumerate(wordlist):
            actree.add_word(word, (index, word))     # 向trie树中添加单词
        actree.make_automaton()    # 将trie树转化为Aho-Corasick自动机
        return actree

build_wdtype_dict函数

该函数根据7类实体构造 {特征词:特征词对应类型} 词典。

wd_dict = dict()
for wd in self.region_words:
    wd_dict[wd] = []
    if wd in self.disease_wds:
        wd_dict[wd].append('disease')
        ...

check_medical函数

通过ahocorasick库的iter()函数匹配领域词,将有重复字符串的领域词去除短的,取最长的领域词返回。功能为过滤问句中含有的领域词,返回{问句中的领域词:词所对应的实体类型}。

def check_medical(self, question):
    region_wds = []
    for i in self.region_tree.iter(question):   # ahocorasick库 匹配问题  iter返回一个元组,i的形式如(3, (23192, '乙肝'))
        wd = i[1][1]      # 匹配到的词
        region_wds.append(wd)
    stop_wds = []
    for wd1 in region_wds:
        for wd2 in region_wds:
            if wd1 in wd2 and wd1 != wd2:
                stop_wds.append(wd1)       # stop_wds取重复的短的词,如region_wds=['乙肝', '肝硬化', '硬化'],则stop_wds=['硬化']
    final_wds = [i for i in region_wds if i not in stop_wds]     # final_wds取长词
    final_dict = {i:self.wdtype_dict.get(i) for i in final_wds}
    return final_dict

check_word函数

该函数检查问句中是否含有某实体类型内的特征词。

def check_words(self, wds, sent):
    for wd in wds:
        if wd in sent:
            return True
    return False

classify函数

该函数为分类主函数。

首先调用check_medical函数,获取问句中包含的领域词及其所在领域,并收集问句当中所涉及到的实体类型;

接着基于特征词进行分类,即调用check_word函数,看问句中是否包含某领域特征词,以及该领域是否在问句中包含的region_words的实体类型(types)里,以此来判断问句属于哪种类型。(好绕)

示例如下:

# 症状
if self.check_words(self.symptom_qwds, question) and ('disease' in types):
    question_type = 'disease_symptom'
    question_types.append(question_type)

if self.check_words(self.symptom_qwds, question) and ('symptom' in types):
    question_type = 'symptom_disease'
    question_types.append(question_type)
#已知食物找疾病
if self.check_words(self.food_qwds+self.cure_qwds, question) and 'food' in types:
    deny_status = self.check_words(self.deny_words, question)
    if deny_status:
        question_type = 'food_not_disease'
    else:
        question_type = 'food_do_disease'
    question_types.append(question_type)

如果没有查到若没有查到相关的外部查询信息,且类型为疾病,那么则将该疾病的描述信息返回(question_types = ['disease_desc']);若类型为症状,那么则将该症状的对应的疾病信息返回(question_types = ['symptom_disease'])。

然后将分类结果进行合并处理,组装成一个字典返回。

注意:

  • 食物相关的问题需要检查否定词self.deny_words来判断是do_eat还是not_eat。
  • 已知食物找疾病和已知检查项目查相应疾病的时候,check_words需要加上self.cure_qwds。

question_parser.py

问句分类后需要对问句进行解析。

该脚本创建一个QuestionPaser类,该类包含三个成员函数。

build_entitydict函数

例如:从分类结果的{'args': {'头痛': ['disease', 'symptom']}, 'question_types': ['disease_cureprob']}中获取args,返回{'disease': ['头痛'], 'symptom': ['头痛']}的形式。

sql_transfer函数

该函数真的不同的问题类型,转换为Cypher查询语言并返回。
例如:

# 查询疾病的原因
if question_type == 'disease_cause':
    sql = ["MATCH (m:Disease) where m.name = '{0}' return m.name, m.cause".format(i) for i in entities]

# 查询疾病的忌口

elif question_type == 'disease_not_food':
    sql = ["MATCH (m:Disease)-[r:no_eat]->(n:Food) where m.name = '{0}' return m.name, r.name, n.name".format(i) for i in entities]

注意:

查询可能为查询中心疾病节点的属性,也可能为查询关联边。
疾病的并发症需要双向查询。
建议吃的东西包括do_eat和recommand_eat两种关联边。
查询药品相关记得扩充药品别名,包括common_drug和recommand_durg两种关联边。
parser_main函数
该函数为问句解析主函数。
首先传入问句分类结果,获取问句中领域词及其实体类型。
接着调用build_entitydict函数,返回形如{'实体类型':['领域词'],...}的entity_dict字典。
然后对问句分类返回值中[‘question_types’]的每一个question_type,调用sql_transfer函数转换为neo4j的Cypher语言。
最后组合每种question_type转换后的sql查询语句。

answer_search.py
问句解析之后需要对解析后的结果进行查询。
该脚本创建了一个AnswerSearcher类。与build_medicalgraph.py类似,该类定义了Graph类的成员变量g和返回答案列举的最大个数num_list。
该类的成员函数有两个,一个查询主函数一个回复模块。

search_main函数
传入问题解析的结果sqls,将保存在queries里的[‘question_type’]和[‘sql’]分别取出。
首先调用self.g.run(query).data()函数执行[‘sql’]中的查询语句得到查询结果,
再根据[‘question_type’]的不同调用answer_prettify函数将查询结果和答案话术结合起来。
最后返回最终的答案。

answer_prettify函数
该函数根据对应的qustion_type,调用相应的回复模板。
示例如下:

elif question_type == 'disease_cause':
    desc = [i['m.cause'] for i in answers]
    subject = answers[0]['m.name']
    final_answer = '{0}可能的成因有:{1}'.format(subject, ';'.join(list(set(desc))[:self.num_limit]))

五、改进

1. 缺失实体填充

在用户连续提问的时候,缺失使用上轮对话的疾病,如:

用户:乙肝怎么治
小助手: 乙肝可以尝试如下治疗:药物治疗;支持性治疗;对症治疗
用户:那有什么忌口吗
小助手: 乙肝忌食的食物包括有:咸鱼;咸鸭蛋;鸭血(白鸭);啤酒

这里用户的第二个问题没有疾病实体,默认采用上一轮的疾病实体。

方法是在question_classifier.py的check_medical函数里增加全局变量:

global diseases_dict
if final_dict:
    diseases_dict = final_dict

并在classify函数里判断:

if not medical_dict:
    if 'diseases_dict' in globals():    # 判断是否是首次提问,若首次提问,则diseases_dict无值
        medical_dict = diseases_dict
    else:
        return {}

2. 增加疾病属性can_eat

增加了一个疾病属性:can_eat,对应增加了一个问题分类:

# 推荐食品
if self.check_words(self.food_qwds, question) and 'disease' in types:
    deny_status = self.check_words(self.deny_words, question)
    if deny_status:
        question_type = 'disease_not_food'
    else:
        question_type = 'disease_do_food'
    if self.check_words(['能吃','能喝','可以吃','可以喝'], question):
        question_types.append('disease_can_eat')
    print(question_type)
    question_types.append(question_type)

从构建知识图谱到问句分类、问句解析、查询结果也需作出相应修改。

3.补充个别问句疑问词

使覆盖的问句更全,详见修改版github。

六、总结

基于规则的问答系统没有复杂的算法,一般采用模板匹配的方式寻找匹配度最高的答案,回答结果依赖于问句类型、模板语料库的覆盖全面性,面对已知的问题,可以给出合适的答案,对于模板匹配不到的问题或问句类型,经常遇到的有三种回答方式:

  1. 给出一个无厘头的答案;
  2. 婉转的回答不知道,提示用户换种方式去问;
  3. 转移话题,回避问题;

基于知识图谱的问答系统的主要特征是知识图谱,系统依赖一个或多个领域的实体,并基于图谱进行推理或演绎,深度回答用户的问题,基于知识图谱的问答系统更擅长回答知识性问题,与基于模板的聊天机器人有所不同的是它更直接、直观的给用户答案。对于不能回答、或不知道的问题,一般直接返回失败,而不是转移话题避免尴尬。

整个问答系统的优劣依赖于知识图谱中知识的数量与质量。也算是利弊共存吧!知识图谱图谱具有良好的可扩展性,扩展了知识图谱也就是扩展了问答系统的知识库。如果问句在射程范围内,可轻松回答,但如果不幸脱靶,则体验大打折扣。

从知识图谱的角度分析,大多数知识图谱规模不足,主要原因还是数据来源以及技术上知识的抽取与推理困难。

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

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

相关文章

上传镜像docker hub登不上和docker desktop的etx4.vhdx占用空间很大等解决办法

平时使用docker一般都在Linux服务器上,但这次需要将镜像上传到docker hub上,但是服务器上一直无法登录本人的账号,(这里的问题应该docker 网络配置中没有开代理的问题,因服务器上有其他用户使用,不可能直接…

大型复杂项目管理怎么结合传统与敏捷

大型复杂项目管理需要综合运用传统的瀑布模型与敏捷方法,两者各具优势,可以在不同的项目阶段和需求下发挥最大效能。首先,在项目的初期阶段,传统方法的详细规划和需求分析能够帮助确保项目方向正确、资源充足;敏捷方法…

PVE中VLAN的设置要点

使用这个拓扑进行连接无法直接访问PVE PVE 设置如下: 核心重点:PVE 的 vmbr0 接口直接绑定了 enp2s0,这会导致 VLAN 流量无法正确处理,因为 PVE 没有专门为 VLAN 3 配置接口。 1.vmbr0 和 vmbr0.3 都是绑定在物理接口 enp2s0 上&…

网络安全防范技术

1 实践内容 1.1 安全防范 为了保障"信息安全金三角"的CIA属性、即机密性、完整性、可用性,信息安全领域提出了一系列安全模型。其中动态可适应网络安全模型基于闭环控制理论,典型的有PDR和P^2DR模型。 1.1.1 PDR模型 信息系统的防御机制能抵抗…

.net —— Razor

文章目录 项目地址一、创建一个Razor项目1.1 创建项目1.2 创建项目所需文件夹1.3 配置项目二、创建Category页面2.1 创建Category的展示页面2.2 增删改2.2.1 创建Edit的razor视图项目地址 教程作者:教程地址:代码仓库地址:所用到的框架和插件:dbt airflow一、创建一个Razo…

学习视频超分辨率扩散模型中的空间适应和时间相干性(原文翻译)

文章目录 摘要1. Introduction2. Related Work3. Our Approach3.1. Video Upscaler3.2. Spatial Feature Adaptation Module3.3. Temporal Feature Alignment Module3.4. Video Refiner3.5. Training Strategy 4. Experiments4.1. Experimental Settings4.2. Comparisons with …

Netty的心跳机制怎么实现的?

大家好,我是锋哥。今天分享关于【Netty的心跳机制怎么实现的?】面试题。希望对大家有帮助; Netty的心跳机制怎么实现的? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Netty 的心跳机制用于维持客户端和服务器之间的…

深度学习:自然语言处理

一、引言 自然语言处理作为人工智能领域的关键分支,致力于使计算机能够理解、分析和生成人类语言。近年来,随着深度学习技术的迅猛发展,自然语言处理取得了前所未有的突破,一系列创新技术和应用不断涌现,极大地推动了…

Android 系统之Init进程分析

1、Init进程流程 2、Init细节逻辑 2.1 Init触发shutdown init进程触发系统重启是一个很合理的逻辑,为什么合理? init进程是android世界的一切基石,如果android世界的某些服务或者进程出现异常,那么会导致整个系统无法正常使用…

轻量化的长时间序列预测模型

✨✨ 欢迎大家来访Srlua的博文(づ ̄3 ̄)づ╭❤~✨✨ 🌟🌟 欢迎各位亲爱的读者,感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢,在这里我会分享我的知识和经验。&am…

【Vue3】从零开始创建一个VUE项目

【Vue3】从零开始创建一个VUE项目 手动创建VUE项目附录 package.json文件报错处理: Failed to get response from https://registry.npmjs.org/vue-cli-version-marker 相关链接: 【VUE3】【Naive UI】<NCard> 标签 【VUE3】【Naive UI】&…

win10中使用ffmpeg的filter滤镜

1 给视频加文字水印 1.1 添加播放时间 ffmpeg -i input.mp4 -vf "drawtextfontfileC\\:/Windows/fonts/consola.ttf:fontsize30:fontcolorwhite:timecode00\:00\:00\:00:rate25:textTCR\::boxcolor0x000000AA:box1:x20:y20" -y output.mp4 在视频的x20:y20位置添加t…

【AI系统】昇腾 AI 架构介绍

昇腾 AI 架构介绍 昇腾计算的基础软硬件是产业的核⼼,也是 AI 计算能⼒的来源。华为,作为昇腾计算产业⽣态的⼀员,是基础软硬件系统的核⼼贡献者。昇腾计算软硬件包括硬件系统、基础软件和应⽤使能等。 而本书介绍的 AI 系统整体架构&#…

Pareidoscope - 语言结构关联工具

文章目录 关于 Pareidoscope安装使用方法输入格式语料库查询 将语料库转换为 SQLite3 数据库两种语言结构之间的关联简单词素分析关联共现和伴随词素分析相关的更大结构可视化关联结构 关于 Pareidoscope Pareidoscope 是一组 用于确定任意语言结构之间 关联的工具&#xff0c…

安装MySQL 5.7 亲测有效

前言:本文是笔者在安装MySQL5.7时根据另一位博主大大的安装教程基础上做了一些修改而成 首先在这里表示对博主大大的感谢 下面附博主大大地址 下面的步骤言简意赅 跟着做就不会出错 希望各位读者耐下心来 慢慢解决安装中出现的问题~MySQL 5.7 安装教程(全…

眼部按摩仪WT2605音频蓝牙语音芯片方案 单芯片实现语音提示及控制/手机无线音频传输功能

随着科技的快速发展,人们的生活方式也在不断改变,智能化、便捷化的产品逐渐成为市场的主流。眼部按摩仪作为一种结合了现代科技与健康生活理念的产品,受到了广大消费者的青睐。而在众多眼部按摩仪中,采用WT2605音频蓝牙芯片的方案…

RK3568平台开发系列讲解(PWM篇)PWM 子系统框架

🚀返回专栏总目录 文章目录 一、PWM 设备驱动层二、PWM 核心层三、PWM 适配器驱动层沉淀、分享、成长,让自己和他人都能有所收获!😄 📢整个 PWM 子系统可以用下面的框图来描述: 再上图中 PWM 子系统被划分为了三个层次, 分别为用户空间、 内核空间和硬件层, 内核空…

使用ESP32通过Arduino IDE点亮1.8寸TFT显示屏

开发板选择 本次使用开发板模块丝印为ESP32-WROOM-32E 开发板库选择 Arduino IDE上型号选择为ESP32-WROOM-DA Module 显示屏选择 使用显示屏为8针SPI接口显示屏 驱动IC为ST7735S 使用库 使用三个Arduino平台库 分别是 Adafruit_GFXAdafruit_ST7735SPI 代码详解 首…

yolo辅助我们健身锻炼

使用软件辅助健身能够大大提升运动效果并帮助你更轻松地达成健身目标。确保每次锻炼都更加高效且针对性强,精确记录你的训练进度,帮助你更清晰地看到自己的进步,避免无效训练。 借助YOLO11的尖端计算机视觉技术,跟踪和分析锻炼变得异常简单。它可以无缝检测和监控多种锻炼…

YOLO系列论文综述(从YOLOv1到YOLOv11)【第12篇:YOLOv9——可编程梯度信息(PGI)+广义高效层聚合网络(GELAN)】

YOLOv9 1 摘要2 改进点3 网络架构 YOLO系列博文: 【第1篇:概述物体检测算法发展史、YOLO应用领域、评价指标和NMS】【第2篇:YOLO系列论文、代码和主要优缺点汇总】【第3篇:YOLOv1——YOLO的开山之作】【第4篇:YOLOv2—…