diff --git a/.gitignore b/.gitignore
index 5a190dbc..416d64cc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@ __pycache__/
*.py[cod]
*$py.class
.vscode
+data/*
# C extensions
*.so
diff --git a/config/setting.py b/config/setting.py
index 78b07945..9c03b1d8 100644
--- a/config/setting.py
+++ b/config/setting.py
@@ -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
diff --git a/docs/ml/14.利用SVD简化数据.md b/docs/ml/14.利用SVD简化数据.md
index 76de7915..ec826a0f 100644
--- a/docs/ml/14.利用SVD简化数据.md
+++ b/docs/ml/14.利用SVD简化数据.md
@@ -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}$$

@@ -61,7 +61,7 @@

* 上述分解中会构建出一个矩阵∑,该矩阵只有对角元素,其他元素均为0(近似于0)。另一个惯例就是,∑的对角元素是从大到小排列的。这些对角元素称为奇异值。
-* 奇异值与特征值(PCA 数据中重要特征)是有关系的。这里的奇异值就是矩阵 \\(Data * Data^T\\) 特征值的平方根。
+* 奇异值与特征值(PCA 数据中重要特征)是有关系的。这里的奇异值就是矩阵 $$Data * Data^T$$ 特征值的平方根。
* 普遍的事实: 在某个奇异值的数目(r 个=>奇异值的平方和累加到总值的90%以上)之后,其他的奇异值都置为0(近似于0)。这意味着数据集中仅有 r 个重要特征,而其余特征则都是噪声或冗余特征。
### SVD 算法特点
diff --git a/docs/ml/6.支持向量机.md b/docs/ml/6.支持向量机.md
index 8b4a8b23..014a5402 100644
--- a/docs/ml/6.支持向量机.md
+++ b/docs/ml/6.支持向量机.md
@@ -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}$$, 点到超平面的距离也是类似的)

> 拉格朗日乘子法
-* 类别标签用-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\\), 因为0~1之间,得到的点是存在误判的可能性,所以要保障 \\(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$$, 因为0~1之间,得到的点是存在误判的可能性,所以要保障 $$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\\) ,表示该点为非支持向量
- * 相当于求解: \\(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$$ ,表示该点为非支持向量
+ * 相当于求解: $$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<学习的对偶算法>

-* 终于得到课本上的公式: \\(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· \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· \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

* 我们知道几乎所有的数据都不那么干净, 通过引入松弛变量来 `允许数据点可以处于分隔面错误的一侧`。
-* 约束条件: \\(C>=a>=0\\) 并且 \\(\sum_{i=1}^{m} a_i·label_i=0\\)
+* 约束条件: $$C>=a>=0$$ 并且 $$\sum_{i=1}^{m} a_i·label_i=0$$
* 总的来说:
*  表示 `松弛变量`
* 常量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 伪代码大致如下:
diff --git a/docs/nlp/README.md b/docs/nlp/README.md
index 5738879f..b595d192 100644
--- a/docs/nlp/README.md
+++ b/docs/nlp/README.md
@@ -1,5 +1,9 @@
# 【入门须知】必须了解
+实体: 抽取
+关系: 图谱
+意图: 分类
+
* **【入门须知】必须了解**:
* **【入门教程】强烈推荐: PyTorch 自然语言处理**:
* Python 自然语言处理 第二版:
diff --git a/requirements.txt b/requirements.txt
index 472afd61..d363a594 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -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
\ No newline at end of file
diff --git a/tutorials/keras/brat_tag.py b/tutorials/keras/brat_tag.py
new file mode 100644
index 00000000..65aa888c
--- /dev/null
+++ b/tutorials/keras/brat_tag.py
@@ -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
+# 除8,9-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)
diff --git a/tutorials/keras/text_NER.py b/tutorials/keras/text_NER.py
index 6ffa7c95..7f4f1cbf 100644
--- a/tutorials/keras/text_NER.py
+++ b/tutorials/keras/text_NER.py
@@ -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()
diff --git a/tool/DecisionTree_getInfoGain.py b/tutorials/tool/DecisionTree_getInfoGain.py
similarity index 100%
rename from tool/DecisionTree_getInfoGain.py
rename to tutorials/tool/DecisionTree_getInfoGain.py
diff --git a/tool/python2libsvm.py b/tutorials/tool/python2libsvm.py
similarity index 100%
rename from tool/python2libsvm.py
rename to tutorials/tool/python2libsvm.py