特定领域知识图谱融合方案:技术知识前置【一】-文本匹配算法、知识融合学术界方案、知识融合

特定领域知识图谱(Domain-specific KnowledgeGraph:DKG)融合方案:技术知识前置【一】-文本匹配算法、知识融合学术界方案、知识融合业界落地方案、算法测评KG生产质量保障

0.前言

本项目主要围绕着特定领域知识图谱(Domain-specific KnowledgeGraph:DKG)融合方案:技术知识前置【一】-文本匹配算法、知识融合学术界方案、知识融合业界落地方案、算法测评KG生产质量保障讲解了文本匹配算法的综述,从经典的传统模型到孪生神经网络“双塔模型”再到预训练模型以及有监督无监督联合模型,期间也涉及了近几年前沿的对比学习模型,之后提出了文本匹配技巧提升方案,最终给出了DKG的落地方案。这边主要以原理讲解和技术方案阐述为主,之后会慢慢把项目开源出来,一起共建KG,从知识抽取到知识融合、知识推理、质量评估等争取走通完整的流程。

1.文本匹配算法综述(短文本匹配)

文本匹配任务在自然语言处理中是非常重要的基础任务之一,一般研究两段文本之间的关系。有很多应用场景;如信息检索、问答系统、智能对话、文本鉴别、智能推荐、文本数据去重、文本相似度计算、自然语言推理、问答系统、信息检索等,但文本匹配或者说自然语言处理仍然存在很多难点。这些自然语言处理任务在很大程度上都可以抽象成文本匹配问题,比如信息检索可以归结为搜索词和文档资源的匹配,问答系统可以归结为问题和候选答案的匹配,复述问题可以归结为两个同义句的匹配。

  1. 如语言不规范,同一句话可以有多种表达方式;如“股市跳水、股市大跌、股市一片绿”
  2. 歧义,同一个词语或句子在不同语境可能表达不同意思;如“割韭菜”,“领盒饭”,“苹果”“小米”等在不同语境下语义完全不同
  3. 不规范或错误的输入;如 “ yyds”,“绝绝子”“夺笋”“耗子尾汁”
  4. 需要知识依赖;如奥运冠军张怡宁绰号“乒乓大魔王”等。

短文本匹配即计算两个短文本的相似度,通常分成无监督方式、有监督方式、有监督+无监督方式

常见的文本匹配算法如下表(简单罗列),按传统模型和深度模型简单的分为两类:

算法

类型

Jaccord

传统模型

BM25

传统模型

VSM

传统模型

SimHash

传统模型

Levenshtein

传统模型

cdssm

深度模型

arc-ii

深度模型

match_pyramid

深度模型

mvlstm

深度模型

bimpm

深度模型

drcn

深度模型

esim

深度模型

textmatching

深度模型

bert-base

深度模型

albert-base

深度模型

albert-large

深度模型

raberta

深度模型

sbert

深度模型

DiffCSE

深度模型

ERNIE-Gram

深度模型

1.1 文本匹配传统模型(无监督方式)

文本表征:词袋模型(one-hot 、TF)、词向量预训练(word2vector、fasttext、glove)

相似度计算:余弦相似度、曼哈顿距离、欧氏距离、jaccard距离等

1.1.1 Jaccord 杰卡德相似系数

jaccard相似度是一种非常直观的相似度计算方式,即两句子分词后词语的交集中词语数与并集中词语数之比。

$\text { jaccard }=\frac{A \bigcap B}{A \bigcup B}$

def jaccard(list1, list2):
    """
    jaccard相似系数
    :param list1:第一句话的词列表 
    :param list2: 第二句话的词列表
    :return:相似度,float值 
    """
    list1, list2 = set(list1), set(list2) #去重
    intersection = list1.intersection(list2) # 交集
    union = list1.union(list2)  # 并集
    Similarity = 1.0 * len(intersection) / len(union) #交集比并集
    return Similarity

a.分词

    内蒙古 锡林郭勒盟 多伦县 县医院    /    多伦县 医院
    绵阳市  四 零 四 医院     /     四川 绵阳 404 医院
    邓州市 人民 医院       /       南召县 人民 医院

b.去重求交集--并集

    多伦县(交集)    --      内蒙古、锡林郭勒盟、多伦县、县医院、医院(并集)
    医院(交集)      --        绵阳市、四、零、医院、四川、绵阳、404(并集)
    人民、医院(交集)    --     邓州市、人民、医院、南召县(并集)

c.相似度

文本对

相似度

真实标签

内蒙古 锡林郭勒盟 多伦县 县医院 / 多伦县 医院

1/5=0.2

1

绵阳市 四零四医院/四川 绵阳 404 医院

1/7 = 0.14

1

邓州市 人民 医院 / 南召县 人民 医院

2/4 = 0.5

0

1.1.2.Levenshtein编辑距离

一个句子转换为另一个句子需要的编辑次数,编辑包括删除、替换、添加,然后使用最长句子的长度归一化得相似度。

def Levenshtein(text1, text2):
    """
    Levenshtein编辑距离
    :param text1:字符串1
    :param text2:字符串2
    :return:相似度,float值
    """
    import Levenshtein
    distance = Levenshtein.distance(text1, text2)
    Similarity = 1 - distance * 1.0 / max(len(text1), len(text2))
    return Similarity

a.分词-计字数

    内 蒙 古 锡 林 郭 勒 盟 多 伦 县 县 医 院 (14)   /    多 伦 县 医 院(5)
    绵 阳 市  四 零 四 医 院(8)     /     四 川 绵 阳 4 0 4 医 院(9)
    邓 州 市 人 民 医 院 (7)      /       南 召 县 人 民 医 院(7)

b.计算编辑距离

   内 蒙 古 锡 林 郭 勒 盟 多 伦 县 县 医 院 ------->删除内、蒙、古、锡、林、郭、勒、盟、县
   绵 阳 市  四 零 四 医 院   ------->加 四、川
                                           ------->删除 市
                                           ------->替换 四(4)、零(0)、四(4)
   邓 州 市 人 民 医 院         ------->替换邓(南)、 州(召)、 市(县)

文本对

距离

真实标签

内蒙古 锡林郭勒盟 多伦县 县医院 / 多伦县 医院

0.357

1

绵阳市 四零四医院/四川 绵阳 404 医院

0.333

1

邓州市 人民 医院 / 南召县 人民 医院

0.571

0

1.1.3 simhash相似度

先计算两句子的simhash二进制编码,然后使用海明距离计算,最后使用两句的最大simhash值归一化得相似度。

def simhash_(text1, text2):
    """
    simhash相似度
    :param s1: 字符串1
    :param s2: 字符串2
    :return: 相似度,float值
    """
    from simhash import Simhash
    text1_simhash = Simhash(text1, f=64)  #计算simhash向量
    text2_simhash = Simhash(text2, f=64)  #计算simhash向量
    distance = text1_simhash.distance(text2_simhash)  #汉明距离
    Similarity = 1 - distance / max(len(bin(text1_simhash.value)), len(bin(text2_simhash.value))) #相似度
    return Similarity

a.分词

    内蒙古 锡林郭勒盟 多伦县 县医院    /    多伦县 医院
    绵阳市  四 零 四 医院     /     四川 绵阳 404 医院
    邓州市 人民 医院       /       南召县 人民 医院

b.计算词权重(此处用tfidf计算,其他方法也可以)

| Text | Text | Text |

内蒙古5

锡林郭勒盟5

多伦县2

县医院5

多伦县7

医院1

绵阳市3

四6

零3

四6

医院1

四川5

绵阳5

4045

医院1

邓州市7

人民4

医院1

南召县7

人民4

医院1

c.hash函数映射词向量

  • 先将词映射到二进制编码,
  • 然后用b步骤中的权重值替换1,
  • b步骤中权重值的负数替换0

d.合并(将一段文本内的词向量进行累加)

e海明距离判断相似度

海明距离可以理解为:两个二进制串之间相同位置不同的个数。举个例子,1,1,1,0,0,0和1,1,1,1,1,1的海明距离就是3。

1.1.4 Bm25相似度

一句话概况其主要思想:对Query(待查询语句)进行语素解析,生成语素qi;然后,对于每个搜索结果D,计算每个语素qi与D的相关性得分,最后,将qi相对于D的相关性得分进行加权求和,从而得到Query与D的相关性得分。公式如下:

$\operatorname{Score}(Q, d)=\sum_i^n W_i \cdot R\left(q_i, d\right)$

Q表示Query,qi即Q分词后的每一个解析语素(对中文而言,我们可以把对Query的分词作为语素分析,每个词看成语素qi)。d表示一个搜索结果文档,Wi表示语素qi的权重,R(qi,d)表示语素qi与文档d的相关性得分。

判断一个词与一个文档的相关性的权重定义Wi方法有多种,较常用的是IDF。公式如下:

$\operatorname{IDF}\left(q_i\right)=\log \frac{N-n\left(q_i\right)+0.5}{n\left(q_i\right)+0.5}$

  • N为索引中的全部文档数,
  • n(qi)为包含了qi的文档数。

根据IDF的定义可以看出当很多文档都包含了qi时,qi的区分度就不高,因此使用qi来判断相关性时的重要度就较低。

$\operatorname{Score}(Q, d)=\sum_i^n I D F\left(q_i\right) \cdot \frac{f_i \cdot\left(k_1+1\right)}{f_i+k_1 \cdot\left(1-b+b \cdot \frac{d l}{a v g d l}\right)}$

求Score(qi,d)具体的公式可以参考文本相似度-BM25算法

其中

  • f(qi, D)为单词在当前候选文档中的词频
  • k1、b为调节因子,通常设为k1=2,b=0.75
  • |D|为当前候选文本数(与目标文本匹配的总条数)
  • avgdl为语料库中所有文档的平均长度。

在做文本匹配的时候(如重复问题检测)可以尝试BM25的方法,但在搜索领域中,有时候搜索query和候选文档的长度是不一样甚至差距很大,所以BM25在计算相似性的时候需要对文档长度做一定的处理。

文本相似度-BM25算法

#Bm25
import math
import jieba
class BM25(object):
    def __init__(self, docs):#docs是一个包含所有文本的列表,每个元素是一个文本
        self.D = len(docs)  #总文本数
        self.avgdl = sum([len(doc)+0.0 for doc in docs]) / self.D   #平均文本长度
        self.docs = docs #文本库列表
        self.f = []  # 列表的每一个元素是一个dict,dict存储着一个文档中每个词的出现次数
        self.df = {} # 存储每个词及出现了该词的文档数量
        self.idf = {} # 存储每个词的idf值
        self.k1 = 1.5
        self.b = 0.75
        self.init()
 
    def init(self):
        for doc in self.docs:  #对每个文本
            tmp = {}   #定义一个字典存储词出现频次
            for word in doc:
                tmp[word] = tmp.get(word, 0) + 1  # 存储每个文档中每个词的出现次数
            self.f.append(tmp)
            for k in tmp.keys():
                self.df[k] = self.df.get(k, 0) + 1
        for k, v in self.df.items():
            self.idf[k] = math.log(self.D-v+0.5)-math.log(v+0.5) #计算idf
 
    def sim(self, doc, index):
        score = 0
        for word in doc:
            if word not in self.f[index]:
                continue
            d = len(self.docs[index])
            score += (self.idf[word]*self.f[index][word]*(self.k1+1)
                      / (self.f[index][word]+self.k1*(1-self.b+self.b*d
                                                      / self.avgdl)))
        return score
 
    def simall(self, doc):
        scores = []
        for index in range(self.D):
            score = self.sim(doc, index)
            scores.append(score)
        return scores
 
if __name__ == '__main__':
    sents1 = ["多伦县医院",  #数据库
                "四川绵阳404医院",
               "南召县人民医院"]
    sents2 = ["内蒙古锡林郭勒盟多伦县县医院","绵阳市四零四医院","邓州市人民医院"]#待匹配文本
    doc = []
    for sent in sents1:
        words = list(jieba.cut(sent))
        doc.append(words)
    print(doc)
    s = BM25(doc)
    print(s.f)
    print(s.idf)
    for k in sents2:
        print(s.simall(jieba.lcut(k))) #打印相似度匹配结果
        
        

1.1.5 VSM(向量空间模型)算法

VSM算法的思路主要分为两步:

(1) 用向量表示句子,用向量表示句子的方法很多,简单的有onehot,词频法,基于语义的有word2vec/fastText/glove/bert/elmo等,本例中使用基于简单的词频的向量化方式。

(2)计算两向量的余弦距离(曼哈顿距离、欧几里得距离、明式距离、切比雪夫距离)得相似度。

#tfidf_余弦
def sim_vecidf(self, s1, s2):
    """词向量通过idf加权平均后计算余弦距离"""
    v1, v2 = [], []
    # 1. 词向量idf加权平均
    for s in jieba.cut(s1):
        idf_v = idf.get(s, 1)
        if s in voc:
            v1.append(1.0 * idf_v * voc[s])
    v1 = np.array(v1).mean(axis=0)
    for s in jieba.lcut(s2):
        idf_v = idf.get(s, 1)
        if s in voc:
            v2.append(1.0 * idf_v * voc[s])
    v2 = np.array(v2).mean(axis=0)
    # 2. 计算cosine
    sim = self.cosine(v1, v2)
    return sim

a.句子向量化

a1.取句子对的唯一词元组

set(内蒙古 锡林郭勒盟 多伦县 县医院 / 多伦县 医院) = (内蒙古 锡林郭勒盟 多伦县 县医院 医院)

set(绵阳市 四 零 四 医院 / 四川 绵阳 404 医院) = (绵阳市 四 零 医院 四川 绵阳 404 )

set(邓州市 人民 医院 / 南召县 人民 医院) = (邓州市 人民 医院 南召县)

a2.根据每个句子在元组中的词频建立向量表示

b.计算余弦距离

$\operatorname{Cos}(x 1, x 2)=\frac{x 1 \cdot x 2}{|x 1||x 2|}$

句子

距离

内蒙古 锡林郭勒盟 多伦县 县医院 / 多伦县 医院

0.3535

绵阳市 四零四医院/四川 绵阳 404 医院

0.1889

邓州市 人民 医院 / 南召县 人民 医院

0.6666

1.1.6 word2vector + 相似度计算(BERT模型+余弦相似度为例)

常用做法是通过word2vec等预训练模型得到词向量,然后对文本做分词,通过embedding_lookup得到每个token对应的词向量,然后得到短文本的句向量。对两个文本的句子向量采用相似度计算方法如余弦相似度、曼哈顿距离、欧氏距离等。无监督方式取得的结果取决于预训练词向量的效果

BERT是谷歌在2018年推出的深度语言表示模型,是关于语言理解的深度双向transformers的预训练模型,开启了预训练模型的新篇章。它可以学习文本的语义信息,通过向量形式的输出可以用于下游任务。也就说,它自己已经在大规模预料上训练好的参数,我们在用的时候只需要在这个基础上训练更新参数。bert模型可以解决多种自然语言处理问题,如单文本分类、语句对分类、序列标注等。在解决文本匹配任务时,有两种思路,第一种直接把文本匹配任务作为语句对分类任务,模型输入语句对,输出是否匹配的标签;第二种利用bert模型预训练文本对的上下文嵌入向量,再通过余弦相似度等相似度计算方法验证文本对是否匹配,在此基础上还有很多基于bert模型的变种,篇幅有限不做一一讲述。接下来简单介绍一下bert预训练文本嵌入+余弦相似度的算法框架。

a.首先使用大量公域文本数据对BERT模型进行预训练(或直接用谷歌预训练好的模型)

b.将文本直接输入模型

c.对模型输出的语义向量C,或中间隐层向量,计算余弦相似度,得到匹配结果。

基于深度学习的匹配算法种类繁多,如基于CNN网络、RNN网络、LSTM网络等及各种变种层出不穷,在此不一一列举实现。

传统的文本匹配方法主要关注文本间字与字,词与词的匹配关系,无法准确识别不同表达方式下不同文本的同一指向关系,即语义关系。因此在这一背景下,要对多源异构的海量地址数据进行匹配,传统的文本匹配方法已不再适用,深度学习方法大行其道。但深度学习方法也有自身的局限性,比如对海量文本和算力的高要求等,都使得深度学习方法的普适性大打折扣,因此没有最好的文本匹配算法,只有当前条件下最适合的文本匹配算法。

2.有监督方式

2.1 孪生神经网络(Siamese Network)

原文:《Learning a Similarity Metric Discriminatively, with Application to Face Verification》

  1. 要解决什么问题?
* 用于解决类别很多(或者说不确定),然而训练样本的类别数较少的分类任务(比如人脸识别、人脸认证)
* 通常的分类任务中,类别数目固定,且每类下的样本数也较多(比如ImageNet)
  1. 用了什么方法解决?

提出了一种思路:将输入映射为一个特征向量,使用两个向量之间的“距离”(L1 Norm)来表示输入之间的差异(图像语义上的差距)。

基于上述思路设计了Siamese Network。每次需要输入两个样本作为一个样本对计算损失函数。

  • 常用的softmax只需要输入一个样本。
  • FaceNet中的Triplet Loss需要输入三个样本。
  • 提出了Contrastive Loss用于训练。
  1. 效果如何?

文中进行了一个衡量两张人脸的相似度的实验,使用了多个数据库,较复杂。siamese network现在依然有很多地方使用,可以取得state-of-the-art的效果。

  1. 还存在什么问题?
  • contrastive loss的训练样本的选择需要注意,论文中都是尽量保证了50%的正样本对和50%的负样本对。

分类问题:

  • 第一类,分类数量较少,每一类的数据量较多,比如ImageNet、VOC等。这种分类问题可以使用神经网络或者SVM解决,只要事先知道了所有的类。
  • 第二类,分类数量较多(或者说无法确认具体数量),每一类的数据量较少,比如人脸识别、人脸验证任务。

文中提出的解决方案:

learn a similar metric from data。核心思想是,寻找一个映射函数,能够将输入图像转换到一个特征空间,每幅图像对应一个特征向量,通过一些简单的“距离度量”(比如欧式距离)来表示向量之间的差异,最后通过这个距离来拟合输入图像的相似度差异(语义差异)。

2.1.1 简介

  • Siamese Network 是一种神经网络的框架,而不是具体的某种网络,就像seq2seq一样,具体实现上可以使用RNN也可以使用CNN。
  • Siamese network就是“连体的神经网络”,神经网络的“连体”是通过共享权值来实现的。(共享权值即左右两个神经网络的权重一模一样)
  • siamese network的作用是衡量两个输入的相似程度。孪生神经网络有两个输入(Input1 and Input2),将两个输入feed进入两个神经网络(Network1 and Network2),这两个神经网络分别将输入映射到新的空间,形成输入在新的空间中的表示。通过Loss的计算,评价两个输入的相似度。

Siamese Network有两个结构相同,且共享权值的子网络。分别接收两个输入X1与X2,将其转换为向量Gw(X1)与Gw(X2),再通过某种距离度量的方式计算两个输出向量的距离Ew。

训练Siamese Network采用的训练样本是一个tuple (X1,X2,y)(X1,X2,y),标签y=0表示X1与X2属于不同类型(不相似、不重复、根据应用场景而定)。y=1则表示X2与X2属于相同类型(相似)。

LOSS函数的设计应该是

  1. 当两个输入样本不相似(y=0)时,距离Ew越大,损失越小,即关于Ew的单调递减函数。
  2. 当两个输入样本相似(y=1)时,距离Ew越大,损失越大,即关于Ew的单调递增函数。

用L+(X1,X2)表示y=1时的LOSS,L−(X1,X2)表示y=0时的LOSS,则LOSS函数可以写成如下形式:

Lw(X1,X2)=(1−y)L−(X1,X2)+yL+(X1,X2)

简单来说:孪生体现在使用相同的编码器(sentence encoder),将文本转为高维向量。具体步骤为,有文本A和文本B分别输入 sentence encoder 进行特征提取和编码,将输入映射到新的空间得到特征向量u和v;最终通过u、v的拼接组合,经过下游网络来计算文本A和B的相似性

  • 在训练和测试中,模型的编码器是权重共享的,编码器可以选择CNN、RNN、LSTM等
  • 提取到特征u、v后,可以使用余弦距离、欧氏距离等得到两个文本的相似度。
  • 缺点是两个文本在编码时候没有交互,缺乏交互的结构没有充分利用到两个文本相互影响的信息

2.2 匹配聚合网络(ESIM,BIMPM)

在上述孪生网络的基础上,得到特征u、v但是不直接计算向量相似度,而是通过注意力机制将两个文本进行信息交互,最后通过全连接层得到相似度。

代表的模型有ESIM,BIMPM等

以ESIM为例

  • 首先是对两个文本的初期编码,就是对两个文本做分词、文本表征,即对句子进行信息的提取。如果使用LSTM作为encoder,可以得到每个时刻(每个单词)的输出,通常维度为batch_size, seq_len, embedding_dim。举例子为,句子A长度10,句子B长度也为10,那么进过编码以后句子A的维度1,10,300,句子B1,10,300,这里就得到了上述所提到的u、v
  • 接下来是交互操作,为了操作简单忽略batchsize维度,交互即矩阵相乘得到10,10,矩阵需要对句子A做横向概率归一,对句子B做纵向概率归一。上面这句话其实就是ESIM的核心要点。它是一个两个item之间互相做attention,简单称之为both attention。
  • 对attention后得到的向量做拼接后输出编码器,输出再接到全连接层、softmax就可以得到结果,即两个文本相似(label 1)或不相似(label 0)

3.预训练语言模型

  1. 第一阶段,使用通用的预料库训练语言模型,
  2. 第二阶段预训练的语言模型(BERT相关衍生的模型)做相似度任务,得到信息交互后的向量,
  3. 连接全连接层,输出概率。即将两个短文本拼接(CLS A1 A2 … A 10 SEP B1 B2 … B10 SEP),然后CLS向量连接全连接层,判断相似与否。

这种模型参数多,并且使用了通用的语料库,能够获取到短文本之间隐藏的交互信息,效果较好。

简单来说用拼接的方法类似“单塔”,孪生网络的方法类似“双塔”,不完全准确后续会详细说明,预训练模型就不展开讲了,大家去官网或者多看几篇学术论文吧,BERT ERNIE。

4.有监督方式 + 无监督方式

无监督:直接相加得到句向量,不能很好的表达语义信息,并且词的位置信息没有得到体现,也不包含上下文的语义信息。

有监督学习:时间复杂度太高。可以将标准库中的句向量计算完成并存储。新的文本来临时,只需要解决用户问题即可,然后与存储在库中的标准问句进行距离度量。

可以使用BERT代替孪生网络的CNN或LSTM结构,获取更多语义信息的句向量,还可以通过蒸馏降低BERT模型的参数,节约时间成本。

4.1 Sentence-BERT

文章链接:https://arxiv.org/pdf/1908.10084.pdf

论文代码:https://github.com/UKPLab/

为了让BERT更好地利用文本信息,作者们在论文中提出了如下的SBERT模型。SBERT沿用了孪生网络的结构,文本Encoder部分用同一个BERT来处理。之后,作者分别实验了CLS-token和2种池化策略(Avg-Pooling、Mean-Pooling),对Bert输出的字向量进一步特征提取、压缩,得到u、v。

关于u、v整合,作者提供了3种策略:

  1. 将u、v拼接,接入全连接网络,经过softmax输出,损失函数用交叉熵损失
  2. 直接计算两个文本的余弦相似度,损失函数用均方根误差

  1. 如果输入的是三元组

SBERT直接用BERT的原始权重初始化,在具体数据集微调,训练过程和传统Siamese Network类似。但是这种训练方式能让Bert更好的捕捉句子之间的关系,生成更优质的句向量。在测试阶段,SBERT直接使用余弦相似度来衡量两个句向量之间的相似度,极大提升了推理速度。

使用NLI和STS为代表的匹配数据集,在分类目标函数训练时,作者测试了不同的整合策略,结果显示“(u, v, |u-v|)”的组合效果最好。最重要的部分是元素差:(|u - v|)。句向量之间的差异度量了两个句子嵌入维度间的距离,确保相似的pair更近,不同的pair更远。

4.2 对比学习

深度学习的本质是做两件事情:①表示学习 ②归纳偏好学习。对比学习(ContrastiveLearning)则是属于表示学习的范畴,它并不需要关注样本的每一个细节,但是学到的特征要使其能够和其他样本区分开。对比学习作为一种无监督表示学习方法,最开始也是在CV领域掀起浪潮,之后NLP跟进,在文本相似度匹配等任务上超过SOTASOTA。该任务主要是对文本进行表征,使相近的文本距离更近,差别大的文本距离更远。

NLP的对比学习算法下文将不详细讲述简单展示更多内容参考链接。

4.2.1 BERT-Flow 2020.11

很多研究发现BERT表示存在问题:未经微调的BERT模型在文本相似度匹配任务上表现不好,甚至不如Glove?作者通过分析BERT的性质,如图:

在理论上BERT确实提取到了足够的语义信息,只是这些信息无法通过简单的consine直接利用。主要是因为:

  • ①BERT的词向量在空间中不是均匀分布,而是呈锥形。高频词都靠近原点,而低频词远离原点,相当于这两种词处于了空间中不同的区域,那高频词和低频词之间的相似度就不再适用;
  • ②低频词的分布很稀疏。低频词表示得到的训练不充分,分布稀疏,导致该区域存在语义定义不完整的地方(poorly defined),这样算出来的相似度存在问题。

针对以上问题,提出了BERT-Flow,基于流式生成模型,将BERT的输出空间由一个锥形可逆地映射为标准的高斯分布空间。

4.2.2 BERT-Whitening 2021.03

BERT-Whitening首先分析了余弦相似度为什么可以衡量向量的相似度:向量A 与B 的乘积等于A AA在B BB所在直线上投影的长度。将两个向量扩展到d维

$\cos (A, B)=\frac{\sum{i=1}^d a_i b_i}{\sqrt{\sum{i=1}^d ai^2} \sqrt{\sum{i=1}^d b_i^2}}$

$\text { 模的计算公式: }|A|=\sqrt{a_1^2+a_2^2+\ldots+a_n^2}$

上述等式的成立,都是在标准正交基(忘了的同学可以自行复习一下)的条件下,也就是说向量依赖我们选择的坐标基,基底不同,内积对应的坐标公式就不一样,从而余弦值的坐标公式也不一样。

所以,BERT的句向量虽然包含了足够的语义,但有可能是因为此时句向量所属的坐标系并非标准正交基,而导致用基于标准正交基的余弦相似度公式计算时效果不好。那么怎么知道具体用了何种基底呢?可以依据统计学去判断,在给向量集合选择基底时,尽量平均地用好每一个基向量,这就体现为每个分量的使用都是独立的、均匀的,如果这组基是标准正交基,那么对应的向量集应该表现出“各向同性”来,如果不是,可以想办法让它变得更加各向同性一写,然后再用余弦公式计算,BERT-Flow正是想到了“flow模型”的办法,而作者则找到了一种更简单的线性变换的方法。

标准化协方差矩阵

BERT-Whitening还支持降维操作,能达到提速和提效的效果。

★PCA和SVD差异分析:PCA可以将方阵分解为特征值和特征向量,SVD则可以分解任意形状的矩阵。

4.2.3 ConSERT 2021.05

https://arxiv.org/pdf/2105.11741.pdf

美团技术团队提出了基于对比学习的句子表示迁移方法——ConSERT,主要证实了以下两点:

①BERT对所有的句子都倾向于编码到一个较小的空间区域内,这使得大多数的句子对都具有较高的相似度分数,即使是那些语义上完全无关的句子对。我们将此称为BERT句子表示的“坍缩(Collapse)”现象。

②BERT句向量表示的坍缩和句子中的高频词有关。当通过平均词向量的方式计算句向量时,高频词的词向量将会主导句向量,使之难以体现其原本的语义。当计算句向量时去除若干高频词时,坍缩现象可以在一定程度上得到缓解。

为了解决BERT存在的坍缩问题,作者提出了句子表示迁移框架:

对BERT encoder做了改进,主要包括三个部分:

*①数据增强模块,作用于embedding层,为同一文本生成不同的编码。

  1. shuffle:更换position id的顺序
  2. token cutoff:在某个token维度把embedding置为0
  3. feature cutoff:在embedding矩阵中,有768个维度,把某个维度的feature置为0
  4. dropout:embedding中每个元素都有一定概率为0,没有行或列的约束

数据增强效果:Token Shuffle > Token Cutoff >> Feature Cutoff ≈ Dropout >> None

  • ②共享的Bert encoder,生成句向量。
  • ③一个对比损失层,在一个Batch内计算损失,拉近同一样本不同句向量的相似度,使不同样本之间相互远离。损失函数:

$L{i, j}=-\log \frac{\exp \left(\operatorname{sim}\left(r_i, r_j\right) / \tau\right)}{\sum{k=1}^{2 N} 1_{k \neq i} \exp \left(\operatorname{sim}\left(r_i, r_k\right) / \tau\right)}$

N:Batchsize,2N表示2种数据增强方式,sim():余弦相似度函数,r:句向量,τ:实验0.08−0.12最优

除了无监督训练之外,作者还提出了三种进一步融合监督信号的策略:

  • ①联合训练(joint):有监督的损失和无监督的损失通过加权联合训练模型。
  • ②先有监督再无监督(sup-unsup):先使用有监督损失训练模型,再使用无监督的方法进行表示迁移。
  • ③联合训练再无监督(joint-unsup):先使用联合损失训练模型,再使用无监督的方法进行表示迁移。

参考链接:https://blog.csdn.net/PX2012007/article/details/127614565

4.2.4 SimCSE:2021.04

前几节讲述了对比学习的原理和几种基于 Bert 的方式获取句子向量,例如 BERT-flow和 BERT-whitening 等,对预训练 Bert 的输出进行变换从而得到更好的句子向量。后面将通过 ①构造目标函数 ②构建正负例 的对比学习方法训练模型,取得SOTA的效果。

SimCSE是有大神陈丹琦发表的《Simple Contrastive Learning of Sentence Embeddings》,简单高效

SimCSE包含无监督(图左部分)和有监督(图右部分)两种方法。实线箭头代表正例,虚线代表负例。

  • Unsupervised

创新点在于使用Dropout对文本增加噪音。

1.正例构造:利用Bert的随机Dropout,同一文本经过两次Bert enconder得到不同的句向量构成相似文本。

2.负例构造:同一个Batch中的其他样本作为负例被随机采样。

  • Supervised

1.正例:标注数据

2.负例:同Batch内的其他样本

4.2.5 R-Drop(Supervised):2021.06

https://arxiv.org/abs/2106.14448

Dropout虽然可以防止模型训练中的过拟合并增强鲁棒性,但是其操作在一定程度上会使训练后的模型成为一种多个子模型的组合约束。SimCSE就是希望Dropout对模型结果不会有太大影响,也就是模型输出对Dropout是鲁棒的。所以,“Dropout两次”这种思想是可以推广到一般任务的,这就是R-Drop(Regularized Dropout),由微软亚洲研究院和苏州大学提出的更加简单有效的正则方法。

  • R-Drop与传统作用于神经元或模型参数的约束方法不同,而是作用于输出层,弥补了Dropout在训练和测试时的不一致性。在每个mini-batch中,每个数据样本过两次带有Dropout的同一个模型,R-Drop再使用KL-divergence(KL散度)约束两次的输出一致。所以,R-Drop约束了由于Dropout带来的两个随机子模型的输出一致性。
  • R-Drop只是简单增加了一个KL-散度损失函数项,并没有其他任何改动。虽然该方法看起来很简单,但在NLP和CV的任务中,都取得了非常不错的SOTA结果。

同样的输入,同样的模型,经过两个 Dropout 得到的将是两个不同的分布,近似将这两个路径网络看作两个不同的模型网络。基于此,这两个不同的模型产生的不同分布而这篇文章的主要贡献就是在训练过程中不断拉低这两个分布之间的KL 散度。由于KL 散度本身具有不对称性,作者通过交换这两种分布的位置以间接使用整体对称的KL 散度,称之为双向KL 散度。

4.2.6 ESimCSE(Unsupervised):2021.09

https://arxiv.org/abs/2109.04380

SimCSE构建正负例时存在两个两个缺点:

  • ①构造正例长度相等,导致模型预测时存在偏差,长度相等的文本会倾向预测相似度高。
  • ②对比学习理论上负例越多,对之间模型学习的越好,但增大Batch会受到性能的限制。

ESimCSE针对以上问题做了相应的改进:

  • 正例构造:通过引入噪声较小的“单词重复”方式改变正例的长度,设置重复率dup_rate,确定dup_len后利用均匀分布随机选取dup_len子词进行重复。
  • 负例构造:为了更有效的扩展负对,同时不降低性能,通过维护一个队列,重用前面紧接的mini-batch的编码嵌入来扩展负对:
    • ①将当前mini-batch的句嵌入放入队列,同时将“最老的”句子踢出队列。由于排队句子嵌入来自前面的mini-batch,通过取其参数的移动平均来保持动量更新模型,并利用动量模型生成排队句子嵌入。
    • 在使用动量编码器时,关闭了dropout,这可以缩小训练和预测之间的差距。

4.2.7 PromptBERT(Unsupervised):2022.01

https://arxiv.org/pdf/2201.04337v1.pdf

Prompt Learning比较火热,号称NLP的第四范式,

  • 作者发现BERT在语义相似度方面表现不好,主要由:static token embeddings biases和ineffective layers,而不是high cosine similarity of the sentence embedding。static token embedding是在bert结构中,输入进block前,通过embedding layer产生的结果,这里强调是静态的embedding,就是embedding metrics中每个token都唯一对应的embedding,是不随句子环境而变化的。至于ineffective layers就很好理解了,就是bert中堆叠的block结构,比如bert-base中的12层。作者认为这些结构,对语义相似度的表征这个方面是无效的。
  • Anisotropy(各向异性):上篇我们已经提到,词向量是有维度的,每个维度上基向量单位向量长度不一样,就是各向异性的。这会造成计算向量相似度的时候产生偏差。如何度量Anisotropy:

作者分析了造成embedding bias的原因,除了token frequency是造成bias的原因,作者又提出了:subwords,case sentitive

图中不同词频token的分布情况,颜色越深代表词频越高,我们可以看出词频高的token,分布比较紧凑,词频低的token,分布较分散。作者输出这个图像还有一个目的是他提出各向异性(anisotropy)和偏差(bias)是不相关的,各向异性不是导致偏差的原因。

Embedding bias意思是映射分布被一些不相关的信息所干扰,是可以用降维的方式去可视化的。

更多细节参考原论文,Prompt效果就不赘述了,百度开发的UIE模型在NLP就很强大!

4.2.8 SNCSE(Unsupervised):2022.01

https://arxiv.org/abs/2201.05979

SNCSE同样是由微软团队提出,主要是针对以上方法存在的问题:当前对比学习的数据增强方式,获取的正样本都极为相似,导致模型存在特征抑制,即模型不能区分文本相似度和语义相似度,并更偏向具有相似文本,而不考虑它们之间的实际语义差异。

为了减轻特征抑制,该论文提出了通过软负样本结合双向边际损失的无监督句子嵌入对比学习方法。其中,软负样本,即具有高度相似,但与原始样本在语义上存在明显的差异的样本。双向边际损失,即通过扩大原始样本与正例和原始样本与软负例之间的距离,使模型更好地学习到句子之间的语义差别。

软负样本构造:为原文本添加显示的否定词。

  • 在获取句子表征时,受PromptBERT启发,通过三种模板表示原样本、正样本和软负样本:

4.2.9 DiffCSE(Unsupervised):2022.04

https://arxiv.org/pdf/2204.10298.pdf

结合句子间差异的无监督句子嵌入对比学习方法——DiffCSE主要还是在SimCSE上进行优化(可见SimCSE的重要性),通过ELECTRA模型的生成伪造样本和RTD(Replaced Token Detection)任务,来学习原始句子与伪造句子之间的差异,以提高句向量表征模型的效果。

其思想同样来自于CV领域(采用不变对比学习和可变对比学习相结合的方法可以提高图像表征的效果)。作者提出使用基于dropout masks机制的增强作为不敏感转换学习对比学习损失和基于MLM语言模型进行词语替换的方法作为敏感转换学习「原始句子与编辑句子」之间的差异,共同优化句向量表征。

在SimCSE模型中,采用pooler层(一个带有tanh激活函数的全连接层)作为句子向量输出。该论文发现,采用带有BN的两层pooler效果更为突出,BN在SimCSE模型上依然有效。

  • ①对于掩码概率,经实验发现,在掩码概率为30%时,模型效果最优。
  • ②针对两个损失之间的权重值,经实验发现,对比学习损失为RTD损失200倍时,模型效果最优。

参考链接:https://blog.csdn.net/PX2012007/article/details/127696477

4.2.10 小结

SimCSE以来几种比较重要的文本增强式的对比学习算法,按时间顺序,理论上应该是距离越近的算法效果越好,但使用时,还是要结合具体的业务场景,算法没有好坏,还是用看怎么用。对于有些内容,可能叙述的不是很细致或是需要一定的知识铺垫,感兴趣的同学可以针对性的研读论文和辅助其他资料。当然,算法层出不穷,更新很快,后续出现比较重要的对比学习算法。

5.文本匹配常见思路(技巧提升)

  • TextCNN/TEXTRNN
  • Siamese-RNN
  • 采用多种BERT类预训练模型
  • 对单模型进行调参
  • 多模型融合
  • BERT后接上RCNN/RNN/CNN/LSTM/Siamese等等

5.1方案一

特征工程

  1. 数据清洗:大赛给的数据比较规整,数据清洗部分工作不多,简单做了特殊字符处理等操作。
  2. 数据增强
  • 传递闭包扩充(标签传递)

根据IF A=B and A=C THEN B=C的规则,对正样本做了扩充增强。

根据IF A=B and A!=C THEN B!=C的规则,对负样本做了扩充增强。

在对负样本进行扩充后, 正负样本比例从原始的1.4:1, 变成2.9:1。 所以又对负样本进行了下采样, 是的正负样本比例1:1。

  • 同义词替换

使用开源包synormise的效果不太好, 后面可以尝试使用公开医学预料训练word2vec模型来做同义词替换(时间问题, 没有尝试)。

随机删除,随机替换, 随机交换

句式比较短, 随机删除更短。

很多query仅仅相差一个单词, 随机替换改变语义。

多数属于问句, 随机交换改变了语义。

  1. 模型选择

在预训练模型的基础上通过对抗训练增强模型的泛化性能。

  • BRET Bert的一个下游基础任务语句对分类(Sentence Pair Classification Task), CLS Bert的输出有一个维度的向量表示
  • BERT+CNN(LSTM) 将BERT的输出特征作为文本的表示向量, 然后后面再接上LSTM或者CNN(效果下降)
  • BERT+siamese 将大赛提供的category信息利用上, 借用孪生网络的思想与两个Query进行拼接(效果下降)。
  1. 结果分析
  • 单模型线上效果

目前所训练的模型中:

小模型中BERT-wwm-ext表现是最好的,

大模型中RoBERTa-large-pair表现最好。

在现有的资源和模型上, 对单模型的参数寻优到达一个天花板,线上最高的分数为0.9603。后面开始探索多模型融合。

  • 多模型融合线上效果

将不同类型的预训练模型作为基模型进行多模型融合。基模型的挑选准则基于单模型的线上提交效果,从不同类型的单模型中挑选线上表现最好的参数, 重新训练融合。

基模型:

BERT-wwm-ext + FGM

RoBERTa-large-pair + FGM

Ernie(BaiDu)+ FGM

模型融合策略使用的是averaging, 为了降低差别比较小的模型对结果的影响,采用sigmoid反函数的方式进行ensemble。

关于对抗训练在NLP中的作用,引用大佬的一句话叫缘,妙不可言~

5.2方案二

  1. 探索分析

文本长度:训练集和验证集分布类似,大都集中在10-20个字

标签分布

总体思路

  1. 数据划分

采用kfold交叉验证(右边的划分方式)

•利用全部数据,获得更多信息

•降低方差,提高模型性能

  1. 模型设计

二分类交叉熵损失函数:
  1. 模型融合

小模型同时加入CHIP2019数据训练

模型

特点

权重

加入外部句对数据

BERT-wwm-ext

全词Mask

1

YES

Ernie-1.0

对词、实体及实体关系建模

1

YES

RoBERTa-large-pair

面向相似性或句子对任务优化

1

NO

  1. 数据预处理

对称扩充、传递扩充(注意要保持原来的分布,否则会过拟合)

  1. 训练
  • 三种结构:(实际使用差别不大,第一种又好又简单)
  • 对抗训练

#代码来自苏剑林bert4keras

def adversarial_training(model, embedding_name, epsilon=1):
    """给模型添加对抗训练
    其中model是需要添加对抗训练的keras模型,embedding_name
    则是model里边Embedding层的名字。要在模型compile之后使用。
    """
    if model.train_function is None:  # 如果还没有训练函数
        model._make_train_function()  # 手动make
    old_train_function = model.train_function  # 备份旧的训练函数

    # 查找Embedding层
    for output in model.outputs:
        embedding_layer = search_layer(output, embedding_name)
        if embedding_layer is not None:
            break
    if embedding_layer is None:
        raise Exception('Embedding layer not found')

    # 求Embedding梯度
    embeddings = embedding_layer.embeddings  # Embedding矩阵
    gradients = K.gradients(model.total_loss, [embeddings])  # Embedding梯度
    gradients = K.zeros_like(embeddings) + gradients[0]  # 转为dense tensor

    # 封装为函数
    inputs = (model._feed_inputs +
              model._feed_targets +
              model._feed_sample_weights)  # 所有输入层
    embedding_gradients = K.function(
        inputs=inputs,
        outputs=[gradients],
        name='embedding_gradients',
    )  # 封装为函数

    def train_function(inputs):  # 重新定义训练函数
        grads = embedding_gradients(inputs)[0]  # Embedding梯度
        delta = epsilon * grads / (np.sqrt((grads**2).sum()) + 1e-8)  # 计算扰动
        K.set_value(embeddings, K.eval(embeddings) + delta)  # 注入扰动
        outputs = old_train_function(inputs)  # 梯度下降
        K.set_value(embeddings, K.eval(embeddings) - delta)  # 删除扰动
        return outputs

    model.train_function = train_function  # 覆盖原训练函数
    
写好函数后,启用对抗训练只需要一行代码
adversarial_training(model, 'Embedding-Token', 0.5)
  1. 预测
  • 算数平均→几何平均→sigmoid平均(用反函数取出sigmoid/softmax归一化之前的状态做平均,信息量更大,提升明显)

  • 分类阈值微调(0.47)
  • 伪标签

5.3 更多方案

更多方案就不一一展开了,参考下方链接:

https://tianchi.aliyun.com/notebook/101626

https://tianchi.aliyun.com/notebook/101648

https://tianchi.aliyun.com/notebook/101648

参考链接:

https://tianchi.aliyun.com/competition/entrance/231776/forum

https://tianchi.aliyun.com/notebook/102057

6.特定领域知识图谱(Domain-specific KnowledgeGraph:DKG)融合方案(重点!)

在前面技术知识下可以看看后续的实际业务落地方案和学术方案

关于图神经网络的知识融合技术学习参考下面链接:PGL图学习项目合集&数据集分享&技术归纳业务落地技巧[系列十]

从入门知识到经典图算法以及进阶图算法等,自行查阅食用!

文章篇幅有限请参考专栏按需查阅:NLP知识图谱相关技术业务落地方案和码源

6.1 特定领域知识图谱知识融合方案(实体对齐):优酷领域知识图谱为例

方案链接:https://blog.csdn.net/sinat_39620217/article/details/128614951

6.2 特定领域知识图谱知识融合方案(实体对齐):文娱知识图谱构建之人物实体对齐

方案链接:https://blog.csdn.net/sinat_39620217/article/details/128673963

6.3 特定领域知识图谱知识融合方案(实体对齐):商品知识图谱技术实战

方案链接:https://blog.csdn.net/sinat_39620217/article/details/128674429

6.4 特定领域知识图谱知识融合方案(实体对齐):基于图神经网络的商品异构实体表征探索

方案链接:https://blog.csdn.net/sinat_39620217/article/details/128674929

6.5 特定领域知识图谱知识融合方案(实体对齐)论文合集

方案链接:https://blog.csdn.net/sinat_39620217/article/details/128675199

论文资料链接:两份内容不相同,且按照序号从小到大重要性依次递减

知识图谱实体对齐资料论文参考(PDF)+实体对齐方案+特定领域知识图谱知识融合方案(实体对齐)

知识图谱实体对齐资料论文参考(CAJ)+实体对齐方案+特定领域知识图谱知识融合方案(实体对齐)

6.6 知识融合算法测试方案(知识生产质量保障)

方案链接:https://blog.csdn.net/sinat_39620217/article/details/128675698

7.总结

本项目主要围绕着特定领域知识图谱(Domain-specific KnowledgeGraph:DKG)融合方案:技术知识前置【一】-文本匹配算法、知识融合学术界方案、知识融合业界落地方案、算法测评KG生产质量保障讲解了文本匹配算法的综述,从经典的传统模型到孪生神经网络“双塔模型”再到预训练模型以及有监督无监督联合模型,期间也涉及了近几年前沿的对比学习模型,之后提出了文本匹配技巧提升方案,最终给出了DKG的落地方案。这边主要以原理讲解和技术方案阐述为主,之后会慢慢把项目开源出来,一起共建KG,从知识抽取到知识融合、知识推理、质量评估等争取走通完整的流程。

本文转载于网络 如有侵权请联系删除

相关文章

  • java中random的用法详解

    大家好,又见面了,我是你们的朋友全栈君。java中存在两个随机函数,它们分别来自java.long.Math.random()和java.util.Random();其中前者的适用范围比较小,完全可以被后者取代。一、java.lang.Math.random()方法的用法①、方法类型: publicstaticdoublerandom();此方法是一个无参,double类型返回值的公开静态方法。返回一个大于0的double类型数据,该值大于等于0.0且小于1.0,返回的是一个伪随机选择数,在该范围内(几乎)均匀分布。例如:publicclassTestRandom{ publicstaticvoidmain(String[]args){ intsum=0; while(true){ floata=(float)Math.random(); System.out.println(a); sum++; if(sum==10) break; } } }复制二、 java.util.Random类用法①、该类的构造方法: Random():构造

  • Chainlink 对 Luna 报价失误分析

    本文作者:Ashton[1]0x01Luna价格崩了,借贷应用躺枪了近期Luna是圈内最热门的话题了,其价格从最高的100多美金,直接跌倒不到0.000001美金,后面又涨了100多倍到0.000X美金。当大家都在分析Luna本身时,币安链上最大的借贷应用Venus却出事了,有人存入大量的Luna,借走了大量资产,导致平台坏账。Venus使用业界头部预言机Chainlink[2]作为价格源,当时Luna的价格在0.01美金左右,但从Chainlink拿到的报价却停留在了0.107美金。Chainlink的报价居然停止工作了0x02Chainlink的回应按照Chainlink官方回应,停止报价的原因是因为Luna的价格波动超出了正常范围,触发了内置的熔断机制,这是协议抗风险的一种措施。只是这个抗风险的措施却带来了实实在在的损失,也是滑稽。官方的第二个回应,是让Luna价格源404(https://data.chain.link/bsc/mainnet/crypto-usd/luna-usd)了。0x03熔断代码分析Chainlink的价格都是最终由一个叫聚合器(Aggregator)的

  • 【Goland】远程开发

    远程开发有很多种类型,有直接线上环境的云端IDE,文件、编译、测试都可以在云端的IDE实现,跟本地的IDE差别不大,这种方案本质上就是一个webconsole。另外的类型就是通过同步本地开发文件夹里的文件,至少实现文件从本地-->远程同步的功能,这种方案本质上就是通过sftp等方法,同步文件,真正的编译还是在远程做的,当然也可以在本地编译好之后直接同步上传到远程运行。本文主要讲的是第二种方式,Goland上的配置跟普通的JetBrains其他产品如IDEA无异,就是通过配置Deployment来实现的。 Step1 点击+号,增加SFTP配置 Step2 配置Connection的参数,就是普通的SSH的参数,注意host和port要填对了。 Step3 配置Mapping,这里的Mapping指的是远程文件夹和本地文件夹的映射关系。在图中,我会把本地的/Users/runzhliu/tencent/glog和远程的/data/k8s给映射起来。 Step4 测试同步。 上图的文件夹树是通过Goland内置的remotehostbrowser查看的,可以配置个快捷键来快

  • View相关问题再探

    昨天发了关于线程更新UI的一些内容,其中关于View的一些问题还是比较重要的。我们再来回顾下,并提出一些问题。Activity从创建到我们看到界面,发生了哪些事首先是通过setContentView加载布局,这其中创建了一个DecorView,然后根据然后根据activity设置的主题(theme)或者特征(Feature)加载不同的根布局文件,最后再通过inflate方法加载layoutResID资源文件,其实就是解析了xml文件,根据节点生成了View对象。流程图:加载布局流程其次就是进行view绘制到界面上,这个过程发生在handleResumeActivity方法中,也就是触发onResume的方法。在这里会创建一个ViewRootImpl对象,作为DecorView的parent然后对DecorView进行测量布局和绘制三大流程。流程图:绘制流程Activity、PhoneWindow、DecorView、ViewRootImpl的关系?PhoneWindow是Window的唯一子类,每个Activity都会创建一个PhoneWindow对象,你可以理解它为一个窗口,但不是真

  • 还在苦恼MySQL如何根据日期精确计算年龄?看这一篇,就够了!

    转译自HowToCalculateAgeFromDateOfBirthInMySQL-Querychat,中文转载,请注明出处。使用SQL语句计算年龄,在事务处理和日期计算中,较为常见。MySQL提供了许多日期函数,可以自由发挥。本文中看我们尝试SQL年龄计算——组件MySQL没有开箱即用的工具,用于计算年龄。所以,这也阻挡不了我们求知的热情。工具不够,自己来凑。没有直接的函数,我们就用给的函数,组装出来一个。说白了,年龄就是啷个日期差。当前日期,减去生日。那就是年龄。MySQL已经提供的函数,下面介绍一下:CURDATE()–返回当前日期TIMESTAMPDIFF()–计算时间差,差值单位自定义这俩函数就够了,日期差,获取年差值,月差值,或者其他。CURDATE()返回MySQL服务器运行时间。无需传参,调用如下:CURDATE()TIMESTAMPDIFF()调用格式如下:TIMESTAMPDIFF(unit,begin_date,end_date)复制单位unit决定了返回数值。unit的可选项如下:YEARQUARTERMONTHWEEKDAYHOURMINUTESECONDM

  • 面试官问我,使用Dubbo有没有遇到一些坑?我笑了。

    本文来源于公众号「肥朝」前言17年的时候,因为一时冲动没把持住(当然最近也有粉丝叫我再冲动一把再更新一波),结合面试题写了一个系列的Dubbo源码解析.目前公众号大部分粉丝都是之前的粉丝,这里不过多介绍.根据我的面试经验而言,能在简历上写上原理、源码等关键词的,是非常具备核心竞争力的.上周和一个公众号粉丝交流面试情况如下面试的时候,把源码一波分析,令面试官虎躯一震!在一阵前戏过后,以为接下来无非就是身体的一顿抽搐一切变得索然无味,不料面试官来了句令剧情发生了反转"你对Dubbo源码这么熟悉,那请问你使用的时候,有没有遇到什么坑"我擦,毫无准备的他,菊花顿时一紧!此时就面临唬住了50K,唬不住就只能5K的局面,慌了!论如何反杀相信大家面试都遇到过类似问题,因为源码解析网上很多,很多人"考前突击"一下,但是遇到喜欢问细节的面试官,终究难逃法眼,无处遁形.遇到这个问题,我们如何反杀一波?那么我就从一次聊天记录说起,毕竟只有关注肥朝公众号,拥有真实场景的源码实战(非常重要),遇到这类问题,才不至于出现猛虎落泪的情形真实场景描述那么我们把业务相关去掉,抽取

  • iOS AFNetworking 源码阅读三

    接下来我们来补充之前AFURLResponseSerialization这一块是如何解析数据的@protocolAFURLResponseSerialization<NSObject,NSSecureCoding,NSCopying> /** Theresponseobjectdecodedfromthedataassociatedwithaspecifiedresponse. @paramresponseTheresponsetobeprocessed. @paramdataTheresponsedatatobedecoded. @paramerrorTheerrorthatoccurredwhileattemptingtodecodetheresponsedata. @returnTheobjectdecodedfromthespecifiedresponsedata. */ -(nullableid)responseObjectForResponse:(nullableNSURLResponse*)response data:(nullableNSData*)d

  • 如何自下而上在腾讯做开源?

    15万颗GitHubStar,57个涵盖人工智能、移动开发、小程序、架构、系统等多个前沿技术领域的开源项目——这是6月26日上午,腾讯移动互联网事业群总经理刘昕,作为腾讯开源顾问和Linux基金会董事,在LC3(LinuxCon+ContainerCon+CloudOpen)国际开源盛会上,介绍的腾讯部分开源成果。在过去六年里,腾讯开源坚持做好开发者体验,从内部开源到对外开源,实现从开源新兵到开源社区一员大将的跨越。 腾讯开源始于2010年,在开放战略之下,“开放、共享、合力开发”的研发模式开始在内部推行。至今,已有超过8000个优质项目在腾讯内部跨团队、跨部门、跨业务地被广泛运用。这为腾讯外部开源打下了坚实基础。2016年至今,腾讯不断将内部开源出来的优质项目在GitHub上发布,腾讯开源逐步进入快节奏时代。其中仅2017年一年,就开源将近20个项目。其中不乏世界排名前十的前端开发工具WeUI,阅文集团、科大讯飞等公司都广泛使用的微服务框架TARS,可以快速建立大规模机器学习平台的AI开源项目Angel等受国际社区高度认可的优秀开源项目。然而,要深度融入开源社区,不只需项目发布,更需

  • 原 GIT忽略本地已存在文件的修改

    1、将文件修改忽略git update-index --assume-unchanged FILENAME复制2、取消文件忽略git update-index --no-assume-unchanged FILENAME复制如果文件未上传到库中,并为提交到本地版本库中记录,最好使用:.gitignore复制

  • 跨境支付:区块链的应用与挑战

    巴洁如 腾讯研究院高级研究员  过去的五十年中,技术创新已成为金融服务产业转型升级过程中的重要驱动力。从半导体、中央处理器、个人电脑、互联网、智能设备、移动通信,到云计算、大数据、物联网、生物识别、区块链,技术创新不断涌现并日益成熟,将引领金融服务领域的下一轮创新浪潮。此前,金融技术创新集中体现在应用层面,对基础设施的改造作用较为局限。 有观点认为,技术的出现实质上是将纸面操作转换成半电子化过程,而整个逻辑还是以纸质文件为基础的。而区块链技术之所以在金融业界引起高度关注,正是因为其有望对金融服务的基础设施产生变革性影响。本文从区块链技术的产生、兴起和基本原理出发,简要探讨区块链技术应用于传统跨境支付业务模式的潜在效益和存在问题。区块链技术溯源 作为比特币的底层技术,区块链技术(也称为分布式账本技术DLT)近年来在科技和金融领域受到广泛关注。2008年,化名为“中本聪”的个人(或组织)发布了一种点对点现金系统及其基础协议,2009年诞生了名为“比特币”的加密货币。与法定货币不同,比特币没有集中的发行方,完全由网络节点计算生成。在经历了大幅度的价格波动之后,对比特币等虚拟货币的讨论逐渐回归

  • Instagram 开源用于 Python 3的MonkeyType 工具

    Instagram宣布将其MonkeyType工具开源。它是通过运行时跟踪类型自动将类型注释添加到您的Python3代码的工具。授权协议:BSD开发语言:Python操作系统:跨平台该公司拥有数百名工程师,编译了超过一百万行代码。它不断地在生产环境中添加新的代码,所以公司需要一种方法来使开发人员更容易阅读和理解代码,同时减少潜在的错误代码。“在MonkeyType的帮助下,我们已经在代码库中对三分之一的功能进行了注释,而且我们已经看到了类型检查会捕获更多的错误。”Instagram基础设施团队工程师CarlMeyer在一篇文章中写道。使用在MonkeyType可以告诉我们任何有用的东西之前,我们需要让它跟踪一些函数调用。最简单的方法是monkeytyperun在MonkeyType跟踪下运行任何Python脚本。例如,您可以在MonkeyType下轻松运行您的测试套件:$monkeytyperunruntests.py或者:monkeytyperun`whichpytest`当你的测试运行时,MonkeyType检查每个函数调用的参数类型和返回/yield类型,并将它们记录在数据库中。

  • SublimeText SFTP连接Amazon EC2

    SublimeTextSFTP连接AmazonEC2实现步骤[^2]SFTP配置参考文献SublimeTextSFTP连接AmazonEC2 SublimeText3正式版发布了,全平台IDE都换成这个。今天终于有点时间来研究下如何使用pem连接EC2ServerEC2Server会提供给你一个.pem的key,但是单纯用这个Key无法直接连接解决办法很简单:将.pem的引用改成对.ppk的引用1实现步骤2 下载安装PuTTYTypeofkeytogenerate,选择RSA如果你在用旧版本的PuTTy,那么就选择SSH-2RSA点击Load,选择你的.pemSFTP配置 { "type":"sftp", "sync_down_on_open":true, "host":"xx.xxx.xx.xx.xx",//hostip "user":"xxxxxx",//username "remote_path":"/"

  • 【Java面试】五年Java程序员去某东面试竟然在MyBatis缓存这道题翻车了

    一个5年工作经验的小伙伴,去面某东被问到MyBatis何时使用一级缓存,何时使用二级缓存?去之前还特地复习了MyBatis的相关知识,想着自己用MyBatis用得比较熟练了,竟然在这道题上翻车了。今天,我给大家来分享一下MyBatis的缓存机制。1、设计思想Mybatis里面设计了两级缓存来提升数据的检索效率,避免每次数据的访问都需要去查询数据库。先来看一级缓存,它是SqlSession级别的缓存,也叫本地缓存,因为每个用户在执行查询的时候都需要使用SqlSession来执行,为了避免每次都去查数据库,MyBatis把查询出来的数据保存到SqlSession的本地缓存中,后续的SQL如果命中缓存,就可以直接从本地缓存读取。那如果想要实现跨SqlSession级别的缓存?一级缓存就无法实现了,因此,MyBatis引入了二级缓存。当多个用户在查询数据的时候,只要有任何一个SqlSession拿到了数据就会放入到二级缓存里面,其他的SqlSession就可以从二级缓存加载数据。ENTERTITLE2、原理分析接下来,我给大家详细分析一下MyBatis缓存机制的实现原理。先来看一级缓存的实现原

  • 运维记录--K8S中java程序频繁死掉killed

    上周上线完之后,平台频繁出现问题,从服务器查看pod状态为Running 但是从日志中查看就是直接被killed 检查过nginx日志、数据库等未发现异常由上图可以看出最后直接就是被killed下意识的我会以为是程序运行超过了所指定的Xmx参数,但是平台运行的情况我还是了解的,之前即便访问量大的是的也是个别服务或者数据库压力大,不会导致这两天无规律性质的死掉服务,几乎什么服务都可能会进行被killed 我尝试调整过启动脚本Xmx参数但是没用,一样还是会被killed之前也处理过关于pod启动异常的问题,然后我去检查各个节点运行资源情况:free-h#查看运行内存 df-h#查看磁盘空间 top#查看CPU复制并未发现异常这里插句话如果磁盘空间超过85%,会导致docker启动回收垃圾机制,删除你的镜像一类的,会导致你的pod启动异常 运行内存不足也会导致pod启动异常 无异常,就更令我感到诧异并无助 解决问题最怕的就是没发现问题然后先经过治理表面先及时解决平台运行问题kubectldeletepodXXX复制经过重启pod,然后重新运行没问题的,不过过一会指不定又是什么服务进行kill

  • 25 内置函数

    #print()#input()#len()#type()#open()#tuple()#list()#int()#bool()#set()#dir()#id()#str()#print(locals())#返回本地作用域中的所有名字#print(globals())#返回全局作用域中的所有名字#global声明全局变量可以修改#nonlocal声明局部变量可以修改#迭代器.__next__()#next(迭代器)等同于上面的迭代器.__next__()#迭代器=可迭代的.__iter__()#迭代器=iter(可迭代的)等同于上面的可迭代的.__iter__()复制 range(10) range(1,11) print('__next__'indir(range(1,11,2)))复制 #dir查看一个变量拥有的方法复制 print(dir([])) print(dir(1)) help help(str)复制 #callable()判断是不是函数,是否可被调用复制 print(callable(print))#True是不是函数,能否被调用 a=1 print(cal

  • 快速制作规则及获取规则提取器API

    1.引言 前面文章的测试案例都用到了集搜客Gooseeker提供的规则提取器,在网页抓取工作中,调试正则表达式或者XPath都是特别繁琐的,耗时耗力,工作枯燥,如果有一个工具可以快速生成规则,而且可以可视化的即时验证,就能把程序员解放出来,投入到创造性工作中。 之前文章所用的例子中的规则都是固定的,如何自定义规则再结合提取器提取我们想要的网页内容呢?对于程序员来说,理想的目标是掌握一个通用的爬虫框架,每增加一个新目标网站就要跟着改代码,这显然不是好工作模式。这就是本篇文章的主要内容了,本文使用一个案例说明怎样将新定义的采集规则融入到爬虫框架中。也就是用可视化的集搜客GooSeeker爬虫软件针对亚马逊图书商品页做一个采集规则,并结合规则提取器抓取网页内容。 2.安装集搜客GooSeeker爬虫软件 2.1.前期准备 进入集搜客官网产品页面,下载对应版本。我的电脑上已经安装了Firefox38,所以这里只需下载爬虫。 2.2安装爬虫 打开Firefox–>点击菜单工具–>附加组件–>点击右上角附加组件的工具–>选择从文件安装附加组件->选中下载好的爬虫xp

  • 功能安全和预期功能安全——iso26262和iso21448

    自动驾驶汽车功能安全的国际标准是iso26262,而自动驾驶预期功能安全(SOTIF)的国际标准是iso21448。这两者之间的关系如何呢? 参考资料: 1、揭秘ISO21448,它是自动驾驶行业的新风向标?,https://baijiahao.baidu.com/s?id=1627688549067562514&wfr=spider&for=pc 2、系统架构图和硬件架构图,有什么区别?,https://mp.weixin.qq.com/s?__biz=MzUyNDc0Njc3Mw==&mid=2247486020&idx=1&sn=cbb7a057c10d056f93c87a8c7a0c9e3a&chksm=fa29e33ecd5e6a283221b9edd62691dbfdf97c781cf15014fbbdd27cc986e43631e5f8027cc0&scene=132#wechat_redirect

  • python 手机App数据抓取实战一

    前言 当前手机使用成为互联网主流,每天手机App产生大量数据,学习爬虫的人也不能只会爬取网页数据,我们需要学习如何从手机APP中获取数据,本文就以豆果美食为例,讲诉爬取手机App的流程 环境准备 python3 fiddler 一款支持桥接模式的安卓虚拟机(本文使用夜神模拟器) 需要准备的知识有: requests的使用 mongodb的使用 fiddler抓包工具的基本操作 线程池ThreadPoolExecutor的基本使用   项目开始 我们项目的目标是将豆果美食App中所有的菜谱都抓取下来到我们的本地数据库中 本文不再讲解fiddler、安卓模拟器、以及某些python第三方库的安装,不会的同学可以百度,非常简单的操作 我们抓取的流程大概就是 安卓模拟器使用代理连接至fiddler 打开安卓模拟器进行操作 分析fiddler抓到的数据 使用python模拟数据给服务器发送request请求得到响应数据 使用多线程抓取并在本地保存至数据库   1)安卓模拟器使用代理连接至fiddler 打开fiddler,进行设置打开最上方菜单栏中的Tools菜

  • 关键路径

    /*程序:求关节点(无向图) *分析: *一个low数组,low[u]=min(low[v]|vinn) *若low[v]>=low[u],则u是关节点 *步骤: *1.初始状态:一个无向图 *1,数据结构:vector<int>邻接表,vis数组,low数组,count序号全局变量 *2,初始化: *2.过程: *1,判断根节点是否是关节点 1,若生成树的根节点有两可或两颗以上的子树,则此根节点必为关节点 *2,深度优先搜索遍历邻接表,更新序号数组 *3,后序遍历 *4,判断:若low[v]>=low[u],则u是关节点,输出,否则更新low[u]值 */ #include<iostream> #include<vector> #include<algorithm> #include<cstring> usingnamespacestd; #defineMAX1001 vector<int>g[MAX]; intvis[MAX]; intlow[MAX]; intcnt; intans; bool

  • leetcode

    1最长公共子序列 给定两个字符串text1和text2,返回这两个字符串的最长公共子序列的长度。如果不存在公共子序列,返回0。一个字符串的子序列是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。   例如,"ace"是"abcde"的子序列,但"aec"不是"abcde"的子序列。两个字符串的公共子序列是这两个字符串所共同拥有的子序列。 输入:text1="abcde",text2="ace" 输出:3 解释:最长公共子序列是"ace",它的长度为3。复制 输入:text1="abc",text2="def" 输出:0 解释:两个字符串没有公共子序列,返回0。方法:动态规划复制   classSolution{ publicintlongestCommonSubsequence(Stringtext1,Stringtext2){ intm=text1.length(); intn=text2.length(); int[][]dp=newint[m+1][n+1]; f

  • Django基础—— 19.Form

     

相关推荐

推荐阅读