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}$$ ![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 算法特点 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}$$, 点到超平面的距离也是类似的) ![点到直线的几何距离](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\\), 因为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<学习的对偶算法> ![计算拉格朗日函数的对偶函数](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· \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 ![松弛变量公式](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 伪代码大致如下: 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