Merge pull request #605 from jiangzhonglian/master

更新公示编译后无法正常现实的问题
This commit is contained in:
片刻
2020-09-11 17:00:12 +08:00
committed by GitHub
10 changed files with 225 additions and 65 deletions

1
.gitignore vendored
View File

@@ -3,6 +3,7 @@ __pycache__/
*.py[cod]
*$py.class
.vscode
data/*
# C extensions
*.so

View File

@@ -5,21 +5,33 @@
'''
class TextNER(object):
DEBUG = False
path_root = "/home/apachecn/jiangzhonglian"
DEBUG = True
if DEBUG:
path_root = "/Users/jiangzhonglian/data/nlp/命名实体识别/data"
path_root = "data/NER3"
chunk_tags = ['O', 'B-ORG', 'I-ORG',
'B-Po_VIEW', 'I-Po_VIEW',
'B-Mi_VIEW', 'I-Mi_VIEW',
'B-Ne_VIEW', 'I-Ne_VIEW'
]
# chunk_tags = ['O', 'B-TIME', 'I-TIME', 'B-LOCATION', 'I-LOCATION',
# "B-PERSON_NAME", "I-PERSON_NAME", "B-ORG_NAME", "I-ORG_NAME",
# "B-COMPANY_NAME", "I-COMPANY_NAME", "B-PRODUCT_NAME", "I-PRODUCT_NAME"]
# chunk_tags = ['O', 'B-PER', 'I-PER', 'B-LOC', 'I-LOC', "B-ORG", "I-ORG"]
else:
path_root = "data/NER"
chunk_tags = ['O', 'B-PER', 'I-PER', 'B-LOC', 'I-LOC', "B-ORG", "I-ORG"]
path_train = '%s/train_data.data' % path_root
path_test = '%s/test_data.data' % path_root
path_config = '%s/config.pkl' % path_root
path_model = '%s/model.h5' % path_root
path_origin = '%s/origin.txt' % path_root
path_train = '%s/train.txt' % path_root
path_test = '%s/test.txt' % path_root
path_config = '%s/config.pkl' % path_root
path_model = '%s/model.h5' % path_root
# 迭代次数
EPOCHS = 3
# embedding的
EPOCHS = 10
# embedding的维度
EMBED_DIM = 128
# LSTM的
# LSTM的维度
BiLSTM_UNITS = 128

View File

@@ -47,12 +47,12 @@
> SVD 是矩阵分解的一种类型,也是矩阵分解最常见的技术
* SVD 将原始的数据集矩阵 Data 分解成三个矩阵 U、∑、V
* 举例: 如果原始矩阵 \\(Data_{m*n}\\) 是m行n列
* \\(U_{m * k}\\) 表示m行k列
* \\(∑_{k * k}\\) 表示k行k列
* \\(V_{k * n}\\) 表示k行n列。
* 举例: 如果原始矩阵 $$Data_{m*n}$$ 是m行n列
* $$U_{m * k}$$ 表示m行k列
* $$∑_{k * k}$$ 表示k行k列
* $$V_{k * n}$$ 表示k行n列。
\\(Data_{m*n} = U_{m\*k} \* ∑_{k\*k} \* V_{k\*n}\\)
$$Data_{m*n} = U_{m\*k} \* ∑_{k\*k} \* V_{k\*n}$$
![SVD公式](http://data.apachecn.org/img/AiLearning/ml/14.SVD/使用SVD简化数据-SVD公式.jpg)
@@ -61,7 +61,7 @@
![SVD公式](http://data.apachecn.org/img/AiLearning/ml/14.SVD/SVD公式的测试案例.jpg)
* 上述分解中会构建出一个矩阵∑该矩阵只有对角元素其他元素均为0(近似于0)。另一个惯例就是,∑的对角元素是从大到小排列的。这些对角元素称为奇异值。
* 奇异值与特征值(PCA 数据中重要特征)是有关系的。这里的奇异值就是矩阵 \\(Data * Data^T\\) 特征值的平方根。
* 奇异值与特征值(PCA 数据中重要特征)是有关系的。这里的奇异值就是矩阵 $$Data * Data^T$$ 特征值的平方根。
* 普遍的事实: 在某个奇异值的数目(r 个=>奇异值的平方和累加到总值的90%以上)之后其他的奇异值都置为0(近似于0)。这意味着数据集中仅有 r 个重要特征,而其余特征则都是噪声或冗余特征。
### SVD 算法特点

View File

@@ -61,44 +61,44 @@ Support Vector Machines: Slide 12 Copyright © 2001, 2003, Andrew W. Moore Why M
> 点到超平面的距离
* 分隔超平面`函数间距`: \\(y(x)=w^Tx+b\\)
* 分类的结果: \\(f(x)=sign(w^Tx+b)\\) (sign表示>0为1<0为-1=0为0)
* 点到超平面的`几何间距`: \\(d(x)=(w^Tx+b)/||w||\\) ||w||表示w矩阵的二范数=> \\(\sqrt{w^T*w}\\), 点到超平面的距离也是类似的)
* 分隔超平面`函数间距`: $$y(x)=w^Tx+b$$
* 分类的结果: $$f(x)=sign(w^Tx+b)$$ (sign表示>0为1<0为-1=0为0)
* 点到超平面的`几何间距`: $$d(x)=(w^Tx+b)/||w||$$ ||w||表示w矩阵的二范数=> $$\sqrt{w^T*w}$$, 点到超平面的距离也是类似的)
![点到直线的几何距离](http://data.apachecn.org/img/AiLearning/ml/6.SVM/SVM_4_point2line-distance.jpg)
> 拉格朗日乘子法
* 类别标签用-1、1是为了后期方便 \\(label*(w^Tx+b)\\) 的标识和距离计算;如果 \\(label*(w^Tx+b)>0\\) 表示预测正确,否则预测错误。
* 类别标签用-1、1是为了后期方便 $$label*(w^Tx+b)$$ 的标识和距离计算;如果 $$label*(w^Tx+b)>0$$ 表示预测正确,否则预测错误。
* 现在目标很明确,就是要找到`w``b`,因此我们必须要找到最小间隔的数据点,也就是前面所说的`支持向量`
* 也就说,让最小的距离取最大.(最小的距离: 就是最小间隔的数据点;最大: 就是最大间距,为了找出最优超平面--最终就是支持向量)
* 目标函数: \\(arg: max_{关于w, b} \left( min[label*(w^Tx+b)]*\frac{1}{||w||} \right) \\)
1. 如果 \\(label*(w^Tx+b)>0\\) 表示预测正确,也称`函数间隔`\\(||w||\\) 可以理解为归一化,也称`几何间隔`
2.\\(label*(w^Tx+b)>=1\\) 因为01之间得到的点是存在误判的可能性所以要保障 \\(min[label*(w^Tx+b)]=1\\),才能更好降低噪音数据影响。
3. 所以本质上是求 \\(arg: max_{关于w, b} \frac{1}{||w||} \\);也就说,我们约束(前提)条件是: \\(label*(w^Tx+b)=1\\)
* 新的目标函数求解: \\(arg: max_{关于w, b} \frac{1}{||w||} \\)
* => 就是求: \\(arg: min_{关于w, b} ||w|| \\) (求矩阵会比较麻烦如果x只是 \\(\frac{1}{2}*x^2\\) 的偏导数,那么。。同样是求最小值)
* => 就是求: \\(arg: min_{关于w, b} (\frac{1}{2}*||w||^2)\\) (二次函数求导,求极值,平方也方便计算)
* 目标函数: $$arg: max_{关于w, b} \left( min[label*(w^Tx+b)]*\frac{1}{||w||} \right) $$
1. 如果 $$label*(w^Tx+b)>0$$ 表示预测正确,也称`函数间隔`$$||w||$$ 可以理解为归一化,也称`几何间隔`
2.$$label*(w^Tx+b)>=1$$ 因为01之间得到的点是存在误判的可能性所以要保障 $$min[label*(w^Tx+b)]=1$$,才能更好降低噪音数据影响。
3. 所以本质上是求 $$arg: max_{关于w, b} \frac{1}{||w||} $$;也就说,我们约束(前提)条件是: $$label*(w^Tx+b)=1$$
* 新的目标函数求解: $$arg: max_{关于w, b} \frac{1}{||w||} $$
* => 就是求: $$arg: min_{关于w, b} ||w|| $$ (求矩阵会比较麻烦如果x只是 $$\frac{1}{2}*x^2$$ 的偏导数,那么。。同样是求最小值)
* => 就是求: $$arg: min_{关于w, b} (\frac{1}{2}*||w||^2)$$ (二次函数求导,求极值,平方也方便计算)
* 本质上就是求线性不等式的二次优化问题(求分隔超平面,等价于求解相应的凸二次规划问题)
* 通过拉格朗日乘子法,求二次优化问题
* 假设需要求极值的目标函数 (objective function) 为 f(x,y),限制条件为 φ(x,y)=M # M=1
* 设g(x,y)=M-φ(x,y) # 临时φ(x,y)表示下文中 \\(label*(w^Tx+b)\\)
* 设g(x,y)=M-φ(x,y) # 临时φ(x,y)表示下文中 $$label*(w^Tx+b)$$
* 定义一个新函数: F(x,y,λ)=f(x,y)+λg(x,y)
* a为λa>=0代表要引入的拉格朗日乘子(Lagrange multiplier)
* 那么: \\(L(w,b,\alpha)=\frac{1}{2} * ||w||^2 + \sum_{i=1}^{n} \alpha_i * [1 - label * (w^Tx+b)]\\)
* 因为: \\(label*(w^Tx+b)>=1, \alpha>=0\\) , 所以 \\(\alpha*[1-label*(w^Tx+b)]<=0\\) , \\(\sum_{i=1}^{n} \alpha_i * [1-label*(w^Tx+b)]<=0\\)
*\\(label*(w^Tx+b)>1\\) 则 \\(\alpha=0\\) ,表示该点为<font color=red>非支持向量</font>
* 相当于求解: \\(max_{关于\alpha} L(w,b,\alpha) = \frac{1}{2} *||w||^2\\)
* 如果求: \\(min_{关于w, b} \frac{1}{2} *||w||^2\\) , 也就是要求: \\(min_{关于w, b} \left( max_{关于\alpha} L(w,b,\alpha)\right)\\)
* 那么: $$L(w,b,\alpha)=\frac{1}{2} * ||w||^2 + \sum_{i=1}^{n} \alpha_i * [1 - label * (w^Tx+b)]$$
* 因为: $$label*(w^Tx+b)>=1, \alpha>=0$$ , 所以 $$\alpha*[1-label*(w^Tx+b)]<=0$$ , $$\sum_{i=1}^{n} \alpha_i * [1-label*(w^Tx+b)]<=0$$
*$$label*(w^Tx+b)>1$$ 则 $$\alpha=0$$ ,表示该点为<font color=red>非支持向量</font>
* 相当于求解: $$max_{关于\alpha} L(w,b,\alpha) = \frac{1}{2} *||w||^2$$
* 如果求: $$min_{关于w, b} \frac{1}{2} *||w||^2$$ , 也就是要求: $$min_{关于w, b} \left( max_{关于\alpha} L(w,b,\alpha)\right)$$
* 现在转化到对偶问题的求解
* \\(min_{关于w, b} \left(max_{关于\alpha} L(w,b,\alpha) \right) \\) >= \\(max_{关于\alpha} \left(min_{关于w, b}\ L(w,b,\alpha) \right) \\)
* $$min_{关于w, b} \left(max_{关于\alpha} L(w,b,\alpha) \right) $$ >= $$max_{关于\alpha} \left(min_{关于w, b}\ L(w,b,\alpha) \right) $$
* 现在分2步
* 先求: \\(min_{关于w, b} L(w,b,\alpha)=\frac{1}{2} * ||w||^2 + \sum_{i=1}^{n} \alpha_i * [1 - label * (w^Tx+b)]\\)
* 先求: $$min_{关于w, b} L(w,b,\alpha)=\frac{1}{2} * ||w||^2 + \sum_{i=1}^{n} \alpha_i * [1 - label * (w^Tx+b)]$$
* 就是求`L(w,b,a)`关于[w, b]的偏导数, 得到`w和b的值`,并化简为: `L和a的方程`
* 参考: 如果公式推导还是不懂,也可以参考《统计学习方法》李航-P103<学习的对偶算法>
![计算拉格朗日函数的对偶函数](http://data.apachecn.org/img/AiLearning/ml/6.SVM/SVM_5_Lagrangemultiplier.png)
* 终于得到课本上的公式: \\(max_{关于\alpha} \left( \sum_{i=1}^{m} \alpha_i - \frac{1}{2} \sum_{i, j=1}^{m} label_i·label_j·\alpha_i·\alpha_j·<x_i, x_j> \right) \\)
* 约束条件: \\(a>=0\\) 并且 \\(\sum_{i=1}^{m} a_i·label_i=0\\)
* 终于得到课本上的公式: $$max_{关于\alpha} \left( \sum_{i=1}^{m} \alpha_i - \frac{1}{2} \sum_{i, j=1}^{m} label_i·label_j·\alpha_i·\alpha_j·<x_i, x_j> \right) $$
* 约束条件: $$a>=0$$ 并且 $$\sum_{i=1}^{m} a_i·label_i=0$$
> 松弛变量(slack variable)
@@ -107,13 +107,13 @@ Support Vector Machines: Slide 12 Copyright © 2001, 2003, Andrew W. Moore Why M
![松弛变量公式](http://data.apachecn.org/img/AiLearning/ml/6.SVM/SVM_松弛变量.jpg)
* 我们知道几乎所有的数据都不那么干净, 通过引入松弛变量来 `允许数据点可以处于分隔面错误的一侧`
* 约束条件: \\(C>=a>=0\\) 并且 \\(\sum_{i=1}^{m} a_i·label_i=0\\)
* 约束条件: $$C>=a>=0$$ 并且 $$\sum_{i=1}^{m} a_i·label_i=0$$
* 总的来说:
* ![松弛变量](http://data.apachecn.org/img/AiLearning/ml/6.SVM/松弛变量.png) 表示 `松弛变量`
* 常量C是 `惩罚因子`, 表示离群点的权重用于控制“最大化间隔”和“保证大部分点的函数间隔小于1.0”
* \\(label*(w^Tx+b) > 1\\) and alpha = 0 (在边界外,就是非支持向量)
* \\(label*(w^Tx+b) = 1\\) and 0< alpha < C (在分割超平面上,就支持向量)
* \\(label*(w^Tx+b) < 1\\) and alpha = C (在分割超平面内,是误差点 -> C表示它该受到的惩罚因子程度)
* $$label*(w^Tx+b) > 1$$ and alpha = 0 (在边界外,就是非支持向量)
* $$label*(w^Tx+b) = 1$$ and 0< alpha < C (在分割超平面上,就支持向量)
* $$label*(w^Tx+b) < 1$$ and alpha = C (在分割超平面内,是误差点 -> C表示它该受到的惩罚因子程度)
* 参考地址: https://www.zhihu.com/question/48351234/answer/110486455
* C值越大表示离群点影响越大就越容易过度拟合反之有可能欠拟合。
* 我们看到,目标函数控制了离群点的数目和程度,使大部分样本点仍然遵守限制条件。
@@ -137,7 +137,7 @@ Support Vector Machines: Slide 12 Copyright © 2001, 2003, Andrew W. Moore Why M
* 这里指的合适必须要符合一定的条件
1. 这两个 alpha 必须要在间隔边界之外
2. 这两个 alpha 还没有进行过区间化处理或者不在边界上。
* 之所以要同时改变2个 alpha原因是我们有一个约束条件: \\(\sum_{i=1}^{m} a_i·label_i=0\\);如果只是修改一个 alpha很可能导致约束条件失效。
* 之所以要同时改变2个 alpha原因是我们有一个约束条件: $$\sum_{i=1}^{m} a_i·label_i=0$$;如果只是修改一个 alpha很可能导致约束条件失效。
> SMO 伪代码大致如下:

View File

@@ -1,5 +1,9 @@
# 【入门须知】必须了解
实体: 抽取
关系: 图谱
意图: 分类
* **【入门须知】必须了解**: <https://github.com/apachecn/AiLearning/tree/master/docs/nlp>
* **【入门教程】强烈推荐: PyTorch 自然语言处理**: <https://github.com/apachecn/NLP-with-PyTorch>
* Python 自然语言处理 第二版: <https://usyiyi.github.io/nlp-py-2e-zh>

View File

@@ -1,6 +1,6 @@
numpy
pandas
sklearn
keras
tensorflow
keras==2.3.1
tensorflow==2.0.0
git+https://www.github.com/keras-team/keras-contrib.git

121
tutorials/keras/brat_tag.py Normal file
View File

@@ -0,0 +1,121 @@
# -*- coding: utf-8 -*-
"""
数据格式转化
"""
import os
import emoji
from middleware.utils import get_catalog_files
from config.setting import Config
tag_dic = {"实体对象": "ORG",
"正向观点": "Po_VIEW",
"中性观点": "Mi_VIEW",
"负向观点": "Ne_VIEW"}
# 转换成可训练的格式,最后以"END O"结尾
def from_ann2dic(r_ann_path, r_txt_path, w_path):
q_dic = {}
print("开始读取文件:%s" % r_ann_path)
with open(r_ann_path, "r", encoding="utf-8") as f:
lines = f.readlines()
for line in lines:
line_arr = line.split()
# print(">>> ", line_arr)
cls = tag_dic[line_arr[1]]
start_index = int(line_arr[2])
end_index = int(line_arr[3])
length = end_index - start_index
for r in range(length):
q_dic[start_index+r] = ("B-%s" % cls) if r == 0 else ("I-%s" % cls)
# 存储坐标和对应的列名: {23: 'B-Ne_VIEW', 24: 'I-Ne_VIEW', 46: 'B-ORG', 47: 'I-ORG'}
print("q_dic: ", q_dic)
print("开始读取文件内容: %s" % r_txt_path)
with open(r_txt_path, "r", encoding="utf-8") as f:
content_str = f.read()
print("开始写入文本%s" % w_path)
with open(w_path, "w", encoding="utf-8") as w:
for i, strA in enumerate(content_str):
# print(">>> %s-%s" % (i, strA))
if strA == "\n":
w.write("\n")
else:
if i in q_dic:
tag = q_dic[i]
else:
tag = "O" # 大写字母O
w.write('%s %s\n' % (strA, tag))
w.write('%s\n' % "END O")
# 生成train.txt、dev.txt、test.txt
# 除89-new.txt分别用于dev和test外,剩下的合并成train.txt
def create_train_data(data_root_dir, w_path):
if os.path.exists(w_path):
os.remove(w_path)
for file in os.listdir(data_root_dir):
path = os.path.join(data_root_dir, file)
if file.endswith("8-new.txt"):
# 重命名为dev.txt
os.rename(path, os.path.join(data_root_dir, "dev.txt"))
continue
if file.endswith("9-new.txt"):
# 重命名为test.txt
os.rename(path, os.path.join(data_root_dir, "test.txt"))
continue
q_list = []
print("开始读取文件:%s" % file)
with open(path, "r", encoding="utf-8") as f:
lines = f.readlines()
for line in lines:
line = line.rstrip()
if line == "END O":
break
q_list.append(line)
# 获取list 列表: ['美 O', ' O', '气 O', '质 O', '特 O', '别 O', '好 O', '', '造 O', '型 O', '独 O', '特 O', ' O', '尺 B-ORG', '码 I-ORG', '偏 B-Ne_VIEW', '大 I-Ne_VIEW', ' O']
# print("q_list: ", q_list)
print("开始写入文本: %s" % w_path)
with open(w_path, "a", encoding="utf-8") as f:
for item in q_list:
f.write('%s\n' % item)
def brat_1_format_origin(catalog):
"""
格式化原始文件去除表情符号的影响brat占2个字符但是python占1个字符
"""
with open('%s/origin/origin.txt' % path_root, "r", encoding="utf-8") as f:
lines = f.readlines()
with open('%s/tag_befer/befer.txt' % path_root, "w", encoding="utf-8") as f:
# 转换原始文件
for line in lines:
text = emoji.demojize(line)
f.write('%s' % text)
# 创建标注的新文件
with open('%s/tag_befer/befer.ann' % path_root, "w", encoding="utf-8") as f:
pass
def brat_2_create_train_data(catalog):
file_list = get_catalog_files("%s/tag_after" % catalog, status=-1, str1=".DS_Store")
file_list = list(set([i.split("/")[-1].split(".")[0] for i in file_list]))
print(file_list)
for filename in file_list:
r_ann_path = os.path.join(catalog, "tag_after/%s.ann" % filename)
r_txt_path = os.path.join(catalog, "tag_after/%s.txt" % filename)
w_path = os.path.join(catalog, "new/%s-new.txt" % filename)
print("filename", r_ann_path, r_txt_path, w_path)
from_ann2dic(r_ann_path, r_txt_path, w_path)
# 生成train.txt、dev.txt、test.txt
create_train_data("%s/new" % catalog, "%s/new/train.txt" % catalog)
def main():
catalog = Config.nlp_ner.path_root
# brat_1_format_origin(catalog)
brat_2_create_train_data(catalog)

View File

@@ -3,9 +3,12 @@ import numpy as np
import pandas as pd
import platform
from collections import Counter
import keras
from keras.models import Sequential
from keras.layers import Embedding, Bidirectional, LSTM
from keras.layers import Embedding, Bidirectional, LSTM, Dropout
from keras_contrib.layers import CRF
from keras_contrib.losses import crf_loss
from keras_contrib.metrics import crf_viterbi_accuracy
"""
# padding: pre(默认) 向前补充0 post 向后补充0
# truncating: 文本超过 pad_num, pre(默认) 删除前面 post 删除后面
@@ -31,7 +34,7 @@ def load_data():
# Counter({'的': 8, '中': 7, '致': 7, '党': 7})
word_counts = Counter(row[0].lower() for sample in train for row in sample)
vocab = [w for w, f in iter(word_counts.items()) if f >= 2]
chunk_tags = ['O', 'B-PER', 'I-PER', 'B-LOC', 'I-LOC', "B-ORG", "I-ORG"]
chunk_tags = Config.nlp_ner.chunk_tags
# 存储保留的有效个数的 vovab 和 对应 chunk_tags
with open(Config.nlp_ner.path_config, 'wb') as outp:
@@ -57,7 +60,10 @@ def _parse_data(filename):
# 主要是分句: split_text 默认每个句子都是一行,所以原来换行就需要 两个split_text
texts = fn.read().decode('utf-8').strip().split(split_text + split_text)
# 对于每个字需要 split_text, 而字的内部需要用空格分隔
data = [[row.split() for row in text.split(split_text)] for text in texts]
# len(row) > 0 避免连续2个换行导致 row 数据为空
# row.split() 会删除空格或特殊符号,导致空格数据缺失!
data = [[[" ", "O"] if len(row.split()) != 2 else row.split() for row in text.split(split_text) if len(row) > 0] for text in texts]
# data = [[row.split() for row in text.split(split_text) if len(row.split()) == 2] for text in texts]
return data
@@ -96,10 +102,17 @@ def create_model(len_vocab, len_chunk_tags):
model = Sequential()
model.add(Embedding(len_vocab, Config.nlp_ner.EMBED_DIM, mask_zero=True)) # Random embedding
model.add(Bidirectional(LSTM(Config.nlp_ner.BiLSTM_UNITS // 2, return_sequences=True)))
model.add(Dropout(0.25))
crf = CRF(len_chunk_tags, sparse_target=True)
model.add(crf)
model.summary()
model.compile('adam', loss=crf.loss_function, metrics=[crf.accuracy])
model.compile('adam', loss=crf_loss, metrics=[crf_viterbi_accuracy])
# model.compile('rmsprop', loss=crf_loss, metrics=[crf_viterbi_accuracy])
# from keras.optimizers import Adam
# adam_lr = 0.0001
# adam_beta_1 = 0.5
# model.compile(optimizer=Adam(lr=adam_lr, beta_1=adam_beta_1), loss=crf_loss, metrics=[crf_viterbi_accuracy])
return model
@@ -115,29 +128,38 @@ def test():
with open(Config.nlp_ner.path_config, 'rb') as inp:
(vocab, chunk_tags) = pickle.load(inp)
model = create_model(len(vocab), len(chunk_tags))
predict_text = '中华人民共和国国务院总理周恩来在外交部长陈毅的陪同下连续访问了埃塞俄比亚等非洲10国以及阿尔巴尼亚'
text_EMBED, length = process_data(predict_text, vocab)
model.load_weights(Config.nlp_ner.path_model)
raw = model.predict(text_EMBED)[0][-length:]
result = [np.argmax(row) for row in raw]
result_tags = [chunk_tags[i] for i in result]
# predict_text = '造型独特,尺码偏大,估计是钉子头圆的半径的缘故'
with open(Config.nlp_ner.path_origin, "r", encoding="utf-8") as f:
lines = f.readlines()
for predict_text in lines:
content = predict_text.strip()
text_EMBED, length = process_data(content, vocab)
model.load_weights(Config.nlp_ner.path_model)
raw = model.predict(text_EMBED)[0][-length:]
pre_result = [np.argmax(row) for row in raw]
result_tags = [chunk_tags[i] for i in pre_result]
per, loc, org = '', '', ''
for s, t in zip(predict_text, result_tags):
if t in ('B-PER', 'I-PER'):
per += ' ' + s if (t == 'B-PER') else s
if t in ('B-ORG', 'I-ORG'):
org += ' ' + s if (t == 'B-ORG') else s
if t in ('B-LOC', 'I-LOC'):
loc += ' ' + s if (t == 'B-LOC') else s
print(['person:' + per, 'location:' + loc, 'organzation:' + org])
# 保存每句话的 实体和观点
result = {}
tag_list = [i for i in chunk_tags if i not in ["O"]]
for word, t in zip(content, result_tags):
# print(word, t)
if t not in tag_list:
continue
for i in range(0, len(tag_list), 2):
if t in tag_list[i:i+2]:
# print("\n>>> %s---%s==%s" % (word, t, tag_list[i:i+2]))
tag = tag_list[i].split("-")[-1]
if tag not in result:
result[tag] = ""
result[tag] += ' '+word if t==tag_list[i] else word
print(result)
def main():
# print("--")
train()
test()
# if __name__ == "__main__":
# train()