0%

1. 准备模型

使用tf.keras训练一个简单的线性回归模型,保存为protobuf文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import tensorflow as tf
from tensorflow.keras import models,layers,optimizers

## 样本数量
n = 800

## 生成测试用数据集
X = tf.random.uniform([n,2],minval=-10,maxval=10)
w0 = tf.constant([[2.0],[-1.0]])
b0 = tf.constant(3.0)

Y = X@w0 + b0 + tf.random.normal([n,1],
mean = 0.0,stddev= 2.0) # @表示矩阵乘法,增加正态扰动

## 建立模型
tf.keras.backend.clear_session()
inputs = layers.Input(shape = (2,),name ="inputs") #设置输入名字为inputs
outputs = layers.Dense(1, name = "outputs")(inputs) #设置输出名字为outputs
linear = models.Model(inputs = inputs,outputs = outputs)
linear.summary()

## 使用fit方法进行训练
linear.compile(optimizer="rmsprop",loss="mse",metrics=["mae"])
linear.fit(X,Y,batch_size = 8,epochs = 100)

tf.print("w = ",linear.layers[1].kernel)
tf.print("b = ",linear.layers[1].bias)

## 将模型保存成pb格式文件
export_path = "linear_model/"
version = "1" #后续可以通过版本号进行模型版本迭代与管理
linear.save(export_path+version, save_format="tf")

查看模型

saved_model_cli show –dir=’linear_model/1’ –all

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
MetaGraphDef with tag-set: 'serve' contains the following SignatureDefs:

signature_def['__saved_model_init_op']:
The given SavedModel SignatureDef contains the following input(s):
The given SavedModel SignatureDef contains the following output(s):
outputs['__saved_model_init_op'] tensor_info:
dtype: DT_INVALID
shape: unknown_rank
name: NoOp
Method name is:

signature_def['serving_default']: # 注意signature_def
The given SavedModel SignatureDef contains the following input(s):
inputs['inputs'] tensor_info: # 注意inputs
dtype: DT_FLOAT
shape: (-1, 2)
name: serving_default_inputs:0
The given SavedModel SignatureDef contains the following output(s):
outputs['outputs'] tensor_info:
dtype: DT_FLOAT
shape: (-1, 1)
name: StatefulPartitionedCall:0
Method name is: tensorflow/serving/predict
WARNING:tensorflow:From /usr/local/lib/python3.6/site-packages/tensorflow_core/python/ops/resource_variable_ops.py:1786: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version.
Instructions for updating:
If using Keras pass *_constraint arguments to layers.

Defined Functions:
Function Name: '__call__'
Option #1
Callable with:
Argument #1
inputs: TensorSpec(shape=(None, 2), dtype=tf.float32, name='inputs')
Argument #2
DType: bool
Value: True
Argument #3
DType: NoneType
Value: None
Option #2
Callable with:
Argument #1
inputs: TensorSpec(shape=(None, 2), dtype=tf.float32, name='inputs')
Argument #2
DType: bool
Value: False
Argument #3
DType: NoneType
Value: None

Function Name: '_default_save_signature'
Option #1
Callable with:
Argument #1
inputs: TensorSpec(shape=(None, 2), dtype=tf.float32, name='inputs')

Function Name: 'call_and_return_all_conditional_losses'
Option #1
Callable with:
Argument #1
inputs: TensorSpec(shape=(None, 2), dtype=tf.float32, name='inputs')
Argument #2
DType: bool
Value: False
Argument #3
DType: NoneType
Value: None
Option #2
Callable with:
Argument #1
inputs: TensorSpec(shape=(None, 2), dtype=tf.float32, name='inputs')
Argument #2
DType: bool
Value: True
Argument #3
DType: NoneType
Value: None

注意:请牢记上面的signature_def值和inputs值及其shape,在grpc调用的时候需要用到。

2. tensorflow/serving docker方式安装
  1. 拉取镜像

    docker pull tensorflow/serving:latest

    在docker hub中有四中镜像。

    • :latest
    • :lasest-gpu
    • :lasest-devel
    • :lasest-devel-gpu

    两种划分共有4种镜像。CPU、GPU、稳定版、开发版。稳定版在dockerfile中启动tensorflow_model_server服务,创建容器即启动服务。开发版需要在创建容器之后,进入容器,手动启动tensorflow_model_server服务。

    以下都已稳定版为例。

  2. 启动容器

    docker run -t -p 8501:8501 -p 8500:8500 -v /root/mutimodel/linear_model:/models/linear_model -e MODEL_NAME=linear_model tensorflow/serving

    ==备注:路径只需到模型这一级,不能精确到版本级别,比如:/root/mutimodel/linear_model而不是/root/mutimodel/linear_model/1,服务会默认加载最大版本号的模型。==

    参数解释:

    • -p : 端口映射,tensorflow serving提供了两种调用方式:gRPC和REST,
      gRPC的默认端口是8500,REST的默认端口是8501.

    • -v:目录映射,需要注意的是,在新版的docker中,已经移除了–mount type=bind,source=%source_path,target=$target_path的挂载目录方式。

    • -e:设置变量。

      • 可选参数: MODLE_NAME(默认值:model)
      • 可选参数:MODEL_BASE_PATH(默认值/models)

      启动容器之后,相当于在容器中启动服务:

      1
      tensorflow_model_server --port=8500 --rest_api_port=8501 --model_name=${MODEL_NAME} --model_base_path=${MODEL_BASE_PATH}/${MODEL_NAME}

    如果需要修改相关参数配置,可以通过如下命令:

    docker run -p 8501:8501 -v /root/mutimodel/linear_model:/models/linear_model -t –entrypoint=tensorflow_model_server tensorflow/serving –port=8500 –model_name=linear_model –model_base_path=/models/linear_model –rest_api_port=8501

    参数解释:

    • -t –entrypoint=tensorflow_model_server tensorflow/serving:如果使用稳定版的docker,启动docker之后是不能进入容器内部bash环境的,–entrypoint的作用是允许你“间接”进入容器内部,然后调用tensorflow_model_server命令来启动TensorFlow Serving,这样才能输入后面的参数。

    tensorflow serving的详细参数如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    Flags:
    --port=8500 int32 Port to listen on for gRPC API
    --grpc_socket_path="" string If non-empty, listen to a UNIX socket for gRPC API on the given path. Can be either relative or absolute path.
    --rest_api_port=0 int32 Port to listen on for HTTP/REST API. If set to zero HTTP/REST API will not be exported. This port must be different than the one specified in --port.
    --rest_api_num_threads=16 int32 Number of threads for HTTP/REST API processing. If not set, will be auto set based on number of CPUs.
    --rest_api_timeout_in_ms=30000 int32 Timeout for HTTP/REST API calls.
    --enable_batching=false bool enable batching
    --batching_parameters_file="" string If non-empty, read an ascii BatchingParameters protobuf from the supplied file name and use the contained values instead of the defaults.
    --model_config_file="" string If non-empty, read an ascii ModelServerConfig protobuf from the supplied file name, and serve the models in that file. This config file can be used to specify multiple models to serve and other advanced parameters including non-default version policy. (If used, --model_name, --model_base_path are ignored.)
    --model_name="default" string name of model (ignored if --model_config_file flag is set)
    --model_base_path="" string path to export (ignored if --model_config_file flag is set, otherwise required)
    --max_num_load_retries=5 int32 maximum number of times it retries loading a model after the first failure, before giving up. If set to 0, a load is attempted only once. Default: 5
    --load_retry_interval_micros=60000000 int64 The interval, in microseconds, between each servable load retry. If set negative, it doesn't wait. Default: 1 minute
    --file_system_poll_wait_seconds=1 int32 Interval in seconds between each poll of the filesystem for new model version. If set to zero poll will be exactly done once and not periodically. Setting this to negative value will disable polling entirely causing ModelServer to indefinitely wait for a new model at startup. Negative values are reserved for testing purposes only.
    --flush_filesystem_caches=true bool If true (the default), filesystem caches will be flushed after the initial load of all servables, and after each subsequent individual servable reload (if the number of load threads is 1). This reduces memory consumption of the model server, at the potential cost of cache misses if model files are accessed after servables are loaded.
    --tensorflow_session_parallelism=0 int64 Number of threads to use for running a Tensorflow session. Auto-configured by default.Note that this option is ignored if --platform_config_file is non-empty.
    --tensorflow_intra_op_parallelism=0 int64 Number of threads to use to parallelize the executionof an individual op. Auto-configured by default.Note that this option is ignored if --platform_config_file is non-empty.
    --tensorflow_inter_op_parallelism=0 int64 Controls the number of operators that can be executed simultaneously. Auto-configured by default.Note that this option is ignored if --platform_config_file is non-empty.
    --ssl_config_file="" string If non-empty, read an ascii SSLConfig protobuf from the supplied file name and set up a secure gRPC channel
    --platform_config_file="" string If non-empty, read an ascii PlatformConfigMap protobuf from the supplied file name, and use that platform config instead of the Tensorflow platform. (If used, --enable_batching is ignored.)
    --per_process_gpu_memory_fraction=0.000000 float Fraction that each process occupies of the GPU memory space the value is between 0.0 and 1.0 (with 0.0 as the default) If 1.0, the server will allocate all the memory when the server starts, If 0.0, Tensorflow will automatically select a value.
    --saved_model_tags="serve" string Comma-separated set of tags corresponding to the meta graph def to load from SavedModel.
    --grpc_channel_arguments="" string A comma separated list of arguments to be passed to the grpc server. (e.g. grpc.max_connection_age_ms=2000)
    --enable_model_warmup=true bool Enables model warmup, which triggers lazy initializations (such as TF optimizations) at load time, to reduce first request latency.
    --version=false bool Display version

    容器启动成功。


    tensorflow_serving/servables/tensorflow/saved_model_warmup.cc:105] No warmup data file found at /models/linear_model/1/assets.extra/tf_serving_warmup_requests
    2020-03-19 01:25:24.979107: I tensorflow_serving/core/loader_harness.cc:87] Successfully loaded servable version {name: linear_model version: 1}
    2020-03-19 01:25:24.982357: I tensorflow_serving/model_servers/server.cc:358] Running gRPC ModelServer at 0.0.0.0:8500 …
    2020-03-19 01:25:24.982960: I tensorflow_serving/model_servers/server.cc:378] Exporting HTTP/REST API at:localhost:8501 …
    [evhttp_server.cc : 238] NET_LOG: Entering the event loop …

    可以看到,启动了grpc的8500端口和RESR的8501端口。

2. REST调用

​ REST api方式调用很简单,可以通过curl或者postman发送一个post请求,也可以用python的requests模拟一个post请求。这里我们使用postman工具。

1584583823994

​ 可以看到正确返回结果。

​ 注意事项:

  • 请求参数:“inputs”,这里对应于模型中的signature_def下面的inputs值。
  • 参数形状:参见tensor_info的shape:(-1, 2)。
  • 参数类型:参见tensor_info的dtype:DT_FLOAT(对应于np.float32)
3. grpc调用
  1. 安装相应的包

    pip install tensorflow-serving-api

  2. 编写代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    import grpc
    import tensorflow as tf
    from tensorflow_serving.apis import predict_pb2
    from tensorflow_serving.apis import prediction_service_pb2_grpc

    options = [('grpc.max_send_message_length', 1000 * 1024 * 1024),
    ('grpc.max_receive_message_length', 1000 * 1024 * 1024)]

    channel = grpc.insecure_channel('ip:8500', options=options)
    stub = prediction_service_pb2_grpc.PredictionServiceStub(channel)

    x = [[1.0, 2.0]]

    request = predict_pb2.PredictRequest()
    request.model_spec.name = "linear_model"
    request.model_spec.signature_name = 'serving_default'
    request.inputs['inputs'].CopyFrom(tf.make_tensor_proto(x, shape=(1, 2)))
    response = stub.Predict(request, 10.0)
    output = tf.make_ndarray(response.outputs["outputs"])[0][0]
    print(output)

    注意事项:

    • request.model_spec.name:模型名
    • request.model_spec.signature_name:必须与模型中定义的一致,参照signature_def值(参见第一节查看模型)
    • request.inputs[‘inputs’]:inputs的key参见tensor_info的inputs值(第一节查看模型)
4. 多模型部署

​ 单一模型部署,上面的方式即可完成。对于多个模型统一部署,基本流程与单模型一致,不同之处在于需要借助模型的配置文件来完成。

  1. model.config

新建mutimodel文件夹,放置多个模型,并建一配置文件model.config.

mutimodel

├── linear_model
│   └── 1
│   ├── assets
│   ├── saved_model.pb
│   └── variables
│   ├── variables.data-00000-of-00001
│   └── variables.index
├── model.config
├── router_model
│   └── 1
│   ├── assets
│   ├── saved_model.pb
│   └── variables
│   ├── variables.data-00000-of-00001
│   └── variables.index
└── textcnn_model
└── 1
├── assets
├── saved_model.pb
└── variables
├── variables.data-00000-of-00001
└── variables.index

12 directories, 10 files

​ model.conf配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
model_config_list {
config {
name: 'linear',
model_platform: "tensorflow",
base_path: '/models/mutimodel/linear_model'
},
config {
name: 'textcnn',
model_platform: "tensorflow",
base_path: '/models/mutimodel/textcnn_model'
},
config {
name: 'router',
model_platform: "tensorflow",
base_path: '/models/mutimodel/router_model'
}
}
  1. 启动容器
1
docker run -p 8501:8501 -p 8500:8500 -v /root/mutimodel/:/models/mutimodel  -t tensorflow/serving --model_config_file=/models/mutimodel/model.config


2020-03-19 0/models/mutimodel/router_model/1/assets.extra/tf_serving_warmup_requests
2020-03-19 02:42:58.197083: I tensorflow_serving/core/loader_harness.cc:87] Successfully loaded servable version {name: router version: 1}
2020-03-19 02:42:58.199987: I tensorflow_serving/model_servers/server.cc:358] Running gRPC ModelServer at 0.0.0.0:8500 …
2020-03-19 02:42:58.200632: I tensorflow_serving/model_servers/server.cc:378] Exporting HTTP/REST API at:localhost:8501 …
[evhttp_server.cc : 238] NET_LOG: Entering the event loop …

REST api 测试。

1584585981550

正常访问。

5. 版本控制
  1. 服务端配置

    tensorflow serving服务默认只会读取最大版本号的版本(按数字来标记版本号),实际上,我们可以通过提供不同的版本的模型,比如提供稳定版、测试版,来实现版本控制,只需要在在配置文件中配置model_version_policy。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    model_config_list {
    config {
    name: 'linear',
    model_platform: "tensorflow",
    base_path: '/models/mutimodel/linear_model'
    model_version_policy{
    specific{
    version: 1,
    version: 2
    }
    }
    version_labels{
    key: "stable",
    value: 1
    }
    version_labels{
    key: "test",
    value: 2
    }
    }
    }

    这里我们同时提供版本号为1和版本号为2的版本,并分别为其取别名stable和test。这样做的好处在于,用户只需要定向到stable或者test版本,而不必关心具体的某个版本号,同时,在不通知用户的情况下,可以调整版本号,比如版本2稳定后,可以升级为稳定版,只需要将stable对应的value改为2即可。同样,若需要版本回滚,将value修改为之前的1即可。

    启动服务

    1
    docker run -p 8501:8501 -p 8500:8500 -v /root/mutimodel/:/models/mutimodel  -t tensorflow/serving --model_config_file=/models/mutimodel/model.config --allow_version_labels_for_unavailable_models=true

    说明:根据官方说明,添加别名只能针对已经加载的模型(先启动服务,再更新配置文件),若想在启动服务的时候设置别名,需要设置allow_version_labels_for_unavailable_models=true。

    官方说明如下:

    Please note that labels can only be assigned to model versions that are already loaded and available for serving. Once a model version is available, one may reload the model config on the fly to assign a label to it. This can be achieved using aHandleReloadConfigRequest RPC or if the server is set up to periodically poll the filesystem for the config file, as described above.

    If you would like to assign a label to a version that is not yet loaded (for ex. by supplying both the model version and the label at startup time) then you must set the --allow_version_labels_for_unavailable_models flag to true, which allows new labels to be assigned to model versions that are not loaded yet.

  2. 客户端调用

    特别说明:version_label设置别名的方式只适用于grpc调用方式,而不适用与REST调用。

    • REST 调用,直接制定版本号。

      1
      2
      3
      4
      5
      6
      7
      curl -d '{"inputs":[[1.0, 2.0]]}' -X POST http://localhost:8501/v1/models/linear/versions/1:predict
      {
      "outputs": [
      [
      2.18523026
      ]
      ]
    • gRPC方式

      使用别名:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      channel = grpc.insecure_channel('49.233.155.170:8500')
      stub = prediction_service_pb2_grpc.PredictionServiceStub(channel)
      x = [[1.0, 2.0]]
      request = predict_pb2.PredictRequest()
      request.model_spec.name = "linear"
      request.model_spec.version_label = "stable"
      request.model_spec.signature_name = 'serving_default'
      request.inputs['inputs'].CopyFrom(tf.make_tensor_proto(x, shape=(1, 2)))
      response = stub.Predict(request, 10.0)
      output = tf.make_ndarray(response.outputs["outputs"])[0][0]
      print(output)

      使用版本号:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      channel = grpc.insecure_channel('49.233.155.170:8500')
      stub = prediction_service_pb2_grpc.PredictionServiceStub(channel)
      x = [[1.0, 2.0]]
      request = predict_pb2.PredictRequest()
      request.model_spec.name = "linear"
      request.model_spec.version.value = 1
      request.model_spec.signature_name = 'serving_default'
      request.inputs['inputs'].CopyFrom(tf.make_tensor_proto(x, shape=(1, 2)))
      response = stub.Predict(request, 10.0)
      output = tf.make_ndarray(response.outputs["outputs"])[0][0]
      print(output)

      ==区别:model_spec.version_label与model_spec.version.value。==

6. 热更新

服务启动后,可以通过重新加载配置文件的方式来实现模型的热更新。可以通过一下两种方式来实现。

  1. HandleReloadConfigRequest (grpc)

    比如我们想新增模型textcnn和router。先更新其配置文件model.config为:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    model_config_list {
    config {
    name: "linear"
    base_path: "/models/mutimodel/linear_model"
    model_platform: "tensorflow"
    model_version_policy {
    specific {
    versions: 1
    versions: 2
    }
    }
    version_labels {
    key: "stable"
    value: 1
    }
    }
    config {
    name: "textcnn"
    base_path: "/models/mutimodel/textcnn_model"
    model_platform: "tensorflow"
    }
    config {
    name: "router"
    base_path: "/models/mutimodel/router_model"
    model_platform: "tensorflow"
    }
    }

    gRPC代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    from google.protobuf import text_format
    from tensorflow_serving.apis import model_management_pb2
    from tensorflow_serving.apis import model_service_pb2_grpc
    from tensorflow_serving.config import model_server_config_pb2

    config_file = "model.config"
    stub = model_service_pb2_grpc.ModelServiceStub(channel)
    request = model_management_pb2.ReloadConfigRequest()

    # # read config file
    config_content = open(config_file, "r").read()
    model_server_config = model_server_config_pb2.ModelServerConfig()
    model_server_config = text_format.Parse(text=config_content, message=model_server_config)
    request.config.CopyFrom(model_server_config)
    request_response = stub.HandleReloadConfigRequest(request, 10)

    if request_response.status.error_code == 0:
    open(config_file, "w").write(str(request.config))
    print("TF Serving config file updated.")
    else:
    print("Failed to update config file.")
    print(request_response.status.error_code)
    print(request_response.status.error_message)

    测试textcnn模型。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
       
    (train_data, train_labels), (test_data, test_labels) = datasets.imdb.load_data(num_words=10000)
    test_data = pad_sequences(test_data, maxlen=200)
    test_data = test_data.astype(np.float32)
    request = predict_pb2.PredictRequest()
    request.model_spec.name = 'textcnn'
    request.model_spec.signature_name = 'serving_default'
    request.inputs['input_1'].CopyFrom(tf.make_tensor_proto(np.array(test_data[0]), shape=(1, 200)))

    start = time.time()
    response = stub.Predict(request, 10.0)
    print("cost time = ", time.time() - start)
    res_from_server_np = tf.make_ndarray(response.outputs["dense"])[0][0]
    label = 1 if res_from_server_np > 0.5 else 0
    print(label)
    1
    2
    cost time =  0.1668863296508789
    0

    模型新增成功。

  2. –model_config_file_poll_wait_seconds

在启动服务的时候,指定重新加载配置文件的时间间隔60s。

1
docker run -p 8501:8501 -p 8500:8500 -v /root/mutimodel/:/models/mutimodel  -t tensorflow/serving --model_config_file=/models/mutimodel/model.config --allow_version_labels_for_unavailable_models=true --model_config_file_poll_wait_seconds=60

立即调用textcnn,可以看到报如下错误。很明显,此时服务并没有加载textcnn模型。

grpc._channel._Rendezvous: <_Rendezvous of RPC that terminated with:
status = StatusCode.NOT_FOUND
details = “Servable not found for request: Latest(textcnn)”
debug_error_string = “{“created”:”@1584608241.949779831”,”description”:”Error received from peer ipv4:49.233.155.170:8500”,”file”:”src/core/lib/surface/call.cc”,”file_line”:1055,”grpc_message”:”Servable not found for request: Latest(textcnn)”,”grpc_status”:5}”

60s之后,观察到服务出现变化,显示已经加载模型textcnn和router。

1584608837466

此时,再次调用textcnn模型

1
2
cost time =  0.1185760498046875
0

正确返回,模型更新成功。

引用:

https://blog.csdn.net/zong596568821xp/article/details/102953720

https://blog.csdn.net/weixin_44899143/article/details/90715186?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task#model_config_file_43

https://blog.csdn.net/JerryZhang__/article/details/86516428

https://stackoverflow.com/questions/54440762/tensorflow-serving-update-model-config-add-additional-models-at-runtime

https://www.tensorflow.org/tfx/serving/serving_config

1. 基本概念

依存句法分析(Dependency Parsing,DP)通过分析语言单位内成分之间的依存关系,揭示其句法结构。直观来讲,就是分析句子中的“主谓宾”、“定状补”这些语法成分,并分析各成分的关系。对句法结构进行分析,一方面是语言理解的自身需求,句法分析是语言理解的基础,另外一方面,句法分析也为其他自然语言处理任务提供支持。比如:句法驱动的统计机器翻译需要对源语言或目标语言进行句法分析。

1.1 谓词

依存句法认为“谓词”中的动词是一个句子的核心,其他成分与动词直接或者间接的产生联系。

1.2 依存理论

依存理论中,“依存”指的是词与词之间处于支配与被支配的关系,这种关系具有方向性。处于支配地位的词称之为支配者(head),处于被支配地位的成分称之为从属者(dependency)。

依存语法存在一个基本假设,句法分析核心是词与词的依存关系,一个依存关系连接两个词:head和dependency。依存关系可以细分为不同类型,表示具体的两个词的依存关系。

1.3 依存关系
关系类型 Tag Description Example
主谓关系 SBV subject-verb 我送她一束花 (我 <– 送)
动宾关系 VOB 直接宾语,verb-object 我送她一束花 (送 –> 花)
间宾关系 IOB 间接宾语,indirect-object 我送她一束花 (送 –> 她)
前置宾语 FOB 前置宾语,fronting-object 他什么书都读 (书 <– 读)
兼语 DBL double 他请我吃饭 (请 –> 我)
定中关系 ATT attribute 红苹果 (红 <– 苹果)
状中结构 ADV adverbial 非常美丽 (非常 <– 美丽)
动补结构 CMP complement 做完了作业 (做 –> 完)
并列关系 COO coordinate 大山和大海 (大山 –> 大海)
介宾关系 POB preposition-object 在贸易区内 (在 –> 内)
左附加关系 LAD left adjunct 大山和大海 (和 <– 大海)
右附加关系 RAD right adjunct 孩子们 (孩子 –> 们)
独立结构 IS independent structure 两个单句在结构上彼此独立
核心关系 HED head 指整个句子的核心

2. 基本方法

  • 基于转移的方法

    基于转移的方法通过shift-reduce两个基本动作,将序列转为树结构。首先用一个 buffer 来存储所有未处理的输入句子,并用一个栈来存储当前的分析状态。动作可以分为:

    1. shift,即将 buffer 中的一个词移到栈中;
    2. $left_arc(x)$,即栈顶两个词 a,b 为 a<-b 的依赖关系,关系种类为 x;
    3. $right_arc(x)$,即栈顶两个词 a,b 为 a->b 的依赖关系,关系种类为 x。后两种动作为 reduce 动作。

    目前,基于转移的方法最好模型是stack lstm。 通过三个 LSTM 来分别建模栈状态、待输入序列和动作序列。 其中因为栈需要入栈和出栈,因此作者提出了一个 Stack LSTM 来建模栈状态。

    1587606360367

    论文地址: https://arxiv.org/pdf/1505.08075.pdf

  • 基于图的方法

    目前的依存句法分析中,最流行的方法是基于图的方法经典的方法是 Biaffine 模型。直接用神经网络来预测每两个词之间存在依存关系的概率,这样我们就得到一个全连接图,图上每个边代表了节点 a 指向节点 b 的概率。然后使用MST等方法来来将图转换为一棵树。

    Biaffine 模型其实和我们目前全连接自注意力模型非常类似。Biaffine 模型十分简单,并且容易理解,并且在很多数据集上都取得了目前最好的结果。

    1587606231909

    论文地址:https://arxiv.org/pdf/1611.01734.pdf

  • 联合模型(深度学习)

    1. 词性标注&句法分析

      联合词性标注和句法分析的模型有很多,可以是基于转移的方法,也可以是基于图的方法,这里介绍一个简单思路。首先利用lstm来预测词性,然后联合词性信息和词信息一起用另外一个lstm来建模,并用Biaffine模型来做句法分析。

      1587606449299

      论文地址:https://arxiv.org/pdf/1807.03955.pdf

    2. 中文分词&句法分析

      中文的句法分析是基于词级别的,所以在句法分析之前,会做分词。为了避免流水线模式的错误积累,很容易想到的就是分词和词法分析联合建模。

      这里主要介绍一下邱希鹏教授实验室提出的模型:joint CWS。

      1587606912240

      其中两个关键点:

      • biaffine parsing
      • ‘app’ 作为特殊的依赖关系

      其实方法很简单,只需要将词内部的字之间加上一个特殊的依赖关系“app”,然后将词级别的依存关系转换为字级别的依存关系。并且用 biaffine 模型来进行同时预测。

      论文地址:https://arxiv.org/pdf/1904.04697.pdf

3. 常用工具

https://www.jianshu.com/p/867bd48cd9ad

3.1 LTP
  1. 安装

    1
    pip install pyltp
  2. 下载数据包

    ltp_data_v3.4.0: 链接: https://pan.baidu.com/s/1aDrb95ylZHoTPKJY6K1Slw 密码: ehe2

  3. 测试代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    from pyltp import Parser, Postagger, Segmentor

    text = 'HanLP是一系列模型与算法组成的自然语言处理工具包,目标是普及自然语言处理在生产环境中的应用。'

    # 分词
    segmentor = Segmentor()
    segmentor.load("/home/sunshine/datasets/other/ltp_data_v3.4.0/cws.model")
    tokens = segmentor.segment(text)

    # 词性
    postagger = Postagger()
    postagger.load('/home/sunshine/datasets/other/ltp_data_v3.4.0/pos.model')
    postags = postagger.postag(tokens)

    # 依存句法分析
    parser = Parser()
    parser.load('/home/sunshine/datasets/other/ltp_data_v3.4.0/parser.model')
    arcs = parser.parse(tokens, postags)

    i = 1
    result = zip(tokens, postags, arcs)
    for item in result:
    print(i, item[0], item[1], item[2].head, item[2].relation)
    i += 1
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    1 HanLP ws 2 SBV
    2 是 v 0 HED
    3 一 m 4 ATT
    4 系列 q 5 ATT
    5 模型 n 8 SBV
    6 与 c 7 LAD
    7 算法 n 5 COO
    8 组成 v 12 ATT
    9 的 u 8 RAD
    10 自然 n 11 ATT
    11 语言 n 12 SBV
    12 处理 v 2 VOB
    13 工具包 n 12 VOB
    14 , wp 2 WP
    15 目标 n 16 SBV
    16 是 v 2 COO
    17 普及 v 16 VOB
    18 自然 n 19 ATT
    19 语言 n 20 ATT
    20 处理 v 17 VOB
    21 在 p 26 ATT
    22 生产 v 23 ATT
    23 环境 n 24 ATT
    24 中 nd 21 POB
    25 的 u 21 RAD
    26 应用 v 20 VOB
    27 。 wp 2 WP
3.2 stanfordNLP
3.2.1 StanordCoreNLP

Github地址:https://github.com/Lynten/stanford-corenlp

官网:https://stanfordnlp.github.io/CoreNLP/

  1. 安装

    1
    pip install stanfordcorenlp
  2. 安装java环境(略)

  3. 下载数据包

    链接: https://pan.baidu.com/s/1kD3gaxVwvxZGaEN3EDedvA 提取码: m72n

    数据包下载之后,解压stanford-corenlp-full-2018-02-27.zip,将stanford-chinese-corenlp-2018-02-27-models.jar拷贝至stanford-corenlp-full-2018-02-27.zip解压目录。

  4. 测试代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from stanfordcorenlp import StanfordCoreNLP
    text = 'HanLP是一系列模型与算法组成的自然语言处理工具包,目标是普及自然语言处理在生产环境中的应用。'
    nlp = StanfordCoreNLP("/home/sunshine/datasets/other/standfordCoreNLP/stanford-corenlp-full-2018-02-27", lang='zh')
    tokens = nlp.word_tokenize(text)
    postags = nlp.pos_tag(text)
    result = nlp.dependency_parse(text)
    i = 1
    for item in zip(tokens, postags, result):
    print(i, item[0], item[1][1], item[2][1], item[2][2])
    i += 1
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    1 HanLP NR 0 12
    2 是 VC 12 1
    3 一 CD 12 2
    4 系列 M 11 3
    5 模型 NN 3 4
    6 与 CC 7 5
    7 算法 NN 7 6
    8 组成 VV 8 7
    9 的 DEC 11 8
    10 自然 NN 8 9
    11 语言 NN 11 10
    12 处理 VV 12 11
    13 工具包 NN 12 13
    14 , PU 12 14
    15 目标 NN 17 15
    16 是 VC 17 16
    17 普及 VV 12 17
    18 自然 NN 19 18
    19 语言 NN 17 19
    20 处理 VV 17 20
    21 在 P 23 21
    22 生产 NN 23 22
    23 环境 NN 26 23
    24 中 LC 23 24
    25 的 DEG 23 25
    26 应用 NN 20 26
    27 。 PU 12 27
  5. 依存句法解释

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    > > ROOT:要处理文本的语句
    > > IP:简单从句
    > > NP:名词短语
    > > VP:动词短语
    > > PU:断句符,通常是句号、问号、感叹号等标点符号
    > > LCP:方位词短语
    > > PP:介词短语
    > > CP:由‘的’构成的表示修饰性关系的短语
    > > DNP:由‘的’构成的表示所属关系的短语
    > > ADVP:副词短语
    > > ADJP:形容词短语
    > > DP:限定词短语
    > > QP:量词短语
    > > NN:常用名词
    > > NR:固有名词
    > > NT:时间名词
    > > PN:代词
    > > VV:动词
    > > VC:是
    > > CC:表示连词
    > > VE:有
    > > VA:表语形容词
    > > AS:内容标记(如:了)
    > > VRD:动补复合词
    > > CD: 表示基数词
    > > DT: determiner 表示限定词
    > > EX: existential there 存在句
    > > FW: foreign word 外来词
    > > IN: preposition or conjunction, subordinating 介词或从属连词
    > > JJ: adjective or numeral, ordinal 形容词或序数词
    > > JJR: adjective, comparative 形容词比较级
    > > JJS: adjective, superlative 形容词最高级
    > > LS: list item marker 列表标识
    > > MD: modal auxiliary 情态助动词
    > > PDT: pre-determiner 前位限定词
    > > POS: genitive marker 所有格标记
    > > PRP: pronoun, personal 人称代词
    > > RB: adverb 副词
    > > RBR: adverb, comparative 副词比较级
    > > RBS: adverb, superlative 副词最高级
    > > RP: particle 小品词
    > > SYM: symbol 符号
    > > TO:”to” as preposition or infinitive marker 作为介词或不定式标记
    > > WDT: WH-determiner WH限定词
    > > WP: WH-pronoun WH代词
    > > WP$: WH-pronoun, possessive WH所有格代词
    > > WRB:Wh-adverb WH副词
    > >
    > > 关系表示
    > > abbrev: abbreviation modifier,缩写
    > > acomp: adjectival complement,形容词的补充;
    > > advcl : adverbial clause modifier,状语从句修饰词
    > > advmod: adverbial modifier状语
    > > agent: agent,代理,一般有by的时候会出现这个
    > > amod: adjectival modifier形容词
    > > appos: appositional modifier,同位词
    > > attr: attributive,属性
    > > aux: auxiliary,非主要动词和助词,如BE,HAVE SHOULD/COULD等到
    > > auxpass: passive auxiliary 被动词
    > > cc: coordination,并列关系,一般取第一个词
    > > ccomp: clausal complement从句补充
    > > complm: complementizer,引导从句的词好重聚中的主要动词
    > > conj : conjunct,连接两个并列的词。
    > > cop: copula。系动词(如be,seem,appear等),(命题主词与谓词间的)连系
    > > csubj : clausal subject,从主关系
    > > csubjpass: clausal passive subject 主从被动关系
    > > dep: dependent依赖关系
    > > det: determiner决定词,如冠词等
    > > dobj : direct object直接宾语
    > > expl: expletive,主要是抓取there
    > > infmod: infinitival modifier,动词不定式
    > > iobj : indirect object,非直接宾语,也就是所以的间接宾语;
    > > mark: marker,主要出现在有“that” or “whether”“because”, “when”,
    > > mwe: multi-word expression,多个词的表示
    > > neg: negation modifier否定词
    > > nn: noun compound modifier名词组合形式
    > > npadvmod: noun phrase as adverbial modifier名词作状语
    > > nsubj : nominal subject,名词主语
    > > nsubjpass: passive nominal subject,被动的名词主语
    > > num: numeric modifier,数值修饰
    > > number: element of compound number,组合数字
    > > parataxis: parataxis: parataxis,并列关系
    > > partmod: participial modifier动词形式的修饰
    > > pcomp: prepositional complement,介词补充
    > > pobj : object of a preposition,介词的宾语
    > > poss: possession modifier,所有形式,所有格,所属
    > > possessive: possessive modifier,这个表示所有者和那个’S的关系
    > > preconj : preconjunct,常常是出现在 “either”, “both”, “neither”的情况下
    > > predet: predeterminer,前缀决定,常常是表示所有
    > > prep: prepositional modifier
    > > prepc: prepositional clausal modifier
    > > prt: phrasal verb particle,动词短语
    > > punct: punctuation,这个很少见,但是保留下来了,结果当中不会出现这个
    > > purpcl : purpose clause modifier,目的从句
    > > quantmod: quantifier phrase modifier,数量短语
    > > rcmod: relative clause modifier相关关系
    > > ref : referent,指示物,指代
    > > rel : relative
    > > root: root,最重要的词,从它开始,根节点
    > > tmod: temporal modifier
    > > xcomp: open clausal complement
    > > xsubj : controlling subject 掌控者
    > > 中心语为谓词
    > > subj — 主语
    > > nsubj — 名词性主语(nominal subject) (同步,建设)
    > > top — 主题(topic) (是,建筑)
    > > npsubj — 被动型主语(nominal passive subject),专指由“被”引导的被动句中的主语,一般是谓词语义上的受事 (称作,镍)
    > > csubj — 从句主语(clausal subject),中文不存在
    > > xsubj — x主语,一般是一个主语下面含多个从句 (完善,有些)
    > > 中心语为谓词或介词
    > > obj — 宾语
    > > dobj — 直接宾语 (颁布,文件)
    > > iobj — 间接宾语(indirect object),基本不存在
    > > range — 间接宾语为数量词,又称为与格 (成交,元)
    > > pobj — 介词宾语 (根据,要求)
    > > lobj — 时间介词 (来,近年)
    > > 中心语为谓词
    > > comp — 补语
    > > ccomp — 从句补语,一般由两个动词构成,中心语引导后一个动词所在的从句(IP) (出现,纳入)
    > > xcomp — x从句补语(xclausal complement),不存在
    > > acomp — 形容词补语(adjectival complement)
    > > tcomp — 时间补语(temporal complement) (遇到,以前)
    > > lccomp — 位置补语(localizer complement) (占,以上)
    > > — 结果补语(resultative complement)
    > > 中心语为名词
    > > mod — 修饰语(modifier)
    > > pass — 被动修饰(passive)
    > > tmod — 时间修饰(temporal modifier)
    > > rcmod — 关系从句修饰(relative clause modifier) (问题,遇到)
    > > numod — 数量修饰(numeric modifier) (规定,若干)
    > > ornmod — 序数修饰(numeric modifier)
    > > clf — 类别修饰(classifier modifier) (文件,件)
    > > nmod — 复合名词修饰(noun compound modifier) (浦东,上海)
    > > amod — 形容词修饰(adjetive modifier) (情况,新)
    > > advmod — 副词修饰(adverbial modifier) (做到,基本)
    > > vmod — 动词修饰(verb modifier,participle modifier)
    > > prnmod — 插入词修饰(parenthetical modifier)
    > > neg — 不定修饰(negative modifier) (遇到,不)
    > > det — 限定词修饰(determiner modifier) (活动,这些)
    > > possm — 所属标记(possessive marker),NP
    > > poss — 所属修饰(possessive modifier),NP
    > > dvpm — DVP标记(dvp marker),DVP (简单,的)
    > > dvpmod — DVP修饰(dvp modifier),DVP (采取,简单)
    > > assm — 关联标记(associative marker),DNP (开发,的)
    > > assmod — 关联修饰(associative modifier),NP|QP (教训,特区)
    > > prep — 介词修饰(prepositional modifier) NP|VP|IP(采取,对)
    > > clmod — 从句修饰(clause modifier) (因为,开始)
    > > plmod — 介词性地点修饰(prepositional localizer modifier) (在,上)
    > > asp — 时态标词(aspect marker) (做到,了)
    > > partmod– 分词修饰(participial modifier) 不存在
    > > etc — 等关系(etc) (办法,等)
    > > 中心语为实词
    > > conj — 联合(conjunct)
    > > cop — 系动(copula) 双指助动词????
    > > cc — 连接(coordination),指中心词与连词 (开发,与)
    > > 其它
    > > attr — 属性关系 (是,工程)
    > > cordmod– 并列联合动词(coordinated verb compound) (颁布,实行)
    > > mmod — 情态动词(modal verb) (得到,能)
    > > ba — 把字关系
    > > tclaus — 时间从句 (以后,积累)
    > > — semantic dependent
    > > cpm — 补语化成分(complementizer),一般指“的”引导的CP (振兴,的)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    ```



    ###### 3.2.2 stanza

    github: <https://github.com/stanfordnlp/stanza>

    stanza同样是stanford发布的版本。

    1. 安装

    ```shell
    pip install stanza
  6. 下载模型

    1
    2
    import stanza
    stanza.download('zh')

    我这里提供一份中文的模型包供大家下载。

    链接: https://pan.baidu.com/s/1hb9ATqpOGC9sHBHZ2hNdeg 提取码: fqdm

  7. 测试代码

    1
    2
    3
    4
    import stanza
    nlp = stanza.Pipeline('zh') # This sets up a default neural pipeline in English
    doc = nlp("HanLP是一系列模型与算法组成的自然语言处理工具包,目标是普及自然语言处理在生产环境中的应用。")
    doc.sentences[0].print_dependencies()
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    ('HanLP', '14', 'nsubj')
    ('是', '14', 'cop')
    ('一', '4', 'nummod')
    ('系列', '5', 'clf')
    ('模型', '8', 'nsubj')
    ('与', '7', 'cc')
    ('算法', '5', 'conj')
    ('组成', '14', 'acl:relcl')
    ('的', '8', 'mark:relcl')
    ('自然', '12', 'nmod')
    ('语言', '12', 'compound')
    ('处', '13', 'nmod')
    ('理工', '14', 'nsubj')
    ('具包', '0', 'root')
    (',', '14', 'punct')
    ('目标', '17', 'nsubj')
    ('是', '14', 'parataxis')
    ('普及', '17', 'xcomp')
    ('自然', '20', 'nmod')
    ('语言', '21', 'nsubj')
    ('处理', '18', 'ccomp')
    ('在', '27', 'det')
    ('生产', '24', 'nmod')
    ('环境', '22', 'nmod')
    ('中', '24', 'acl')
    ('的', '22', 'case:dec')
    ('应用', '18', 'obj')
    ('。', '14', 'punct')
3.3 HaNLP

官网:http://hanlp.linrunsoft.com/

在线演示:http://hanlp.com/

3.3.1 pyhanlp(hanlp1.x)

Github地址:https://github.com/hankcs/pyhanlp

  1. 安装

    1
    pip install pyhanlp
  2. 下载数据包

    data:链接: https://pan.baidu.com/s/169Fgb6vhfsx10O2xEomY1Q 提取码: r4zv

    将下载的数据包解压至%python_lib%/site-packages/pyhanlp/static文件夹。我这里提供的是1.7.5版本,同样支持1.7.7版本的pyhanlp。

    默认会自动下载相关的jar包。

  3. 测试代码

    1
    2
    from pyhanlp import HanLP
    print(HanLP.parseDependency("HanLP是一系列模型与算法组成的自然语言处理工具包,目标是普及自然语言处理在生产环境中的应用"))
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    1	HanLP	HanLP	ws	nx	_	2	主谓关系	_	_
    2 是 是 v v _ 0 核心关系 _ _
    3 一系列 一系列 n n _ 4 定中关系 _ _
    4 模型 模型 n n _ 7 主谓关系 _ _
    5 与 与 p p _ 7 状中结构 _ _
    6 算法 算法 n n _ 5 介宾关系 _ _
    7 组成 组成 v v _ 10 定中关系 _ _
    8 的 的 u u _ 7 右附加关系 _ _
    9 自然语言处理 自然语言处理 nz nz _ 10 定中关系 _ _
    10 工具包 工具包 n n _ 2 动宾关系 _ _
    11 , , wp w _ 2 标点符号 _ _
    12 目标 目标 n n _ 13 主谓关系 _ _
    13 是 是 v v _ 2 并列关系 _ _
    14 普及 普及 v v _ 13 动宾关系 _ _
    15 自然语言处理 自然语言处理 nz nz _ 19 主谓关系 _ _
    16 在 在 p p _ 19 状中结构 _ _
    17 生产环境 生产环境 n n _ 16 介宾关系 _ _
    18 中的 中的 v v _ 19 状中结构 _ _
    19 应用 应用 v vn _ 14 动宾关系 _ _
3.3.2 hanlp2.0
  1. 安装

    1
    pip install hanlp

    hanlp2.0是基于tensorflow2.1训练的网络模型,线上提供了很多训练好的预训练模型,问题在于基本上不可能自动下载成功,需要手动下载模型并存放到相应的位置。

  2. 查看已经提供的模型

    1
    2
    3
    import hanlp
    for k,v in hanlp.pretrained.ALL.items():
    print(k, v)
  3. 测试代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    tokenizer = hanlp.load('CTB6_CONVSEG')
    tagger = hanlp.load('CTB5_POS_RNN')
    syntactic_parser = hanlp.load('CTB7_BIAFFINE_DEP_ZH')

    pipeline = hanlp.pipeline() \
    .append(hanlp.utils.rules.split_sentence, output_key='sentences') \
    .append(tokenizer, output_key='tokens') \
    .append(tagger, output_key='part_of_speech_tags') \
    .append(syntactic_parser, input_key=('tokens', 'part_of_speech_tags'), output_key='syntactic_dependencies',
    conll=False)

    text = 'HanLP是一系列模型与算法组成的自然语言处理工具包,目标是普及自然语言处理在生产环境中的应用'

    doc = pipeline(text)
    tokens = doc.tokens[0]
    pos = doc.part_of_speech_tags[0]
    dependencies = doc.syntactic_dependencies[0]

    for i in range(len(tokens)):
    print(i, tokens[i], pos[i], dependencies[i][0], dependencies[i][1])
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    0 HanLP NN 2 top
    1 是 VC 0 root
    2 一系列 NN 6 nn
    3 模型 NN 6 conj
    4 与 CC 6 cc
    5 算法 NN 7 nsubj
    6 组成 VV 10 rcmod
    7 的 DEC 7 cpm
    8 自然 NN 10 nn
    9 语言 NN 11 nsubj
    10 处理 VV 2 ccomp
    11 工具包 PU 11 punct
    12 , PU 2 punct
    13 目标 NN 15 top
    14 是 VC 2 conj
    15 普及 VV 15 ccomp
    16 自然 NN 18 nn
    17 语言 NN 16 dobj
    18 处理 VV 16 conj
    19 在 P 25 assmod
    20 生产 NN 22 nn
    21 环境 NN 23 lobj
    22 中 LC 20 plmod
    23 的 DEG 20 assm
    24 应用 NN 19 dobj

4. 数据集

5. 可视化工具

  1. conllu.js

    https://github.com/spyysalo/conllu.js

  2. DependencyViewer.exe

    http://nlp.nju.edu.cn/tanggc/tools/DependencyViewer.html

参考:

https://mp.weixin.qq.com/s/AP4TCnRfIccqAxDu4FlBew

实体关系抽取(Entity and Relation Extraction,ERE)是信息抽取的关键任务之一。ERE是一个级联任务,分为两个子任务:实体抽取和关系抽取。主流的抽取模式有两类:Pipline和联合抽取。

对比联合模型,Pipline的优缺点:

  • 易于实现,实体和关系任务解耦,灵活性高,可以使用独立的数据集。

  • 暴露偏差:关系训练输入的是gold实体,而预测时候输入的是实体模型预测的实体

  • 实体冗余:存在大量的没有关系的实体,提升错误率,增加计算复杂度

  • 交互缺失:忽略了两个任务之间的内在联系和依赖关系

1. pipline

1.1 NER

  1. 序列标注:SoftMax和CRF

    每个token只能属于一个标签,不能解决重叠实体问题

    • 采用token-level的多label分类,将Softmax替换为Sigmoid。这种方式会导致label之间的依赖关系缺失,可采用后处理规则进行约束

      image-20210521163318056

    • Neural Architectures for Nested NER through Linearization

      采取CRF,但是设置多个标签层,然后讲所有标签层合并。增加lable数量,导致label不平衡问题

      image-20210521163800149

  2. 指针网络

    • MRC-QA+单层指针网络(A Unified MRC Framework for Named Entity Recognition )

      构建query问题指代所要抽取的实体类型,同时引入先验知识。

      image-20210521164345702

    • 多层指针网络

      构建多层指针网络,每层对应一个实体类型

      image-20210521164426461

    注意:

    • MRC-QA会引入query对实体类型编码,需要对原始文本重复编码以构造不同实体类型的query,将会大大增加计算量
    • 多层指针网络(n个2元sigmoid分类),会导致样本tag空间稀疏,收敛较慢。
  3. 片段排列+分类(Span-Level Model for Relation Extraction)

    针对Span排列的方式,显示所有可能的span排列,针对每个独立的span进行分类。由于选择的每个span都是独立的,所有该方式可以解决重叠实体问题。

    image-20210521165013140

    若文本过长,会产生大量的负样本,所以在实践中需要选择合理的span长度(窗口)。

  4. MRC(A Unified MRC Framework for Named Entity Recognition)

    image-20210525085754303

    实验证明,MRC效果的提升主要来自于基于自然语言的标签描述引入了更多的先验信息,对数据稀少的标签提升比较明显。

    • query问题设置标准比较模糊,不同的query构建方式导致不同的实验效果

    • 针对一条样本,需要构造多个不同的query,重复编码,增加计算量

    • 标签不平衡问题,真实场景下,大部分文本中只存在少量类别的实体,绝大部分query对对应了负样本。针对该,该团队提出了DSC loss,参考:Dice Loss for Data-imbalanced NLP Tasks

  5. bi-affine(Named Entity Recognition as Dependency Parsing)

    将实体识别任务转化为start和end索引问题,采用biaffine模型对句子中的tokens的start和end对进行评分。最终biaffine模型的输出为$l\times l\times c$ 的矩阵(l为句子长度,c为标签类别数)

$$
h_s(i) = FFNN_s(x_{s_i})
$$

$$
h_e(i) = FFNN_e(x_{e_i})
$$

$$
r_m(i)=h_s(i)^TU_mh_e(i)+W_m(h_s(i)\oplus h_e(i))+b_m
$$

image-20210521170107671

备注:

  • 线性模型(linear): $Wx^T$
  • 双线性模型(blinear): $xWy^T$
  • 仿射模型(affine): $Wx^T+b$ 或者写作 $W[x:1]$
  • 双仿射模型(bi-affine): $[x:1]W[y:1]$

1.2 关系分类

  1. Matching the Blanks: Distributional Similarity for Relation Learning

    image-20210521171350234

    基于bert,采用6中不同结构来进行实体pair的pooling,然后讲pooling后的编码进行关系分类。实验显示(f)结果最好。

    image-20210521171610550

  2. Extracting Multiple-Relations in One-Pass with Pre-Trained Transformers

    image-20210521171853468

    Pipline方式下的关系分类,同一个句子通常会有多个不同的实体对关系,一般的做法是构造多个实体对,进行多次关系分类,本质是上一个muti pass问题,同一个句子会进行多次计算,增加计算时间。

    • 本文将多次关系分类问题转化为one pass问题。一条样本输入模型,即可完成多个关系的分类。

    • 本文将还编码词和实体之间的相对距离计算Entity-Aware Self-Attention。$w_{d(i-j)}$ 代表实体$x_i$ 到token $x_j$的相对距离的embedding。

      image-20210610142844105

      在标准self-attention的基础上增加了实体距离信息。
      $$
      Q_{south}=h_{south}W^Q
      $$

      $$
      K_{in}=h_{in}W^K+A^K_{south_in}
      $$

      $$
      V_{in}=h_{in}W^V+B^V_{south_in}
      $$

      $$
      Z_{south_in}=softmax(\frac{Q_{south}K_{in}}{\sqrt{d_{k}}})V_{in}
      $$

      实体距离信息计算如下:

      • if south is entity: $A^K_{south_in}=W^K_{d(index(south), index(in))}$
      • if in is entity: $B^V_{south_in}=W^V_{d(index(south), index(in))}$
      • else: $A^K_{south_in}=O$
  3. Enriching Pre-trained Language Model with Entity Information for Relation Classification

    image-20210522110111197

  4. Simultaneously Self-Attending to All Mentions for Full-Abstract Biological Relation Extraction

    • 采用one-pass对所有实体进行关系分类,从所有实体mention中定位关系
    • 文档级别关系抽取,引入NER辅助进行多任务学习
    • 关系分类采用Bi-affine,而不是采用Softmax

    使用Tansformer编码,对每个token通过两个独立的MLP进行三元组中的head和tail表征,最后使用Bi-affine计算每个三元组的得分。

    image-20210522110921353

  5. A Frustratingly Easy Approach for Joint Entity and Relation Extraction

    • 实体模型采用Span-level NER的方式

    • 关系模型:将实体边界和实体类型作为标记符加入到实体span前后

    • 近似模型:将实体边界和标记符放到文本之后,与原文对应的实体共享位置向量。具体实现中,attention层,文本token只attend文本token,不去attend标记符token,而标记符token可以attend原文token。

    • 跨句信息:通过窗口滑动的方式引入跨句信息,即文本输入的左右上下文中分别滑动$(W-n)/2$ 个词,n为文本长度,W为固定窗口大小。image-20210522111559571

      attention mask实现:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      # Compute the attention mask matrix
      attention_mask = []
      for _, from_mask in enumerate(input_mask):
      attention_mask_i = []
      for to_mask in input_mask:
      if to_mask <= 1:
      attention_mask_i.append(to_mask)
      elif from_mask == to_mask and from_mask > 0:
      attention_mask_i.append(1)
      else:
      attention_mask_i.append(0)
      attention_mask.append(attention_mask_i)
      1
      input_mask = [1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
      [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
      [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
      [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
      [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
      [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
      [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
      [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]
      [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]
      [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]
      [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]
      [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]
      [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]
      [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]
      [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]

2. Joint Model

联合模型就是只有一个模型,将两个子任务统一建模。联合抽取可以进一步利用两个任务之间的潜在信息,缓解错误传播的缺点。

联合抽取的难点在于何如加强实体模型和关系模型之间的交互,比如实体模型和关系模型的输出之间存在一定的约束,在建模时考虑此种约束有利于联合模型的性能。

  • 共享参数的联合模型

    通过共享参数(共享输入特征或者内部隐藏状态)实现联合,这种方式对子模型没有限制,但是由于使用独立的解码算法,导致实体模型和关系模型之间的交互不强

  • 联合解码的联合模型

2.1 共享参数的联合抽取方法

基于参数共享的联合抽取方法的解码主要包括:序列标注CRF/Softmax、指针网络、分类Softmax、seq2seq等。最终的loss为实体loss和关系loss相加。

  1. 多头选择+sigmoid: Joint entity recognition and relation extraction as a multi-head selection problem

    image-20210522114945385

    先抽取实体,再利用实体边界信息进行关系抽取

    • 实体抽取:BIO标注,CRF解码

    • 关系抽取:sigmoid多头选择。对于含有n的token的句子,最终构成的关系矩阵为$n\times r \times n $ ,其中r为关系数。

    • 引入实体识别后的entity label embedding(BIO)进行关系抽取,训练是使用gold label,预测时使用predict label。

  2. SPO+指针网络: Joint Extraction of Entities and Relations Based on a Novel Decomposition Strategy

    image-20210524105215439

    image-20210524105239802

    • spo问题,先抽S,再抽PO

    • 在训练时,subject的选取是随机的,并没有将所有的subject统一进行po抽取,所以需要增大epochs训练,保证训练充分。ps:可以遍历的方式训练所有的subject(大约能提高1个百分点)

  3. LIC2020冠军方案

    image-20210524113526222

    • spo抽取,先抽s,再抽o,最后抽取p
    • 随机的把subject加到句子的开头,用sep分割组成新的输入,预测o。预测p同理

2.2 基于联合解码的联合抽取方法

​ 基于共享参数的联合抽取方法中,并没有显示的刻画两个任务之间的交互。同时,训练和预测仍然存在gap。

  1. Joint Extraction of Entities and Overlapping Relations Using Position-Attentive Sequence Labeling

    image-20210524115043806

    image-20210610105307448

    标记过程如下:

    对于含有n个token的句子,为每个token创建一个长度为n的序列并标记,所以总共会标注n个长度为n的序列。根据不同的查询位置p(目标单词所在句子中的位置)对n个不同的标记序列进行标记

    • 若查询位置p在实体的开始处,则在p处标记实体的类型
    • 若p处的实体为subject,则在与p处实体有关系的其他实体(object)用关系类型标记
    • 若p处的实体为object,则其余位置标记为“O”
  2. Joint extraction of entities and relations based on a novel tagging scheme

    image-20210524115546893

    image-20210524120026450

    该方案是LIC2020和LIC2021关系抽取的baseline方案,统一了实体和关系的SPO标注框架

    • token level的多标签分类,单个token对应多个不同的label
    • 假定存在R个关系,则label一共有(2*R+2)个。
    • 该框架不发解决实体重叠的关系抽取
  3. TPLinker: Single-stage Joint Extraction of Entities and Relations Through Token Pair Linking

    TPLinker整体标注框架是基于token pair进行的,本质上是一个span矩阵(类似于多头标注、bi-affine)。

    image-20210524120815690

    TPLinker通过链接三种类型的span矩阵来实现编码(关系类别总数为R)

    • 紫色标注:EH to ET,表示实体的首位关系,表示为一个$N \times N$ 的矩阵,如两个实体:New York City:M(New, City) =1; De Blasio:M(De, Blasio) =1
    • 红色标注:SH to OH,表示subject和object的头token的关系,表示为R个$N \times N$的矩阵。如三元组(New York City, mayor,De Blasio):M(New, De)=1
    • 蓝色标注:ST to OT,表示subject和object的尾部token间的关系,表示为R个$N \times N$矩阵;如三元组(New York City, mayor,De Blasio):M(City, Blasio)=1

    最终,会得到2*R+1个矩阵。为防止稀疏计算,下三角不参与计算,如果关系存在与下三角,则将其转置为上三角,并将标记1替换为2.

    image-20210524120802248

    通过解码结构可以看到,每个token pair对应了2*R+1个label。对于N个token的序列,最终会展开为一个$N \times (N+1)/2$ 的 序列,也就是将token pair的每个token编码拼接在一起。ps:一般来说,显卡都是支持不了一次性预测$N \times (N+1)/2$的序列,源码中设置了参数p(0-1),表示为单轮预测序列长度为:$N \times p$

    解码过程为:

    1. 解码EH-to-ET可以得到句子中所有的实体,用实体头token idx作为key,实体作为value,存入字典D中;
    2. 对每种关系r,解码ST-to-OT得到token对存入集合E中,解码SH-to-OH得到token对并在D中关联其token idx的实体value;
    3. 对上一步中得到的SH-to-OH token对的所有实体value对,在集合E中依次查询是否其尾token对在E中,进而可以得到三元组信息。

    结合上图的具体case,我们具体描述一下解码过程:

    解码EH-to-ET中得到3个实体:{New York,New York City,De Blasio}; 字典D为:{New:(New York,New York City),De:(De Blasio)}

    以关系“mayor”为例,

    1. 解码ST-to-OT得到集合E:{(City,Blasio)}; 解码SH-to-OH得到{(New,De)},其在字典D中可关联的subject实体集合为: {New York,New York City};object集合{De Blasio};
    2. 遍历上述subject集合和object集合,并在集合E中查询尾token,发现只有一个实体三元组{New York City,mayor,De Blasio}

    以关系“born in”为例,

    1. 解码ST-to-OT得到集合E:{(Blasio,York),(Blasio,City)};解码SH-to-OH得到{(De,New)},其在字典D中可关联的subject实体集合为{De Blasio};object集合为{New York,New York City};
    2. 遍历上述subject集合和object集合,并在集合E中查询尾token,可得到2个实体三元组:{De Blasio,born in,New York}和{De Blasio,born in,New York City}

    由于关系live in与born in一样,所以我们最终可得到5个三元组:

    (New York City, mayor, De Blasio), (De Blasio, born in, New York), (De Blasio, born in, New York City), (De Blasio, live in, New York), (De Blasio, live in, New York City)

1. 知识图谱概述与架构

1.1 web发展路线
  • web 1.0时代:文档互联
  • web 2.0 时代:数据互联
  • web 3.0时代:知识互联,知识图谱强大的语义理解和开放互联能力为基础

RDF(resource description framework)和OWL(web ontology language),基于使用本体模式来形式化的表达数据中的隐含语义的目的。知识图谱是基于语义网的相关研究,是对语义网标准与技术的一次扬弃与升华。

1.2 知识图谱

知识图谱2015年,goole为解决收索引擎的能力,增强用户的搜索质量与体验,正是提出知识图谱。目前已广泛用于智能搜索,智能问答,个性化推荐等领域。

  • 定义

    狭义的讲(维基百科),知识图谱是google用于增强其搜索功能的知识库。本质上讲,知识图谱是一种揭示实体之间关系的语义网络,对现实世界的事物以及相互关系进行形式化的描述。目前的知识图谱广泛的指各大规模的知识库。

  • 表示

    • 三元组:$G=(E, R, S)$

      • $E={e_{1}, e_{2}, … e_{n}}$ 是知识库中实体集合。
      • $R={r_{1}, r_{2}, … r_{n}}$ 是知识库中的关系集合。
      • $S ={ r | r \in E × R × E}$ 代表知识库中三元组集合
    • 三元组的基本形式

      • 实体:知识图谱中的最基本元素

      • 关系:连接两个实体,刻画它们之间的联系

      • 概念:主要指集合、类别、对象类型、事物的种类。例如:人物、地理等

      • 属性:对象可能具有的属性、特征、特点、参数等。例如:国籍、姓名、生日等。

      • 属性值:对象属性的值。

        每个实体(概念的外延)可用全局唯一确定的ID来标识,属性对(attribute-value par, AVP)用来刻画实体的内在特性。

  • 分类

    • 通用知识图谱:注重广度,覆盖行业多,范围大,但准确度不够高。主要应用与智能搜索。
    • 行业知识图谱(垂直领域):依靠特定行业的数据来构建,具有特定的行业意义。专业性较强。
  • 知识图谱架构

    • 逻辑结构

      • 模式层: 构建于数据层之上,通过本体库来规范数据层的一些列事实表达。
      • 数据层:事实数据,知识以事实为单位存储。常用的图数据库有:Neo4j, gStore, Twitter的FlockDB, sones的GraphDB等。
      • 本体:本体是结构化知识库的概率模板。层次结构强,冗余程度小。
    • 体系结构

      知识图谱的体系结构指构建模式。如下图所示。

      ![1577761955307](https://raw.githubusercontent.com/fushengwuyu/blog_images/main/img/1577761955307.png)
      
      • 自顶向下(top-down):先定义本体与数据模式,再将实体加入到知识库。例如:Freebase。
      • 自底向上(bottom-up):从一些开放链路数据中提取实体,选择置信度较高的实体加入知识库,最后再构建本体模式。目前,大多数采用自底向上的模式构建知识图谱,典型的有Google的Knowledge Vault。

2. 大规模知识库

2.1 开放链接知识库
  • Freebase:Metaweb(创建)->Google(收购)。Freebase在人工构建的基础上,融合了维基百科、IMDB、Flick等语料库。截止2014年底,Freebase包含6800万实体,10亿条关系信息,24亿条事实三元组信息。2015年6月,Freebase整体移入WikiData。

  • Wikidata:维基媒体基金会主持的一个自由的协作式多语言辅助知识库。Wikidata中的数据主要以文档的形式进行存储,目前已包含了超过1 700万个文档。其中的每个文档都有一个主题或一个管理页面,且被唯一的数字标识。

  • DBpedia:DBpedia[18]是由德国莱比锡大学和曼海姆大学的科研人员创建的多语言综合型知识库,在LOD项目中处于最核心的地位。截止至2014年年底,DBpedia中的事实三元组 数量已经超过了30亿条。

  • YAGO:YAGO[19]是由德国马普所(max planck institute,MPI)的科研人员构建的综合型知识库。YAGO整合了维基百科、WordNet以及GeoNames等数据源。2012年发布的第二版本,包含了超过1000万的实体以及超过1.2亿的事实。

2.2 垂直行业知识库
  • IMDB:关于电影、演员、电视节目的知识库。截止到2012年2月,IMDB共收集了2 132 383部作品资料和4 530 159名人物资料。

      MusicBrainz:一个结构化的音乐维基百科,致力于收藏所有的音乐元数据,并向大众用户开放。
    
  • ConceptNet:语义知识网络。与链路数据和Google知识图谱相比,ConceptNet更加侧重与词与词的关系。ConceptNet完全免费开放,并支持多种语言。

3. 知识图谱的关键技术

3.1 知识抽取

知识抽取主要面向开放的链接数据,通过自动化技术抽取出可用的知识单元,知识单元包括:实体、关系、属性。

  • 实体抽取(NER)

    • 基于规则和词典
    • 基于统计机器学习:隐马尔科夫模型(HMM)、条件马尔科夫模型(CMM)、最大熵模型(MaxEnt)、条件随机场(CRF)。
    • 基于深度学习:LSTM+CRF、LSTM+CNNs+CRF、 BERT、Attention
  • 关系抽取

    目标在于解决实体间语义链接的问题,早期的关系抽取主要是通过构造人工语义规则和模板,发展至今,实体间的关系模型成为主流抽取方法。

    • 基于模板:二元开放式 vs n元开放式

    • 基于监督学习

      基于监督学习的关系抽取方法核心在于将关系抽取转化为分类问题。在大量标注数据的基础上,训练监督模型进行关系抽取,一般步骤如下:a. 预定义关系类型, b. 人工标注数据 c. 设计关系识别所需要的特征 d. 选择分类模型 e. 训练模型

      传统的基于监督学习的关系抽取严重依赖与特征工程,而深度学习的方法自动学习特征,不再需要人工构建各种特征,大大简化了人工操作。

      • 基于深度学习流水线的关系抽取方法

        CR-CNN模型、Attention CNNs模型、Attention BLSTM模型 …

      • 基于深度学习的联合关系抽取方法

    • 基于若监督学习的关系抽取方法

      监督学习需要大量的标注预料,当预料不足时,弱监督学习可以只利用少量标注数据进行模型学习。

      • 远程监督方法

        远程监督方法通过讲知识图谱与非机构化文本对齐的方式自动构建大量的训练预料,减少模型对人工标注训练数据的依赖。远程监督的基本假设是如果两个实体在知识图谱中存在某种关系,则包含两个实体的句子均表达了这种关系。例如:在某知识图谱中存在实体关系创始人(乔布斯,苹果公司),那么,包含实体乔布斯和苹果公司的句子“乔布斯是苹果公司的联合创始人和CEO” 可以被用作关系创始人的训练正例。远程监督的一般步骤为:

        1. 从知识图谱中抽取存在的目标关系的实体对
        2. 从非机构化文本中抽取包含实体对的句子作为训练样例
        3. 训练监督学习模型进行关系抽取
      • Bootstrapping方法

        Boostrapping方法利用少量的实例作为初始种子集合,然后在种子集合上学习关系抽取的模板,再利用模板抽取更多的实例,加入种子集合中,通过不断的迭代,Boostrapping可以从文本中抽取关系的大量实例。

  • 属性抽取

    针对实体而言,通过属性形成对实体的完整刻画。实体的属性抽取可以转化为关系抽取问题。

  • 事件抽取

    事件抽取指从自然语言中抽取出用户感兴趣的事件信息,并以结构化的形式呈现出来。事件指发生的事件,通常具有时间、地点、参与者等属性。事件的发生可能因为一个动作的产生或者系统状态的改变。一般地,事件抽取任务包含的子任务有:

    • 识别事件触发词及事件类型
    • 识别事件元素同时判断其角色
    • 抽取描述事件的词或者句子
    • 事件属性标注
    • 事件共指消解

    同样的,事件抽取可分为以下两类:

    • 基于流水线的事件抽取

      流水线方法将事件抽取任务划分为一系列基于分类的子任务,每个子任务由一个机器学习器负责实施。

    • 联合抽取

      流水线方法存在误差传递问题,导致误差不断积累,事件抽取性能急剧衰减。在联合抽取方法中,事件的所有相关信息会通过一个模型同时抽取出来。

      • 联合推断:建立事件抽取子任务的模型,然后将各个模型的目标函数进行组合,形成联合推断的目标函数,通过对联合目标函数的优化,获得事件抽取各个子任务的结果。
      • 在充分分析子任务之间的关系之后,基于概率图模型进行联合建模,获得事件抽取的总体结果。
3.2 知识表示
 知识表示主要有两种:基于离散符号的知识表示和基于连续向量的知识表示方法

​ 基于离散符号化的表示方法可以很有效的将数据结构化,节点对应着三元组的头实体和尾实体,边对应着三元组的关系。但是它并不能在计算机中表达相应的语义层面的信息,也不能进行语义计算。

  • 基于离散符号的知识表示

    随着语义网的发展,早期web的标准语言HTML和XML无法适应语义网对知识表示的要求,W3C提出了新的标准语言:RDF、RDFS和OWL

    • RDF

      知识总是以三元组的形式出现,表示为:(subject,predicate,object)。例如:“IBM邀请Jeff Pan作为讲者,演讲主题是知识图谱”,可以以下RDF三元组:(IBM-Talk,speaker,Jeff),(IBM-Talk,theme,KG)。

      RDF中的主语是一个个体,个体是类的实例。谓语是一个属性。宾语可以是一个个体,如(IBM-Talk,speaker,Jeff),也可以是一个数据类型的实例,例如:(IBM-Talk,TalkDate,“05-10-2012”^xsd:date)

    • RDFS

      RDFS在RDF的基础上定义了类和属性的模式,RDF Schema(简称 RDFS)提供了对类和属性的简单描述。

      RDFS提供了最基本的对类和属性的描述原语:

      • rdf:type: 用于指定个体的类
      • rdfs:subClassOf:指定父类
      • rdfs:subPropertyOf:属性的父属性
      • rdfs:domain:属性的定义域
      • rdfs:range:属性的值域
    • OWL

      相对于RDF和RDFS,OWL能够表达更丰富的信息,应用与更加复杂的场景。OWL的常见词汇有:

      • 等价性声明:声明两个类、属性、实例是等价的。例如:exp:运动员 owl:equivalentClass exp:体育选手;exp:获得 owl:equivalentProperty exp:取得;exp:运动员 A owl:sameIndividualAs exp:小明

      • 属性传递声明:声明一个属性是传递关系,例如:exp:ancestor rdf:type owl:TransitiveProperty 指的是exp:ancestor是一个传递关系。

      • 属性互逆声明:声明两个属性有互逆的关系,owl:inverseOf

      • 属性的函数性声明:声明一个属性是函数。例如:exp:hasMother rdf:type owl:FunctionalProperty 指的是exp:hasmother是一个函数,即一个生物只有一个母亲。

      • 属性的对称性声明:声明一个属性是对称的。owl:SymmetricProperty

      • 属性的全称限定声明:声明一个属性是全称限定的。例如:

        exp:Person owl:allValuesFrom exp:Woman

        exp:Person owl:onProperty exp:hasMother

        上诉说明exp:haMother在主语exp:Person类的条件下,宾语的取值只能来自于exp:Women类。

      • 属性的存在限定声明。例如:

        exp:SemanticWebPaper owl:someValuesFrom exp:AAAI

        exp:SemanticWebPaper owl:onProperty exp:publishedIn

        上诉表明,exp:publishedIn的取值部分来自于exp:AAAI

      • 属性的基数限定声明:声明一个属性的基数,例如:

        exp:Person owl:cardinality “1”^^xsd:integer

        exp:Person owl:onProperty exp:hasMother

        上述表明,exp:hasMother在主语属于exp:person类的条件下,宾语的取值只能有一个,“1”的数据类型被声明为xsd:integer。

      • 相交的类声明:声明一个类是等价与两个类相交。例如:

        exp:Mother owl:intersectionOf _tmp

        _tmp rdf:type rdfs:Collection

        _tmp rdfs:member exp:Person

        _tmp:rdfs:member exp:HasChildren

        上述说明,exp:Mother是exp:Person和exp:HasChildren两个类的交集。

  • 连续向量的表示方法

    KG embedding主要是将KG中实体与关系隐射到一个低维的向量空间。KG embedding也是通过机器学习的方法对模型进行学习,与one-hot、word2vec的最大区别在于,它需要进行监督学习。

    • 转移距离模型(Translation Distance Model)

      transD模型的主要思想是讲衡量向量化的知识图谱中三元组的合理性问题,转化为衡量头实体和尾实体的距离问题。核心在于如何设计得分函数,得分函数通常被设计成利用关系把头实体转移到尾实体的合理性的函数。

      TransE受到词向量中平移不变性的启发,把实体和关系表示成向量,对某一个具体的关系(h, r, t),把关系的向量表示解释成头实体的向量到尾实体的向量的转移向量,即满足关系$h+r \approx t$关系。

      $$
      vec(Rome)+vec(is-capital-of) \approx vec(Italy)
      $$

    • 语义匹配模型(Semantic Matching Models)

      语义匹配模型更加注重挖掘向量化后的实体和关系的潜在语义,该方向上的模型主要是RESCAL以及它的延伸模型。

      在RESCAL模型中,知识库中的三元组(h,r,t)集合被表示为一个三阶张量,该张量可以分解为一个核心张量和一个因子矩阵,核心张量中的每个二维矩阵切片代表一个关系,因子矩阵中的每一行代表一个实体。三阶张量中的值表示对应三元组成立的概率,如果概率大于某个阈值,则三元组成立,否则不成立。其得分函数如下:
      $$
      f_{r}(h,t)=h^{T}M_{r}t=\sum_{i=0}^{d-1}\sum_{j=0}^{d-1}[M_{r}]{ij}\cdot[h]{i}\cdot[r]_{j}
      $$

    • 考虑附加信息的模型

      除了仅仅依靠知识图谱中的三元组构造KG embedding的模型,还有一些模型考虑额外的附加信息进行提升。

      通常考虑的附加信息有:实体类型、关系路劲、文本描述、逻辑规则等。

3.3 知识融合

​ 知识图谱中的知识来源广泛,存在着数据质量良莠不齐、来源于不同数据源的知识重复、知识间的关联不够明确等问题。

​ 知识融合是高层次的知识组织,使来自不同知识源的知识在同一框架规范下进行异构数据整合、消歧、加工、推理验证、更新等步骤,形成高质量的知识库。

  1. 实体对齐

    实体对齐又称为实体匹配,主要目的在于消除异构数据中实体冲突、指向不明等不一致性问题。

    实体对齐主要面临以下几个挑战:

    • 计算复杂度:匹配算法的计算复杂度会随着知识库的规模呈二次增长。
    • 数据质量:不同知识库的数据质量良莠不齐。
    • 先验训练数据:难以获取先验数据,大部分情况下,只能手动构造。

    知识库实体对齐的主要流程如下:

    1. 将待对齐数据进行分区索引
    2. 利用相似度函数或者相似算法查找匹配实例
    3. 使用实体对齐算法进行实例融合
    4. 将步骤2和步骤3结合,形成最终的对齐结果

    知识融合主要分为:本体对齐、实体对齐。两者的基本流程大致相似,如下所示:

    1578539136186

    • 数据预处理

      数据预处理阶段,原始数据的质量会直接影响到最终链接的结果,不同的数据集对同一实体的描述方式往往是不相同的,对这些数据进行归一化是提高后续链接精确度的重要步骤

      • 语法正规化
        • 语法匹配:如联系电话的表示方法
        • 综合属性:如家庭地址的表达方法
      • 数据正规化
        • 移除空格、{}等符号
        • 用正式名字替换昵称和缩写等
    • 分块

      分块是从给定的知识库中的所有实体对中,选出潜在匹配的记录对作为候选项,尽可能的缩小候选项,减少数据量、

      Hash函数的分块

      • 给定记录$x$,$hash(x)=h_{i}$ 则x映射到关键字$h_{i}$ 绑定的块$C_{i}$ 上。

      • 近邻分块

        canopy聚类、排序邻居算法、Red-Blue Set Cover等

    • 负载均衡

      负载均衡 (Load Balance)来保证所有块中的实体数目相当,从而保证分块对性能的提升程度。最简单的方法是多次Map-Reduce操作。

    • 记录链接

      假定两个实体$X={x_{0}, x_{1},…,x_{n}} ,Y={y_{0}, y_{1},…,y_{n}}$ ,$x_{i}$是实体X第$i$个属性的值。

      • 属性相似度

        综合单个属性相似度得到属性相似度向量:
        $$
        [sim(x_{1},y_{1}),sim(x_{2},y_{2}),…,sim(x_{n},y_{n})]
        $$
        属性相似度的计算方式通常有以下几类:

        • 编辑距离:最小编辑距离(Levenstein)、Wagner and Fisher Distance、Edit Distance with affine gaps
        • 集合相似度计算:Dice系数、Jaccard系数
        • 基于向量的相似度计算:TF-IDF
      • 实体相似度

        根据属性相似度向量得到一个实体的相似度。计算实体相似度方法主要有以下三大类。

        • 聚合

          • 加权平均

            对相似度向量各个分量加权求和,得到最终的实体相似度:
            $$
            S = w_{1}\ast sim(x_{1}, y_{1}) +…+w_{n} \ast sim(x_{n}, y_{n})
            $$

          • 规则

            可以为每个相似度分量设置一个阈值,若果超过改阈值则将两实体融合。
            $$
            sim(x_{1}, y_{1}) >T_{1} and(or) … sim(x_{n}, y_{n}) >T_{n}
            $$

          • 分类器

            常用的分类模型,但存在最大问题在于如何生成训练集合。

        • 聚类

          • 层次聚类
          • 相关性聚类
          • Canopy + Kmeans
        • 表示学习:知识嵌入

          将知识图谱中的实体和关系都隐射到低维向量空间,直接用距离公式来计算各个实体间的相似度。这种方法不依赖任何的问题信息,直接提取数据的深度特征。

  2. 质量评估

    ​ 对知识库的质量评估通常和实体对齐任务一起进行,其意义在于对知识的可信度量化,保留置信度较高的,舍弃置信度较低的,确保知识的质量。

  3. 知识更新

    随着知识储备和业务需求的不断递增,知识图谱的内容需要与时俱进,不断迭代更新,扩展现有的知识,增加新的知识。

    根据知识图谱的逻辑结构,更新主要包括:模式(本体)层的更新和数据层的更新

    • 模式层的更新

      本体元素的更新,包括:概念的增、删、改,概念属性的更新以及概念的上下位关系的更新等。

    • 数据层的更新

3.4 知识推理

​ 对于推理规则的挖掘,主要还是依赖于实体及实体关系间的丰富同现情况,知识推理的对象可以是实体、关系、属性、本体库中的概念的层次结构等。

  1. 基于逻辑的推理

    • 一阶谓词逻辑推理:以命题为基本进行推理,命题包含个体和谓词。逻辑中的个体对应实体,谓词对应关系或个体的属性。
    • 描述逻辑:在命题逻辑之上发展而来,追求表示能力与推理复杂度之间的平衡。
  2. 基于图的推理

    利用关系路劲中的蕴含信息,通过图中两个实体间的多步路劲来预测他们之间的语义关系。

  3. 时序预测推理

  4. 基于强化学习的知识图谱推理

  5. 开源的知识推理工具

    • jena:开源支持语义网络和数据链接应用的java框架。
    • drools:基于Charles Forgy 的RETE算法的规则引擎的java实现。

4. 典型应用

​ 知识图谱为互联网上海量、异构、动态的大数据表达、组织、管理以及利用提供了一种更为有效的方式,使得网络的智能化水平更高,更加接近人类的认知思维。

4.1 智能搜索

​ 基于知识图谱的智能搜索是一种基于长尾的搜索,并将结果以知识卡片的形式展示出来(参考google)。查询请求主要经过两个阶段:查询式语义理解和知识检索。

  1. 语义理解

    语义分析主要包含以下阶段。

    • 查询文本预处理:分词、词性标注、文本纠错
    • 描述归一化:与知识库中的相关知识匹配
    • 语境分析:不同语境(上下文),查询对象有所差别,因此知识图谱需要结合用户当时的情感,给出相应的反馈。
    • 查询扩展:明确查询意图及相关概念之后,需要加入当前语境下的相关概念进行扩展。
  2. 知识检索

    经过查询式分析后的标准查询语句进入知识库检索引擎,引擎会在知识库中检索相应的实体及其相关属性、关系,通过对知识库的深层挖掘和提炼后,引擎给出具有重要性排序的知识体系。

  3. 常见的基于知识图谱的搜索引擎

    • 国外: Google Search、微软的Bing Search。
    • 国内:搜狗的知立方、百度的知心。
4.2 智能问答

​ 问答系统是信息检索系统的一种高级形式,能 够以准确简洁的自然语言为用户提供问题的解答。之所以说问答是一种高级形式的检索,是因为在问答系统中同样有查询式理解与知识检索这两个重要的过程,并且与智能搜索中相应过程中的相关细节是完全一致的。多数问答系统更倾向于将给定的问 题分解为多个小的问题,然后逐一去知识库中抽取 匹配的答案,并自动检测其在时间与空间上的吻合 度等,最后将答案进行合并,以直观的方式展现给用户。

​ 目前,常见基于知识图谱的问答平台有

  • 国外:华盛顿大学的Paralex系统、苹果公司的Siri、亚马逊的Evi。
  • 国内:百度机器人小度、聚问网络的在线问答系统OASK。
4.3 垂直行业的应用
  • 金融: 识别反欺诈、定制化销售策略。
  • 医疗:疾病图谱、中医图谱。
  • 电商:商品展示