如果你看懂了skipgram和cbow的区别,那么实现上面就很简单了。skipgram是中心词预测周围词,cbow是周围词预测中心词,即dataset那里更换下input和target即可。
具体就不细讲了,大家看源码吧~。
1 |
|
本文分享几个好玩的知识点:
什么叫前馈神经网络呢,emmm,自个去看百度百科定义前馈神经网络。简单来说,就是两个linear加一个激活函数,简单结构如下:
1 | class FFNN(nn.Module): |
其中大名鼎鼎的transformer中也用到了FFNN,所以要认真对待每一种结构哦。
啥叫词袋呢,emmmm,这个咋解释呢?就是从一堆词取context_size大小的词回来。它没有顺序,所以叫做词袋。比如unigram, bigram, trigram,ngram,都是属于词袋。
而大名鼎鼎的word2vec也是属于词袋这种的哦!这里画重点。
这里就不难理解了,就是换一种方式来实现词向量的获取方式。我在这两采用了两种方式,第一种是以前面两个词为准,获取当前词,这叫做用过去的词来预测未来的词。嘿嘿,如果脑洞大开点的话,是不是有种transformer encoder的感觉😂😂😂。
1 | # Defined in Section 5.3.1.2 |
是不是像cbow~
1 |
|
这两者之间就以下几点不同:
其余都一样哦,可以自己跑一跑呢。
当当当,欢迎来学习word2vec skipgram,关于word2vec,网上介绍的例子一大堆,这里就简单说明下。
最开始进行tokenizer的时候,是使用onehot编码,缺点就是矩阵太大,另外太稀疏,而且词和词之前是不具备语义信息的。
你说什么叫语义?语义没有官方定义,可以简单理解成更符合人类认知的,我觉得就可以理解成语义。
而word2vec带来了稠密向量,并且词和词之间有了语义关联,可以用于计算词和词之间的空间距离,也可以叫做相似度。
实现word2vec的方式有两种,一个是Hierarchical Softmax(也是softmax),另外一种是negative sampling。
下面将分别介绍这两种方式的实现思路。
偷懒群众可以直接看:
啥叫Hierarchical Softmax,嘿嘿,这个我没看😂😂😂。总而言之也是softmax,不过应用场景主要在对大规模语料进行softmax的时候加速计算结果,比如softmax(100w个),那么他的优势就体现出来了。
如果感兴趣其实现原理的可以自行百度,我就葛优躺了😂😂😂。
1 | def load_reuters(): |
其中corpus
长下面这个样子:
1 | corpus[:2] |
构建训练数据集的步骤如下:
1 | class SkipGramDataset(Dataset): |
看这段代码,其核心在于,取当前词的index,然后以当前词取左右大小为context_size
的词出来来作为他的中心词,然后在collate_fn那里就转换成当前词的id,和周围词的id作为其预测目标。
是不是瞬间明白他想干什么事儿了吧!!
没明白是吧,继续往下看。
1 | class SkipGramModel(nn.Module): |
这个结构是不是相当简单,从今天来看,这个结构很简单,另外pytorch已经帮忙做了很多,但是放到实现那年,不得不佩服这些研究者。
训练部分就很直白了,每次取batch_size=1024个样本,然后输入模型,获得log_probs=(1024, 31081)结果,其中31081是指vocab_size,然后交叉熵算loss。
到这是不是明白了Hierarchical Softmax而不是softmax的意义了吧。
当面对百万级的文本,就算是隐藏层是检索功能,其计算量也是相当大,而且还会造成冗余计算,这时候对高频词抽样以及负采样就应运而生了。
他的做法是对文档中出现的每个词计算其出现频率,然后以当前词周围context_size大小的作为postive sampling,和选中的词无关的并且以词出现频率高为negative sampling。分别计算当前词和positive以及negative的相关度,就是直接计算其点积,将其loss最低即完成训练。
1 |
|
其中get_unigram_distribution
是获取每个词的出现概率。每次记不住这个unigram,bigram,还有trigram。。。
1 | class SGNSDataset(Dataset): |
这地方有两个地方需要注意的:
第一是获取positive sampling,也就是以当前词周围context_size大小的作为postive sampling,这个在__init__
函数中完成。
第二是获取negative sampling,这个是在collate_fn中完成,其中涉及到一个采样函数multinomial
,这个大家可以参考这篇文章。
1 | class SGNSModel(nn.Module): |
这部分可以直接看源代码了,其中在计算负样本的分类(对数)似然地方,我改了下,更方便理解,其实本质没啥~
1 | # 负样本的分类(对数)似然 |
这部分属于个人猜测部分,不保证其准确性。
抛开所有的理论,单纯看代码思考一个问题,源码这里使用了两个embedding,分别是词嵌入
和上下文嵌入
,那我们能不能只用一个embedding呢?
那既然如此,我们需要修改下源码,有两个地方需要修改:
关于第一点,为什么要在负样本中去掉当前词?
不可能让当前词和当前词在计算相似度时出现悖论吧😂😂😂。
关于第二点,这个没啥好解释的了。
修改后的完整代码如下:
1 | # Defined in Section 5.2.3.3 |
在训练的过程中,发现其loss是往下不断的降低,那么我们可以认为是有用的,但是具体效果要再自行实验下。
关于transformer的一些基础知识,之前在看李宏毅视频的时候总结了一些,可以看here,到写此文章时,也基本忘的差不多了,故也不深究,讲两个关于transformer的基本应用,来方便理解与应用。
1 | #加载数据 |
其中load_treebank代码:
1 | def load_treebank(): |
加载后可以看到,train_data
和test_data
都是list,其中每一个sample都是tuple,分别是input和target。如下:
1 | >>> train_data[0] |
1 |
|
1 | class PositionalEncoding(nn.Module): |
这里有几点可能需要注意的:
因为self attention是没有像rnn位置信息编码的,所以transformer引入了positional encoding,使用绝对位置进行编码,对每一个输入加上position信息,可以看self.pe
,这个一个static lookup table。目前也出现一些使用relative positional encoding的,也就是加入相对位置编码,这个在ner任务中挺常见,比如TENER和Flat-Lattice-Transformer。但是最近google证明这种相对位置编码只是引入了更多的信息特征进来😭😭😭😭。。
扯完上面这个,进入正题,那就是如何计算的。
看forward部分,发现首先进行了torch.transpose操作,然后进行self.position_embedding,这个transpose是否让你感到困惑呢?
如果没有就不用看了😭😭😭。。。
一般输入Embedding的shape是(batch_size, seq_length),然后对每个seq_length那维的token进行编码获取对应的feature。但是这里将其transpose了,变成了(seq_length, batch_size),这种操作是否理解呢?ok,举个例子:
1 | tensor([[1, 2, 3], |
这个就是我们通常理解的(batch_size, seq_length),如果将其transpose下就变成了:
1 | tensor([[1, 4], |
囔,是不是理解了呢,是对position进行embedding,然后接着看PositionalEncoding是如何forward的。
1 | def forward(self, x): |
那么上述例子就是指获取self.pe
前70个长度的位置编码信息,然后和x
进行相加返回,从而带入了位置编码信息。
1 | >>> encoder_layer = nn.TransformerEncoderLayer(d_model=512, nhead=8) |
这部分就容易理解了,使用多少nhead和TransformerEncoder的num_layers。
这地方基本和之前一样,就是linear n_out=2,然后交叉熵算loss就行。
我稍微改动了下源码,这样理解起来会更方便。
1 | class Transformer(nn.Module): |
目前nlp都变成了微调时代,关于transformer网络结构,感兴趣可以点击我上面链接,可以看看从代码层面如果实现encoder和decoder部分。
共指解析,按照百度的定义如下:
1 | 众所周知,人们为了避免重复,习惯用代词、称谓和缩略语来指代前面提到的实体全称。例如,在文章开始处会写“哈尔滨工业大学”,后面可能会说“哈工大”、“工大”等,还会提到“这所大学”、“她”等。这种现象称为共指现象。 |
简而言之,其目的在于自动识别表示同一实体的名词短语或代词等。
举个例子:
哈尔滨工业大学,一般学生或者大众喜欢简称为哈工大,工大等,她是一所美丽的大学。
实体(entity): 应是唯一定义的,并且具有共知的。哈尔滨工业大学
即为这句话的实体。
指称(mention): 实体在自然语言文本中的另外一种表达形式,哈工大
,工大
,她
都是指称。
共指(coreference): 如果文本或句子中的两个或多个mention指向同一个entity,那么则称为共指。
到这里可以看出,一个复杂的句子中可能会有多个实体以及对应的多个指称共指于不同的实体,这可以是一个分类任务也可以是一个聚类任务。
根据认知,中文里面能做实体的一般是专有名词
,比如清华大学
,《海蒂》
,各行各业有不同的专有名词。另外就是名词
或者名词短语
以及代词
,比如这人
,他
,它
,她
等。
下面介绍一种算法。
论文地址: Word-Level Coreference Resolution
代码地址:wl-coref
先说个人感受,这个咋感觉更像是提升速度,topK操作,而没有那么多骚操作来提升效果。代码质量杠杠的,但是不是batch训练,又有点怪怪的~
代码对于训练部分看完了,如果有说的不对的,或者没有涵盖到重点的,非常欢迎指教!
1 | def _bertify(self, doc: Doc) -> torch.Tensor: |
1 | from typing import Tuple |
假设tokens长度为455, 这里输出就变成了word level embedding。
还是觉得,不考虑batch_size那一维,整个代码都方便理解许多😂😂😂😂😂😂😂😂😂😂。
1 | class RoughScorer(torch.nn.Module): |
看到么看到么,人家到这里才开始干活~
top_indices的维度为(405,50),表示这个句子一共有405个tokens,然后获取每个token最相关联的50个tokens的索引。
1 | def forward(self, # type: ignore # pylint: disable=arguments-differ #35566 in pytorch |
这部分看着有点绕,看如下代码:
1 | def forward(self, *, # type: ignore # pylint: disable=arguments-differ #35566 in pytorch |
_get_pair_matrix中的b_mentions,可参考b_mentions。后续接了个ffnn,获得其最终得分。
整体代码作者挺喜欢参差网络和前馈神经网络这种操作。
CorefLoss计算分成了两部分,一个是NLML,另外一个BCELoss.
1 | @staticmethod |
1 | # -*- coding: utf8 -*- |
1 | >>> a |
这种写法我挺喜欢的,比如:
1 |
|
快速想一想,你能想到torch有哪些常见的index操作??
1 | >>> a = torch.tensor([[1, 2, 3], |
1 | >>> a |
根据上面例子可以看到,a
为矩阵,选择a
中的index,但是下面介绍一个map操作.
1 | >>> index |
这种操作有一个真实场景,比如:
1 | # 1. 这是两个特征 |
1 | import torch |
语义依存分析 (Semantic Dependency Parsing, SDP),分析句子各个语言单位之间的语义关联,并将语义关联以依存结构呈现。
使用语义依存刻画句子语义,好处在于不需要去抽象词汇本身,而是通过词汇所承受的语义框架来描述该词汇,而论元的数目相对词汇来说数量总是少了很多的。
语义依存分析目标是跨越句子表层句法结构的束缚,直接获取深层的语义信息。
例如以下三个句子,用不同的表达方式表达了同一个语义信息,即张三实施了一个吃的动作,吃的动作是对苹果实施的。
语义依存分析不受句法结构的影响,将具有直接语义关联的语言单元直接连接依存弧并标记上相应的语义关系。这也是语义依存分析与句法依存分析的重要区别。
如上例对比了句法依存和语义分析的结果,可以看到两者存在两个显著差别。
第一,句法依存某种程度上更重视非实词(如介词)在句子结构分析中的作用,而语义依存更倾向在具有直接语义关联的实词之间建立直接依存弧,非实词作为辅助标记存在。
第二,两者依存弧上标记的语义关系完全不同,语义依存关系是由论元关系引申归纳而来,可以用于回答问题,如我在哪里喝汤,我在用什么喝汤,谁在喝汤,我在喝什么。但是句法依存却没有这个能力。
第三,句法依存为树结构,语义依存为图结构,即是说当前词的依存弧可以有多个。
语义依存与语义角色标注之间也存在关联,语义角色标注只关注句子主要谓词的论元及谓词与论元之间的关系,而语义依存不仅关注谓词与论元的关系,还关注谓词与谓词之间、论元与论元之间、论元内部的语义关系。语义依存对句子语义信息的刻画更加完整全面。
https://github.com/geasyheart/semantic-dependency-parser
欢迎Star!
目前貌似公开的只有SEMEVAL2016数据集,地址在:HIT-SCIR/SemEval-2016,代码仓库中的数据集是将text和news两类合并而来。
额外插一句,对于一个算法项目来讲,不仅仅是算法部分,还要有数据,即使不能公开,也可以造一些例子,能够跑通算法,HanLP在这方面真的是无敌存在!
1 | semantic_dependency_parser.py [line:34] INFO SemanticDependencyModel( |
1 | BiaffineDependencyModel( |
和dependency parser结构相同,但是loss计算和解码部分不同。
区别点在于,举个例子:
1 | # pred_arcs.shape |
因为dependency parser有一个限制,即当前词只可能依存其他一个词,那么argmax(-1)即是在49那里获取最大的,表示和这49个词中最大的作为依存关系,使用交叉熵。
而semantic dependency parser没有这个限制,当前词可能和多个词存在依存关系,那么他的pred_arcs和true_arcs的维度是一样的,都是(32, 49, 49),所以使用BCELoss。
当然也可以用交叉熵,只需要将pred_arcs的维度转换成(32, 49, 49, 2)即可,也是我下面的做法。
在这里计算loss时,采用的是交叉熵,也就是说s_edge.size(-1) == 2,表示当前词和句子所有词之间是
或者否
,然后argmax(-1)进行解码。
在HanLP计算loss时,对于arc(即edge)的shape为(batch_size, seq_length, seq_length),因为biaffine的输出维度为1,所以这里计算loss时使用BCELoss,表示当前词和句子所有词之间是否存在关系。
另外一个两者的区别点在于计算rel时,HanLP采取的方式是各自计算各自的loss(即arc和rel),然后loss相加。
这里计算rel loss时融合了arc的信息进来,好处就在于能够快速收敛和提升准确度吧。
https://www.ltp-cloud.com/intro#benchmark
关系类型 | Tag | Description | Example |
---|---|---|---|
施事关系 | Agt | Agent | 我送她一束花 (我 <-- 送) |
当事关系 | Exp | Experiencer | 我跑得快 (跑 --> 我) |
感事关系 | Aft | Affection | 我思念家乡 (思念 --> 我) |
领事关系 | Poss | Possessor | 他有一本好读 (他 <-- 有) |
受事关系 | Pat | Patient | 他打了小明 (打 --> 小明) |
客事关系 | Cont | Content | 他听到鞭炮声 (听 --> 鞭炮声) |
成事关系 | Prod | Product | 他写了本小说 (写 --> 小说) |
源事关系 | Orig | Origin | 我军缴获敌人四辆坦克 (缴获 --> 坦克) |
涉事关系 | Datv | Dative | 他告诉我个秘密 ( 告诉 --> 我 ) |
比较角色 | Comp | Comitative | 他成绩比我好 (他 --> 我) |
属事角色 | Belg | Belongings | 老赵有俩女儿 (老赵 <-- 有) |
类事角色 | Clas | Classification | 他是中学生 (是 --> 中学生) |
依据角色 | Accd | According | 本庭依法宣判 (依法 <-- 宣判) |
缘故角色 | Reas | Reason | 他在愁女儿婚事 (愁 --> 婚事) |
意图角色 | Int | Intention | 为了金牌他拼命努力 (金牌 <-- 努力) |
结局角色 | Cons | Consequence | 他跑了满头大汗 (跑 --> 满头大汗) |
方式角色 | Mann | Manner | 球慢慢滚进空门 (慢慢 <-- 滚) |
工具角色 | Tool | Tool | 她用砂锅熬粥 (砂锅 <-- 熬粥) |
材料角色 | Malt | Material | 她用小米熬粥 (小米 <-- 熬粥) |
时间角色 | Time | Time | 唐朝有个李白 (唐朝 <-- 有) |
空间角色 | Loc | Location | 这房子朝南 (朝 --> 南) |
历程角色 | Proc | Process | 火车正在过长江大桥 (过 --> 大桥) |
趋向角色 | Dir | Direction | 部队奔向南方 (奔 --> 南) |
范围角色 | Sco | Scope | 产品应该比质量 (比 --> 质量) |
数量角色 | Quan | Quantity | 一年有365天 (有 --> 天) |
数量数组 | Qp | Quantity-phrase | 三本书 (三 --> 本) |
频率角色 | Freq | Frequency | 他每天看书 (每天 <-- 看) |
顺序角色 | Seq | Sequence | 他跑第一 (跑 --> 第一) |
描写角色 | Desc(Feat) | Description | 他长得胖 (长 --> 胖) |
宿主角色 | Host | Host | 住房面积 (住房 <-- 面积) |
名字修饰角色 | Nmod | Name-modifier | 果戈里大街 (果戈里 <-- 大街) |
时间修饰角色 | Tmod | Time-modifier | 星期一上午 (星期一 <-- 上午) |
反角色 | r + main role | 打篮球的小姑娘 (打篮球 <-- 姑娘) | |
嵌套角色 | d + main role | 爷爷看见孙子在跑 (看见 --> 跑) | |
并列关系 | eCoo | event Coordination | 我喜欢唱歌和跳舞 (唱歌 --> 跳舞) |
选择关系 | eSelt | event Selection | 您是喝茶还是喝咖啡 (茶 --> 咖啡) |
等同关系 | eEqu | event Equivalent | 他们三个人一起走 (他们 --> 三个人) |
先行关系 | ePrec | event Precedent | 首先,先 |
顺承关系 | eSucc | event Successor | 随后,然后 |
递进关系 | eProg | event Progression | 况且,并且 |
转折关系 | eAdvt | event adversative | 却,然而 |
原因关系 | eCau | event Cause | 因为,既然 |
结果关系 | eResu | event Result | 因此,以致 |
推论关系 | eInf | event Inference | 才,则 |
条件关系 | eCond | event Condition | 只要,除非 |
假设关系 | eSupp | event Supposition | 如果,要是 |
让步关系 | eConc | event Concession | 纵使,哪怕 |
手段关系 | eMetd | event Method | |
目的关系 | ePurp | event Purpose | 为了,以便 |
割舍关系 | eAban | event Abandonment | 与其,也不 |
选取关系 | ePref | event Preference | 不如,宁愿 |
总括关系 | eSum | event Summary | 总而言之 |
分叙关系 | eRect | event Recount | 例如,比方说 |
连词标记 | mConj | Recount Marker | 和,或 |
的字标记 | mAux | Auxiliary | 的,地,得 |
介词标记 | mPrep | Preposition | 把,被 |
语气标记 | mTone | Tone | 吗,呢 |
时间标记 | mTime | Time | 才,曾经 |
范围标记 | mRang | Range | 都,到处 |
程度标记 | mDegr | Degree | 很,稍微 |
频率标记 | mFreq | Frequency Marker | 再,常常 |
趋向标记 | mDir | Direction Marker | 上去,下来 |
插入语标记 | mPars | Parenthesis Marker | 总的来说,众所周知 |
否定标记 | mNeg | Negation Marker | 不,没,未 |
情态标记 | mMod | Modal Marker | 幸亏,会,能 |
标点标记 | mPunc | Punctuation Marker | ,。! |
重复标记 | mPept | Repetition Marker | 走啊走 (走 --> 走) |
多数标记 | mMaj | Majority Marker | 们,等 |
实词虚化标记 | mVain | Vain Marker | |
离合标记 | mSepa | Seperation Marker | 吃了个饭 (吃 --> 饭) 洗了个澡 (洗 --> 澡) |
根节点 | Root | Root | 全句核心节点 |
1 | Semantic Role Labeling (SRL) is defined as the task to recognize arguments for a given predicate and assign semantic role labels to them. |
1 | 语义角色标注 (Semantic Role Labeling, SRL) 是一种浅层的语义分析技术,标注句子中某些短语为给定谓词的论元 (语义角色) ,如施事、受事、时间和地点等。其能够对问答系统、信息抽取和机器翻译等应用产生推动作用。 仍然是上面的例子,语义角色标注的结果为: |
https://github.com/geasyheart/srl-parser
欢迎Star!
看黄色那部分:
施事者
,叫为谓语
,汤姆为受事者
施事者
,拿为谓语
,外衣为受事者
‘各位/PN 好/VA ,/PU 欢迎/VV 您/PN 收看/VV 国际/NN 频道/NN 的/DEG 今日/NT 关注/NN 。/PU’
此图自己画的,如有需要可参考
谓语
,您为受事者
,收看国际频道的今日关注为语义角色
数据集来自ontonotes5.0,但是此为收费数据集,或者需要大学帐号注册,找到一个开源的https://github.com/GuocaiL/Coref_Resolution/archive/master.zip#data/,处理后的数据集以 jsonlines后缀存储,放到此处。
具体的处理逻辑可参考这里。
目前常见的有span-based,bio-based,treecrf,treecrf是yzhangcs的实现方式。bio-based是用序列标注的方式来做(hanlp和ltp均以此实现),故是本文的重点。
看这个文件,其中预测的label处理后是这个样子,解释如下:
1 | tensor([[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], |
看到这里是否知道其模型结构了,biaffine
+crf
哇,biaffine
转换成临接矩阵,用于预测谓词
和论元
的关系,论元
用crf序列标注的方式来进行预测。
1 | SpanBIOSemanticRoleLabelingModel( |
到biaffine
这一层没什么需要特别注意的,bert获取词向量的方式从以前的求平均改成了以首字代表词向量。后面接两个mlp以及biaffine。重点在于如何和crf融合到一起?
基于上述两个前提,将batch_size
和第一个seq_length
进行flatten,因为第一个seq_length为谓语,不影响论元的预测,转换后输入到crf中,就可以计算loss了,解码一样。
预测出来的结果示例如下:
1 | # pred |
pred类型为List[List[int]]
,他的长度等于batch_tokens中每个词的长度,即:
1 | len(pred) == sum([len(i) for i in batch["batch_tokens"]]) |
** 其中每一行表示的是当前词和整句每个词所呈现出来的关系。 **
基于上面结论,就不难写评估代码了,将其转成(token_index, start, end, label)
,然后set取交集,最终计算f1值,可看这里。
基本如上,具体可看。
从这里也可以看出,语义角色标注任务任重道远。
关系类型 | Tag | Description | Example |
---|---|---|---|
ARG0 | causers or experiencers | 施事者、主体、触发者 | [政府 ARG0]鼓励个人投资服务业。 |
ARG1 | patient | 受事者 | 政府鼓励[个人 ARG1]投资服务业。 |
ARG2 | range | 语义角色2 | 政府鼓励个人[投资服务业 ARG2]。 |
ARG3 | starting point | 语义角色3 | 巴基斯坦[对谈判前景 ARG3]表示悲观。 |
ARG4 | end point | 语义角色4 | 产检部门将产检时间缩短到[一至三天 ARG4]。 |
ADV | adverbial | 状语 | 我们[即将 ADV]迎来新年。 |
BNF | beneficiary | 受益人 | 义务[为学童及老师 BNF]做超音波检查 。 |
CND | condition | 条件 | [如果早期发现 CND],便能提醒当事人注意血压的变化。 |
CRD | coordinated arguments | 并列 | 跟南韩、[跟美国 CRD]谋求和平关系的举动也更加积极。 |
DGR | degree | 程度 | 贫铀弹含有放射性比铀强[20万倍 DGR]。 |
DIR | direction | 方向 | [从此处 DIR] 我们可以发现寇克斯报告的精髓。 |
DIS | discourse marker | 会话标记 | 警方上午针对目击者做笔录,[而 DIS]李士东仍然不见踪影。 |
EXT | extent 基于树形条件随机场的高阶句法分析此篇文章貌似没有重点,日常笔记吧。 基于树形条件随机场的高阶句法分析作者硕士毕业论文,关于句法分析的历史与实现基本讲了一遍,包括作者使用TreeCRF高阶建模等工作。 对于句法分析工作,百度ddparser相比下来可能是工业上更好的选择,不过目前个人更倾向于语义句法工作,相比下来更接近直观感受(还是看任务啦~)。 不管是semantic role labeling(语义角色标注)或者semantic dependency parser(语义依存分析),看ltp的演示效果。 ![]() 但是不能光看这种效果,从目前公开的论文水平来看,准确率并没有很高,另外高质量,高数量的标注数据集也相对少。 大家都是一样的模型,比的就是数据集喽,这点不得不夸HanLP,至少人家代码里面都有数据集,方便学习。
缺失模块。 jsonContent: meta: false pages: false posts: title: true date: true path: true text: false raw: false content: false slug: false updated: false comments: false link: false permalink: false excerpt: false categories: false tags: true
探索世界美好的存在。
|