旅途——参考博客
Sampler.
DataLoader.
plt.rcParams参数详解.
yield .
argparse .
Neo4j入门教程.
python_neo4j.
py2neo简单教程.
旅途——部分函数解析
DataLoader()
DataLoader本质上就是一个iterable(跟python的内置类型list等一样),并利用多进程来加速batch data的处理,使用yield来使用有限的内存
plt.rcParams()
yield:
具体看博客链接;我自己总结了一下,相当于就是一个return,但是还能继续执行;其本质是一个iterator,实现了既节约内存又能在函数中返回中间结果的功能。
argparse — 命令行选项、参数和子命令解析器
argparse 模块可以让人轻松编写用户友好的命令行接口。程序定义它需要的参数,然后 argparse 将弄清如何从 sys.argv 解析出那些参数。 argparse 模块还会自动生成帮助和使用手册,并在用户给程序传入无效参数时报出错误信息。
if __name = "__main__"
parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('integers', metavar='N', type=int, nargs='+',
help='an integer for the accumulator')
parser.add_argument('--sum', dest='accumulate', action='store_const',
const=sum, default=max,
help='sum the integers (default: find the max)')
args = parser.parse_args()
print(args.accumulate(args.integers))
旅途——思路
将Bert-Bilstm-CRF得到的预测的string和flag导入neo4j进行查询,得到多个子图,然后将这些子图与问题的实体进行相似度计算,进行排序,找到最接近的。
首先需要连接neo4j数据库,接下来需要解决的问题就是连接构建好的neo4j数据库。
旅途——连接Neo4j
首先去官方网站下载neo4j的包,在这之前需要下载好JDK11(目前好像就只有这个版本的JDK支持neo4j)
接下来是学习Neo4j的record.值得一提的是Neo4j使用的是Cypher语言(听说内部使用Java 实现的),可以在Python里面嵌入Cypher。
- 删除数据库中的图,确保一个空白的环境进行操作
'''
这里,MATCH是匹配操作,而小括号()代表一个节点node
(可理解为括号类似一个圆形),括号里面的n为标识符。
'''
MATCH (n) DETACH DELETE n
- 接着,我们创建一个人物节点:
'''
CREATE是创建操作,Person是标签,代表节点的类型。花括号{}代表节点的属性,属性类似Python的字典。
这条语句的含义就是创建一个标签为Person的节点,该节点具有一个name属性,属性值是John。
'''
CREATE (n:Person {name:'John'}) RETURN n
- 我们继续来创建更多的人物节点,并分别命名:
'''
注意后面的‘;’,Otherwise,会报错!!!
'''
CREATE (n:Person {name:'Sally'}) RETURN n;
CREATE (n:Person {name:'Steve'}) RETURN n;
CREATE (n:Person {name:'Mike'}) RETURN n;
CREATE (n:Person {name:'Liz'}) RETURN n;
CREATE (n:Person {name:'Shawn'}) RETURN n;
- 接下来创建地区节点
'''
注意';'! 注意';'! 注意';'! (three times)
'''
CREATE (n:Location {city:'Miami', state:'FL'});
CREATE (n:Location {city:'Boston', state:'MA'});
CREATE (n:Location {city:'Lynn', state:'MA'});
CREATE (n:Location {city:'Portland', state:'ME'});
CREATE (n:Location {city:'San Francisco', state:'CA'});
- 接下来创建关系
'''
在关系中,同样的使用花括号{}来增加关系的属性,也是类似Python的字典,
这里给FRIENDS关系增加了since属性,属性值为2001,表示他们建立朋友关系的时间。
'''
MATCH (a:Person {name:'Liz'}),
(b:Person {name:'Mike'})
MERGE (a)-[:FRIENDS]->(b)
- 关系也可以增加属性
'''
在关系中,同样的使用花括号{}来增加关系的属性,也是类似Python的字典,
这里给FRIENDS关系增加了since属性,属性值为2001,表示他们建立朋友关系的时间。
'''
MATCH (a:Person {name:'Shawn'}),
(b:Person {name:'Sally'})
MERGE (a)-[:FRIENDS {since:2001}]->(b)
- 接下来增加更多的关系
MATCH (a:Person {name:'Shawn'}), (b:Person {name:'John'}) MERGE (a)-[:FRIENDS {since:2012}]->(b);
MATCH (a:Person {name:'Mike'}), (b:Person {name:'Shawn'}) MERGE (a)-[:FRIENDS {since:2006}]->(b);
MATCH (a:Person {name:'Sally'}), (b:Person {name:'Steve'}) MERGE (a)-[:FRIENDS {since:2006}]->(b);
MATCH (a:Person {name:'Liz'}), (b:Person {name:'John'}) MERGE (a)-[:MARRIED {since:1998}]->(b);
- 然后,我们需要建立不同类型节点之间的关系-人物和地点的关系
'''
这里的关系是BORN_IN,表示出生地,同样有一个属性,表示出生年份。
'''
MATCH (a:Person {name:'John'}), (b:Location {city:'Boston'}) MERGE (a)-[:BORN_IN {year:1978}]->(b)
- 同样建立更多人的出生地
MATCH (a:Person {name:'Liz'}), (b:Location {city:'Boston'}) MERGE (a)-[:BORN_IN {year:1981}]->(b)
MATCH (a:Person {name:'Mike'}), (b:Location {city:'San Francisco'}) MERGE (a)-[:BORN_IN {year:1960}]->(b)
MATCH (a:Person {name:'Shawn'}), (b:Location {city:'Miami'}) MERGE (a)-[:BORN_IN {year:1960}]->(b)
MATCH (a:Person {name:'Steve'}), (b:Location {city:'Lynn'}) MERGE (a)-[:BORN_IN {year:1970}]->(b)
创建好的知识图谱如下图所示:
10. 至此,知识图谱的数据已经插入完毕,可以开始做查询了。我们查询下所有在Boston出生的人物
MATCH (a:Person)-[:BORN_IN]->(b:Location {city:'Boston'}) RETURN a,b
11. 查询所有对外有关系的节点
'''
注意这里箭头的方向,返回结果不含任何地区节点,
因为地区并没有指向其他节点(只是被指向)
'''
MATCH (a)-->() RETURN a
12. 查询所有有关系的节点
MATCH (a)--() RETURN a
13. 查询所有对外有关系的节点,以及关系类型
MATCH (a)-[r]->() RETURN a.name, type(r)
14. 查询所有有结婚关系的节点
MATCH (n)-[:MARRIED]-() RETURN n
- 创建节点的时候就建好关系
CREATE (a:Person {name:'Todd'})-[r:FRIENDS]->(b:Person {name:'Carlos'})
16. 查找某人的朋友的朋友
MATCH (a:Person {name:'Mike'})-[r1:FRIENDS]-()-[r2:FRIENDS]-(friend_of_a_friend) RETURN friend_of_a_friend.name AS fofName
17. 增加/修改节点的属性
'''
这里,SET表示修改操作
'''
MATCH (a:Person {name:'Liz'}) SET a.age=34
MATCH (a:Person {name:'Shawn'}) SET a.age=32
MATCH (a:Person {name:'John'}) SET a.age=44
MATCH (a:Person {name:'Mike'}) SET a.age=25
- 删除节点的属性
'''
删除属性操作主要通过REMOVE
'''
MATCH (a:Person {name:'Mike'}) SET a.test='test'
MATCH (a:Person {name:'Mike'}) REMOVE a.test
- 删除节点
'''删除节点操作是DELETE'''
MATCH (a:Location {city:'Portland'}) DELETE a
- 删除有关系的节点
MATCH (a:Person {name:'Todd'})-[rel]-(b:Person) DELETE a,b,rel
旅途——neo4j与Python
neo4j模块:执行CQL ( cypher ) 语句
'''
这里需要注意的是:看到print_friends()函数中,第一行的$name后边是有一个空格的,这个一定要注意。
我刚开始运行手敲,没注意看,一直报错;空格!空格!空格!
'''
# step 1:导入 Neo4j 驱动包
from neo4j import GraphDatabase
# step 2:连接 Neo4j 图数据库
driver = GraphDatabase.driver("bolt://localhost:7687", auth=("neo4j", "password"))
# 添加 关系 函数
def add_friend(tx, name, friend_name):
tx.run("MERGE (a:Person {name: $name}) "
"MERGE (a)-[:KNOWS]->(friend:Person {name: $friend_name})",
name=name, friend_name=friend_name)
# 定义 关系函数
def print_friends(tx, name):
for record in tx.run("MATCH (a:Person)-[:KNOWS]->(friend) WHERE a.name = $name "
"RETURN friend.name ORDER BY friend.name", name=name):
print(record["friend.name"])
# step 3:运行
with driver.session() as session:
session.write_transaction(add_friend, "Arthur", "Guinevere")
session.write_transaction(add_friend, "Arthur", "Lancelot")
session.write_transaction(add_friend, "Arthur", "Merlin")
session.read_transaction(print_friends, "Arthur")
上述程序的核心部分,抽象一下就是:
neo4j.GraphDatabase.driver(xxxx).session().write_transaction(函数(含tx.run(CQL语句)))
or
neo4j.GraphDatabase.driver(xxxx).session().begin_transaction.run(CQL语句)
py2neo模块:通过操作python变量,达到操作neo4j的目的
# step 1:导包
from py2neo import Graph, Node, Relationship
# step 2:构建图
g = Graph()#这里按照自己的localhost,auth进行配置
#例如:graph = Graph("http://localhost:7474",auth=("neo4j","password"))
# step 3:创建节点
tx = g.begin()
a = Node("Person", name="Alice")
tx.create(a)
b = Node("Person", name="Bob")
# step 4:创建边
ab = Relationship(a, "KNOWS", b)
# step 5:运行
tx.create(ab)
tx.commit()
py2neo模块符合python的习惯,写着感觉顺畅,其实可以完全不会CQL也能写
旅途——通过csv文件批量导入图数据
本来是想先做NER,然后NER在图数据库中进行查询子图,最后通过这些子图与原来的问题进行语义相似度分析,但是知识图谱的数据问题以及时间问题,这个想法只能放下了,其实刚开始这样的时候,整个人都炸了,看了这么长时间的NER结果用不了,是吧。
下面就是使用BERT实现一个语义分析的过程,直接使用FQA的方式,做一个自动问答系统。
学习笔记
思路
首先对数据进行预处理;
将问题放到 q_list这样一个列表中
将答案放大 a_list这样一个列表中
使用NLTK的停用词本加上自己设定的标点符号
将每一个问题拆成一个一个的子,并使用前面的工具去除掉中间的停用词和标点符号;这里我将清理之后的问题存放到了列表:clean_q_list当中,并且列表中的每一个单元就是一个问题,与原来问题和答案的下标依然是一一对应的。
整体思路:
首先得到query,然后对这个query进行clean等数据整理操作,接着到构建好的相似表中去寻找最相似的几个问题。接着将similar_question与原来的query连接起来作为一个句子把他作为bert模型的输入;接着使用余弦距离公式计算其中的距离,找到最好的5个问题,最后返回这五个问题的答案。
参考博客
collections.Counter.
Python读取txt文件.
函数解析
Python collections.Counter用法
Ex:
#统计词频
colors = ['red', 'blue', 'red', 'green', 'blue', 'blue']
result = {}
for color in colors:
if result.get(color)==None:
result[color]=1
else:
result[color]+=1
print (result)
#{'red': 2, 'blue': 3, 'green': 1}
Counter:
from collections import Counter
colors = ['red', 'blue', 'red', 'green', 'blue', 'blue']
c = Counter(colors)
print (dict(c))
思路
首先使用爬虫去网络上爬下来一些关于麻将问答的数据(中文)
然后,对这些"脏"数据进行清理,得到正确问题与答案的数据,保存为.csv文件
接着,将问题存储到q_list.csv,答案存储到a_list.csv;这样它们的下标是一一对应的;方便匹配到问题后,可以直接返回答案,
接着将所有的问题句子输入到训练好的NER模型,这里我使用的是之前训练好的Bert-Bilstm-CRF模型,这样每个问题就变成了一些实体;(目的是为了提高计算相似度时的准确度)
接着把这些实体分别用空格隔开,最后存储到txt文件中,然后使用Glove向量将这些语料进行训练得到一个训练好的Glove词向量模型;
将爬下来的数据一部分作为训练数据,一部分作为测试数据;
将训练好的词向量模型中的所有词语,计算它们分别与哪些词语是近似的;然后,得到一个倒序表,将每个词语其相关联的问题与它建立一个字典或者序列。
对于每个询问的问题,将其进行初始化后,首先确定它的相似单词,然后通过倒序表找到它的相似问题;最后将它的query与它的所有相似问题通过bert的wordEmbbeding并使用余弦距离公式计算其相似度,最后找到最相似的5个答案,最后将这5个答案返回。
Python读取txt文件
f = open("data.txt","r") #设置文件对象
data = f.readlines() #直接将文件中按行读到list里,效果与方法2一样
f.close() #关闭文件
毕设叙述
首先我的work由两个模块组成:1.命名实体识别模型 2. 语义相似度计算模型
首先是第一个模型:
理论:对于命名实体识别模型,这里我采用Bert-Bilstm-CRF;Bert实现WordEmbedding,将bert的输出作为Bilstm(双向的长短期记忆)在提取一次Word的特征;最后使用条件随机场,实现对句子中每个类型的预测,提取出实体;
实验:对于这个模块,我的数据是王老师实验室给我的,刚开始的F1值比较低,在1400次epoch后,达到了F1值达到了92%。这个模块,我预计给出loss,准确率,召回率与F1值的变化曲线。
接着是第二个模型:
理论:对于语义相似度模型,我首先使用Glove向量模型,去对数据进行训练,得到每个词语的词向量,接着对于数据中的每一个问题使用NER模型识别出其实体,将每个问题转化为一个一个实体;对于每个问题去匹配Glove词向量,然后将每个问题以及对应的答案存储起来,创建一个语义相似表(问题中的每一个词会对应10个相似的词语);接着再对所有的词语,创建一个倒序表,即每个单词关联最相关的10个问题。
对于每一个question,首先先去除空白字符,然后放到NER模型中,得到实体;然后将question首先再语义相似表中去寻找相似的单词,接下来找到这些相似单词所有对应的问题。最后将这些问题与原来的问题放到bert模型中得到它们的WordEmbbeding,最后通过计算它们之间的语义相似度去计算距离,找到其中最相似的五个问题。最后返回这五个问题的答案。
实验: 这里的数据,我通过使用Python的爬虫技术去百度知道中去爬取数据;然后使用Python进行数据清洗。对于这个模块,我预计给出一些代表性的问题询问以及回答的样例以及准确率。
这次毕业设计给我最大的感受是,自己的基础知识薄弱;而且我发现其实数据真的好重要,毕设的数据基本没有,因为毕设限定在了麻将领域,很难受;Google之所以能够给出很多落地的模型出来,一方面是算法,而另一方面需要看到的是Google有大量最为真实的数据为它的模型做支撑。
现在论文写完了就是给论文降查重率。