├── __init__.py ├── checkpoints └── 占位.txt ├── tensorboard └── 占位.txt ├── utils ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-36.pyc │ ├── __init__.cpython-37.pyc │ ├── commonUtils.cpython-36.pyc │ ├── commonUtils.cpython-37.pyc │ ├── decodeUtils.cpython-37.pyc │ ├── trainUtils.cpython-37.pyc │ ├── cutSentences.cpython-36.pyc │ ├── cutSentences.cpython-37.pyc │ └── metricsUtils.cpython-37.pyc ├── metricsUtils.py ├── commonUtils.py ├── cutSentences.py ├── trainUtils.py └── decodeUtils.py ├── data ├── cner │ ├── __init__.py │ ├── raw_data │ │ ├── __init__.py │ │ └── process.py │ ├── aug_data │ │ ├── RACE.txt │ │ ├── CONT.txt │ │ ├── LOC.txt │ │ ├── EDU.txt │ │ ├── PRO.txt │ │ ├── NAME.txt │ │ └── TITLE.txt │ ├── mid_data │ │ ├── labels.json │ │ └── nor_ent2id.json │ ├── final_data │ │ ├── dev.pkl │ │ ├── test.pkl │ │ └── train.pkl │ └── .gitignore ├── CHIP2020 │ └── raw_data │ │ └── process.py ├── CLUE │ └── raw_data │ │ └── process.py ├── msra │ └── raw_data │ │ └── process.py ├── weibo │ └── raw_data │ │ └── process.py ├── sighan2005 │ └── raw_data │ │ └── process.py ├── gdcq │ └── raw_data │ │ └── process.py ├── addr │ └── raw_data │ │ └── process.py ├── onenotes4.0 │ └── raw_data │ │ └── process.py └── attr │ └── raw_data │ └── process.py ├── scripts ├── restart_server.sh ├── start_server.sh ├── stop_server.sh ├── test_requests.py ├── templates │ └── predict.html └── server.py ├── dataset.py ├── bert_base_model.py ├── cut.py ├── config.py ├── data_augment └── aug.py ├── convert_onnx ├── bert_ner_model_onnx.py └── convert_onnx.py ├── predict.py ├── predict_gdcq.py ├── bert_ner_model.py ├── layers └── CRF.py ├── knowledge_distillation └── kd.py └── preprocess.py /__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /checkpoints/占位.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tensorboard/占位.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /data/cner/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /data/cner/raw_data/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /data/cner/aug_data/RACE.txt: -------------------------------------------------------------------------------- 1 | 土家族 2 | 汉族人 3 | 汉 4 | 维吾尔族 5 | 汉族 6 | 白族 -------------------------------------------------------------------------------- /scripts/restart_server.sh: -------------------------------------------------------------------------------- 1 | sh ./stop_server.sh 2 | sh ./start_server.sh -------------------------------------------------------------------------------- /scripts/start_server.sh: -------------------------------------------------------------------------------- 1 | nohup python -u dq_ner_server_main.py > nohup.log & -------------------------------------------------------------------------------- /data/cner/mid_data/labels.json: -------------------------------------------------------------------------------- 1 | ["PRO", "ORG", "CONT", "RACE", "NAME", "EDU", "LOC", "TITLE"] -------------------------------------------------------------------------------- /scripts/stop_server.sh: -------------------------------------------------------------------------------- 1 | ps -ef|grep "server.py"|grep -v grep|awk '{print $2}'|xargs kill -9 -------------------------------------------------------------------------------- /data/cner/final_data/dev.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taishan1994/pytorch_bert_bilstm_crf_ner/HEAD/data/cner/final_data/dev.pkl -------------------------------------------------------------------------------- /data/cner/final_data/test.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taishan1994/pytorch_bert_bilstm_crf_ner/HEAD/data/cner/final_data/test.pkl -------------------------------------------------------------------------------- /data/cner/final_data/train.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taishan1994/pytorch_bert_bilstm_crf_ner/HEAD/data/cner/final_data/train.pkl -------------------------------------------------------------------------------- /utils/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taishan1994/pytorch_bert_bilstm_crf_ner/HEAD/utils/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /utils/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taishan1994/pytorch_bert_bilstm_crf_ner/HEAD/utils/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /data/cner/aug_data/CONT.txt: -------------------------------------------------------------------------------- 1 | 美国国籍 2 | 日本籍 3 | 印度国籍 4 | 中国籍 5 | 新加坡 6 | 德国国籍 7 | 日本国籍 8 | 加拿大国籍 9 | 英国籍 10 | 国籍:日本 11 | 中国国籍 12 | 中国公民 13 | 国籍马来西亚 14 | 新西兰国籍 -------------------------------------------------------------------------------- /utils/__pycache__/commonUtils.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taishan1994/pytorch_bert_bilstm_crf_ner/HEAD/utils/__pycache__/commonUtils.cpython-36.pyc -------------------------------------------------------------------------------- /utils/__pycache__/commonUtils.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taishan1994/pytorch_bert_bilstm_crf_ner/HEAD/utils/__pycache__/commonUtils.cpython-37.pyc -------------------------------------------------------------------------------- /utils/__pycache__/decodeUtils.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taishan1994/pytorch_bert_bilstm_crf_ner/HEAD/utils/__pycache__/decodeUtils.cpython-37.pyc -------------------------------------------------------------------------------- /utils/__pycache__/trainUtils.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taishan1994/pytorch_bert_bilstm_crf_ner/HEAD/utils/__pycache__/trainUtils.cpython-37.pyc -------------------------------------------------------------------------------- /utils/__pycache__/cutSentences.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taishan1994/pytorch_bert_bilstm_crf_ner/HEAD/utils/__pycache__/cutSentences.cpython-36.pyc -------------------------------------------------------------------------------- /utils/__pycache__/cutSentences.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taishan1994/pytorch_bert_bilstm_crf_ner/HEAD/utils/__pycache__/cutSentences.cpython-37.pyc -------------------------------------------------------------------------------- /utils/__pycache__/metricsUtils.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taishan1994/pytorch_bert_bilstm_crf_ner/HEAD/utils/__pycache__/metricsUtils.cpython-37.pyc -------------------------------------------------------------------------------- /scripts/test_requests.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | import requests 3 | import time 4 | 5 | params = { 6 | "text": "虞兔良先生:1963年12月出生,汉族,中国国籍,无境外永久居留权,浙江绍兴人,中共党员,MBA,经济师。" 7 | } 8 | 9 | url = "http://0.0.0.0:9277/extraction/" 10 | start = time.time() 11 | res = requests.post(url=url, json=params) 12 | print(res.text) 13 | end = time.time() 14 | print("耗时:{}s".format(end - start)) -------------------------------------------------------------------------------- /data/cner/mid_data/nor_ent2id.json: -------------------------------------------------------------------------------- 1 | {"O": 0, "B-PRO": 1, "I-PRO": 2, "E-PRO": 3, "S-PRO": 4, "B-ORG": 5, "I-ORG": 6, "E-ORG": 7, "S-ORG": 8, "B-CONT": 9, "I-CONT": 10, "E-CONT": 11, "S-CONT": 12, "B-RACE": 13, "I-RACE": 14, "E-RACE": 15, "S-RACE": 16, "B-NAME": 17, "I-NAME": 18, "E-NAME": 19, "S-NAME": 20, "B-EDU": 21, "I-EDU": 22, "E-EDU": 23, "S-EDU": 24, "B-LOC": 25, "I-LOC": 26, "E-LOC": 27, "S-LOC": 28, "B-TITLE": 29, "I-TITLE": 30, "E-TITLE": 31, "S-TITLE": 32} -------------------------------------------------------------------------------- /data/cner/aug_data/LOC.txt: -------------------------------------------------------------------------------- 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 | 天津 -------------------------------------------------------------------------------- /data/cner/aug_data/EDU.txt: -------------------------------------------------------------------------------- 1 | 博士学位 2 | 双学士 3 | 博士研究生学历 4 | 大专毕业 5 | 博士研究生 6 | ACIS 7 | 大学专科 8 | 硕士 9 | 在职研究生 10 | 研究生文化程度 11 | 在职硕士 12 | 大学本科学历 13 | 硕士研究生学历 14 | MPACC学员 15 | 中专学历 16 | 研究生同等学历 17 | 在职研究生班 18 | 在职MBA 19 | MPAcc 20 | 高中文化 21 | 工程硕士学位 22 | 大学 23 | HKICS 24 | MBA学位 25 | 大学本科 26 | 研究生 27 | MBA进修班 28 | 研究生学历 29 | 大专 30 | 大学普通班学历 31 | 学士 32 | 中专文化 33 | 硕士同等学力 34 | 院士 35 | MBA硕士研究生 36 | 硕士研究生 37 | 博士 38 | EMBA 39 | FHKSA 40 | 研究生进修班 41 | 专科 42 | 本科 43 | 大学专科学历 44 | 全国会计硕士专业学位 45 | 学士学位 46 | 大学文化程度 47 | MBA硕士 48 | 大专学历 49 | 硕士在读 50 | FCCA 51 | 在职博士 52 | 大学学历 53 | MBA 54 | 初中学历 55 | 专科学历 56 | 大本学历 57 | 大学文化 58 | 硕士学位 59 | 高中文化程度 60 | 53岁 61 | 硕士学历 62 | 本科学历 63 | 大专文化程度 64 | 高中学历 65 | ACCA 66 | 大专文化 67 | 在读硕士 68 | 在职研究生学历 69 | 专修科 70 | 在读硕士研究生 -------------------------------------------------------------------------------- /dataset.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from torch.utils.data import Dataset, DataLoader 3 | from preprocess import BertFeature 4 | from utils import commonUtils 5 | 6 | 7 | class NerDataset(Dataset): 8 | def __init__(self, features): 9 | # self.callback_info = callback_info 10 | self.nums = len(features) 11 | 12 | self.token_ids = [torch.tensor(example.token_ids).long() for example in features] 13 | self.attention_masks = [torch.tensor(example.attention_masks, dtype=torch.uint8) for example in features] 14 | self.token_type_ids = [torch.tensor(example.token_type_ids).long() for example in features] 15 | self.labels = [torch.tensor(example.labels).long() for example in features] 16 | 17 | def __len__(self): 18 | return self.nums 19 | 20 | def __getitem__(self, index): 21 | data = { 22 | 'token_ids': self.token_ids[index], 23 | 'attention_masks': self.attention_masks[index], 24 | 'token_type_ids': self.token_type_ids[index] 25 | } 26 | 27 | data['labels'] = self.labels[index] 28 | 29 | return data 30 | -------------------------------------------------------------------------------- /data/cner/aug_data/PRO.txt: -------------------------------------------------------------------------------- 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 | MBA 26 | 企业管理专业 27 | 法律 28 | 经管专业 29 | 经济管理专业 30 | 工业电气自动化专业 31 | EMBA专业 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 | (金融专业方向)EMBA 100 | 金融投资与管理 101 | 工商管理专业 102 | 计算机工程 103 | 工学 104 | 统计学专业 105 | 数量经济学专业 106 | 经济管理学 107 | 项目管理专业 108 | 管理学(会计) 109 | 生化药学 110 | 国际会计商学 111 | 电子与通讯专业 112 | 电子电机专业 113 | 财税专业 114 | 金融学 115 | 高级管理人员工商管理 116 | 内燃机专业 117 | 企业管理现代财务与会计专业 -------------------------------------------------------------------------------- /data/CHIP2020/raw_data/process.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | 4 | labels = set() 5 | 6 | 7 | def preprocess(path, save_path): 8 | res = [] 9 | with open(path, 'r', encoding='utf-8') as fp: 10 | data = fp.readlines() 11 | i = 0 12 | for d in data: 13 | tmp = {"id":i, 'labels':[]} 14 | d = d.strip() 15 | d = d.split('|||') 16 | text = d[0] 17 | tmp['text'] = text 18 | for j,entity in enumerate(d[1:]): 19 | entity = entity.split(' ') 20 | if len(entity) == 3: 21 | tmp['labels'].append( 22 | ["T{}".format(str(j)), entity[2], int(entity[0]), int(entity[1])+1, text[int(entity[0]):int(entity[1])+1]] 23 | ) 24 | labels.add(entity[2]) 25 | res.append(tmp) 26 | with open(save_path, 'w', encoding='utf-8') as fp: 27 | json.dump(res, fp, ensure_ascii=False) 28 | 29 | 30 | 31 | if __name__ == "__main__": 32 | preprocess('train_data_all.txt', '../mid_data/train.json') 33 | preprocess('val_data.txt', '../mid_data/dev.json') 34 | with open('../mid_data/labels.json', 'w', encoding='utf-8') as fp: 35 | json.dump(list(labels), fp, ensure_ascii=False) 36 | 37 | ent2id_list = ['O'] 38 | for label in labels: 39 | ent2id_list.append('B-' + label) 40 | ent2id_list.append('I-' + label) 41 | ent2id_list.append('E-' + label) 42 | ent2id_list.append('S-' + label) 43 | ent2id_dict = {} 44 | for i, ent in enumerate(ent2id_list): 45 | ent2id_dict[ent] = i 46 | 47 | 48 | with open('../mid_data/nor_ent2id.json', 'w', encoding='utf-8') as fp: 49 | json.dump(ent2id_dict, fp, ensure_ascii=False) 50 | -------------------------------------------------------------------------------- /data/CLUE/raw_data/process.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | 4 | labels = set() 5 | 6 | 7 | def preprocess(path, save_path): 8 | res = [] 9 | with open(path, 'r', encoding='utf-8') as fp: 10 | data = fp.readlines() 11 | i = 0 12 | for d in data: 13 | d = json.loads(d) 14 | tmp = {"id":i, 'labels':[]} 15 | text = d['text'] 16 | tmp['text'] = text 17 | entities = d['entity_list'] 18 | for j, entity in enumerate(entities): 19 | entity_type = entity['entity_type'] 20 | ent = entity['entity'] 21 | start = entity['entity_index']['begin'] 22 | end = entity['entity_index']['end'] 23 | tmp['labels'].append( 24 | ["T{}".format(str(j)), entity_type, int(start), int(end), ent] 25 | ) 26 | labels.add(entity_type) 27 | 28 | res.append(tmp) 29 | with open(save_path, 'w', encoding='utf-8') as fp: 30 | json.dump(res, fp, ensure_ascii=False) 31 | 32 | 33 | 34 | if __name__ == "__main__": 35 | preprocess('train.txt', '../mid_data/train.json') 36 | preprocess('dev.txt', '../mid_data/dev.json') 37 | with open('../mid_data/labels.json', 'w', encoding='utf-8') as fp: 38 | json.dump(list(labels), fp, ensure_ascii=False) 39 | 40 | ent2id_list = ['O'] 41 | for label in labels: 42 | ent2id_list.append('B-' + label) 43 | ent2id_list.append('I-' + label) 44 | ent2id_list.append('E-' + label) 45 | ent2id_list.append('S-' + label) 46 | ent2id_dict = {} 47 | for i, ent in enumerate(ent2id_list): 48 | ent2id_dict[ent] = i 49 | 50 | 51 | with open('../mid_data/nor_ent2id.json', 'w', encoding='utf-8') as fp: 52 | json.dump(ent2id_dict, fp, ensure_ascii=False) 53 | -------------------------------------------------------------------------------- /bert_base_model.py: -------------------------------------------------------------------------------- 1 | import os 2 | import torch.nn as nn 3 | from transformers import BertModel, AutoModel 4 | 5 | 6 | class BaseModel(nn.Module): 7 | def __init__(self, bert_dir, dropout_prob, model_name=""): 8 | super(BaseModel, self).__init__() 9 | config_path = os.path.join(bert_dir, 'config.json') 10 | 11 | assert os.path.exists(bert_dir) and os.path.exists(config_path), \ 12 | 'pretrained bert file does not exist' 13 | 14 | if 'electra' in model_name or 'albert' in model_name: 15 | self.bert_module = AutoModel.from_pretrained(bert_dir, output_hidden_states=True, 16 | hidden_dropout_prob=dropout_prob) 17 | else: 18 | self.bert_module = BertModel.from_pretrained(bert_dir, output_hidden_states=True, 19 | hidden_dropout_prob=dropout_prob) 20 | self.bert_config = self.bert_module.config 21 | 22 | @staticmethod 23 | def _init_weights(blocks, **kwargs): 24 | """ 25 | 参数初始化,将 Linear / Embedding / LayerNorm 与 Bert 进行一样的初始化 26 | """ 27 | for block in blocks: 28 | for module in block.modules(): 29 | if isinstance(module, nn.Linear): 30 | if module.bias is not None: 31 | nn.init.zeros_(module.bias) 32 | elif isinstance(module, nn.Embedding): 33 | nn.init.normal_(module.weight, mean=0, std=kwargs.pop('initializer_range', 0.02)) 34 | elif isinstance(module, nn.LayerNorm): 35 | nn.init.ones_(module.weight) 36 | nn.init.zeros_(module.bias) 37 | -------------------------------------------------------------------------------- /data/cner/.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /data/msra/raw_data/process.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | 4 | def get_data(path, mode="train"): 5 | with open(path, 'r', encoding="utf-8") as fp: 6 | data = fp.readlines() 7 | ents = set() 8 | res = [] 9 | i = 0 10 | for d in data: 11 | d = json.loads(d) 12 | text = d["text"] 13 | if not text: 14 | continue 15 | entities = d["entity_list"] 16 | j = 0 17 | labels = [] 18 | for entity in entities: 19 | entity_index = entity["entity_index"] 20 | start = entity_index["begin"] 21 | end = entity_index["end"] 22 | dtype = entity["entity_type"] 23 | ents.add(dtype) 24 | e = entity["entity"] 25 | labels.append([ 26 | "T{}".format(j), 27 | dtype, 28 | start, 29 | end, 30 | e 31 | ]) 32 | j += 1 33 | res.append({ 34 | "id": i, 35 | "text": text, 36 | "labels": labels 37 | }) 38 | i += 1 39 | 40 | with open("../mid_data/" + mode + ".json", "w", encoding="utf-8") as fp: 41 | json.dump(res, fp, ensure_ascii=False) 42 | 43 | if mode == "train": 44 | with open("../mid_data/" + "labels.json", "w", encoding="utf-8") as fp: 45 | json.dump(list(ents), fp, ensure_ascii=False) 46 | 47 | nor_ent2id = {"O": 0} 48 | i = 1 49 | for label in ents: 50 | nor_ent2id["B-" + label] = i 51 | i += 1 52 | nor_ent2id["I-" + label] = i 53 | i += 1 54 | nor_ent2id["E-" + label] = i 55 | i += 1 56 | nor_ent2id["S-" + label] = i 57 | i += 1 58 | 59 | with open("../mid_data/" + "nor_ent2id.json", "w", encoding="utf-8") as fp: 60 | json.dump(nor_ent2id, fp, ensure_ascii=False) 61 | 62 | 63 | get_data("msra_train.txt", mode="train") 64 | get_data("msra_1000.txt", mode="dev") -------------------------------------------------------------------------------- /data/weibo/raw_data/process.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | 4 | def get_data(path, mode="train"): 5 | with open(path, 'r', encoding="utf-8") as fp: 6 | data = fp.readlines() 7 | ents = set() 8 | res = [] 9 | i = 0 10 | for d in data: 11 | d = json.loads(d) 12 | text = d["text"] 13 | if not text: 14 | continue 15 | entities = d["entity_list"] 16 | j = 0 17 | labels = [] 18 | for entity in entities: 19 | entity_index = entity["entity_index"] 20 | start = entity_index["begin"] 21 | end = entity_index["end"] 22 | dtype = entity["entity_type"] 23 | ents.add(dtype) 24 | e = entity["entity"] 25 | labels.append([ 26 | "T{}".format(j), 27 | dtype, 28 | start, 29 | end, 30 | e 31 | ]) 32 | j += 1 33 | res.append({ 34 | "id": i, 35 | "text": text, 36 | "labels": labels 37 | }) 38 | i += 1 39 | 40 | with open("../mid_data/" + mode + ".json", "w", encoding="utf-8") as fp: 41 | json.dump(res, fp, ensure_ascii=False) 42 | 43 | if mode == "train": 44 | with open("../mid_data/" + "labels.json", "w", encoding="utf-8") as fp: 45 | json.dump(list(ents), fp, ensure_ascii=False) 46 | 47 | nor_ent2id = {"O": 0} 48 | i = 1 49 | for label in ents: 50 | nor_ent2id["B-" + label] = i 51 | i += 1 52 | nor_ent2id["I-" + label] = i 53 | i += 1 54 | nor_ent2id["E-" + label] = i 55 | i += 1 56 | nor_ent2id["S-" + label] = i 57 | i += 1 58 | 59 | with open("../mid_data/" + "nor_ent2id.json", "w", encoding="utf-8") as fp: 60 | json.dump(nor_ent2id, fp, ensure_ascii=False) 61 | 62 | 63 | get_data("weibo_ner_train.txt", mode="train") 64 | get_data("weibo_ner_dev.txt", mode="dev") -------------------------------------------------------------------------------- /scripts/templates/predict.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | file 10 | 38 | 39 | 40 | 41 | 42 |
43 |
44 |

命名实体识别

45 |
46 |
47 | 48 |
49 | 50 | 51 |
52 |

预测结果

53 |
54 | {{text}} 55 |
56 |
57 | {% if ucode == 200 %} 58 | {% for item in result%} 59 | {{item}}: 60 | {% for item2 in result[item] %} 61 | 【{{item2}}】 62 | {% endfor %} 63 |
64 | {% endfor %} 65 | {% else %} 66 | {{msg}} 67 | {% endif %} 68 | 69 |
70 |
71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /cut.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | 4 | def cut_sentences_v1(sent): 5 | """ 6 | the first rank of sentence cut 7 | """ 8 | sent = re.sub('([。!?\?])([^”’])', r"\1\n\2", sent) # 单字符断句符 9 | sent = re.sub('(\.{6})([^”’])', r"\1\n\2", sent) # 英文省略号 10 | sent = re.sub('(\…{2})([^”’])', r"\1\n\2", sent) # 中文省略号 11 | sent = re.sub('([。!?\?][”’])([^,。!?\?])', r"\1\n\2", sent) 12 | # 如果双引号前有终止符,那么双引号才是句子的终点,把分句符\n放到双引号后 13 | return sent.split("\n") 14 | 15 | 16 | def cut_sentences_v2(sent): 17 | """ 18 | the second rank of spilt sentence, split ';' | ';' 19 | """ 20 | sent = re.sub('([;;])([^”’])', r"\1\n\2", sent) 21 | return sent.split("\n") 22 | 23 | 24 | def cut_sentences_v3(sent): 25 | """以逗号进行分句""" 26 | sent = re.sub('([,,])([^”’])', r'\1\n\2', sent) 27 | return sent.split("\n") 28 | 29 | 30 | def cut_sentences_main(text, max_seq_len): 31 | # 将句子分句,细粒度分句后再重新合并 32 | sentences = [] 33 | if len(text) <= max_seq_len: 34 | return [text] 35 | 36 | # 细粒度划分 37 | sentences_v1 = cut_sentences_v1(text) 38 | # print("sentences_v1=", sentences_v1) 39 | for sent_v1 in sentences_v1: 40 | # print(sent_v1) 41 | if len(sent_v1) > max_seq_len: 42 | sentences_v2 = cut_sentences_v2(sent_v1) 43 | sentences.extend(sentences_v2) 44 | else: 45 | sentences.append(sent_v1) 46 | # if ''.join(sentences) != text: 47 | # print(len(''.join(sentences)), len(text)) 48 | 49 | res = [] 50 | for sent in sentences: 51 | # print(sentences) 52 | if len(sent) > max_seq_len: 53 | sent_v3 = cut_sentences_v3(sent) 54 | # print(sent_v3) 55 | tmp = [] 56 | length = 0 57 | for i in range(len(sent_v3)): 58 | if length + len(sent_v3[i]) < max_seq_len: 59 | tmp.append(sent_v3[i]) 60 | length = length + len(sent_v3[i]) 61 | else: 62 | if "".join(tmp) != "": 63 | res.append("".join(tmp)) 64 | tmp = [sent_v3[i]] 65 | length = len(sent_v3[i]) 66 | if "".join(tmp) != "": 67 | res.append("".join(tmp)) 68 | else: 69 | res.append(sent) 70 | # assert ''.join(sentences) == text 71 | # 过滤掉空字符 72 | final_res = [] 73 | for i in res: 74 | if i.strip() != "": 75 | final_res.append(i) 76 | return final_res -------------------------------------------------------------------------------- /utils/metricsUtils.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from __future__ import division 3 | from __future__ import print_function 4 | 5 | from collections import defaultdict 6 | 7 | import numpy as np 8 | 9 | 10 | 11 | def calculate_metric(gt, predict): 12 | """ 13 | 计算 tp fp fn 14 | """ 15 | tp, fp, fn = 0, 0, 0 16 | for entity_predict in predict: 17 | flag = 0 18 | for entity_gt in gt: 19 | if entity_predict[0] == entity_gt[0] and entity_predict[1] == entity_gt[1]: 20 | flag = 1 21 | tp += 1 22 | break 23 | if flag == 0: 24 | fp += 1 25 | 26 | fn = len(gt) - tp 27 | 28 | return np.array([tp, fp, fn]) 29 | 30 | 31 | def get_p_r_f(tp, fp, fn): 32 | p = tp / (tp + fp) if tp + fp != 0 else 0 33 | r = tp / (tp + fn) if tp + fn != 0 else 0 34 | f1 = 2 * p * r / (p + r) if p + r != 0 else 0 35 | return np.array([p, r, f1]) 36 | 37 | def classification_report(metrics_matrix, label_list, id2label, total_count, digits=2, suffix=False): 38 | name_width = max([len(label) for label in label_list]) 39 | last_line_heading = 'micro-f1' 40 | width = max(name_width, len(last_line_heading), digits) 41 | 42 | headers = ["precision", "recall", "f1-score", "support"] 43 | head_fmt = u'{:>{width}s} ' + u' {:>9}' * len(headers) 44 | report = head_fmt.format(u'', *headers, width=width) 45 | report += u'\n\n' 46 | 47 | row_fmt = u'{:>{width}s} ' + u' {:>9.{digits}f}' * 3 + u' {:>9}\n' 48 | 49 | ps, rs, f1s, s = [], [], [], [] 50 | for label_id, label_matrix in enumerate(metrics_matrix): 51 | type_name = id2label[label_id] 52 | p,r,f1 = get_p_r_f(label_matrix[0],label_matrix[1],label_matrix[2]) 53 | nb_true = total_count[label_id] 54 | report += row_fmt.format(*[type_name, p, r, f1, nb_true], width=width, digits=digits) 55 | ps.append(p) 56 | rs.append(r) 57 | f1s.append(f1) 58 | s.append(nb_true) 59 | 60 | report += u'\n' 61 | mirco_metrics = np.sum(metrics_matrix, axis=0) 62 | mirco_metrics = get_p_r_f(mirco_metrics[0], mirco_metrics[1], mirco_metrics[2]) 63 | # compute averages 64 | print('precision:{:.4f} recall:{:.4f} micro_f1:{:.4f}'.format(mirco_metrics[0],mirco_metrics[1],mirco_metrics[2])) 65 | report += row_fmt.format(last_line_heading, 66 | mirco_metrics[0], 67 | mirco_metrics[1], 68 | mirco_metrics[2], 69 | np.sum(s), 70 | width=width, digits=digits) 71 | 72 | return report -------------------------------------------------------------------------------- /data/sighan2005/raw_data/process.py: -------------------------------------------------------------------------------- 1 | import json 2 | from pprint import pprint 3 | 4 | max_seq_len= 512 5 | # -1:索引为0-511,-2:去掉CLS和SEP,+1:词索引到下一位 6 | max_seq_len = max_seq_len - 1 - 2 + 1 7 | 8 | with open("training.txt", "r", encoding="utf-8") as fp: 9 | data = fp.readlines() 10 | 11 | res = [] 12 | i = 0 13 | for d in data: 14 | d = d.strip().split(" ") 15 | dtype = "word" 16 | start = 0 17 | tmp = [] 18 | labels = [] 19 | j = 0 20 | for word in d: 21 | start = len("".join(tmp)) 22 | tmp.append(word) 23 | end = start + len(word) 24 | labels.append(["T{}".format(j), dtype, start, end, word]) 25 | j += 1 26 | if end > max_seq_len: 27 | sub_tmp = tmp[:-1] 28 | sub_labels = labels[:-1] 29 | end = start + len("".join(sub_tmp)) 30 | text = "".join(sub_tmp) 31 | res.append({ 32 | "id": i, 33 | "text": text, 34 | "labels": sub_labels 35 | }) 36 | 37 | start = 0 38 | tmp = [word] 39 | end = len("".join(tmp)) 40 | labels = [["T{}".format(0), dtype, 0, end, word]] 41 | i += 1 42 | 43 | if tmp: 44 | text = "".join(tmp) 45 | res.append({ 46 | "id": i, 47 | "text": text, 48 | "labels": labels 49 | }) 50 | i += 1 51 | 52 | with open("../mid_data/train.json", 'w', encoding="utf-8") as fp: 53 | json.dump(res, fp, ensure_ascii=False) 54 | 55 | labels = ["word"] 56 | with open("../mid_data/labels.json", 'w', encoding="utf-8") as fp: 57 | json.dump(labels, fp, ensure_ascii=False) 58 | 59 | nor_ent2id = {"O":0, "B-word":1, "I-word":2, "E-word":3, "S-word":4} 60 | with open("../mid_data/nor_ent2id.json", 'w', encoding="utf-8") as fp: 61 | json.dump(nor_ent2id, fp, ensure_ascii=False) 62 | 63 | with open("test.txt", "r", encoding="utf-8") as fp: 64 | data = fp.readlines() 65 | 66 | res = [] 67 | i = 0 68 | for d in data: 69 | d = d.strip().split(" ") 70 | dtype = "word" 71 | start = 0 72 | tmp = [] 73 | labels = [] 74 | j = 0 75 | for word in d: 76 | start = len("".join(tmp)) 77 | tmp.append(word) 78 | end = start + len(word) 79 | labels.append(["T{}".format(j), dtype, start, end, word]) 80 | j += 1 81 | if end > max_seq_len: 82 | sub_tmp = tmp[:-1] 83 | sub_labels = labels[:-1] 84 | end = start + len("".join(sub_tmp)) 85 | text = "".join(sub_tmp) 86 | res.append({ 87 | "id": i, 88 | "text": text, 89 | "labels": sub_labels 90 | }) 91 | 92 | start = 0 93 | tmp = [word] 94 | end = len("".join(tmp)) 95 | labels = [["T{}".format(0), dtype, 0, end, word]] 96 | i += 1 97 | 98 | if tmp: 99 | text = "".join(tmp) 100 | res.append({ 101 | "id": i, 102 | "text": text, 103 | "labels": labels 104 | }) 105 | i += 1 106 | 107 | with open("../mid_data/test.json", 'w', encoding="utf-8") as fp: 108 | json.dump(res, fp, ensure_ascii=False) -------------------------------------------------------------------------------- /utils/commonUtils.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | import random 3 | import os 4 | import json 5 | import logging 6 | import time 7 | import pickle 8 | import numpy as np 9 | import torch 10 | 11 | 12 | 13 | def timer(func): 14 | """ 15 | 函数计时器 16 | :param func: 17 | :return: 18 | """ 19 | 20 | @functools.wraps(func) 21 | def wrapper(*args, **kwargs): 22 | start = time.time() 23 | res = func(*args, **kwargs) 24 | end = time.time() 25 | print("{}共耗时约{:.4f}秒".format(func.__name__, end - start)) 26 | return res 27 | 28 | return wrapper 29 | 30 | 31 | def set_seed(seed=123): 32 | """ 33 | 设置随机数种子,保证实验可重现 34 | :param seed: 35 | :return: 36 | """ 37 | random.seed(seed) 38 | torch.manual_seed(seed) 39 | np.random.seed(seed) 40 | torch.cuda.manual_seed_all(seed) 41 | 42 | 43 | def set_logger(log_path): 44 | """ 45 | 配置log 46 | :param log_path:s 47 | :return: 48 | """ 49 | logger = logging.getLogger() 50 | logger.setLevel(logging.INFO) 51 | 52 | # 由于每调用一次set_logger函数,就会创建一个handler,会造成重复打印的问题,因此需要判断root logger中是否已有该handler 53 | if not any(handler.__class__ == logging.FileHandler for handler in logger.handlers): 54 | file_handler = logging.FileHandler(log_path) 55 | formatter = logging.Formatter( 56 | '%(asctime)s - %(levelname)s - %(filename)s - %(funcName)s - %(lineno)d - %(message)s') 57 | file_handler.setFormatter(formatter) 58 | logger.addHandler(file_handler) 59 | 60 | if not any(handler.__class__ == logging.StreamHandler for handler in logger.handlers): 61 | stream_handler = logging.StreamHandler() 62 | stream_handler.setFormatter(logging.Formatter('%(message)s')) 63 | logger.addHandler(stream_handler) 64 | 65 | 66 | def save_json(data_dir, data, desc): 67 | """保存数据为json""" 68 | if not os.path.exists(data_dir): 69 | os.makedirs(data_dir) 70 | with open(os.path.join(data_dir, '{}.json'.format(desc)), 'w', encoding='utf-8') as f: 71 | json.dump(data, f, ensure_ascii=False, indent=2) 72 | 73 | 74 | def read_json(data_dir, desc): 75 | """读取数据为json""" 76 | with open(os.path.join(data_dir, '{}.json'.format(desc)), 'r', encoding='utf-8') as f: 77 | data = json.load(f) 78 | return data 79 | 80 | 81 | def save_pkl(data_dir, data, desc): 82 | if not os.path.exists(data_dir): 83 | os.makedirs(data_dir) 84 | """保存.pkl文件""" 85 | with open(os.path.join(data_dir, '{}.pkl'.format(desc)), 'wb') as f: 86 | pickle.dump(data, f) 87 | 88 | 89 | def read_pkl(data_dir, desc): 90 | """读取.pkl文件""" 91 | with open(os.path.join(data_dir, '{}.pkl'.format(desc)), 'rb') as f: 92 | data = pickle.load(f) 93 | return data 94 | 95 | 96 | def fine_grade_tokenize(raw_text, tokenizer): 97 | """ 98 | 序列标注任务 BERT 分词器可能会导致标注偏移, 99 | 用 char-level 来 tokenize 100 | """ 101 | tokens = [] 102 | 103 | for _ch in raw_text: 104 | if _ch in [' ', '\t', '\n']: 105 | tokens.append('[BLANK]') 106 | else: 107 | if not len(tokenizer.tokenize(_ch)): 108 | tokens.append('[INV]') 109 | else: 110 | tokens.append(_ch) 111 | 112 | return tokens 113 | -------------------------------------------------------------------------------- /data/gdcq/raw_data/process.py: -------------------------------------------------------------------------------- 1 | import json 2 | import random 3 | import pandas as pd 4 | from collections import Counter 5 | 6 | 7 | data = pd.read_csv("./Train_merge.csv", encoding="utf-8") 8 | 9 | # ======================== 10 | # 列名:文本唯一标识、主体,主体开始,主体结束,评价,评价开始,评价结束,主体类别,情感,文本 11 | """ 12 | Index(['Unnamed: 0', 'id', 'AspectTerms', 'A_start', 'A_end', 'OpinionTerms', 13 | 'O_start', 'O_end', 'Categories', 'Polarities', 'text'], 14 | dtype='object') 15 | """ 16 | print(data.columns) 17 | # ======================== 18 | 19 | # ======================== 20 | # 统计文本的长度,最大长度为69 21 | text = data['text'].values.tolist() 22 | text = list(set(text)) 23 | text_length = list(map(lambda x: len(x), text)) 24 | text_length_counter = Counter(text_length) 25 | print(text_length_counter) 26 | text_length_counter = sorted(text_length_counter.items(), key=lambda x: x[0]) 27 | print(text_length_counter) 28 | # ======================== 29 | 30 | # ======================== 31 | # 获取主体的类别 32 | cates = data['Categories'].values.tolist() 33 | cates = list(set(cates)) 34 | print(cates) 35 | 36 | # ======================== 37 | # 获取评价类别 38 | polars = data['Polarities'].values.tolist() 39 | polars = list(set(polars)) 40 | print(polars) 41 | 42 | labels = cates + polars 43 | with open('../mid_data/labels.json', 'w', encoding="utf-8") as fp: 44 | json.dump(labels, fp, ensure_ascii=False) 45 | # ======================== 46 | 47 | # ======================== 48 | # 制作BIOES标签 49 | i = 1 50 | ent_label = {"O": 0} 51 | for label in labels: 52 | ent_label['B-{}'.format(label)] = i 53 | i += 1 54 | ent_label['I-{}'.format(label)] = i 55 | i += 1 56 | ent_label['E-{}'.format(label)] = i 57 | i += 1 58 | ent_label['S-{}'.format(label)] = i 59 | i += 1 60 | with open('../mid_data/nor_ent2id.json', 'w', encoding="utf-8") as fp: 61 | json.dump(ent_label, fp, ensure_ascii=False) 62 | # ======================== 63 | 64 | # ======================== 65 | # 转换数据为我们所需要的格式 66 | id_set = set() 67 | res = [] 68 | tmp = {} 69 | for d in data.iterrows(): 70 | d = d[1] 71 | did = d[1] 72 | aspect = d[2] 73 | a_start = d[3] 74 | a_end = d[4] 75 | opinion = d[5] 76 | o_start = d[6] 77 | o_end = d[7] 78 | category = d[8] 79 | polary = d[9] 80 | text = d[10] 81 | # print(did, aspect, a_start, a_end, opinion, o_start, o_end, 82 | # category, polary, text) 83 | if did not in id_set: 84 | if tmp: 85 | print(tmp) 86 | res.append(tmp) 87 | id_set.add(did) 88 | tmp = {} 89 | tmp['id'] = did 90 | tmp['text'] = text 91 | tmp['labels'] = [] 92 | try: 93 | if aspect != "_": 94 | tmp['labels'].append(["T0", category, int(a_start), int(a_end), aspect]) 95 | if category != "_": 96 | tmp['labels'].append(["T0", polary, int(o_start), int(o_end), opinion]) 97 | except Exception as e: 98 | continue 99 | 100 | random.seed(123) 101 | random.shuffle(res) 102 | 103 | ratio = 0.9 104 | length = len(res) 105 | train_data = res[:int(ratio*length)] 106 | dev_data = res[int(ratio*length):] 107 | with open('../mid_data/train.json', 'w', encoding="utf-8") as fp: 108 | json.dump(train_data, fp, ensure_ascii=False) 109 | with open('../mid_data/dev.json', 'w', encoding="utf-8") as fp: 110 | json.dump(dev_data, fp, ensure_ascii=False) 111 | # ======================== 112 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | 4 | class Args: 5 | @staticmethod 6 | def parse(): 7 | parser = argparse.ArgumentParser() 8 | return parser 9 | 10 | @staticmethod 11 | def initialize(parser): 12 | # args for path 13 | parser.add_argument('--output_dir', default='./checkpoints/', 14 | help='the output dir for model checkpoints') 15 | 16 | parser.add_argument('--bert_dir', default='../model_hub/bert-base-chinese/', 17 | help='bert dir for uer') 18 | parser.add_argument('--data_dir', default='./data/cner/', 19 | help='data dir for uer') 20 | parser.add_argument('--log_dir', default='./logs/', 21 | help='log dir for uer') 22 | 23 | # other args 24 | parser.add_argument('--num_tags', default=53, type=int, 25 | help='number of tags') 26 | parser.add_argument('--seed', type=int, default=123, help='random seed') 27 | 28 | parser.add_argument('--gpu_ids', type=str, default='0', 29 | help='gpu ids to use, -1 for cpu, "0,1" for multi gpu') 30 | 31 | parser.add_argument('--max_seq_len', default=256, type=int) 32 | 33 | parser.add_argument('--eval_batch_size', default=12, type=int) 34 | 35 | parser.add_argument('--swa_start', default=3, type=int, 36 | help='the epoch when swa start') 37 | 38 | # train args 39 | parser.add_argument('--train_epochs', default=15, type=int, 40 | help='Max training epoch') 41 | 42 | parser.add_argument('--dropout_prob', default=0.1, type=float, 43 | help='drop out probability') 44 | 45 | # 2e-5 46 | parser.add_argument('--lr', default=3e-5, type=float, 47 | help='bert学习率') 48 | # 2e-3 49 | parser.add_argument('--other_lr', default=3e-4, type=float, 50 | help='bilstm和多层感知机学习率') 51 | parser.add_argument('--crf_lr', default=3e-2, type=float, 52 | help='条件随机场学习率') 53 | # 0.5 54 | parser.add_argument('--max_grad_norm', default=1, type=float, 55 | help='max grad clip') 56 | 57 | parser.add_argument('--warmup_proportion', default=0.1, type=float) 58 | 59 | parser.add_argument('--weight_decay', default=0.01, type=float) 60 | 61 | parser.add_argument('--adam_epsilon', default=1e-8, type=float) 62 | 63 | parser.add_argument('--train_batch_size', default=32, type=int) 64 | parser.add_argument('--use_lstm', type=str, default='True', 65 | help='是否使用BiLstm') 66 | parser.add_argument('--lstm_hidden', default=128, type=int, 67 | help='lstm隐藏层大小') 68 | parser.add_argument('--num_layers', default=1, type=int, 69 | help='lstm层数大小') 70 | parser.add_argument('--dropout', default=0.3, type=float, 71 | help='lstm中dropout的设置') 72 | parser.add_argument('--use_crf', type=str, default='True', 73 | help='是否使用Crf') 74 | parser.add_argument('--use_idcnn', type=str, default='False', 75 | help='是否使用Idcnn') 76 | parser.add_argument('--data_name', type=str, default='c', 77 | help='数据集名字') 78 | parser.add_argument('--model_name', type=str, default='bert', 79 | help='模型名字') 80 | parser.add_argument('--use_tensorboard', type=str, default='True', 81 | help='是否使用tensorboard可视化') 82 | parser.add_argument('--use_kd', type=str, default='False', 83 | help='是否使用知识蒸馏') 84 | return parser 85 | 86 | def get_parser(self): 87 | parser = self.parse() 88 | parser = self.initialize(parser) 89 | return parser.parse_args() 90 | -------------------------------------------------------------------------------- /data/addr/raw_data/process.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | import json 4 | 5 | def preprocess(input_path, save_path, mode): 6 | if not os.path.exists(save_path): 7 | os.makedirs(save_path) 8 | data_path = os.path.join(save_path, mode + ".json") 9 | labels = set() 10 | result = [] 11 | tmp = {} 12 | tmp['id'] = 0 13 | tmp['text'] = '' 14 | tmp['labels'] = [] 15 | # =======先找出句子和句子中的所有实体和类型======= 16 | with open(input_path,'r',encoding='utf-8') as fp: 17 | lines = fp.readlines() 18 | texts = [] 19 | entities = [] 20 | words = [] 21 | entity_tmp = [] 22 | entities_tmp = [] 23 | for line in lines: 24 | line = line.strip().split(" ") 25 | if len(line) == 2: 26 | word = line[0] 27 | label = line[1] 28 | words.append(word) 29 | 30 | if "B-" in label: 31 | entity_tmp.append(word) 32 | elif "I-" in label: 33 | entity_tmp.append(word) 34 | elif "E-" in label: 35 | entity_tmp.append(word) 36 | if ("".join(entity_tmp), label.split("-")[-1]) not in entities_tmp: 37 | entities_tmp.append(("".join(entity_tmp), label.split("-")[-1])) 38 | labels.add(label.split("-")[-1]) 39 | entity_tmp = [] 40 | 41 | else: 42 | texts.append("".join(words)) 43 | entities.append(entities_tmp) 44 | words = [] 45 | entities_tmp = [] 46 | 47 | # for text,entity in zip(texts, entities): 48 | # print(text, entity) 49 | # print(labels) 50 | # ========================================== 51 | # =======找出句子中实体的位置======= 52 | i = 0 53 | for text,entity in zip(texts, entities): 54 | 55 | if entity: 56 | ltmp = [] 57 | for ent,type in entity: 58 | for span in re.finditer(ent, text): 59 | start = span.start() 60 | end = span.end() 61 | ltmp.append((type, start, end, ent)) 62 | # print(ltmp) 63 | ltmp = sorted(ltmp, key=lambda x:(x[1],x[2])) 64 | tmp['id'] = i 65 | tmp['text'] = text 66 | for j in range(len(ltmp)): 67 | tmp['labels'].append(["T{}".format(str(j)), ltmp[j][0], ltmp[j][1], ltmp[j][2], ltmp[j][3]]) 68 | else: 69 | tmp['id'] = i 70 | tmp['text'] = text 71 | tmp['labels'] = [] 72 | result.append(tmp) 73 | # print(i, text, entity, tmp) 74 | tmp = {} 75 | tmp['id'] = 0 76 | tmp['text'] = '' 77 | tmp['labels'] = [] 78 | i += 1 79 | 80 | with open(data_path,'w', encoding='utf-8') as fp: 81 | fp.write(json.dumps(result, ensure_ascii=False)) 82 | 83 | if mode == "train": 84 | label_path = os.path.join(save_path, "labels.json") 85 | with open(label_path, 'w', encoding='utf-8') as fp: 86 | fp.write(json.dumps(list(labels), ensure_ascii=False)) 87 | 88 | preprocess("train.conll", '../mid_data', "train") 89 | preprocess("dev.conll", '../mid_data', "dev") 90 | 91 | labels_path = os.path.join('../mid_data/labels.json') 92 | with open(labels_path, 'r') as fp: 93 | labels = json.load(fp) 94 | 95 | tmp_labels = [] 96 | tmp_labels.append('O') 97 | for label in labels: 98 | tmp_labels.append('B-' + label) 99 | tmp_labels.append('I-' + label) 100 | tmp_labels.append('E-' + label) 101 | tmp_labels.append('S-' + label) 102 | 103 | label2id = {} 104 | for k,v in enumerate(tmp_labels): 105 | label2id[v] = k 106 | path = '../mid_data/' 107 | if not os.path.exists(path): 108 | os.makedirs(path) 109 | with open(os.path.join(path, "nor_ent2id.json"),'w') as fp: 110 | fp.write(json.dumps(label2id, ensure_ascii=False)) 111 | -------------------------------------------------------------------------------- /data/onenotes4.0/raw_data/process.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import os 3 | import re 4 | import json 5 | 6 | 7 | def preprocess(input_path, save_path, mode): 8 | if not os.path.exists(save_path): 9 | os.makedirs(save_path) 10 | data_path = os.path.join(save_path, mode + ".json") 11 | labels = set() 12 | result = [] 13 | tmp = {} 14 | tmp['id'] = 0 15 | tmp['text'] = '' 16 | tmp['labels'] = [] 17 | # =======先找出句子和句子中的所有实体和类型======= 18 | texts = [] 19 | entities = [] 20 | words = [] 21 | entity_tmp = [] 22 | entities_tmp = [] 23 | data = pd.read_csv(input_path) 24 | for i,d in enumerate(data.iterrows()): 25 | d = d[1] 26 | word = d[0] 27 | label = d[1] 28 | if str(word).lower() != "nan": 29 | words.append(word) 30 | if "B-" in label: 31 | entity_tmp.append(word) 32 | elif "M-" in label: 33 | entity_tmp.append(word) 34 | elif "E-" in label: 35 | entity_tmp.append(word) 36 | if ("".join(entity_tmp), label.split("-")[-1]) not in entities_tmp: 37 | entities_tmp.append(("".join(entity_tmp), label.split("-")[-1])) 38 | labels.add(label.split("-")[-1]) 39 | entity_tmp = [] 40 | 41 | if "S-" in label: 42 | entity_tmp.append(word) 43 | if ("".join(entity_tmp), label.split("-")[-1]) not in entities_tmp: 44 | entities_tmp.append(("".join(entity_tmp), label.split("-")[-1])) 45 | entity_tmp = [] 46 | labels.add(label.split("-")[-1]) 47 | else: 48 | texts.append("".join(words)) 49 | entities.append(entities_tmp) 50 | words = [] 51 | entities_tmp = [] 52 | 53 | # for text,entity in zip(texts, entities): 54 | # print(text, entity) 55 | # print(labels) 56 | # ========================================== 57 | # =======找出句子中实体的位置======= 58 | i = 0 59 | for text,entity in zip(texts, entities): 60 | 61 | if entity: 62 | ltmp = [] 63 | for ent,type in entity: 64 | for span in re.finditer(ent, text): 65 | start = span.start() 66 | end = span.end() 67 | ltmp.append((type, start, end, ent)) 68 | # print(ltmp) 69 | ltmp = sorted(ltmp, key=lambda x:(x[1],x[2])) 70 | tmp['id'] = i 71 | tmp['text'] = text 72 | for j in range(len(ltmp)): 73 | tmp['labels'].append(["T{}".format(str(j)), ltmp[j][0], ltmp[j][1], ltmp[j][2], ltmp[j][3]]) 74 | else: 75 | tmp['id'] = i 76 | tmp['text'] = text 77 | tmp['labels'] = [] 78 | result.append(tmp) 79 | # print(i, text, entity, tmp) 80 | tmp = {} 81 | tmp['id'] = 0 82 | tmp['text'] = '' 83 | tmp['labels'] = [] 84 | i += 1 85 | 86 | with open(data_path,'w', encoding='utf-8') as fp: 87 | fp.write(json.dumps(result, ensure_ascii=False)) 88 | 89 | if mode == "train": 90 | label_path = os.path.join(save_path, "labels.json") 91 | with open(label_path, 'w', encoding='utf-8') as fp: 92 | fp.write(json.dumps(list(labels), ensure_ascii=False)) 93 | 94 | 95 | preprocess("char_ner_train.csv", '../mid_data', "train") 96 | labels_path = os.path.join('../mid_data/labels.json') 97 | with open(labels_path, 'r') as fp: 98 | labels = json.load(fp) 99 | 100 | tmp_labels = [] 101 | tmp_labels.append('O') 102 | for label in labels: 103 | tmp_labels.append('B-' + label) 104 | tmp_labels.append('I-' + label) 105 | tmp_labels.append('E-' + label) 106 | tmp_labels.append('S-' + label) 107 | 108 | label2id = {} 109 | for k,v in enumerate(tmp_labels): 110 | label2id[v] = k 111 | path = '../mid_data/' 112 | if not os.path.exists(path): 113 | os.makedirs(path) 114 | with open(os.path.join(path, "nor_ent2id.json"),'w') as fp: 115 | fp.write(json.dumps(label2id, ensure_ascii=False)) 116 | -------------------------------------------------------------------------------- /data_augment/aug.py: -------------------------------------------------------------------------------- 1 | import copy 2 | import glob 3 | import json 4 | import os 5 | import random 6 | import re 7 | from pprint import pprint 8 | 9 | from tqdm import tqdm 10 | import argparse 11 | 12 | parser = argparse.ArgumentParser() 13 | parser.add_argument('--data_name', type=str, default='c', 14 | help='数据集名字') 15 | parser.add_argument('--text_repeat', type=int, default=2, 16 | help='增强的数目') 17 | 18 | args = parser.parse_args() 19 | data_dir = "../data/{}".format(args.data_name) 20 | text_repeat = args.text_repeat 21 | if not os.path.exists(data_dir): 22 | raise Exception("请确认数据集是否存在") 23 | 24 | train_file = os.path.join(data_dir, "mid_data/train.json") 25 | labels_file = os.path.join(data_dir, "mid_data/labels.json") 26 | 27 | output_dir = os.path.join(data_dir, "aug_data") 28 | if not os.path.exists(output_dir): 29 | os.makedirs(output_dir) 30 | 31 | def get_data(): 32 | # ["PRO", "ORG", "CONT", "RACE", "NAME", "EDU", "LOC", "TITLE"] 33 | 34 | """获取基本的数据""" 35 | with open(train_file, "r", encoding="utf-8") as fp: 36 | data = fp.read() 37 | 38 | with open(labels_file, "r", encoding="utf-8") as fp: 39 | labels = json.loads(fp.read()) 40 | 41 | entities = {k:[] for k in labels} 42 | 43 | texts = [] 44 | 45 | data = json.loads(data) 46 | for d in data: 47 | text = d['text'] 48 | labels = d['labels'] 49 | for label in labels: 50 | text = text.replace(label[4], "#;#{}#;#".format(label[1])) 51 | entities[label[1]].append(label[4]) 52 | texts.append(text) 53 | 54 | for k,v in entities.items(): 55 | with open(output_dir + "/" + k + ".txt", "w", encoding="utf-8") as fp: 56 | fp.write("\n".join(list(set(v)))) 57 | 58 | with open(output_dir + "/texts.txt", 'w', encoding="utf-8") as fp: 59 | fp.write("\n".join(texts)) 60 | 61 | def aug_by_template(text_repeat=2): 62 | """基于模板的增强 63 | text_repeat:每条文本重复的次数 64 | """ 65 | with open(output_dir + "/texts.txt", 'r', encoding="utf-8") as fp: 66 | texts = fp.read().strip().split('\n') 67 | 68 | with open(labels_file, "r", encoding="utf-8") as fp: 69 | labels = json.loads(fp.read()) 70 | 71 | entities = {} 72 | for ent_txt in glob.glob(output_dir + "/*.txt"): 73 | if "texts.txt" in ent_txt: 74 | continue 75 | with open(ent_txt, 'r', encoding="utf-8") as fp: 76 | label = fp.read().strip().split("\n") 77 | ent_txt = ent_txt.replace("\\", "/") 78 | 79 | label_name = ent_txt.split("/")[-1].split(".")[0] 80 | entities[label_name] = label 81 | 82 | entities_copy = copy.deepcopy(entities) 83 | 84 | with open(train_file, "r", encoding="utf-8") as fp: 85 | ori_data = json.loads(fp.read()) 86 | 87 | res = [] 88 | text_id = ori_data[-1]['id'] + 1 89 | for text in tqdm(texts, ncols=100): 90 | text = text.split("#;#") 91 | text_tmp = [] 92 | labels_tmp = [] 93 | for i in range(text_repeat): 94 | ent_id = 0 95 | for t in text: 96 | if t == "": 97 | continue 98 | if t in entities: 99 | # 不放回抽样,为了维持实体的多样性 100 | if not entities[t]: 101 | entities[t] = copy.deepcopy(entities_copy[t]) 102 | ent = random.choice(entities[t]) 103 | entities[t].remove(ent) 104 | length = len("".join(text_tmp)) 105 | text_tmp.append(ent) 106 | labels_tmp.append(("T{}".format(ent_id), t, length, length + len(ent), ent)) 107 | ent_id += 1 108 | else: 109 | text_tmp.append(t) 110 | tmp = { 111 | "id": text_id, 112 | "text": "".join(text_tmp), 113 | "labels": labels_tmp 114 | } 115 | text_id += 1 116 | text_tmp = [] 117 | labels_tmp = [] 118 | res.append(tmp) 119 | # 加上原始的 120 | res = ori_data + res 121 | 122 | with open(data_dir + "/mid_data/train_aug.json", "w", encoding="utf-8") as fp: 123 | json.dump(res, fp, ensure_ascii=False) 124 | 125 | 126 | if __name__ == '__main__': 127 | # 1、第一步:获取基本数据 128 | get_data() 129 | # 2、第二步:进行模板类数据增强 130 | aug_by_template(text_repeat=text_repeat) -------------------------------------------------------------------------------- /utils/cutSentences.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | 4 | def cut_sentences_v1(sent): 5 | """ 6 | the first rank of sentence cut 7 | """ 8 | sent = re.sub('([。!?\?])([^”’])', r"\1\n\2", sent) # 单字符断句符 9 | sent = re.sub('(\.{6})([^”’])', r"\1\n\2", sent) # 英文省略号 10 | sent = re.sub('(\…{2})([^”’])', r"\1\n\2", sent) # 中文省略号 11 | sent = re.sub('([。!?\?][”’])([^,。!?\?])', r"\1\n\2", sent) 12 | # 如果双引号前有终止符,那么双引号才是句子的终点,把分句符\n放到双引号后 13 | return sent.split("\n") 14 | 15 | 16 | def cut_sentences_v2(sent): 17 | """ 18 | the second rank of spilt sentence, split ';' | ';' 19 | """ 20 | sent = re.sub('([;;])([^”’])', r"\1\n\2", sent) 21 | return sent.split("\n") 22 | 23 | 24 | def cut_sent_for_bert(text, max_seq_len): 25 | # 将句子分句,细粒度分句后再重新合并 26 | sentences = [] 27 | 28 | # 细粒度划分 29 | sentences_v1 = cut_sentences_v1(text) 30 | print("sentences_v1=", sentences_v1) 31 | for sent_v1 in sentences_v1: 32 | if len(sent_v1) > max_seq_len - 2: 33 | sentences_v2 = cut_sentences_v2(sent_v1) 34 | sentences.extend(sentences_v2) 35 | else: 36 | sentences.append(sent_v1) 37 | 38 | assert ''.join(sentences) == text 39 | 40 | # 合并 41 | merged_sentences = [] 42 | start_index_ = 0 43 | 44 | while start_index_ < len(sentences): 45 | tmp_text = sentences[start_index_] 46 | 47 | end_index_ = start_index_ + 1 48 | # 针对于bert模型,注意这里最大长度要减去2 49 | while end_index_ < len(sentences) and \ 50 | len(tmp_text) + len(sentences[end_index_]) <= max_seq_len - 2: 51 | tmp_text += sentences[end_index_] 52 | end_index_ += 1 53 | 54 | start_index_ = end_index_ 55 | 56 | merged_sentences.append(tmp_text) 57 | 58 | return merged_sentences 59 | 60 | 61 | def refactor_labels(sent, labels, start_index): 62 | """ 63 | 分句后需要重构 labels 的 offset 64 | :param sent: 切分并重新合并后的句子 65 | :param labels: 原始文档级的 labels 66 | :param start_index: 该句子在文档中的起始 offset 67 | :return (type, entity, offset) 68 | """ 69 | new_labels = [] 70 | end_index = start_index + len(sent) 71 | # _label: TI, 实体类别, 实体起始位置, 实体结束位置, 实体名) 72 | for _label in labels: 73 | if start_index <= _label[2] <= _label[3] <= end_index: 74 | new_offset = _label[2] - start_index 75 | if sent[new_offset: new_offset + len(_label[-1])] != _label[-1]: 76 | continue 77 | # assert sent[new_offset: new_offset + len(_label[-1])] == _label[-1] 78 | 79 | new_labels.append((_label[1], _label[-1], new_offset)) 80 | # label 被截断的情况 81 | elif _label[2] < end_index < _label[3]: 82 | raise RuntimeError(f'{sent}, {_label}') 83 | 84 | return new_labels 85 | 86 | 87 | if __name__ == '__main__': 88 | raw_examples = [{ 89 | "text": "深圳市沙头角保税区今后五年将充分发挥保税区的区位优势和政策优势,以高新技术产业为先导,积极调整产品结构,实施以转口贸易和仓储业为辅助的经营战略。把沙头角保税区建成按国际惯例运作、国内领先的特殊综合经济区域,使其成为该市外向型经济的快速增长点。", 90 | "labels": [ 91 | [ 92 | "T0", 93 | "GPE", 94 | 0, 95 | 3, 96 | "深圳市" 97 | ], 98 | [ 99 | "T1", 100 | "GPE", 101 | 3, 102 | 6, 103 | "沙头角" 104 | ], 105 | [ 106 | "T2", 107 | "LOC", 108 | 6, 109 | 9, 110 | "保税区" 111 | ], 112 | [ 113 | "T3", 114 | "LOC", 115 | 18, 116 | 21, 117 | "保税区" 118 | ], 119 | [ 120 | "T4", 121 | "GPE", 122 | 73, 123 | 76, 124 | "沙头角" 125 | ], 126 | [ 127 | "T5", 128 | "LOC", 129 | 76, 130 | 79, 131 | "保税区" 132 | ] 133 | ] 134 | }] 135 | for i, item in enumerate(raw_examples): 136 | text = item['text'] 137 | print(text[:90]) 138 | sentences = cut_sent_for_bert(text, 90) 139 | start_index = 0 140 | 141 | for sent in sentences: 142 | labels = refactor_labels(sent, item['labels'], start_index) 143 | start_index += len(sent) 144 | 145 | print(sent) 146 | print(labels) 147 | -------------------------------------------------------------------------------- /data/cner/raw_data/process.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | import json 4 | 5 | def preprocess(input_path, save_path, mode): 6 | if not os.path.exists(save_path): 7 | os.makedirs(save_path) 8 | data_path = os.path.join(save_path, mode + ".json") 9 | labels = set() 10 | result = [] 11 | tmp = {} 12 | tmp['id'] = 0 13 | tmp['text'] = '' 14 | tmp['labels'] = [] 15 | # =======先找出句子和句子中的所有实体和类型======= 16 | with open(input_path,'r',encoding='utf-8') as fp: 17 | lines = fp.readlines() 18 | texts = [] 19 | entities = [] 20 | words = [] 21 | entity_tmp = [] 22 | entities_tmp = [] 23 | for line in lines: 24 | line = line.strip().split(" ") 25 | if len(line) == 2: 26 | word = line[0] 27 | label = line[1] 28 | words.append(word) 29 | 30 | if "B-" in label: 31 | entity_tmp.append(word) 32 | elif "M-" in label: 33 | entity_tmp.append(word) 34 | elif "E-" in label: 35 | entity_tmp.append(word) 36 | if ("".join(entity_tmp), label.split("-")[-1]) not in entities_tmp: 37 | entities_tmp.append(("".join(entity_tmp), label.split("-")[-1])) 38 | labels.add(label.split("-")[-1]) 39 | entity_tmp = [] 40 | 41 | if "S-" in label: 42 | entity_tmp.append(word) 43 | if ("".join(entity_tmp), label.split("-")[-1]) not in entities_tmp: 44 | entities_tmp.append(("".join(entity_tmp), label.split("-")[-1])) 45 | entity_tmp = [] 46 | labels.add(label.split("-")[-1]) 47 | else: 48 | texts.append("".join(words)) 49 | entities.append(entities_tmp) 50 | words = [] 51 | entities_tmp = [] 52 | 53 | # for text,entity in zip(texts, entities): 54 | # print(text, entity) 55 | # print(labels) 56 | # ========================================== 57 | # =======找出句子中实体的位置======= 58 | i = 0 59 | for text,entity in zip(texts, entities): 60 | 61 | if entity: 62 | ltmp = [] 63 | for ent,type in entity: 64 | for span in re.finditer(ent, text): 65 | start = span.start() 66 | end = span.end() 67 | ltmp.append((type, start, end, ent)) 68 | # print(ltmp) 69 | ltmp = sorted(ltmp, key=lambda x:(x[1],x[2])) 70 | tmp['id'] = i 71 | tmp['text'] = text 72 | for j in range(len(ltmp)): 73 | tmp['labels'].append(["T{}".format(str(j)), ltmp[j][0], ltmp[j][1], ltmp[j][2], ltmp[j][3]]) 74 | else: 75 | tmp['id'] = i 76 | tmp['text'] = text 77 | tmp['labels'] = [] 78 | result.append(tmp) 79 | # print(i, text, entity, tmp) 80 | tmp = {} 81 | tmp['id'] = 0 82 | tmp['text'] = '' 83 | tmp['labels'] = [] 84 | i += 1 85 | 86 | with open(data_path,'w', encoding='utf-8') as fp: 87 | fp.write(json.dumps(result, ensure_ascii=False)) 88 | 89 | if mode == "train": 90 | label_path = os.path.join(save_path, "labels.json") 91 | with open(label_path, 'w', encoding='utf-8') as fp: 92 | fp.write(json.dumps(list(labels), ensure_ascii=False)) 93 | 94 | preprocess("train.char.bmes", '../mid_data', "train") 95 | preprocess("dev.char.bmes", '../mid_data', "dev") 96 | preprocess("test.char.bmes", '../mid_data', "test") 97 | 98 | labels_path = os.path.join('../mid_data/labels.json') 99 | with open(labels_path, 'r') as fp: 100 | labels = json.load(fp) 101 | 102 | tmp_labels = [] 103 | tmp_labels.append('O') 104 | for label in labels: 105 | tmp_labels.append('B-' + label) 106 | tmp_labels.append('I-' + label) 107 | tmp_labels.append('E-' + label) 108 | tmp_labels.append('S-' + label) 109 | 110 | label2id = {} 111 | for k,v in enumerate(tmp_labels): 112 | label2id[v] = k 113 | path = '../mid_data/' 114 | if not os.path.exists(path): 115 | os.makedirs(path) 116 | with open(os.path.join(path, "nor_ent2id.json"),'w') as fp: 117 | fp.write(json.dumps(label2id, ensure_ascii=False)) 118 | -------------------------------------------------------------------------------- /utils/trainUtils.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | import os 3 | import logging 4 | from transformers import AdamW, get_linear_schedule_with_warmup 5 | import torch 6 | 7 | logger = logging.getLogger(__name__) 8 | 9 | 10 | def build_optimizer_and_scheduler(args, model, t_total): 11 | module = ( 12 | model.module if hasattr(model, "module") else model 13 | ) 14 | 15 | # 差分学习率 16 | no_decay = ["bias", "LayerNorm.weight"] 17 | model_param = list(module.named_parameters()) 18 | 19 | bert_param_optimizer = [] 20 | crf_param_optimizer = [] 21 | other_param_optimizer = [] 22 | 23 | for name, para in model_param: 24 | space = name.split('.') 25 | # print(name) 26 | if space[0] == 'bert_module' or space[0] == "bert": 27 | bert_param_optimizer.append((name, para)) 28 | elif space[0] == 'crf': 29 | crf_param_optimizer.append((name, para)) 30 | else: 31 | other_param_optimizer.append((name, para)) 32 | 33 | optimizer_grouped_parameters = [ 34 | # bert other module 35 | {"params": [p for n, p in bert_param_optimizer if not any(nd in n for nd in no_decay)], 36 | "weight_decay": args.weight_decay, 'lr': args.lr}, 37 | {"params": [p for n, p in bert_param_optimizer if any(nd in n for nd in no_decay)], 38 | "weight_decay": 0.0, 'lr': args.lr}, 39 | 40 | # crf模块 41 | {"params": [p for n, p in crf_param_optimizer if not any(nd in n for nd in no_decay)], 42 | "weight_decay": args.weight_decay, 'lr': args.crf_lr}, 43 | {"params": [p for n, p in crf_param_optimizer if any(nd in n for nd in no_decay)], 44 | "weight_decay": 0.0, 'lr': args.other_lr}, 45 | 46 | # 其他模块,差分学习率 47 | {"params": [p for n, p in other_param_optimizer if not any(nd in n for nd in no_decay)], 48 | "weight_decay": args.weight_decay, 'lr': args.other_lr}, 49 | {"params": [p for n, p in other_param_optimizer if any(nd in n for nd in no_decay)], 50 | "weight_decay": 0.0, 'lr': args.other_lr}, 51 | ] 52 | 53 | optimizer = AdamW(optimizer_grouped_parameters, lr=args.lr, eps=args.adam_epsilon) 54 | scheduler = get_linear_schedule_with_warmup( 55 | optimizer, num_warmup_steps=int(args.warmup_proportion * t_total), num_training_steps=t_total 56 | ) 57 | 58 | return optimizer, scheduler 59 | 60 | def save_model(args, model, model_name, global_step): 61 | """保存最好的验证集效果最好那个模型""" 62 | output_dir = os.path.join(args.output_dir, '{}'.format(model_name, global_step)) 63 | if not os.path.exists(output_dir): 64 | os.makedirs(output_dir, exist_ok=True) 65 | 66 | # take care of model distributed / parallel training 67 | model_to_save = ( 68 | model.module if hasattr(model, "module") else model 69 | ) 70 | logger.info('Saving model checkpoint to {}'.format(output_dir)) 71 | torch.save(model_to_save.state_dict(), os.path.join(output_dir, 'model.pt')) 72 | 73 | def save_model_step(args, model, global_step): 74 | """根据global_step来保存模型""" 75 | output_dir = os.path.join(args.output_dir, 'checkpoint-{}'.format(global_step)) 76 | if not os.path.exists(output_dir): 77 | os.makedirs(output_dir, exist_ok=True) 78 | 79 | # take care of model distributed / parallel training 80 | model_to_save = ( 81 | model.module if hasattr(model, "module") else model 82 | ) 83 | logger.info('Saving model & optimizer & scheduler checkpoint to {}.format(output_dir)') 84 | torch.save(model_to_save.state_dict(), os.path.join(output_dir, 'model.pt')) 85 | 86 | def load_model_and_parallel(model, gpu_ids, ckpt_path=None, strict=True): 87 | """ 88 | 加载模型 & 放置到 GPU 中(单卡 / 多卡) 89 | """ 90 | gpu_ids = gpu_ids.split(',') 91 | 92 | # set to device to the first cuda 93 | device = torch.device("cpu" if gpu_ids[0] == '-1' else "cuda:" + gpu_ids[0]) 94 | 95 | if ckpt_path is not None: 96 | logger.info('Load ckpt from {}'.format(ckpt_path)) 97 | # model.load_state_dict(torch.load(ckpt_path, map_location=torch.device('cpu')), strict=strict) 98 | state_dict = torch.load(ckpt_path, map_location=torch.device('cpu')) 99 | if torch.__version__.startswith("2."): 100 | unwanted_prefix = '_orig_mod.' 101 | for k,v in list(state_dict.items()): 102 | if k.startswith(unwanted_prefix): 103 | state_dict[k[len(unwanted_prefix):]] = state_dict.pop(k) 104 | model.load_state_dict(state_dict, strict=strict) 105 | 106 | # model.to(device) 107 | 108 | if len(gpu_ids) > 1: 109 | logger.info('Use multi gpus in: {}'.format(gpu_ids)) 110 | gpu_ids = [int(x) for x in gpu_ids] 111 | model = torch.nn.DataParallel(model, device_ids=gpu_ids) 112 | else: 113 | logger.info('Use single gpu in: {}'.format(gpu_ids)) 114 | 115 | return model, device 116 | -------------------------------------------------------------------------------- /convert_onnx/bert_ner_model_onnx.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.append('..') 3 | import torch 4 | import torch.nn as nn 5 | # from torchcrf import CRF 6 | from layers.CRF import CRF 7 | from transformers import BertModel 8 | 9 | class BertNerModel(nn.Module): 10 | def __init__(self, 11 | args, 12 | **kwargs): 13 | super(BertNerModel, self).__init__() 14 | self.bert_module = BertModel.from_pretrained(args.bert_dir, output_hidden_states=True, 15 | hidden_dropout_prob=args.dropout_prob) 16 | self.args = args 17 | self.num_layers = args.num_layers 18 | self.lstm_hidden = args.lstm_hidden 19 | gpu_ids = args.gpu_ids.split(',') 20 | device = torch.device("cpu" if gpu_ids[0] == '-1' else "cuda:" + gpu_ids[0]) 21 | self.device = device 22 | 23 | self.bert_config = self.bert_module.config 24 | out_dims = self.bert_config.hidden_size 25 | init_blocks = [] 26 | self.linear = nn.Linear(args.lstm_hidden * 2, args.num_tags) 27 | init_blocks.append(self.linear) 28 | 29 | if args.use_lstm == 'True': 30 | self.lstm = nn.LSTM(out_dims, args.lstm_hidden, args.num_layers, bidirectional=True,batch_first=True, dropout=args.dropout) 31 | 32 | self.criterion = nn.CrossEntropyLoss() 33 | # init_blocks = [self.linear] 34 | # init_blocks = [self.classifier] 35 | self._init_weights(init_blocks, initializer_range=self.bert_config.initializer_range) 36 | else: 37 | mid_linear_dims = kwargs.pop('mid_linear_dims', 256) 38 | self.mid_linear = nn.Sequential( 39 | nn.Linear(out_dims, mid_linear_dims), 40 | nn.ReLU(), 41 | nn.Dropout(args.dropout)) 42 | # 43 | out_dims = mid_linear_dims 44 | 45 | # self.dropout = nn.Dropout(dropout_prob) 46 | self.classifier = nn.Linear(out_dims, args.num_tags) 47 | # self.criterion = nn.CrossEntropyLoss(reduction='none') 48 | self.criterion = nn.CrossEntropyLoss() 49 | 50 | 51 | init_blocks = [self.mid_linear, self.classifier] 52 | # init_blocks = [self.classifier] 53 | self._init_weights(init_blocks, initializer_range=self.bert_config.initializer_range) 54 | 55 | if args.use_crf == 'True': 56 | self.crf = CRF(args.num_tags, batch_first=True) 57 | 58 | def _init_weights(self, blocks, **kwargs): 59 | """ 60 | 参数初始化,将 Linear / Embedding / LayerNorm 与 Bert 进行一样的初始化 61 | """ 62 | for block in blocks: 63 | for module in block.modules(): 64 | if isinstance(module, nn.Linear): 65 | if module.bias is not None: 66 | nn.init.zeros_(module.bias) 67 | elif isinstance(module, nn.Embedding): 68 | nn.init.normal_(module.weight, mean=0, std=kwargs.pop('initializer_range', 0.02)) 69 | elif isinstance(module, nn.LayerNorm): 70 | nn.init.ones_(module.weight) 71 | nn.init.zeros_(module.bias) 72 | 73 | def init_hidden(self, batch_size): 74 | h0 = torch.randn(2 * self.num_layers, batch_size, self.lstm_hidden, requires_grad=True).to(self.device) 75 | c0 = torch.randn(2 * self.num_layers, batch_size, self.lstm_hidden, requires_grad=True).to(self.device) 76 | return h0, c0 77 | 78 | def forward(self, 79 | input_ids, 80 | attention_mask, 81 | token_type_ids, 82 | ): 83 | bert_outputs = self.bert_module( 84 | input_ids=input_ids, 85 | attention_mask=attention_mask, 86 | token_type_ids=token_type_ids 87 | ) 88 | 89 | # 常规 90 | seq_out = bert_outputs[0] # [batchsize, max_len, 768] 91 | batch_size = seq_out.size(0) 92 | 93 | if self.args.use_lstm == 'True': 94 | # hidden = self.init_hidden(batch_size) 95 | # seq_out, (hn, _) = self.lstm(seq_out, hidden) 96 | # seq_out = seq_out.contiguous().view(-1, self.lstm_hidden * 2) 97 | seq_out, _ = self.lstm(seq_out) 98 | seq_out = seq_out.contiguous().view(-1, self.lstm_hidden * 2) 99 | seq_out = self.linear(seq_out) 100 | seq_out = seq_out.contiguous().view(batch_size, self.args.max_seq_len, -1) #[batchsize, max_len, num_tags] 101 | if self.args.use_lstm == 'False': 102 | seq_out = self.mid_linear(seq_out) # [batchsize, max_len, 256] 103 | # seq_out = self.dropout(seq_out) 104 | seq_out = self.classifier(seq_out) # [24, 256, 53] 105 | 106 | if self.args.use_crf == 'True': 107 | logits = self.crf.decode(seq_out) 108 | return torch.tensor(logits) 109 | if self.args.use_crf == 'False': 110 | logits = seq_out 111 | return logits 112 | 113 | -------------------------------------------------------------------------------- /utils/decodeUtils.py: -------------------------------------------------------------------------------- 1 | from torch import Tensor 2 | import numpy as np 3 | from collections import defaultdict 4 | 5 | def get_entities(seq, text, suffix=False): 6 | """Gets entities from sequence. 7 | Args: 8 | seq (list): sequence of labels. 9 | Returns: 10 | list: list of (chunk_type, chunk_start, chunk_end). 11 | Example: 12 | >>> from seqeval.metrics.sequence_labeling import get_entities 13 | >>> seq = ['B-PER', 'I-PER', 'O', 'B-LOC'] 14 | >>> get_entities(seq) 15 | [('PER', 0, 1), ('LOC', 3, 3)] 16 | """ 17 | # for nested list 18 | if any(isinstance(s, list) for s in seq): 19 | seq = [item for sublist in seq for item in sublist + ['O']] 20 | 21 | prev_tag = 'O' 22 | prev_type = '' 23 | begin_offset = 0 24 | chunks = [] 25 | for i, chunk in enumerate(seq + ['O']): 26 | if suffix: 27 | tag = chunk[-1] 28 | type_ = chunk.split('-')[0] 29 | else: 30 | tag = chunk[0] 31 | type_ = chunk.split('-')[-1] 32 | 33 | if end_of_chunk(prev_tag, tag, prev_type, type_): 34 | # chunks.append((prev_type, begin_offset, i-1)) 35 | # 高勇:男,中国国籍,无境外居留权, 高勇:0-2,这里就为text[begin_offset:i],如果是0-1,则是text[begin_offset:i+1] 36 | chunks.append((text[begin_offset:i+1],begin_offset,prev_type)) 37 | if start_of_chunk(prev_tag, tag, prev_type, type_): 38 | begin_offset = i 39 | prev_tag = tag 40 | prev_type = type_ 41 | 42 | return chunks 43 | 44 | 45 | def end_of_chunk(prev_tag, tag, prev_type, type_): 46 | """Checks if a chunk ended between the previous and current word. 47 | Args: 48 | prev_tag: previous chunk tag. 49 | tag: current chunk tag. 50 | prev_type: previous type. 51 | type_: current type. 52 | Returns: 53 | chunk_end: boolean. 54 | """ 55 | chunk_end = False 56 | 57 | if prev_tag == 'E': chunk_end = True 58 | if prev_tag == 'S': chunk_end = True 59 | 60 | if prev_tag == 'B' and tag == 'B': chunk_end = True 61 | if prev_tag == 'B' and tag == 'S': chunk_end = True 62 | if prev_tag == 'B' and tag == 'O': chunk_end = True 63 | if prev_tag == 'I' and tag == 'B': chunk_end = True 64 | if prev_tag == 'I' and tag == 'S': chunk_end = True 65 | if prev_tag == 'I' and tag == 'O': chunk_end = True 66 | 67 | if prev_tag != 'O' and prev_tag != '.' and prev_type != type_: 68 | chunk_end = True 69 | 70 | return chunk_end 71 | 72 | 73 | def start_of_chunk(prev_tag, tag, prev_type, type_): 74 | """Checks if a chunk started between the previous and current word. 75 | Args: 76 | prev_tag: previous chunk tag. 77 | tag: current chunk tag. 78 | prev_type: previous type. 79 | type_: current type. 80 | Returns: 81 | chunk_start: boolean. 82 | """ 83 | chunk_start = False 84 | 85 | if tag == 'B': chunk_start = True 86 | if tag == 'S': chunk_start = True 87 | 88 | if prev_tag == 'E' and tag == 'E': chunk_start = True 89 | if prev_tag == 'E' and tag == 'I': chunk_start = True 90 | if prev_tag == 'S' and tag == 'E': chunk_start = True 91 | if prev_tag == 'S' and tag == 'I': chunk_start = True 92 | if prev_tag == 'O' and tag == 'E': chunk_start = True 93 | if prev_tag == 'O' and tag == 'I': chunk_start = True 94 | 95 | if tag != 'O' and tag != '.' and prev_type != type_: 96 | chunk_start = True 97 | 98 | return chunk_start 99 | 100 | def bioes_decode(decode_tokens, raw_text, id2ent): 101 | predict_entities = {} 102 | if isinstance(decode_tokens, Tensor): 103 | decode_tokens = decode_tokens.numpy().tolist() 104 | index_ = 0 105 | 106 | while index_ < len(decode_tokens): 107 | if decode_tokens[index_] == 0: 108 | token_label = id2ent[1].split('-') 109 | else: 110 | token_label = id2ent[decode_tokens[index_]].split('-') 111 | if token_label[0].startswith('S'): 112 | token_type = token_label[1] 113 | tmp_ent = raw_text[index_] 114 | 115 | if token_type not in predict_entities: 116 | predict_entities[token_type] = [(tmp_ent, index_)] 117 | else: 118 | predict_entities[token_type].append((tmp_ent, int(index_))) 119 | 120 | index_ += 1 121 | 122 | elif token_label[0].startswith('B'): 123 | token_type = token_label[1] 124 | start_index = index_ 125 | 126 | index_ += 1 127 | while index_ < len(decode_tokens): 128 | if decode_tokens[index_] == 0: 129 | temp_token_label = id2ent[1].split('-') 130 | else: 131 | temp_token_label = id2ent[decode_tokens[index_]].split('-') 132 | 133 | if temp_token_label[0].startswith('I') and token_type == temp_token_label[1]: 134 | index_ += 1 135 | elif temp_token_label[0].startswith('E') and token_type == temp_token_label[1]: 136 | end_index = index_ 137 | index_ += 1 138 | 139 | tmp_ent = raw_text[start_index: end_index + 1] 140 | 141 | if token_type not in predict_entities: 142 | predict_entities[token_type] = [(tmp_ent, start_index)] 143 | else: 144 | predict_entities[token_type].append((tmp_ent, int(start_index))) 145 | 146 | break 147 | else: 148 | break 149 | else: 150 | index_ += 1 151 | 152 | return predict_entities 153 | -------------------------------------------------------------------------------- /predict.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | import torch 4 | import json 5 | from utils import commonUtils, metricsUtils, decodeUtils, trainUtils 6 | import bert_ner_model 7 | from transformers import BertTokenizer 8 | from collections import defaultdict 9 | 10 | from cut import cut_sentences_main 11 | 12 | def batch_predict(raw_text, model, device, args, id2query): 13 | model = model.to(device) 14 | model.eval() 15 | with torch.no_grad(): 16 | tokenizer = BertTokenizer( 17 | os.path.join(args.bert_dir, 'vocab.txt')) 18 | # tokens = commonUtils.fine_grade_tokenize(raw_text, tokenizer) 19 | # tokens = [[i for i in text] for text in raw_text] 20 | tokens = [[i for i in text] for text in raw_text] 21 | print(tokens) 22 | encode_dict_all = defaultdict(list) 23 | for token in tokens: 24 | encode_dict = tokenizer.encode_plus(token, 25 | max_length=args.max_seq_len, 26 | padding='max_length', 27 | truncation='longest_first', 28 | return_token_type_ids=True, 29 | return_attention_mask=True) 30 | # tokens = ['[CLS]'] + tokens + ['[SEP]'] 31 | encode_dict_all['input_ids'].append(encode_dict['input_ids']) 32 | encode_dict_all['attention_mask'].append(encode_dict['attention_mask']) 33 | encode_dict_all['token_type_ids'].append(encode_dict['token_type_ids']) 34 | 35 | # print(encode_dict_all) 36 | token_ids = torch.from_numpy(np.array(encode_dict_all['input_ids'])).long().to(device) 37 | # attention_masks = torch.from_numpy(np.array(encode_dict_all['attention_mask'], dtype=np.uint8)).to(device) 38 | try: 39 | attention_masks = torch.from_numpy(np.array(encode_dict['attention_mask'], dtype=np.uint8)).unsqueeze(0).to(device) 40 | except Exception as e: 41 | attention_masks = torch.from_numpy(np.array(encode_dict['attention_mask'])).long().unsqueeze(0).to(device) 42 | token_type_ids = torch.from_numpy(np.array(encode_dict_all['token_type_ids'])).to(device) 43 | logits = model(token_ids, attention_masks, token_type_ids, None) 44 | if args.use_crf == 'True': 45 | output = logits 46 | else: 47 | output = logits.detach().cpu().numpy() 48 | output = np.argmax(output, axis=2) 49 | pred_entities = [] 50 | for out, token in zip(output, tokens): 51 | entities = decodeUtils.bioes_decode(out[1:1 + len(token)], "".join(token), id2query) 52 | pred_entities.append(entities) 53 | return pred_entities 54 | 55 | 56 | def predict(raw_text, model, device, args, id2query): 57 | model = model.to(device) 58 | model.eval() 59 | with torch.no_grad(): 60 | tokenizer = BertTokenizer( 61 | os.path.join(args.bert_dir, 'vocab.txt')) 62 | # tokens = commonUtils.fine_grade_tokenize(raw_text, tokenizer) 63 | tokens = [i for i in raw_text] 64 | encode_dict = tokenizer.encode_plus(text=tokens, 65 | max_length=args.max_seq_len, 66 | padding='max_length', 67 | truncation='longest_first', 68 | is_pretokenized=True, 69 | return_token_type_ids=True, 70 | return_attention_mask=True) 71 | # tokens = ['[CLS]'] + tokens + ['[SEP]'] 72 | token_ids = torch.from_numpy(np.array(encode_dict['input_ids'])).unsqueeze(0).to(device) 73 | # attention_masks = torch.from_numpy(np.array(encode_dict['attention_mask'], dtype=np.uint8)).unsqueeze(0).to(device) 74 | try: 75 | attention_masks = torch.from_numpy(np.array(encode_dict['attention_mask'], dtype=np.uint8)).unsqueeze(0).to(device) 76 | except Exception as e: 77 | attention_masks = torch.from_numpy(np.array(encode_dict['attention_mask'])).long().unsqueeze(0).to(device) 78 | token_type_ids = torch.from_numpy(np.array(encode_dict['token_type_ids'])).unsqueeze(0).to(device) 79 | logits = model(token_ids.to(device), attention_masks.to(device), token_type_ids.to(device), None) 80 | if args.use_crf == 'True': 81 | output = logits 82 | else: 83 | output = logits.detach().cpu().numpy() 84 | output = np.argmax(output, axis=2) 85 | pred_entities = decodeUtils.bioes_decode(output[0][1:1 + len(tokens)], "".join(tokens), id2query) 86 | # print(pred_entities) 87 | return pred_entities 88 | 89 | 90 | if __name__ == "__main__": 91 | args_path = "checkpoints/bert_crf_cner/args.json" 92 | 93 | with open(args_path, "r", encoding="utf-8") as fp: 94 | tmp_args = json.load(fp) 95 | 96 | 97 | class Dict2Class: 98 | def __init__(self, **entries): 99 | self.__dict__.update(entries) 100 | 101 | 102 | args = Dict2Class(**tmp_args) 103 | args.gpu_ids = "0" if torch.cuda.is_available() else "-1" 104 | print(args.__dict__) 105 | 106 | other_path = os.path.join(args.data_dir, 'mid_data') 107 | ent2id_dict = commonUtils.read_json(other_path, 'nor_ent2id') 108 | query2id = {} 109 | id2query = {} 110 | for k, v in ent2id_dict.items(): 111 | query2id[k] = v 112 | id2query[v] = k 113 | 114 | raw_text = "虞兔良先生:1963年12月出生,汉族,中国国籍,无境外永久居留权,浙江绍兴人,中共党员,MBA,经济师。" 115 | print(raw_text) 116 | model_name = args.model_name 117 | model_path = './checkpoints/{}_{}/model.pt'.format(model_name, args.data_name) 118 | if args.model_name.split('_')[0] not in ['bilstm', 'crf', 'idcnn']: 119 | model = bert_ner_model.BertNerModel(args) 120 | else: 121 | model = bert_ner_model.NormalNerModel(args) 122 | model, device = trainUtils.load_model_and_parallel(model, args.gpu_ids, model_path) 123 | 124 | # print(predict(raw_text, model, device, args, id2query)) 125 | raw_text = cut_sentences_main(raw_text, max_seq_len=args.max_seq_len-2) 126 | print(batch_predict(raw_text, model, device, args, id2query)) 127 | -------------------------------------------------------------------------------- /predict_gdcq.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | import numpy as np 4 | import torch 5 | from torch import Tensor 6 | import json 7 | from utils import commonUtils, metricsUtils, decodeUtils, trainUtils 8 | import bert_ner_model 9 | from transformers import BertTokenizer 10 | 11 | 12 | def decode(decode_tokens, raw_text, id2ent): 13 | predict_entities = [] 14 | if isinstance(decode_tokens, Tensor): 15 | decode_tokens = decode_tokens.numpy().tolist() 16 | index_ = 0 17 | 18 | while index_ < len(decode_tokens): 19 | if decode_tokens[index_] == 0: 20 | token_label = id2ent[1].split('-') 21 | else: 22 | token_label = id2ent[decode_tokens[index_]].split('-') 23 | if token_label[0].startswith('S'): 24 | token_type = token_label[1] 25 | tmp_ent = raw_text[index_] 26 | 27 | predict_entities.append((tmp_ent, index_, token_type)) 28 | 29 | index_ += 1 30 | 31 | elif token_label[0].startswith('B'): 32 | token_type = token_label[1] 33 | start_index = index_ 34 | 35 | index_ += 1 36 | while index_ < len(decode_tokens): 37 | if decode_tokens[index_] == 0: 38 | temp_token_label = id2ent[1].split('-') 39 | else: 40 | temp_token_label = id2ent[decode_tokens[index_]].split('-') 41 | 42 | if temp_token_label[0].startswith('I') and token_type == temp_token_label[1]: 43 | index_ += 1 44 | elif temp_token_label[0].startswith('E') and token_type == temp_token_label[1]: 45 | end_index = index_ 46 | index_ += 1 47 | 48 | tmp_ent = raw_text[start_index: end_index + 1] 49 | 50 | predict_entities.append((tmp_ent, start_index, token_type)) 51 | break 52 | else: 53 | break 54 | else: 55 | index_ += 1 56 | 57 | return predict_entities 58 | 59 | 60 | def predict(raw_text, model, device, args, id2query): 61 | model = model.to(device) 62 | model.eval() 63 | with torch.no_grad(): 64 | tokenizer = BertTokenizer( 65 | os.path.join(args.bert_dir, 'vocab.txt')) 66 | # tokens = commonUtils.fine_grade_tokenize(raw_text, tokenizer) 67 | tokens = [i for i in raw_text] 68 | encode_dict = tokenizer.encode_plus(text=tokens, 69 | max_length=args.max_seq_len, 70 | padding='max_length', 71 | truncation='longest_first', 72 | is_pretokenized=True, 73 | return_token_type_ids=True, 74 | return_attention_mask=True) 75 | # tokens = ['[CLS]'] + tokens + ['[SEP]'] 76 | token_ids = torch.from_numpy(np.array(encode_dict['input_ids'])).long().unsqueeze(0).to(device) 77 | # attention_masks = torch.from_numpy(np.array(encode_dict['attention_mask'], dtype=np.uint8)).unsqueeze(0).to(device) 78 | try: 79 | attention_masks = torch.from_numpy(np.array(encode_dict['attention_mask'], dtype=np.uint8)).unsqueeze(0).to(device) 80 | except Exception as e: 81 | attention_masks = torch.from_numpy(np.array(encode_dict['attention_mask'])).long().unsqueeze(0).to(device) 82 | token_type_ids = torch.from_numpy(np.array(encode_dict['token_type_ids'])).unsqueeze(0).to(device) 83 | logits = model(token_ids.to(device), attention_masks.to(device), token_type_ids.to(device), None) 84 | if args.use_crf == 'True': 85 | output = logits 86 | else: 87 | output = logits.detach().cpu().numpy() 88 | output = np.argmax(output, axis=2) 89 | 90 | pred_entities = decode(output[0][1:1 + len(tokens)], "".join(tokens), id2query) 91 | # print(pred_entities) 92 | return pred_entities 93 | 94 | 95 | import re 96 | tmp = ['正面', '中性', '负面'] 97 | def post_process(entities, text): 98 | """ 99 | 后处理操作:如果主体和评价在同一段文本里面,且主体在前,则可合并主体和评价 100 | 在此基础上: 101 | 如存在多个主体对一个评价,则多对一 102 | 如存在一个主体和多个评价,则一对多 103 | """ 104 | if len(entities) <= 1: 105 | return entities, [] 106 | entities_res = [] 107 | relation_res = [] 108 | tmp_entities_res = [] 109 | for i in range(len(entities) - 1): 110 | # print(entities[i], entities[i+1]) 111 | if entities[i][-1] not in tmp and entities[i+1][-1] in tmp: 112 | left_end = entities[i][1] + len(entities[i][0]) 113 | right_start = entities[i+1][1] 114 | tmp_text = text[left_end:right_start] 115 | if sum([1 if x in tmp_text else 0 for x in [',',',','。','!','!','?','?']]) == 0: 116 | relation_res.append((entities[i][0]+entities[i+1][0], entities[i+1][-1])) 117 | tmp_entities_res.append(entities[i]) 118 | tmp_entities_res.append(entities[i+1]) 119 | entities_res = [i for i in entities if i not in tmp_entities_res] 120 | return entities_res, relation_res 121 | 122 | 123 | 124 | 125 | if __name__ == "__main__": 126 | args_path = "checkpoints/bert_crf_gdcq/args.json" 127 | 128 | with open(args_path, "r", encoding="utf-8") as fp: 129 | tmp_args = json.load(fp) 130 | 131 | class Dict2Class: 132 | def __init__(self, **entries): 133 | self.__dict__.update(entries) 134 | 135 | args = Dict2Class(**tmp_args) 136 | args.gpu_ids = "0" if torch.cuda.is_available() else "-1" 137 | print(args.__dict__) 138 | 139 | other_path = os.path.join(args.data_dir, 'mid_data') 140 | ent2id_dict = commonUtils.read_json(other_path, 'nor_ent2id') 141 | query2id = {} 142 | id2query = {} 143 | for k, v in ent2id_dict.items(): 144 | query2id[k] = v 145 | id2query[v] = k 146 | 147 | raw_text = "***的化妆品还是不错的,值得购买,性价比很高的活动就参加了!!!" 148 | raw_text = "挺好用的,以前皮肤很容易过敏,用了好多种都过敏,用了这套后就慢慢不过敏了,用完继续" 149 | raw_text = "多次购买了,效果不错哦,价格便宜" 150 | print(raw_text) 151 | model_name = args.model_name 152 | model_path = './checkpoints/{}_{}/model.pt'.format(model_name, args.data_name) 153 | if args.model_name.split('_')[0] not in ['bilstm', 'crf', "idcnn"]: 154 | model = bert_ner_model.BertNerModel(args) 155 | else: 156 | model = bert_ner_model.BilstmNerModel(args) 157 | # print(model) 158 | model, device = trainUtils.load_model_and_parallel(model, args.gpu_ids, model_path) 159 | entities = predict(raw_text, model, device, args, id2query) 160 | print("实体识别结果:", entities) 161 | entities_res, relation_res = post_process(entities, raw_text) 162 | print("未进行关联的实体:", entities_res) 163 | print("关系合并:", relation_res) 164 | -------------------------------------------------------------------------------- /convert_onnx/convert_onnx.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | sys.path.append('..') 4 | import os 5 | import json 6 | import logging 7 | from pprint import pprint 8 | import torch 9 | import numpy as np 10 | from transformers import BertTokenizer 11 | import time 12 | 13 | from bert_ner_model_onnx import BertNerModel 14 | from utils import decodeUtils 15 | 16 | 17 | class Dict2Obj(dict): 18 | """让字典可以使用.调用""" 19 | 20 | def __init__(self, *args, **kwargs): 21 | super(Dict2Obj, self).__init__(*args, **kwargs) 22 | 23 | def __getattr__(self, key): 24 | value = self[key] 25 | if isinstance(value, dict): 26 | value = Dict2Obj(value) 27 | return value 28 | 29 | 30 | class ConverttOnnx: 31 | def __init__(self, args, model, tokenizer, idx2tag): 32 | self.args = args 33 | self.model = model 34 | self.tokenizer = tokenizer 35 | self.idx2tag = idx2tag 36 | 37 | def inference(self, texts): 38 | self.model.eval() 39 | with torch.no_grad(): 40 | tokens = [i for i in texts] 41 | encode_dict = self.tokenizer.encode_plus(text=tokens, 42 | max_length=self.args.max_seq_len, 43 | pad_to_max_length=True, 44 | return_token_type_ids=True, 45 | return_attention_mask=True, 46 | return_tensors="pt") 47 | token_ids = encode_dict['input_ids'] 48 | attention_masks = encode_dict['attention_mask'].bool() 49 | token_type_ids = encode_dict['token_type_ids'] 50 | s1 = time.time() 51 | for i in range(NUM): 52 | logits = self.model(token_ids, attention_masks, token_type_ids) 53 | # print(logits) 54 | e1 = time.time() 55 | print('原版耗时:', (e1 - s1) / NUM) 56 | if self.args.use_crf == 'True': 57 | output = logits 58 | else: 59 | output = logits.detach().cpu().numpy() 60 | output = np.argmax(output, axis=2) 61 | pred_entities = decodeUtils.bioes_decode(output[0][1:1 + len(texts)], texts, self.idx2tag) 62 | print(pred_entities) 63 | 64 | def convert(self, save_path): 65 | self.model.eval() 66 | inputs = {'token_ids': torch.ones(1, args.max_seq_len, dtype=torch.long), 67 | 'attention_masks': torch.ones(1, args.max_seq_len, dtype=torch.uint8), 68 | 'token_type_ids': torch.ones(1, args.max_seq_len, dtype=torch.long)} 69 | 70 | symbolic_names = {0: 'batch_size', 1: 'max_seq_len'} 71 | with torch.no_grad(): 72 | torch.onnx.export( 73 | self.model, 74 | (inputs["token_ids"], 75 | inputs["attention_masks"], 76 | inputs["token_type_ids"]), 77 | save_path, 78 | opset_version=11, 79 | do_constant_folding=True, 80 | input_names=["token_ids", "attention_masks", "token_type_ids"], 81 | output_names=["logits"], 82 | dynamic_axes={'token_ids': symbolic_names, 83 | 'attention_masks': symbolic_names, 84 | 'token_type_ids': symbolic_names, 85 | 'logits': symbolic_names} 86 | ) 87 | 88 | def onnx_inference(self, ort_session, texts): 89 | def to_numpy(tensor): 90 | return tensor.detach().cpu().numpy() if tensor.requires_grad else tensor.cpu().numpy() 91 | 92 | tokens = [i for i in texts] 93 | encode_dict = tokenizer.encode_plus(text=tokens, 94 | max_length=args.max_seq_len, 95 | padding="max_length", 96 | truncation="longest_first", 97 | return_token_type_ids=True, 98 | return_attention_mask=True, 99 | return_tensors="pt") 100 | token_ids = encode_dict['input_ids'] 101 | attention_masks = torch.tensor(encode_dict['attention_mask'], dtype=torch.uint8) 102 | token_type_ids = encode_dict['token_type_ids'] 103 | token_ids = to_numpy(token_ids) 104 | attention_masks = to_numpy(attention_masks) 105 | token_type_ids = to_numpy(token_type_ids) 106 | s2 = time.time() 107 | for i in range(NUM): 108 | output = ort_session.run(None, {'token_ids': token_ids, "attention_masks": attention_masks, 109 | "token_type_ids": token_type_ids}) 110 | e2 = time.time() 111 | print('onnx耗时:', (e2 - s2) / NUM) 112 | output = output[0] 113 | pred_entities = decodeUtils.bioes_decode(output[0][1:1 + len(texts)], texts, self.idx2tag) 114 | print(pred_entities) 115 | 116 | 117 | if __name__ == "__main__": 118 | # 加载模型、配置及其它的一些 119 | # =================================== 120 | ckpt_path = "../checkpoints/bert_crf_c/" 121 | model_path = os.path.join(ckpt_path, "model.pt") 122 | args_path = os.path.join(ckpt_path, "args.json") 123 | with open(args_path, 'r') as fp: 124 | args = json.load(fp) 125 | args = Dict2Obj(args) 126 | 127 | args.bert_dir = '../model_hub/chinese-bert-wwm-ext/' 128 | args.data_dir = '../data/cner/' 129 | NUM = 10 130 | model = BertNerModel(args) 131 | model.load_state_dict(torch.load(model_path, map_location=torch.device('cpu')), strict=True) 132 | pprint('Load ckpt from {}'.format(ckpt_path)) 133 | 134 | with open(os.path.join(args.data_dir, "mid_data/nor_ent2id.json"), 'r') as fp: 135 | labels = json.load(fp) 136 | id2tag = {v: k for k, v in labels.items()} 137 | tokenizer = BertTokenizer.from_pretrained(args.bert_dir) 138 | # =================================== 139 | 140 | # 定义转换器 141 | # =================================== 142 | convertOnnx = ConverttOnnx(args, model, tokenizer, id2tag) 143 | # =================================== 144 | 145 | texts = "虞兔良先生:1963年12月出生,汉族,中国国籍,无境外永久居留权,浙江绍兴人,中共党员,MBA,经济师。" 146 | 147 | # 一般的推理 148 | # =================================== 149 | convertOnnx.inference(texts) 150 | # =================================== 151 | 152 | # 转换成onnx 153 | # =================================== 154 | save_path = "model.onnx" 155 | convertOnnx.convert(save_path) 156 | # =================================== 157 | 158 | # 转Onnx后的推理 159 | # =================================== 160 | import onnxruntime 161 | 162 | ort_session = onnxruntime.InferenceSession(save_path) 163 | convertOnnx.onnx_inference(ort_session, texts) 164 | 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /scripts/server.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | import sys 3 | 4 | sys.path.append('..') 5 | import os 6 | import torch 7 | import json 8 | import logging 9 | 10 | from utils import commonUtils, metricsUtils, decodeUtils, trainUtils 11 | import bert_ner_model 12 | from predict import predict, batch_predict 13 | from cut import cut_sentences_main 14 | 15 | logger = logging.getLogger(__name__) 16 | commonUtils.set_logger("predictor.log") 17 | 18 | args_path = "../checkpoints/bert_crf_cner/args.json" 19 | 20 | with open(args_path, "r", encoding="utf-8") as fp: 21 | tmp_args = json.load(fp) 22 | 23 | 24 | class Dict2Class: 25 | def __init__(self, **entries): 26 | self.__dict__.update(entries) 27 | 28 | 29 | class Predictor: 30 | def __init__(self): 31 | args = Dict2Class(**tmp_args) 32 | args.gpu_ids = "0" if torch.cuda.is_available() else "-1" 33 | print(args.__dict__) 34 | other_path = os.path.join('../data/{}'.format(args.data_name), 'mid_data').replace("\\\\", "/") 35 | ent2id_dict = commonUtils.read_json(other_path, 'nor_ent2id') 36 | query2id = {} 37 | id2query = {} 38 | for k, v in ent2id_dict.items(): 39 | query2id[k] = v 40 | id2query[v] = k 41 | 42 | model_path = '../checkpoints/{}_{}/model.pt'.format(args.model_name, args.data_name) 43 | args.bert_dir = '../../model_hub/chinese-bert-wwm-ext/' 44 | if args.model_name.split('_')[0] not in ['bilstm', 'crf', 'idcnn']: 45 | model = bert_ner_model.BertNerModel(args) 46 | else: 47 | model = bert_ner_model.NormalNerModel(args) 48 | model, device = trainUtils.load_model_and_parallel(model, args.gpu_ids, model_path) 49 | self.model = model 50 | self.device = device 51 | self.id2query = id2query 52 | self.args = args 53 | 54 | def do_predict(self, raw_text): 55 | raw_text = cut_sentences_main(raw_text, 510) 56 | entities = [] 57 | entities = batch_predict(raw_text, self.model, self.device, self.args, self.id2query) 58 | return raw_text, entities 59 | 60 | def merge(self, entities): 61 | """合并抽取结果""" 62 | with open(os.path.join('../data/{}'.format(self.args.data_name), 'mid_data/') + 'labels.json', 'r', encoding='utf-8') as fp: 63 | labels = json.load(fp) 64 | res = {label:[] for label in labels} 65 | for tmp in entities: 66 | for k, entity in tmp.items(): 67 | if entity: 68 | for e in entity: 69 | if e[0] not in res[k]: 70 | res[k].append(e[0]) 71 | # print(res) 72 | return res 73 | 74 | def merge_with_loc(self, raw_text, entities): 75 | """返回的结果带上位置,并且合并每一条句子的结果""" 76 | res = [] 77 | length = 0 78 | for text, tmp in zip(raw_text, entities): 79 | for k, entity in tmp.items(): 80 | for e in entity: 81 | res.append((e[0], k, e[1] + length, e[1] + length + len(e[0]) - 1)) 82 | length = length + len(text) 83 | if res: 84 | res = sorted(res, key=lambda x:x[2]) 85 | return res 86 | 87 | 88 | import json 89 | from flask import Flask 90 | from flask import request 91 | 92 | app = Flask(__name__) 93 | app.config['JSON_AS_ASCII'] = False 94 | app.config['JSONIFY_MIMETYPE'] = "application/json;charset=utf-8" 95 | 96 | @app.route("/extraction/", methods=["POST"]) 97 | def extract_data(): 98 | if request.method == "POST": 99 | params = request.get_json() 100 | text = params["text"] 101 | if not text: 102 | return json.dumps({"msg": "输入的文本为空", 103 | "ucode": 404, 104 | "result": {} 105 | }, ensure_ascii=False) 106 | # 抽取关联信息 107 | try: 108 | texts, entities = predictor.do_predict(text) 109 | res = predictor.merge(entities) 110 | except Exception as e: 111 | logger.error(text) 112 | logger.error(e) 113 | return json.dumps({"msg": e, 114 | "ucode": 500, 115 | "result": {} 116 | }, ensure_ascii=False) 117 | return json.dumps({"msg": "success", 118 | "ucode": 200, 119 | "result": res 120 | }, ensure_ascii=False) 121 | else: 122 | return json.dumps({"msg": "请求方式为post", 123 | "ucode": 500, 124 | "result": {} 125 | }, ensure_ascii=False) 126 | 127 | class ReturnResult: 128 | def __init__(self, msg=None, result=None, ucode=None): 129 | self.msg = msg 130 | self.result = result 131 | self.ucode = ucode 132 | 133 | @app.route("/show/", methods=["POST"]) 134 | def show_html(): 135 | returnResult = ReturnResult() 136 | if request.method == "POST": 137 | # 抽取关联信息 138 | try: 139 | text = request.form.get("text") 140 | if not text: 141 | returnResult.msg = "输入的文本为空" 142 | returnResult.result = {} 143 | returnResult.ucode = 404 144 | # res = json.dumps({"msg": "输入的文本为空", 145 | # "ucode": 404, 146 | # "result": {} 147 | # }, ensure_ascii=False) 148 | else: 149 | texts, entities = predictor.do_predict(text) 150 | res = predictor.merge(entities) 151 | returnResult.ucode = 200 152 | returnResult.msg = "请求成功" 153 | returnResult.result = res 154 | except Exception as e: 155 | logger.error(text) 156 | logger.error(e) 157 | returnResult.msg = "e" 158 | returnResult.result = res 159 | returnResult.ucode = 500 160 | # res = json.dumps({"msg": e, 161 | # "ucode": 500, 162 | # "result": {} 163 | # }, ensure_ascii=False) 164 | else: 165 | returnResult.msg = "请求方式为post" 166 | returnResult.result = {} 167 | returnResult.ucode = 500 168 | # res = json.dumps({"msg": "请求方式为post", 169 | # "ucode": 500, 170 | # "result": {} 171 | # }, ensure_ascii=False) 172 | return render_template("predict.html", 173 | result=returnResult.result, 174 | msg=returnResult.msg, 175 | ucode=returnResult.ucode, 176 | text=text) 177 | 178 | 179 | if __name__ == '__main__': 180 | predictor = Predictor() 181 | # raw_text = "虞兔良先生:1963年12月出生,汉族,中国国籍,无境外永久居留权,浙江绍兴人,中共党员,MBA,经济师。" 182 | # print(raw_text) 183 | # print(len(raw_text)) 184 | # texts, entities = predictor.do_predict(raw_text) 185 | # print(predictor.merge(entities)) 186 | app.run(host="0.0.0.0", port=9277, debug=False, threaded=False) 187 | -------------------------------------------------------------------------------- /data/cner/aug_data/NAME.txt: -------------------------------------------------------------------------------- 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 | 龚少晖 164 | 林少明 165 | 顾启峰 166 | 王江安 167 | 赵瑞航 168 | 王敏 169 | 曲晓辉 170 | 柳振江 171 | 袁中强 172 | 马崇贤 173 | 赖国华 174 | 梁桂秋 175 | 许倩 176 | 孙 177 | 刘会生 178 | 曹海燕 179 | 谭秋斌 180 | 李水荣 181 | 柴强 182 | 付瑞军 183 | 谢获宝 184 | 范志伟 185 | 何三星 186 | 申林 187 | 薛广志 188 | 贾建军 189 | 雷蕾 190 | 陈盟飞 191 | 罗军 192 | 荆云涛 193 | 刘振宇 194 | 戴佐军 195 | 李祥玉 196 | 李宏 197 | 陈江良 198 | 黄忠和 199 | 臧伟 200 | 高利民 201 | 白维 202 | 王秋霜 203 | 张广生 204 | 周新兵 205 | 雷自力 206 | 马磊 207 | 温萍 208 | 潘兴祥 209 | 黄卫东 210 | 夏仲昊 211 | 张磊乐 212 | 乐湘安 213 | 张学军 214 | 胡奎 215 | 梁津明 216 | 王素玲 217 | 马强 218 | 戴大双 219 | 杨蔚东 220 | 毛育铭 221 | 吕宏 222 | 牛海艇 223 | 由立明 224 | 谢名优 225 | 万曾炜 226 | 梁中华 227 | 张小静 228 | 李明山 229 | 王北婴 230 | 丁昀 231 | 张建平 232 | 陆长荣 233 | 张秋贵 234 | 葛晓智 235 | 秦宏武 236 | 戴波 237 | 孙忠义 238 | 丁文艺 239 | 王时中 240 | 赵柏福 241 | 陈继勇 242 | 吕晓明 243 | 邓荔遐 244 | 黄旭晖 245 | 杨旭东 246 | 黄永锡 247 | 李中 248 | 张晓辉 249 | 蒋兴灿 250 | 严志荣 251 | 张焱 252 | 杨黎升 253 | 崔基道 254 | 陆志强 255 | 凌 256 | 杨莉 257 | 郑扬宏 258 | 刘岚 259 | 韩复龄 260 | 李仁虎 261 | 骆百能 262 | 王宏军 263 | 龚高 264 | 孙有文 265 | 高圣平 266 | 林福臣 267 | 孙建华 268 | 范鸿贤 269 | 李建伟 270 | 张礼进 271 | 杜少先 272 | 梁卓昭 273 | 李长俊 274 | 刘 275 | 耿加怀 276 | 李 277 | 李新宇 278 | 张家明 279 | 周兆雪 280 | 袁哲 281 | 李军 282 | 韩雪 283 | 龚建平 284 | 罗凌 285 | 倪为民 286 | 李健 287 | 邓涛 288 | 高力生 289 | 邱九辉 290 | 吴桥 291 | 李跃军 292 | 侯功海 293 | 周益明 294 | 赵燕红 295 | 龙凤鸣 296 | 陈醒 297 | 郭建堂 298 | 陈信康 299 | 刘蔚 300 | StephenBird 301 | 马 302 | 刘晔 303 | 毛文群 304 | 吴伟钢 305 | 吉兴军 306 | 吴 307 | 张蕊 308 | 周程爱 309 | 杨志友 310 | 张学斌 311 | 包炜堂 312 | 王宏伟 313 | 汪 314 | 胡北忠 315 | 马兴亚 316 | TARONAKAYAMA 317 | 彭国泉 318 | 杨威 319 | 叶志超 320 | 熊澄宇 321 | 金向宝 322 | 周伟兴 323 | 王丽梅 324 | 卓曦文 325 | 祖国 326 | 何维嘉 327 | 霍美英 328 | 陆江 329 | 宋深海 330 | 罗会榕 331 | 王玉田 332 | 荣幸华 333 | 胡本源 334 | 程友海 335 | 徐金发 336 | 佘建 337 | 潘峰 338 | 林松生 339 | 蔡炬怡 340 | 丁衬欢 341 | 杨育红 342 | 陶正利 343 | 龙泉 344 | 梁仕念 345 | 唐泓 346 | 黎燕红 347 | 俞立 348 | 张立和 349 | 周润南 350 | 石英 351 | 金德环 352 | 丁爱兵 353 | 顾敏 354 | 刘才庆 355 | 杨丽云 356 | 李国庆 357 | 王文霞 358 | 马西庆 359 | 张辉 360 | 钟表 361 | 张秀生 362 | 赵春年 363 | 干勇 364 | 方驰 365 | 祝鹏 366 | 小六修一郎 367 | 李志鹏 368 | 潘玲曼 369 | 于广勇 370 | 陈平 371 | 潘亚敏 372 | 杨超 373 | 黄南山 374 | 杨帆 375 | 江树邦 376 | 刘志坚 377 | 谭力文 378 | 李云章 379 | 高树林 380 | 胡曙光 381 | 刘向宁 382 | 李维维 383 | 胡波 384 | 高勇 385 | 顾斌 386 | 杨艳萍 387 | 于建全 388 | 邵淑婉 389 | 蒋明刚 390 | JerryMa 391 | 吴赞 392 | 孙黎明 393 | 朱学军 394 | 苏红 395 | 陈永愉 396 | 徐玉锁 397 | 华伟 398 | 于东 399 | 袁端淇 400 | 刘天倪 401 | 管一民 402 | 张立鸿 403 | 沈明 404 | 阿肖克·阿格瓦 405 | 刘时祯 406 | 赵霞 407 | 易睿 408 | 耿佃杰 409 | 王彦亮 410 | 占磊 411 | 黄龙德 412 | 吴海波 413 | 汤建华 414 | 刘恩孝 415 | 王 416 | 李永胜 417 | 王一宁 418 | 孙凯 419 | 陈振平 420 | 夏小强 421 | 蒋敏玲 422 | 彭珏 423 | 涂善忠 424 | 胡晓辉 425 | 赵志锠 426 | 王学闻 427 | 邓勇 428 | 吕廷杰 429 | 丁安华 430 | 郜卫华 431 | 罗祝平 432 | 黄金陵 433 | 陈占飞 434 | 宋君恩 435 | 张新泽 436 | 万启成 437 | 杨海江 438 | 孟建新 439 | 张兆善 440 | 程少博 441 | 李钟民 442 | 李红旗 443 | 姚桂清 444 | 杨奇逊 445 | 兰国政 446 | 李玉霞 447 | 李东友 448 | 秦和清 449 | 薛瑞勇 450 | 王兆庆 451 | 范小平 452 | 孟颖超 453 | 张忠 454 | 樊燕 455 | 房晓焱 456 | 陈华明 457 | 屈伟华 458 | 王苏生 459 | 沈健斌 460 | 肖寒梅 461 | 史晋京 462 | StephenLong 463 | 米海祥 464 | 朱兆麒 465 | 刘春凤 466 | 魏立军 467 | 孙醒 468 | 胡三忠 469 | 李风东 470 | 苏春轩 471 | 何腾国 472 | 刘诚 473 | 张振武 474 | 盛毅 475 | 卢建华 476 | 宋权礼 477 | 刘华蓉 478 | 张同松 479 | 杨媛媛 480 | 杨兴全 481 | 李罗生 482 | 曲禄生 483 | 彭毅 484 | 刘方权 485 | 李从容 486 | 周云 487 | 蒋毅 488 | 杨振宇 489 | 刘瑞萍 490 | 孙亚明 491 | 陈光保 492 | 陈礼璠 493 | 张彬贤 494 | 程文旦 495 | 陈彰清 496 | 夏玉龙 497 | 张大钰 498 | 吕厚军 499 | 王晓东 500 | 吴国芝 501 | 陈方 502 | 李晓鹏 503 | 孙永法 504 | 谢东城 505 | 马斌武 506 | 赵 507 | 吕先锫 508 | 张铭杰 509 | 申萍 510 | 叶明星 511 | 李礼辉 512 | 白 513 | 常晓波 514 | 邹兰 515 | 张英惠 516 | 陈云峰 517 | 高涛 518 | 闻建中 519 | 李令红 520 | 林钟高 521 | 陈荣秋 522 | 梁锦棋 523 | 蔡锦波 524 | 孙降龙 525 | 蒋涵庭 526 | 徐凤江 527 | 隋玉民 528 | 袁志刚 529 | 杨芳 530 | 张敷彪 531 | 穆学奎 532 | 张凯 533 | 高忠 534 | 邬红华 535 | 付宇卓 536 | 欧炯实 537 | 楚国志 538 | 宋学勇 539 | 武佩雄 540 | 王勇 541 | 石海宁 542 | 张万山 543 | 陈伯富 544 | 黄生荣 545 | 黄 546 | 左爱军 547 | 张美文 548 | 徐益民 549 | 谢明允 550 | 黄宁宅 551 | 任有法 552 | 鲍涌波 553 | 徐菲 554 | 中山太郎 555 | 曹海成 556 | 鞠在云 557 | 韩江龙 558 | 程家安 559 | 荆林波 560 | 刘志军 561 | 吴鹰 562 | 张孟青 563 | 张元领 564 | 林江南 565 | 闵勇 566 | 黄教授 567 | 张一巍 568 | 贡华章 569 | 段连吉 570 | 杨俊 571 | 姜少军 572 | 张赤雷 573 | 王醒 574 | 张殷 575 | 张雨歌 576 | 李华夏 577 | 梁桂添 578 | 冯莉莉 579 | 李世壮 580 | 佗文汉 581 | 刘河 582 | 刘万赋 583 | 孙伟强 584 | 王凤仙 585 | 高锦芬 586 | 刘绪芳 587 | 李旦生 588 | 彭 589 | 张德仲 590 | 孙新虎 591 | 赵洁 592 | 沈国泉 593 | 彭建波 594 | 王毅刚 595 | 吴建南 596 | 林乐清 597 | 刘志敏 598 | 姚越灿 599 | 任兴洲 600 | 袁 601 | 戴青 602 | 段继东 603 | 王黄来 604 | 王文杰 605 | 魏相永 606 | 张惠强 607 | 田承明 608 | 舒涛 609 | 杨掌怀 610 | 卢立新 611 | 闻连茹 612 | 杨稔年 613 | 严昌来 614 | 师志刚 615 | 李启盛 616 | 王方明 617 | 马国鑫 618 | 喻陆 619 | 谈锋 620 | 周逸群 621 | 吴赞平 622 | 任晓常 623 | 管 624 | 姜雨松 625 | 彭纯 626 | 杨越山 627 | 匡献平 628 | 陈海明 629 | 徐尚林 630 | 林海 631 | 翟凤银 632 | 于剑波 633 | 杜凡 634 | 唐福生 635 | 吴胜军 636 | 潘平 637 | 王友权 638 | 范震东 639 | 朱小雄 640 | 王志新 641 | 吴友富 642 | 黄锦官 643 | 白永强 644 | 刘道仁 645 | 程凡贵 646 | 何祥兴 647 | 卢立勇 648 | 张跃 649 | 李耀基 650 | 王昌东 651 | 申万秋 652 | CarolleePedersen 653 | 胡刚 654 | 孙喜田 655 | 邱永宁 656 | 陈庇昌 657 | 何曲 658 | 周舟 659 | 陈淑兰 660 | 冯宝珊 661 | 崔建明 662 | 冯淑华 663 | 张莹升 664 | 康玉星 665 | 李秦生 666 | 赵勇敏 667 | 曹中 668 | 王武龙 669 | 焦迎光 670 | 姚木成 671 | 徐志翰 672 | 陈传贤 673 | 李国平 674 | 唐劲然 675 | 周 676 | 蔡增正 677 | 刘意 678 | 唐 679 | 邹健中 680 | 朱国章 681 | 胡颖 682 | 曾谦 683 | 许红超 684 | 李俊峰 685 | 蒲承民 686 | 徐世森 687 | 邓一平 688 | 张宏鹰 689 | 李梅 690 | 唐宁 691 | 敖治平 692 | 赵景华 693 | 王振刚 694 | 周和华 695 | 王铁明 696 | 程则虎 697 | 徐智麟 698 | 贾志颖 699 | 艾依热提·麦麦提吐尔逊 700 | 张崇滨 701 | 万毅 702 | 王坚能 703 | 谭焕珠 704 | 彭少民 705 | 徐勇 706 | 曹海峰 707 | 董刚 708 | 赏冠军 709 | 吴国政 710 | 张乐鸣 711 | 游善芬 712 | 兰正恩 713 | 杨启明 714 | 张嘉玲 715 | 张航 716 | 舒适广 717 | 闫建平 718 | 马俊霞 719 | 覃丽芳 720 | 马红星 721 | 邵瑞庆 722 | 曹国华 723 | 李滔 724 | 高峰 725 | 刘义传 726 | 丁笑 727 | 张逢春 728 | 王成义 729 | 袁怀中 730 | 孙向浩 731 | 郝敬开 732 | 高欣 733 | 杨书剑 734 | 吴贵槐 735 | 白有忠 736 | 张振生 737 | 张卫国 738 | 杨建萍 739 | 魏永 740 | 吴光 741 | 朱军 742 | 李波 743 | 陈步林 744 | 黄颂恩 745 | 郝立华 746 | 王玉 747 | 方夕刚 748 | 王昕 749 | 陈雪凤 750 | 陈桂霞 751 | 曲锋 752 | 张洪发 753 | 张长安 754 | 奎伟 755 | 汪群斌 756 | 连维新 757 | 张佐刚 758 | 王之钧 759 | 张建民 760 | 孙利明 761 | 吴邦明 762 | 丁靖国 763 | 申小林 764 | 朱天培 765 | 朱润资 766 | 蔡景川 767 | 刘凯风 768 | 杨铁强 769 | 葛均友 770 | 姚 771 | 王洋 772 | 汤民强 773 | 郑杏建 774 | 史 775 | 段威 776 | 黄建 777 | 孙治成 778 | 魏玲丽 779 | 陈 780 | 付万君 781 | 方慎非 782 | 王洵 783 | 丁 784 | 姚方 785 | 高靖桓 786 | 金立山 787 | 王斌 788 | 唐根初 789 | 张启銮 790 | 王跃堂 791 | 陈俊孟 792 | 郑世伟 793 | 李恩明 794 | 王笃祥 795 | 刘韵洁 796 | 刘马克 797 | 任随安 798 | 郭章鹏 799 | 李晓擎 800 | 陈福华 801 | 管振毅 802 | 吴建敏 803 | 沈予方 804 | 夏朝怡 805 | 夏峰 806 | 郝彭 807 | 曾雪琴 808 | 赵斌 809 | 李峰 810 | 雷霞 811 | 朱舫 812 | 刘军 813 | 凌伯辉 814 | 高其品 815 | 赵小青 816 | 唐长虹 817 | 陈伟强 818 | 王卫红 819 | 张文斌 820 | 贝政新 821 | 吕学强 822 | 郁武铮 823 | 吴力 824 | 张雁冰 825 | 顾政巍 826 | 卢明 827 | 朱平礼 828 | 刘强 829 | 张晓荣 830 | 戴红兵 831 | 任宇光 832 | 张翼 833 | 罗 834 | 方敏宗 835 | 丁吉 836 | 张敏康 837 | 曾燕云 838 | 杨春山 839 | 曹润珊 840 | 罗筱溪 841 | 魏毅军 842 | 王建华 843 | 肖春华 844 | 傅祖平 845 | 唐少文 846 | 方培琦 847 | 宋永红 848 | 顾 849 | 赵永宏 850 | 郑亿华 851 | 张广智 -------------------------------------------------------------------------------- /data/attr/raw_data/process.py: -------------------------------------------------------------------------------- 1 | import os 2 | import warnings 3 | import json 4 | import random 5 | 6 | 7 | def get_entities(seq, suffix=False): 8 | """Gets entities from sequence. 9 | 10 | Args: 11 | seq (list): sequence of labels. 12 | 13 | Returns: 14 | list: list of (chunk_type, chunk_start, chunk_end). 15 | 16 | Example: 17 | >>> from seqeval.metrics.sequence_labeling import get_entities 18 | >>> seq = ['B-PER', 'I-PER', 'O', 'B-LOC'] 19 | >>> get_entities(seq) 20 | [('PER', 0, 1), ('LOC', 3, 3)] 21 | """ 22 | 23 | def _validate_chunk(chunk, suffix): 24 | if chunk in ['O', 'B', 'I', 'E', 'S']: 25 | return 26 | 27 | if suffix: 28 | if not chunk.endswith(('-B', '-I', '-E', '-S')): 29 | warnings.warn('{} seems not to be NE tag.'.format(chunk)) 30 | 31 | else: 32 | if not chunk.startswith(('B-', 'I-', 'E-', 'S-')): 33 | warnings.warn('{} seems not to be NE tag.'.format(chunk)) 34 | 35 | # for nested list 36 | if any(isinstance(s, list) for s in seq): 37 | seq = [item for sublist in seq for item in sublist + ['O']] 38 | 39 | prev_tag = 'O' 40 | prev_type = '' 41 | begin_offset = 0 42 | chunks = [] 43 | for i, chunk in enumerate(seq + ['O']): 44 | _validate_chunk(chunk, suffix) 45 | 46 | if suffix: 47 | tag = chunk[-1] 48 | type_ = chunk[:-1].rsplit('-', maxsplit=1)[0] or '_' 49 | else: 50 | tag = chunk[0] 51 | type_ = chunk[1:].split('-', maxsplit=1)[-1] or '_' 52 | 53 | if end_of_chunk(prev_tag, tag, prev_type, type_): 54 | chunks.append((prev_type, begin_offset, i - 1)) 55 | if start_of_chunk(prev_tag, tag, prev_type, type_): 56 | begin_offset = i 57 | prev_tag = tag 58 | prev_type = type_ 59 | 60 | return chunks 61 | 62 | 63 | def end_of_chunk(prev_tag, tag, prev_type, type_): 64 | """Checks if a chunk ended between the previous and current word. 65 | 66 | Args: 67 | prev_tag: previous chunk tag. 68 | tag: current chunk tag. 69 | prev_type: previous type. 70 | type_: current type. 71 | 72 | Returns: 73 | chunk_end: boolean. 74 | """ 75 | chunk_end = False 76 | 77 | if prev_tag == 'E': 78 | chunk_end = True 79 | if prev_tag == 'S': 80 | chunk_end = True 81 | 82 | if prev_tag == 'B' and tag == 'B': 83 | chunk_end = True 84 | if prev_tag == 'B' and tag == 'S': 85 | chunk_end = True 86 | if prev_tag == 'B' and tag == 'O': 87 | chunk_end = True 88 | if prev_tag == 'I' and tag == 'B': 89 | chunk_end = True 90 | if prev_tag == 'I' and tag == 'S': 91 | chunk_end = True 92 | if prev_tag == 'I' and tag == 'O': 93 | chunk_end = True 94 | 95 | if prev_tag != 'O' and prev_tag != '.' and prev_type != type_: 96 | chunk_end = True 97 | 98 | return chunk_end 99 | 100 | 101 | def start_of_chunk(prev_tag, tag, prev_type, type_): 102 | """Checks if a chunk started between the previous and current word. 103 | 104 | Args: 105 | prev_tag: previous chunk tag. 106 | tag: current chunk tag. 107 | prev_type: previous type. 108 | type_: current type. 109 | 110 | Returns: 111 | chunk_start: boolean. 112 | """ 113 | chunk_start = False 114 | 115 | if tag == 'B': 116 | chunk_start = True 117 | if tag == 'S': 118 | chunk_start = True 119 | 120 | if prev_tag == 'E' and tag == 'E': 121 | chunk_start = True 122 | if prev_tag == 'E' and tag == 'I': 123 | chunk_start = True 124 | if prev_tag == 'S' and tag == 'E': 125 | chunk_start = True 126 | if prev_tag == 'S' and tag == 'I': 127 | chunk_start = True 128 | if prev_tag == 'O' and tag == 'E': 129 | chunk_start = True 130 | if prev_tag == 'O' and tag == 'I': 131 | chunk_start = True 132 | 133 | if tag != 'O' and tag != '.' and prev_type != type_: 134 | chunk_start = True 135 | 136 | return chunk_start 137 | 138 | 139 | def preprocess(input_path, save_path, mode, split=None, ratio=None): 140 | if not os.path.exists(save_path): 141 | os.makedirs(save_path) 142 | result = [] 143 | tmp = {} 144 | tmp['id'] = 0 145 | tmp['text'] = '' 146 | tmp['labels'] = [] 147 | # =======先找出句子和句子中的所有实体和类型======= 148 | with open(input_path, 'r', encoding='utf-8') as fp: 149 | lines = fp.readlines() 150 | texts = [] 151 | words = [] 152 | entities = [] 153 | char_label_tmp = [] 154 | for line in lines: 155 | line = line.strip().split(" ") 156 | if len(line) == 2: 157 | word = line[0] 158 | label = line[1] 159 | words.append(word) 160 | char_label_tmp.append(label) 161 | else: 162 | texts.append("".join(words)) 163 | entities.append(get_entities(char_label_tmp)) 164 | words = [] 165 | char_label_tmp = [] 166 | 167 | # ========================================== 168 | # =======找出句子中实体的位置======= 169 | # entities里面每一个元素:[实体类别, 实体起始位置, 实体结束位置] 170 | i = 0 171 | labels = set() 172 | for text, entity in zip(texts, entities): 173 | if entity: 174 | tmp['id'] = i 175 | tmp['text'] = text 176 | for j, ent in enumerate(entity): 177 | labels.add(ent[0]) 178 | tmp['labels'].append(["T{}".format(str(j)), ent[0], ent[1], ent[2] + 1, 179 | text[int(ent[1]):int(ent[2] + 1)]]) 180 | else: 181 | tmp['id'] = i 182 | tmp['text'] = text 183 | tmp['labels'] = [] 184 | result.append(tmp) 185 | # print(i, text, entity, tmp) 186 | tmp = {} 187 | tmp['id'] = 0 188 | tmp['text'] = '' 189 | tmp['labels'] = [] 190 | i += 1 191 | 192 | if mode == "train": 193 | label_path = os.path.join(save_path, "labels.json") 194 | with open(label_path, 'w', encoding='utf-8') as fp: 195 | fp.write(json.dumps(list(labels), ensure_ascii=False)) 196 | 197 | 198 | if split: 199 | train_data_path = os.path.join(save_path, mode + ".json") 200 | dev_data_path = os.path.join(save_path, "dev" + ".json") 201 | random.shuffle(result) 202 | train_result = result[:int(len(result) * (1 - ratio))] 203 | dev_result = result[int(len(result) * (1 - ratio)):] 204 | with open(train_data_path, 'w', encoding='utf-8') as fp: 205 | fp.write(json.dumps(train_result, ensure_ascii=False)) 206 | with open(dev_data_path, 'w', encoding='utf-8') as fp: 207 | fp.write(json.dumps(dev_result, ensure_ascii=False)) 208 | else: 209 | data_path = os.path.join(save_path, mode + ".json") 210 | with open(data_path, 'w', encoding='utf-8') as fp: 211 | fp.write(json.dumps(result, ensure_ascii=False)) 212 | 213 | 214 | path = '../mid_data/' 215 | preprocess("train.txt", path, "train", split=True, ratio=0.2) 216 | # preprocess("train.txt", path, "train", split=None, ratio=None) 217 | # preprocess("dev.txt", path, "dev", split=None, ratio=None) 218 | 219 | labels_path = os.path.join(path, 'labels.json') 220 | with open(labels_path, 'r') as fp: 221 | labels = json.load(fp) 222 | 223 | tmp_labels = [] 224 | tmp_labels.append('O') 225 | for label in labels: 226 | tmp_labels.append('B-' + label) 227 | tmp_labels.append('I-' + label) 228 | tmp_labels.append('E-' + label) 229 | tmp_labels.append('S-' + label) 230 | 231 | label2id = {} 232 | for k, v in enumerate(tmp_labels): 233 | label2id[v] = k 234 | 235 | if not os.path.exists(path): 236 | os.makedirs(path) 237 | with open(os.path.join(path, "nor_ent2id.json"), 'w') as fp: 238 | fp.write(json.dumps(label2id, ensure_ascii=False)) 239 | -------------------------------------------------------------------------------- /bert_ner_model.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.nn.functional as F 4 | from collections import OrderedDict 5 | 6 | from bert_base_model import BaseModel 7 | from transformers import AutoConfig, AutoModel, BertModel 8 | from torchcrf import CRF 9 | import config 10 | 11 | 12 | 13 | class LayerNorm(nn.Module): 14 | def __init__(self, filters, elementwise_affine=False): 15 | super(LayerNorm, self).__init__() 16 | self.LN = nn.LayerNorm([filters],elementwise_affine=elementwise_affine) 17 | 18 | def forward(self, x): 19 | x = x.permute(0, 2, 1) 20 | out = self.LN(x) 21 | return out.permute(0, 2, 1) 22 | 23 | 24 | 25 | class IDCNN(nn.Module): 26 | """ 27 | (idcnns): ModuleList( 28 | (0): Sequential( 29 | (layer0): Conv1d(10, 1, kernel_size=(3,), stride=(1,), padding=(1,)) 30 | (layer1): Conv1d(1, 1, kernel_size=(3,), stride=(1,), padding=(1,)) 31 | (layer2): Conv1d(1, 1, kernel_size=(3,), stride=(1,), padding=(2,), dilation=(2,)) 32 | ) 33 | (1): Sequential( 34 | (layer0): Conv1d(10, 1, kernel_size=(3,), stride=(1,), padding=(1,)) 35 | (layer1): Conv1d(1, 1, kernel_size=(3,), stride=(1,), padding=(1,)) 36 | (layer2): Conv1d(1, 1, kernel_size=(3,), stride=(1,), padding=(2,), dilation=(2,)) 37 | ) 38 | (2): Sequential( 39 | (layer0): Conv1d(10, 1, kernel_size=(3,), stride=(1,), padding=(1,)) 40 | (layer1): Conv1d(1, 1, kernel_size=(3,), stride=(1,), padding=(1,)) 41 | (layer2): Conv1d(1, 1, kernel_size=(3,), stride=(1,), padding=(2,), dilation=(2,)) 42 | ) 43 | (3): Sequential( 44 | (layer0): Conv1d(10, 1, kernel_size=(3,), stride=(1,), padding=(1,)) 45 | (layer1): Conv1d(1, 1, kernel_size=(3,), stride=(1,), padding=(1,)) 46 | (layer2): Conv1d(1, 1, kernel_size=(3,), stride=(1,), padding=(2,), dilation=(2,)) 47 | ) 48 | ) 49 | ) 50 | """ 51 | def __init__(self, input_size, filters, kernel_size=3, num_block=4): 52 | super(IDCNN, self).__init__() 53 | self.layers = [ 54 | {"dilation": 1}, 55 | {"dilation": 1}, 56 | {"dilation": 2} 57 | ] 58 | net = nn.Sequential() 59 | norms_1 = nn.ModuleList([LayerNorm(filters) for _ in range(len(self.layers))]) 60 | norms_2 = nn.ModuleList([LayerNorm(filters) for _ in range(num_block)]) 61 | for i in range(len(self.layers)): 62 | dilation = self.layers[i]["dilation"] 63 | single_block = nn.Conv1d(in_channels=filters, 64 | out_channels=filters, 65 | kernel_size=kernel_size, 66 | dilation=dilation, 67 | padding=kernel_size // 2 + dilation - 1) 68 | net.add_module("layer%d"%i, single_block) 69 | net.add_module("relu", nn.ReLU()) 70 | net.add_module("layernorm", norms_1[i]) 71 | 72 | self.linear = nn.Linear(input_size, filters) 73 | self.idcnn = nn.Sequential() 74 | 75 | for i in range(num_block): 76 | self.idcnn.add_module("block%i" % i, net) 77 | self.idcnn.add_module("relu", nn.ReLU()) 78 | self.idcnn.add_module("layernorm", norms_2[i]) 79 | 80 | def forward(self, embeddings): 81 | embeddings = self.linear(embeddings) 82 | embeddings = embeddings.permute(0, 2, 1) 83 | output = self.idcnn(embeddings).permute(0, 2, 1) 84 | return output 85 | 86 | 87 | class NormalNerModel(nn.Module): 88 | def __init__(self, 89 | args, 90 | **kwargs): 91 | super(NormalNerModel, self).__init__() 92 | config = AutoConfig.from_pretrained(args.bert_dir) 93 | vocab_size = config.vocab_size 94 | out_dims = config.hidden_size 95 | self.embedding = nn.Embedding(vocab_size, out_dims) 96 | 97 | self.args = args 98 | self.num_layers = args.num_layers 99 | self.lstm_hidden = args.lstm_hidden 100 | gpu_ids = args.gpu_ids.split(',') 101 | device = torch.device("cpu" if gpu_ids[0] == '-1' else "cuda:" + gpu_ids[0]) 102 | self.device = device 103 | 104 | init_blocks = [] 105 | self.criterion = nn.CrossEntropyLoss() 106 | self.linear = nn.Linear(args.lstm_hidden * 2, args.num_tags) 107 | init_blocks.append(self.linear) 108 | 109 | if args.use_lstm == 'True': 110 | self.lstm = nn.LSTM(out_dims, args.lstm_hidden, args.num_layers, bidirectional=True, batch_first=True, 111 | dropout=args.dropout) 112 | elif args.use_idcnn == "True": 113 | self.idcnn = IDCNN(out_dims, args.lstm_hidden * 2) 114 | 115 | if args.use_crf == 'True': 116 | if args.model_name.split('_')[0] == "crf": 117 | self.crf_linear = nn.Linear(out_dims, args.num_tags) 118 | init_blocks = [self.crf_linear] 119 | self.crf = CRF(args.num_tags, batch_first=True) 120 | 121 | self._init_weights(init_blocks, initializer_range=0.02) 122 | 123 | def _init_weights(self, blocks, **kwargs): 124 | """ 125 | 参数初始化,将 Linear / Embedding / LayerNorm 与 Bert 进行一样的初始化 126 | """ 127 | for block in blocks: 128 | for module in block.modules(): 129 | if isinstance(module, nn.Linear): 130 | if module.bias is not None: 131 | nn.init.zeros_(module.bias) 132 | elif isinstance(module, nn.Embedding): 133 | nn.init.normal_(module.weight, mean=0, std=kwargs.pop('initializer_range', 0.02)) 134 | elif isinstance(module, nn.LayerNorm): 135 | nn.init.ones_(module.weight) 136 | nn.init.zeros_(module.bias) 137 | 138 | def init_hidden(self, batch_size): 139 | h0 = torch.randn(2 * self.num_layers, batch_size, self.lstm_hidden, requires_grad=True).to(self.device) 140 | c0 = torch.randn(2 * self.num_layers, batch_size, self.lstm_hidden, requires_grad=True).to(self.device) 141 | return h0, c0 142 | 143 | def forward(self, 144 | token_ids, 145 | attention_masks, 146 | token_type_ids, 147 | labels, 148 | word_ids=None): 149 | 150 | seq_out = self.embedding(token_ids) 151 | 152 | batch_size = seq_out.size(0) 153 | 154 | if self.args.use_idcnn == "True": 155 | seq_out = self.idcnn(seq_out) 156 | seq_out = self.linear(seq_out) 157 | elif self.args.use_lstm == 'True': 158 | # hidden = self.init_hidden(batch_size) 159 | # seq_out, (hn, _) = self.lstm(seq_out, hidden) 160 | # seq_out = seq_out.contiguous().view(-1, self.lstm_hidden * 2) 161 | seq_out, _ = self.lstm(seq_out) 162 | seq_out = seq_out.contiguous().view(-1, self.lstm_hidden * 2) 163 | seq_out = self.linear(seq_out) 164 | seq_out = seq_out.contiguous().view(batch_size, self.args.max_seq_len, -1) # [batchsize, max_len, num_tags] 165 | 166 | if self.args.use_crf == 'True': 167 | if self.args.model_name.split('_')[0] == "crf": 168 | seq_out = self.crf_linear(seq_out) 169 | logits = self.crf.decode(seq_out, mask=attention_masks) 170 | if labels is None: 171 | return logits 172 | loss = -self.crf(seq_out, labels, mask=attention_masks, reduction='mean') 173 | if self.args.use_kd == "True": 174 | active_loss = attention_masks.view(-1) == 1 175 | active_logits = seq_out.view(-1, seq_out.size()[2])[active_loss] 176 | outputs = (loss,) + (active_logits,) 177 | return outputs 178 | outputs = (loss,) + (logits,) 179 | return outputs 180 | else: 181 | logits = seq_out 182 | if labels is None: 183 | return logits 184 | active_loss = attention_masks.view(-1) == 1 185 | active_logits = logits.view(-1, logits.size()[2])[active_loss] 186 | active_labels = labels.view(-1)[active_loss] 187 | loss = self.criterion(active_logits, active_labels) 188 | if self.args.use_kd == "True": 189 | active_loss = attention_masks.view(-1) == 1 190 | active_logits = seq_out.view(-1, seq_out.size()[2])[active_loss] 191 | outputs = (loss,) + (active_logits,) 192 | return outputs 193 | outputs = (loss,) + (logits,) 194 | return outputs 195 | 196 | 197 | class BertNerModel(BaseModel): 198 | def __init__(self, 199 | args, 200 | **kwargs): 201 | super(BertNerModel, self).__init__(bert_dir=args.bert_dir, dropout_prob=args.dropout_prob, model_name=args.model_name) 202 | self.args = args 203 | self.num_layers = args.num_layers 204 | self.lstm_hidden = args.lstm_hidden 205 | gpu_ids = args.gpu_ids.split(',') 206 | device = torch.device("cpu" if gpu_ids[0] == '-1' else "cuda:" + gpu_ids[0]) 207 | self.device = device 208 | 209 | out_dims = self.bert_config.hidden_size 210 | 211 | init_blocks = [] 212 | self.criterion = nn.CrossEntropyLoss() 213 | self.linear = nn.Linear(args.lstm_hidden * 2, args.num_tags) 214 | init_blocks.append(self.linear) 215 | 216 | if args.use_lstm == 'True': 217 | self.lstm = nn.LSTM(out_dims, args.lstm_hidden, args.num_layers, bidirectional=True,batch_first=True, dropout=args.dropout) 218 | elif args.use_idcnn == "True": 219 | self.idcnn = IDCNN(out_dims, args.lstm_hidden * 2) 220 | else: 221 | mid_linear_dims = kwargs.pop('mid_linear_dims', 256) 222 | self.mid_linear = nn.Sequential( 223 | nn.Linear(out_dims, mid_linear_dims), 224 | nn.ReLU(), 225 | nn.Dropout(args.dropout)) 226 | # 227 | out_dims = mid_linear_dims 228 | 229 | # self.dropout = nn.Dropout(dropout_prob) 230 | self.classifier = nn.Linear(out_dims, args.num_tags) 231 | # self.criterion = nn.CrossEntropyLoss(reduction='none') 232 | self.criterion = nn.CrossEntropyLoss() 233 | 234 | 235 | init_blocks = [self.mid_linear, self.classifier] 236 | # init_blocks = [self.classifier] 237 | self._init_weights(init_blocks, initializer_range=self.bert_config.initializer_range) 238 | 239 | if args.use_crf == 'True': 240 | self.crf = CRF(args.num_tags, batch_first=True) 241 | 242 | self._init_weights(init_blocks, initializer_range=self.bert_config.initializer_range) 243 | 244 | def init_hidden(self, batch_size): 245 | h0 = torch.randn(2 * self.num_layers, batch_size, self.lstm_hidden, requires_grad=True).to(self.device) 246 | c0 = torch.randn(2 * self.num_layers, batch_size, self.lstm_hidden, requires_grad=True).to(self.device) 247 | return h0, c0 248 | 249 | def forward(self, 250 | token_ids, 251 | attention_masks, 252 | token_type_ids, 253 | labels): 254 | bert_outputs = self.bert_module( 255 | input_ids=token_ids, 256 | attention_mask=attention_masks, 257 | token_type_ids=token_type_ids 258 | ) 259 | 260 | # 常规 261 | seq_out = bert_outputs[0] # [batchsize, max_len, 768] 262 | batch_size = seq_out.size(0) 263 | 264 | if self.args.use_lstm == 'True': 265 | # hidden = self.init_hidden(batch_size) 266 | # seq_out, (hn, _) = self.lstm(seq_out, hidden) 267 | # seq_out = seq_out.contiguous().view(-1, self.lstm_hidden * 2) 268 | seq_out, _ = self.lstm(seq_out) 269 | seq_out = seq_out.contiguous().view(-1, self.lstm_hidden * 2) 270 | seq_out = self.linear(seq_out) 271 | seq_out = seq_out.contiguous().view(batch_size, self.args.max_seq_len, -1) #[batchsize, max_len, num_tags] 272 | elif self.args.use_idcnn == "True": 273 | seq_out = self.idcnn(seq_out) 274 | seq_out = self.linear(seq_out) 275 | else: 276 | seq_out = self.mid_linear(seq_out) # [batchsize, max_len, 256] 277 | # seq_out = self.dropout(seq_out) 278 | seq_out = self.classifier(seq_out) # [24, 256, 53] 279 | 280 | if self.args.use_crf == 'True': 281 | logits = self.crf.decode(seq_out, mask=attention_masks) 282 | if labels is None: 283 | return logits 284 | loss = -self.crf(seq_out, labels, mask=attention_masks, reduction='mean') 285 | if self.args.use_kd == "True": 286 | active_loss = attention_masks.view(-1) == 1 287 | active_logits = seq_out.view(-1, seq_out.size()[2])[active_loss] 288 | outputs = (loss,) + (active_logits,) 289 | return outputs 290 | outputs = (loss, ) + (logits,) 291 | return outputs 292 | else: 293 | logits = seq_out 294 | if labels is None: 295 | return logits 296 | active_loss = attention_masks.view(-1) == 1 297 | active_logits = logits.view(-1, logits.size()[2])[active_loss] 298 | active_labels = labels.view(-1)[active_loss] 299 | loss = self.criterion(active_logits, active_labels) 300 | if self.args.use_kd == "True": 301 | active_loss = attention_masks.view(-1) == 1 302 | active_logits = seq_out.view(-1, seq_out.size()[2])[active_loss] 303 | outputs = (loss,) + (active_logits,) 304 | return outputs 305 | outputs = (loss,) + (logits,) 306 | return outputs 307 | 308 | if __name__ == '__main__': 309 | args = config.Args().get_parser() 310 | args.num_tags = 33 311 | args.use_lstm = 'True' 312 | args.use_crf = 'True' 313 | model = BertNerModel(args) 314 | for name,weight in model.named_parameters(): 315 | print(name) 316 | -------------------------------------------------------------------------------- /layers/CRF.py: -------------------------------------------------------------------------------- 1 | __version__ = '0.7.2' 2 | 3 | from typing import Optional 4 | 5 | import torch 6 | import torch.nn as nn 7 | 8 | 9 | class CRF(nn.Module): 10 | """Conditional random field. 11 | This module implements a conditional random field [LMP01]_. The forward computation 12 | of this class computes the log likelihood of the given sequence of tags and 13 | emission score tensor. This class also has `~CRF.decode` method which finds 14 | the best tag sequence given an emission score tensor using `Viterbi algorithm`_. 15 | Args: 16 | num_tags: Number of tags. 17 | batch_first: Whether the first dimension corresponds to the size of a minibatch. 18 | < 19 | Attributes: 20 | start_transitions (`~torch.nn.Parameter`): Start transition score tensor of size 21 | ``(num_tags,)``. 22 | end_transitions (`~torch.nn.Parameter`): End transition score tensor of size 23 | ``(num_tags,)``. 24 | transitions (`~torch.nn.Parameter`): Transition score tensor of size 25 | ``(num_tags, num_tags)``. 26 | .. [LMP01] Lafferty, J., McCallum, A., Pereira, F. (2001). 27 | "Conditional random fields: Probabilistic models for segmenting and 28 | labeling sequence data". *Proc. 18th International Conf. on Machine 29 | Learning*. Morgan Kaufmann. pp. 282–289. 30 | .. _Viterbi algorithm: https://en.wikipedia.org/wiki/Viterbi_algorithm 31 | """ 32 | 33 | def __init__(self, num_tags: int, batch_first: bool = False) -> None: 34 | if num_tags <= 0: 35 | raise ValueError(f'invalid number of tags: {num_tags}') 36 | super().__init__() 37 | self.num_tags = num_tags 38 | self.batch_first = batch_first 39 | self.start_transitions = nn.Parameter(torch.empty(num_tags)) 40 | self.end_transitions = nn.Parameter(torch.empty(num_tags)) 41 | self.transitions = nn.Parameter(torch.empty(num_tags, num_tags)) 42 | 43 | self.reset_parameters() 44 | 45 | def reset_parameters(self) -> None: 46 | """Initialize the transition parameters. 47 | The parameters will be initialized randomly from a uniform distribution 48 | between -0.1 and 0.1. 49 | """ 50 | nn.init.uniform_(self.start_transitions, -0.1, 0.1) 51 | nn.init.uniform_(self.end_transitions, -0.1, 0.1) 52 | nn.init.uniform_(self.transitions, -0.1, 0.1) 53 | 54 | def __repr__(self) -> str: 55 | return f'{self.__class__.__name__}(num_tags={self.num_tags})' 56 | 57 | def forward( 58 | self, 59 | emissions: torch.Tensor, 60 | tags: torch.LongTensor, 61 | mask: Optional[torch.ByteTensor] = None, 62 | reduction: str = 'sum', 63 | ) -> torch.Tensor: 64 | """Compute the conditional log likelihood of a sequence of tags given emission scores. 65 | Args: 66 | emissions (`~torch.Tensor`): Emission score tensor of size 67 | ``(seq_length, batch_size, num_tags)`` if ``batch_first`` is ``False``, 68 | ``(batch_size, seq_length, num_tags)`` otherwise. 69 | tags (`~torch.LongTensor`): Sequence of tags tensor of size 70 | ``(seq_length, batch_size)`` if ``batch_first`` is ``False``, 71 | ``(batch_size, seq_length)`` otherwise. 72 | mask (`~torch.ByteTensor`): Mask tensor of size ``(seq_length, batch_size)`` 73 | if ``batch_first`` is ``False``, ``(batch_size, seq_length)`` otherwise. 74 | reduction: Specifies the reduction to apply to the output: 75 | ``none|sum|mean|token_mean``. ``none``: no reduction will be applied. 76 | ``sum``: the output will be summed over batches. ``mean``: the output will be 77 | averaged over batches. ``token_mean``: the output will be averaged over tokens. 78 | Returns: 79 | `~torch.Tensor`: The log likelihood. This will have size ``(batch_size,)`` if 80 | reduction is ``none``, ``()`` otherwise. 81 | """ 82 | self._validate(emissions, tags=tags, mask=mask) 83 | if reduction not in ('none', 'sum', 'mean', 'token_mean'): 84 | raise ValueError(f'invalid reduction: {reduction}') 85 | if mask is None: 86 | mask = torch.ones_like(tags, dtype=torch.uint8) 87 | 88 | if self.batch_first: 89 | emissions = emissions.transpose(0, 1) 90 | tags = tags.transpose(0, 1) 91 | mask = mask.transpose(0, 1) 92 | 93 | # shape: (batch_size,) 94 | numerator = self._compute_score(emissions, tags, mask) 95 | # shape: (batch_size,) 96 | denominator = self._compute_normalizer(emissions, mask) 97 | # shape: (batch_size,) 98 | llh = numerator - denominator 99 | 100 | if reduction == 'none': 101 | return llh 102 | if reduction == 'sum': 103 | return llh.sum() 104 | if reduction == 'mean': 105 | return llh.mean() 106 | assert reduction == 'token_mean' 107 | return llh.sum() / mask.float().sum() 108 | 109 | def decode(self, emissions: torch.Tensor) -> torch.LongTensor: 110 | """Find the most likely tag sequence using Viterbi algorithm. 111 | Args: 112 | emissions (`~torch.Tensor`): Emission score tensor of size 113 | ``(seq_length, batch_size, num_tags)`` if ``batch_first`` is ``False``, 114 | ``(batch_size, seq_length, num_tags)`` otherwise. 115 | Returns: 116 | List of list containing the best tag sequence for each batch. 117 | """ 118 | #self._validate(emissions, mask=mask) 119 | if self.batch_first: 120 | emissions = emissions.transpose(0, 1) 121 | 122 | return self._viterbi_decode(emissions) 123 | 124 | def _validate( 125 | self, 126 | emissions: torch.Tensor, 127 | tags: Optional[torch.LongTensor] = None, 128 | mask: Optional[torch.ByteTensor] = None) -> None: 129 | if emissions.dim() != 3: 130 | raise ValueError( 131 | f'emissions must have dimension of 3, got {emissions.dim()}') 132 | if emissions.size(2) != self.num_tags: 133 | raise ValueError( 134 | f'expected last dimension of emissions is {self.num_tags}, ' 135 | f'got {emissions.size(2)}') 136 | 137 | if tags is not None: 138 | if emissions.shape[:2] != tags.shape: 139 | raise ValueError( 140 | 'the first two dimensions of emissions and tags must match, ' 141 | f'got {tuple(emissions.shape[:2])} and {tuple(tags.shape)}') 142 | 143 | if mask is not None: 144 | if emissions.shape[:2] != mask.shape: 145 | raise ValueError( 146 | 'the first two dimensions of emissions and mask must match, ' 147 | f'got {tuple(emissions.shape[:2])} and {tuple(mask.shape)}') 148 | no_empty_seq = not self.batch_first and mask[0].all() 149 | no_empty_seq_bf = self.batch_first and mask[:, 0].all() 150 | if not no_empty_seq and not no_empty_seq_bf: 151 | raise ValueError('mask of the first timestep must all be on') 152 | 153 | def _compute_score( 154 | self, emissions: torch.Tensor, tags: torch.LongTensor, 155 | mask: torch.ByteTensor) -> torch.Tensor: 156 | # emissions: (seq_length, batch_size, num_tags) 157 | # tags: (seq_length, batch_size) 158 | # mask: (seq_length, batch_size) 159 | assert emissions.dim() == 3 and tags.dim() == 2 160 | assert emissions.shape[:2] == tags.shape 161 | assert emissions.size(2) == self.num_tags 162 | assert mask.shape == tags.shape 163 | assert mask[0].all() 164 | 165 | seq_length, batch_size = tags.shape 166 | mask = mask.float() 167 | 168 | # Start transition score and first emission 169 | # shape: (batch_size,) 170 | score = self.start_transitions[tags[0]] 171 | score += emissions[0, torch.arange(batch_size), tags[0]] 172 | 173 | for i in range(1, seq_length): 174 | # Transition score to next tag, only added if next timestep is valid (mask == 1) 175 | # shape: (batch_size,) 176 | score += self.transitions[tags[i - 1], tags[i]] * mask[i] 177 | 178 | # Emission score for next tag, only added if next timestep is valid (mask == 1) 179 | # shape: (batch_size,) 180 | score += emissions[i, torch.arange(batch_size), tags[i]] * mask[i] 181 | 182 | # End transition score 183 | # shape: (batch_size,) 184 | seq_ends = mask.long().sum(dim=0) - 1 185 | # shape: (batch_size,) 186 | last_tags = tags[seq_ends, torch.arange(batch_size)] 187 | # shape: (batch_size,) 188 | score += self.end_transitions[last_tags] 189 | 190 | return score 191 | 192 | def _compute_normalizer( 193 | self, emissions: torch.Tensor, mask: torch.ByteTensor) -> torch.Tensor: 194 | # emissions: (seq_length, batch_size, num_tags) 195 | # mask: (seq_length, batch_size) 196 | assert emissions.dim() == 3 and mask.dim() == 2 197 | assert emissions.shape[:2] == mask.shape 198 | assert emissions.size(2) == self.num_tags 199 | assert mask[0].all() 200 | 201 | seq_length = emissions.size(0) 202 | 203 | # Start transition score and first emission; score has size of 204 | # (batch_size, num_tags) where for each batch, the j-th column stores 205 | # the score that the first timestep has tag j 206 | # shape: (batch_size, num_tags) 207 | score = self.start_transitions + emissions[0] 208 | 209 | for i in range(1, seq_length): 210 | # Broadcast score for every possible next tag 211 | # shape: (batch_size, num_tags, 1) 212 | broadcast_score = score.unsqueeze(2) 213 | 214 | # Broadcast emission score for every possible current tag 215 | # shape: (batch_size, 1, num_tags) 216 | broadcast_emissions = emissions[i].unsqueeze(1) 217 | 218 | # Compute the score tensor of size (batch_size, num_tags, num_tags) where 219 | # for each sample, entry at row i and column j stores the sum of scores of all 220 | # possible tag sequences so far that end with transitioning from tag i to tag j 221 | # and emitting 222 | # shape: (batch_size, num_tags, num_tags) 223 | next_score = broadcast_score + self.transitions + broadcast_emissions 224 | 225 | # Sum over all possible current tags, but we're in score space, so a sum 226 | # becomes a log-sum-exp: for each sample, entry i stores the sum of scores of 227 | # all possible tag sequences so far, that end in tag i 228 | # shape: (batch_size, num_tags) 229 | next_score = torch.logsumexp(next_score, dim=1) 230 | 231 | # Set score to the next score if this timestep is valid (mask == 1) 232 | # shape: (batch_size, num_tags) 233 | score = torch.where(mask[i].unsqueeze(1), next_score, score) 234 | 235 | # End transition score 236 | # shape: (batch_size, num_tags) 237 | score += self.end_transitions 238 | 239 | # Sum (log-sum-exp) over all possible tags 240 | # shape: (batch_size,) 241 | return torch.logsumexp(score, dim=1) 242 | 243 | def _viterbi_decode(self, emissions: torch.FloatTensor) -> torch.LongTensor: 244 | # emissions: (seq_length, batch_size, num_tags) 245 | score = self.start_transitions + emissions[0] 246 | # print('score', score.shape) 247 | score, history = viterbi_compute_score( 248 | emissions, self.transitions, score) 249 | score += self.end_transitions 250 | 251 | last_label = score.argmax(dim=1) 252 | 253 | return viterbi_path_generation(history, last_label) 254 | 255 | 256 | @torch.jit.script 257 | def viterbi_compute_score(emissions, transitions, initial_score): 258 | score = initial_score 259 | history = torch.zeros( 260 | emissions.shape, dtype=torch.long).to(emissions.device) 261 | 262 | # Viterbi algorithm recursive case: we compute the score of the best tag sequence 263 | # for every possible next tag 264 | for i in range(1, emissions.shape[0]): 265 | # Broadcast viterbi score for every possible next tag 266 | # shape: (batch_size, num_tags, 1) 267 | broadcast_score = score.unsqueeze(2) 268 | 269 | # Broadcast emission score for every possible current tag 270 | # shape: (batch_size, 1, num_tags) 271 | broadcast_emission = emissions[i].unsqueeze(1) 272 | 273 | # Compute the score tensor of size (batch_size, num_tags, num_tags) where 274 | # for each sample, entry at row i and column j stores the score of the best 275 | # tag sequence so far that ends with transitioning from tag i to tag j and emitting 276 | # shape: (batch_size, num_tags, num_tags) 277 | next_score = broadcast_score + transitions + broadcast_emission 278 | 279 | # Find the maximum score over all possible current tag 280 | # shape: (batch_size, num_tags) 281 | score, indices = next_score.max(dim=1) 282 | 283 | history[i] = indices 284 | 285 | return score, history 286 | 287 | 288 | @torch.jit.script 289 | def viterbi_path_generation(history, last_label): 290 | """ 291 | :param history: LongTensor(seq_length, batch_size, num_tags) 292 | :param last_label: LongTensor(1) 293 | :return: best_tags_list: LongTensor(batch_size, seq_length) 294 | """ 295 | best_tags_list = torch.zeros((history.shape[1], history.shape[0]), dtype=torch.long)\ 296 | .to(history.device) #[150,2] 297 | 298 | # flip用于进行翻转 299 | history = history[1:].flip(dims=[0]) #[149,2,33] 300 | best_tags_list[:, 0] = last_label 301 | 302 | for i in torch.arange(history.shape[0]): 303 | last_idx = best_tags_list[:, i] 304 | best_tags_list[:, i + 1] = history[i, :, last_idx].squeeze(1) 305 | 306 | best_tags_list = best_tags_list.flip(dims=[1]) 307 | 308 | return best_tags_list 309 | -------------------------------------------------------------------------------- /knowledge_distillation/kd.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | sys.path.append('..') 4 | 5 | import os 6 | import json 7 | import torch 8 | import logging 9 | import numpy as np 10 | import torch.nn as nn 11 | import torch.nn.functional as F 12 | from torch.utils.data import DataLoader, RandomSampler 13 | from transformers import BertTokenizer 14 | 15 | import bert_ner_model 16 | import dataset 17 | from utils import commonUtils, trainUtils, decodeUtils, metricsUtils 18 | from predict import batch_predict 19 | from cut import cut_sentences_main 20 | # 要显示传入BertFeature 21 | from preprocess import BertFeature 22 | 23 | special_model_list = ['bilstm', 'crf', 'idcnn'] 24 | 25 | logger = logging.getLogger(__name__) 26 | 27 | 28 | class Dict2Class: 29 | def __init__(self, **entries): 30 | self.__dict__.update(entries) 31 | 32 | 33 | def load_model(args): 34 | model_path = '../checkpoints/{}_{}/model.pt'.format(args.model_name, args.data_name) 35 | args.gpu_ids = "0" if torch.cuda.is_available() else "-1" 36 | if args.model_name.split('_')[0] not in special_model_list: 37 | model = bert_ner_model.BertNerModel(args) 38 | else: 39 | model = bert_ner_model.NormalNerModel(args) 40 | model, device = trainUtils.load_model_and_parallel(model, args.gpu_ids, model_path) 41 | return model, device 42 | 43 | 44 | class KDTrainer: 45 | def __init__(self, args, train_loader, dev_loader, test_loader, idx2tag, teacher, student, device): 46 | self.train_loader = train_loader 47 | self.dev_loader = dev_loader 48 | self.test_loader = test_loader 49 | self.args = args 50 | self.idx2tag = idx2tag 51 | self.teacher = teacher 52 | self.student = student 53 | self.device = device 54 | self.t_total = len(self.train_loader) * args.train_epochs 55 | self.optimizer, self.scheduler = trainUtils.build_optimizer_and_scheduler(args, student, self.t_total) 56 | self.kd_ceriterion = nn.KLDivLoss() 57 | self.T = 1 58 | 59 | def train(self): 60 | # Train 61 | global_step = 0 62 | self.student.zero_grad() 63 | eval_steps = 90 # 每多少个step打印损失及进行验证 64 | best_f1 = 0.0 65 | for epoch in range(self.args.train_epochs): 66 | for step, batch_data in enumerate(self.train_loader): 67 | self.args.use_kd = "True" 68 | self.student.train() 69 | for key in batch_data.keys(): 70 | if key != 'texts': 71 | batch_data[key] = batch_data[key].to(self.device) 72 | # 知识蒸馏核心代码 73 | # ================================ 74 | # 不让教师模型训练 75 | self.teacher.eval() 76 | with torch.no_grad(): 77 | _, teacher_logits = self.teacher(batch_data['token_ids'], batch_data['attention_masks'], 78 | batch_data['token_type_ids'], batch_data['labels']) 79 | hard_loss, student_logits = self.student(batch_data['token_ids'], batch_data['attention_masks'], 80 | batch_data['token_type_ids'], batch_data['labels']) 81 | soft_loss = self.kd_ceriterion(F.log_softmax(student_logits / self.T), 82 | F.softmax(teacher_logits / self.T)) 83 | loss = hard_loss + soft_loss 84 | # ================================ 85 | loss.backward() 86 | torch.nn.utils.clip_grad_norm_(self.student.parameters(), self.args.max_grad_norm) 87 | self.optimizer.step() 88 | self.scheduler.step() 89 | self.student.zero_grad() 90 | logger.info('【train】 epoch:{} {}/{} loss:{:.4f}'.format(epoch, global_step, self.t_total, loss.item())) 91 | global_step += 1 92 | if global_step % eval_steps == 0: 93 | dev_loss, precision, recall, f1_score = self.dev() 94 | logger.info( 95 | '[eval] loss:{:.4f} precision={:.4f} recall={:.4f} f1_score={:.4f}'.format(dev_loss, precision, 96 | recall, f1_score)) 97 | if f1_score > best_f1: 98 | trainUtils.save_model(self.args, self.student, 99 | "kd_" + self.args.model_name + '_' + self.args.data_name, global_step) 100 | best_f1 = f1_score 101 | 102 | def dev(self): 103 | self.student.eval() 104 | self.args.use_kd = "False" 105 | with torch.no_grad(): 106 | batch_output_all = [] 107 | tot_dev_loss = 0.0 108 | for eval_step, dev_batch_data in enumerate(self.dev_loader): 109 | for key in dev_batch_data.keys(): 110 | dev_batch_data[key] = dev_batch_data[key].to(self.device) 111 | dev_loss, dev_logits = self.student(dev_batch_data['token_ids'], dev_batch_data['attention_masks'], 112 | dev_batch_data['token_type_ids'], dev_batch_data['labels']) 113 | tot_dev_loss += dev_loss.item() 114 | if self.args.use_crf == 'True': 115 | batch_output = dev_logits 116 | else: 117 | batch_output = dev_logits.detach().cpu().numpy() 118 | batch_output = np.argmax(batch_output, axis=2) 119 | if len(batch_output_all) == 0: 120 | batch_output_all = batch_output 121 | else: 122 | batch_output_all = np.append(batch_output_all, batch_output, axis=0) 123 | total_count = [0 for _ in range(len(label2id))] 124 | role_metric = np.zeros([len(id2label), 3]) 125 | for pred_label, tmp_callback in zip(batch_output_all, dev_callback_info): 126 | text, gt_entities = tmp_callback 127 | tmp_metric = np.zeros([len(id2label), 3]) 128 | pred_entities = decodeUtils.bioes_decode(pred_label[1:1 + len(text)], text, self.idx2tag) 129 | for idx, _type in enumerate(label_list): 130 | if _type not in pred_entities: 131 | pred_entities[_type] = [] 132 | total_count[idx] += len(gt_entities[_type]) 133 | tmp_metric[idx] += metricsUtils.calculate_metric(gt_entities[_type], pred_entities[_type]) 134 | 135 | role_metric += tmp_metric 136 | 137 | mirco_metrics = np.sum(role_metric, axis=0) 138 | mirco_metrics = metricsUtils.get_p_r_f(mirco_metrics[0], mirco_metrics[1], mirco_metrics[2]) 139 | # print('[eval] loss:{:.4f} precision={:.4f} recall={:.4f} f1_score={:.4f}'.format(tot_dev_loss, mirco_metrics[0], mirco_metrics[1], mirco_metrics[2])) 140 | return tot_dev_loss, mirco_metrics[0], mirco_metrics[1], mirco_metrics[2] 141 | 142 | def test(self, model_path): 143 | self.args.use_kd = "False" 144 | if self.args.model_name.split('_')[0] not in special_model_list: 145 | model = bert_ner_model.BertNerModel(self.args) 146 | else: 147 | model = bert_ner_model.NormalNerModel(self.args) 148 | model, device = trainUtils.load_model_and_parallel(model, self.args.gpu_ids, model_path) 149 | model.eval() 150 | pred_label = [] 151 | with torch.no_grad(): 152 | for eval_step, dev_batch_data in enumerate(dev_loader): 153 | for key in dev_batch_data.keys(): 154 | dev_batch_data[key] = dev_batch_data[key].to(device) 155 | _, logits = model(dev_batch_data['token_ids'], dev_batch_data['attention_masks'], 156 | dev_batch_data['token_type_ids'], dev_batch_data['labels']) 157 | if self.args.use_crf == 'True': 158 | batch_output = logits 159 | else: 160 | batch_output = logits.detach().cpu().numpy() 161 | batch_output = np.argmax(batch_output, axis=2) 162 | if len(pred_label) == 0: 163 | pred_label = batch_output 164 | else: 165 | pred_label = np.append(pred_label, batch_output, axis=0) 166 | total_count = [0 for _ in range(len(id2label))] 167 | role_metric = np.zeros([len(id2label), 3]) 168 | for pred, tmp_callback in zip(pred_label, dev_callback_info): 169 | text, gt_entities = tmp_callback 170 | tmp_metric = np.zeros([len(id2label), 3]) 171 | pred_entities = decodeUtils.bioes_decode(pred[1:1 + len(text)], text, self.idx2tag) 172 | for idx, _type in enumerate(label_list): 173 | if _type not in pred_entities: 174 | pred_entities[_type] = [] 175 | total_count[idx] += len(gt_entities[_type]) 176 | tmp_metric[idx] += metricsUtils.calculate_metric(gt_entities[_type], pred_entities[_type]) 177 | 178 | role_metric += tmp_metric 179 | logger.info(metricsUtils.classification_report(role_metric, label_list, id2label, total_count)) 180 | 181 | def predict(self, raw_text, model_path): 182 | self.args.use_kd = "False" 183 | if self.args.model_name.split('_')[0] not in special_model_list: 184 | model = bert_ner_model.BertNerModel(self.args) 185 | else: 186 | model = bert_ner_model.NormalNerModel(self.args) 187 | model, device = trainUtils.load_model_and_parallel(model, self.args.gpu_ids, model_path) 188 | model.eval() 189 | with torch.no_grad(): 190 | tokenizer = BertTokenizer( 191 | os.path.join(self.args.bert_dir, 'vocab.txt')) 192 | # tokens = commonUtils.fine_grade_tokenize(raw_text, tokenizer) 193 | tokens = [i for i in raw_text] 194 | encode_dict = tokenizer.encode_plus(text=tokens, 195 | max_length=self.args.max_seq_len, 196 | padding='max_length', 197 | truncation='longest_first', 198 | is_pretokenized=True, 199 | return_token_type_ids=True, 200 | return_attention_mask=True) 201 | # tokens = ['[CLS]'] + tokens + ['[SEP]'] 202 | token_ids = torch.from_numpy(np.array(encode_dict['input_ids'])).unsqueeze(0) 203 | attention_masks = torch.from_numpy(np.array(encode_dict['attention_mask'], dtype=np.uint8)).unsqueeze(0) 204 | token_type_ids = torch.from_numpy(np.array(encode_dict['token_type_ids'])).unsqueeze(0) 205 | logits = model(token_ids.to(device), attention_masks.to(device), token_type_ids.to(device), None) 206 | if self.args.use_crf == 'True': 207 | output = logits 208 | else: 209 | output = logits.detach().cpu().numpy() 210 | output = np.argmax(output, axis=2) 211 | pred_entities = decodeUtils.bioes_decode(output[0][1:1 + len(tokens)], "".join(tokens), self.idx2tag) 212 | logger.info(pred_entities) 213 | 214 | 215 | if __name__ == "__main__": 216 | # 加载参数并修改相关的一些配置 217 | # ================================= 218 | student_args = "../checkpoints/idcnn_crf_cner/args.json" 219 | with open(student_args, "r", encoding="utf-8") as fp: 220 | student_args = json.load(fp) 221 | student_args = Dict2Class(**student_args) 222 | setattr(student_args, "use_kd", "True") 223 | student_args.bert_dir = os.path.join("..", student_args.bert_dir) 224 | logger.info(student_args.__dict__) 225 | # 将配置参数都保存下来 226 | student_args.log_dir = "../logs/" 227 | student_args.output_dir = "../checkpoints/" 228 | commonUtils.set_logger( 229 | os.path.join(student_args.log_dir, 'kd_{}_{}.log'.format(student_args.model_name, student_args.data_name))) 230 | student_model, _ = load_model(student_args) 231 | # print(idcnn_crf) 232 | 233 | teacher_args = "../checkpoints/bert_idcnn_crf_cner/args.json" 234 | with open(teacher_args, "r", encoding="utf-8") as fp: 235 | teacher_args = json.load(fp) 236 | teacher_args = Dict2Class(**teacher_args) 237 | setattr(teacher_args, "use_kd", "True") 238 | teacher_args.bert_dir = os.path.join("..", teacher_args.bert_dir) 239 | logger.info(teacher_args.__dict__) 240 | teacher_model, _ = load_model(teacher_args) 241 | # print(bert_idcnn_crf) 242 | 243 | device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") 244 | # ================================= 245 | 246 | # 加载一些标签映射字典 247 | # ================================= 248 | args = student_args 249 | 250 | data_dir = os.path.join("../data/", args.data_name) 251 | other_path = os.path.join(data_dir, 'mid_data') 252 | data_path = os.path.join(data_dir, 'final_data') 253 | other_path = os.path.join(data_dir, 'mid_data') 254 | ent2id_dict = commonUtils.read_json(other_path, 'nor_ent2id') 255 | label_list = commonUtils.read_json(other_path, 'labels') 256 | label2id = {} 257 | id2label = {} 258 | for k, v in enumerate(label_list): 259 | label2id[v] = k 260 | id2label[k] = v 261 | query2id = {} 262 | id2query = {} 263 | for k, v in ent2id_dict.items(): 264 | query2id[k] = v 265 | id2query[v] = k 266 | logger.info(id2query) 267 | args.num_tags = len(ent2id_dict) 268 | 269 | # 这里可以修改训练的一些参数 270 | # ========================================= 271 | args.train_batch_size = 32 272 | args.train_epochs = 3 273 | args.eval_batch_size = 32 274 | args.lr = 3e-5 275 | args.crf_lr = 3e-2 276 | argsother_lr = 3e-4 277 | logger.info(vars(args)) 278 | # ========================================= 279 | 280 | train_features, train_callback_info = commonUtils.read_pkl(data_path, 'train') 281 | train_dataset = dataset.NerDataset(train_features) 282 | train_sampler = RandomSampler(train_dataset) 283 | train_loader = DataLoader(dataset=train_dataset, 284 | batch_size=args.train_batch_size, 285 | sampler=train_sampler, 286 | num_workers=2) 287 | dev_features, dev_callback_info = commonUtils.read_pkl(data_path, 'dev') 288 | dev_dataset = dataset.NerDataset(dev_features) 289 | dev_loader = DataLoader(dataset=dev_dataset, 290 | batch_size=args.eval_batch_size, 291 | num_workers=2) 292 | 293 | test_features, test_callback_info = commonUtils.read_pkl(data_path, 'test') 294 | test_dataset = dataset.NerDataset(test_features) 295 | test_loader = DataLoader(dataset=test_dataset, 296 | batch_size=args.eval_batch_size, 297 | num_workers=2) 298 | 299 | kdTrainer = KDTrainer(args, train_loader, dev_loader, test_loader, id2query, teacher_model, student_model, device) 300 | kdTrainer.train() 301 | 302 | model_path = '../checkpoints/kd_{}_{}/model.pt'.format(args.model_name, args.data_name) 303 | kdTrainer.test(model_path) 304 | 305 | raw_text = "虞兔良先生:1963年12月出生,汉族,中国国籍,无境外永久居留权,浙江绍兴人,中共党员,MBA,经济师。" 306 | logger.info(raw_text) 307 | kdTrainer.predict(raw_text, model_path) 308 | 309 | # 将配置参数都保存下来 310 | args.data_dir = os.path.join("./data/", args.data_name) 311 | args.bert_dir = args.bert_dir[args.bert_dir.index("/") + 1:] 312 | args.log_dir = "./logs/" 313 | args.output_dir = "./checkpoints/" 314 | commonUtils.save_json('../checkpoints/kd_{}_{}/'.format(args.model_name, args.data_name), vars(args), 'args') -------------------------------------------------------------------------------- /preprocess.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | import logging 4 | from transformers import BertTokenizer 5 | from utils import cutSentences, commonUtils 6 | import config 7 | 8 | logger = logging.getLogger(__name__) 9 | 10 | 11 | class InputExample: 12 | def __init__(self, set_type, text, labels=None): 13 | self.set_type = set_type 14 | self.text = text 15 | self.labels = labels 16 | 17 | 18 | class BaseFeature: 19 | def __init__(self, token_ids, attention_masks, token_type_ids): 20 | # BERT 输入 21 | self.token_ids = token_ids 22 | self.attention_masks = attention_masks 23 | self.token_type_ids = token_type_ids 24 | 25 | 26 | class BertFeature(BaseFeature): 27 | def __init__(self, token_ids, attention_masks, token_type_ids, labels=None): 28 | super(BertFeature, self).__init__( 29 | token_ids=token_ids, 30 | attention_masks=attention_masks, 31 | token_type_ids=token_type_ids) 32 | # labels 33 | self.labels = labels 34 | 35 | 36 | class NerProcessor: 37 | def __init__(self, cut_sent=True, cut_sent_len=256): 38 | self.cut_sent = cut_sent 39 | self.cut_sent_len = cut_sent_len 40 | 41 | @staticmethod 42 | def read_json(file_path): 43 | with open(file_path, encoding='utf-8') as f: 44 | raw_examples = json.load(f) 45 | return raw_examples 46 | 47 | def get_examples(self, raw_examples, set_type): 48 | examples = [] 49 | # 这里是从json数据中的字典中获取 50 | for i, item in enumerate(raw_examples): 51 | # print(i,item) 52 | text = item['text'] 53 | if self.cut_sent: 54 | sentences = cutSentences.cut_sent_for_bert(text, self.cut_sent_len) 55 | start_index = 0 56 | 57 | for sent in sentences: 58 | labels = cutSentences.refactor_labels(sent, item['labels'], start_index) 59 | 60 | start_index += len(sent) 61 | 62 | examples.append(InputExample(set_type=set_type, 63 | text=sent, 64 | labels=labels)) 65 | else: 66 | labels = item['labels'] 67 | if len(labels) != 0: 68 | labels = [(label[1],label[4],label[2]) for label in labels] 69 | examples.append(InputExample(set_type=set_type, 70 | text=text, 71 | labels=labels)) 72 | return examples 73 | 74 | 75 | def convert_bert_example(ex_idx, example: InputExample, tokenizer: BertTokenizer, 76 | max_seq_len, ent2id, labels): 77 | set_type = example.set_type 78 | raw_text = example.text 79 | entities = example.labels 80 | # 文本元组 81 | callback_info = (raw_text,) 82 | # 标签字典 83 | callback_labels = {x: [] for x in labels} 84 | # _label:实体类别 实体名 实体起始位置 85 | for _label in entities: 86 | # print(_label) 87 | callback_labels[_label[0]].append((_label[1], _label[2])) 88 | 89 | callback_info += (callback_labels,) 90 | # 序列标注任务 BERT 分词器可能会导致标注偏 91 | # tokens = commonUtils.fine_grade_tokenize(raw_text, tokenizer) 92 | tokens = [i for i in raw_text] 93 | 94 | assert len(tokens) == len(raw_text) 95 | 96 | label_ids = None 97 | 98 | # information for dev callback 99 | # ======================== 100 | label_ids = [0] * len(tokens) 101 | 102 | # tag labels ent ex. (T1, DRUG_DOSAGE, 447, 450, 小蜜丸) 103 | for ent in entities: 104 | # ent: ('PER', '陈元', 0) 105 | ent_type = ent[0] # 类别 106 | 107 | ent_start = ent[-1] # 起始位置 108 | ent_end = ent_start + len(ent[1]) - 1 109 | 110 | if ent_start == ent_end: 111 | label_ids[ent_start] = ent2id['S-' + ent_type] 112 | else: 113 | label_ids[ent_start] = ent2id['B-' + ent_type] 114 | label_ids[ent_end] = ent2id['E-' + ent_type] 115 | for i in range(ent_start + 1, ent_end): 116 | label_ids[i] = ent2id['I-' + ent_type] 117 | 118 | 119 | if len(label_ids) > max_seq_len - 2: 120 | label_ids = label_ids[:max_seq_len - 2] 121 | 122 | label_ids = [0] + label_ids + [0] 123 | 124 | # pad 125 | if len(label_ids) < max_seq_len: 126 | pad_length = max_seq_len - len(label_ids) 127 | label_ids = label_ids + [0] * pad_length # CLS SEP PAD label都为O 128 | 129 | assert len(label_ids) == max_seq_len, f'{len(label_ids)}' 130 | 131 | # ======================== 132 | encode_dict = tokenizer.encode_plus(text=tokens, 133 | max_length=max_seq_len, 134 | padding="max_length", 135 | truncation='longest_first', 136 | return_token_type_ids=True, 137 | return_attention_mask=True) 138 | tokens = ['[CLS]'] + tokens + ['[SEP]'] 139 | token_ids = encode_dict['input_ids'] 140 | attention_masks = encode_dict['attention_mask'] 141 | token_type_ids = encode_dict['token_type_ids'] 142 | 143 | if ex_idx < 3: 144 | logger.info(f"*** {set_type}_example-{ex_idx} ***") 145 | print(tokenizer.decode(token_ids[:len(raw_text)+2])) 146 | logger.info(f'text: {str(" ".join(tokens))}') 147 | logger.info(f"token_ids: {token_ids}") 148 | logger.info(f"attention_masks: {attention_masks}") 149 | logger.info(f"token_type_ids: {token_type_ids}") 150 | logger.info(f"labels: {label_ids}") 151 | logger.info('length: ' + str(len(token_ids))) 152 | # for word, token, attn, label in zip(tokens, token_ids, attention_masks, label_ids): 153 | # print(word + ' ' + str(token) + ' ' + str(attn) + ' ' + str(label)) 154 | feature = BertFeature( 155 | # bert inputs 156 | token_ids=token_ids, 157 | attention_masks=attention_masks, 158 | token_type_ids=token_type_ids, 159 | labels=label_ids, 160 | ) 161 | 162 | return feature, callback_info 163 | 164 | 165 | def convert_examples_to_features(examples, max_seq_len, bert_dir, ent2id, labels): 166 | tokenizer = BertTokenizer(os.path.join(bert_dir, 'vocab.txt')) 167 | features = [] 168 | callback_info = [] 169 | 170 | logger.info(f'Convert {len(examples)} examples to features') 171 | 172 | for i, example in enumerate(examples): 173 | # 有可能text为空,过滤掉 174 | if not example.text: 175 | continue 176 | feature, tmp_callback = convert_bert_example( 177 | ex_idx=i, 178 | example=example, 179 | max_seq_len=max_seq_len, 180 | ent2id=ent2id, 181 | tokenizer=tokenizer, 182 | labels = labels, 183 | ) 184 | if feature is None: 185 | continue 186 | features.append(feature) 187 | callback_info.append(tmp_callback) 188 | logger.info(f'Build {len(features)} features') 189 | 190 | out = (features,) 191 | 192 | if not len(callback_info): 193 | return out 194 | 195 | out += (callback_info,) 196 | return out 197 | 198 | def get_data(processor, raw_data_path, json_file, mode, ent2id, labels, args): 199 | raw_examples = processor.read_json(os.path.join(raw_data_path, json_file)) 200 | examples = processor.get_examples(raw_examples, mode) 201 | data = convert_examples_to_features(examples, args.max_seq_len, args.bert_dir, ent2id, labels) 202 | save_path = os.path.join(args.data_dir, 'final_data') 203 | if not os.path.exists(save_path): 204 | os.makedirs(save_path) 205 | commonUtils.save_pkl(save_path, data, mode) 206 | return data 207 | 208 | def save_file(filename, data ,id2ent): 209 | features, callback_info = data 210 | file = open(filename,'w',encoding='utf-8') 211 | for feature,tmp_callback in zip(features, callback_info): 212 | text, gt_entities = tmp_callback 213 | for word, label in zip(text, feature.labels[1:len(text)+1]): 214 | file.write(word + ' ' + id2ent[label] + '\n') 215 | file.write('\n') 216 | file.close() 217 | 218 | 219 | if __name__ == '__main__': 220 | 221 | dataset = "cner" 222 | args = config.Args().get_parser() 223 | args.bert_dir = '../model_hub/chinese-bert-wwm-ext/' 224 | commonUtils.set_logger(os.path.join(args.log_dir, 'preprocess.log')) 225 | 226 | use_aug = False 227 | 228 | if dataset == "cner": 229 | args.data_dir = './data/cner' 230 | args.max_seq_len = 150 231 | 232 | labels_path = os.path.join(args.data_dir, 'mid_data', 'labels.json') 233 | with open(labels_path, 'r') as fp: 234 | labels = json.load(fp) 235 | 236 | ent2id_path = os.path.join(args.data_dir, 'mid_data') 237 | with open(os.path.join(ent2id_path, 'nor_ent2id.json'), encoding='utf-8') as f: 238 | ent2id = json.load(f) 239 | id2ent = {v: k for k, v in ent2id.items()} 240 | 241 | mid_data_path = os.path.join(args.data_dir, 'mid_data') 242 | processor = NerProcessor(cut_sent=True, cut_sent_len=args.max_seq_len) 243 | 244 | if use_aug: 245 | train_data = get_data(processor, mid_data_path, "train_aug.json", "train", ent2id, labels, args) 246 | else: 247 | train_data = get_data(processor, mid_data_path, "train.json", "train", ent2id, labels, args) 248 | save_file(os.path.join(mid_data_path,"cner_{}_cut.txt".format(args.max_seq_len)), train_data, id2ent) 249 | dev_data = get_data(processor, mid_data_path, "dev.json", "dev", ent2id, labels, args) 250 | test_data = get_data(processor, mid_data_path, "test.json", "test", ent2id, labels, args) 251 | 252 | elif dataset == "chip": 253 | args.data_dir = './data/CHIP2020' 254 | args.max_seq_len = 150 255 | 256 | labels_path = os.path.join(args.data_dir, 'mid_data', 'labels.json') 257 | with open(labels_path, 'r') as fp: 258 | labels = json.load(fp) 259 | 260 | ent2id_path = os.path.join(args.data_dir, 'mid_data') 261 | with open(os.path.join(ent2id_path, 'nor_ent2id.json'), encoding='utf-8') as f: 262 | ent2id = json.load(f) 263 | id2ent = {v: k for k, v in ent2id.items()} 264 | 265 | mid_data_path = os.path.join(args.data_dir, 'mid_data') 266 | processor = NerProcessor(cut_sent=True, cut_sent_len=args.max_seq_len) 267 | 268 | if use_aug: 269 | train_data = get_data(processor, mid_data_path, "train_aug.json", "train", ent2id, labels, args) 270 | else: 271 | train_data = get_data(processor, mid_data_path, "train.json", "train", ent2id, labels, args) 272 | save_file(os.path.join(mid_data_path,"chip_{}_cut.txt".format(args.max_seq_len)), train_data, id2ent) 273 | dev_data = get_data(processor, mid_data_path, "dev.json", "dev", ent2id, labels, args) 274 | # test_data = get_data(processor, mid_data_path, "test.json", "test", ent2id, labels, args) 275 | 276 | elif dataset == "clue": 277 | args.data_dir = './data/CLUE' 278 | args.max_seq_len = 150 279 | 280 | labels_path = os.path.join(args.data_dir, 'mid_data', 'labels.json') 281 | with open(labels_path, 'r') as fp: 282 | labels = json.load(fp) 283 | 284 | ent2id_path = os.path.join(args.data_dir, 'mid_data') 285 | with open(os.path.join(ent2id_path, 'nor_ent2id.json'), encoding='utf-8') as f: 286 | ent2id = json.load(f) 287 | id2ent = {v: k for k, v in ent2id.items()} 288 | 289 | mid_data_path = os.path.join(args.data_dir, 'mid_data') 290 | processor = NerProcessor(cut_sent=True, cut_sent_len=args.max_seq_len) 291 | 292 | if use_aug: 293 | train_data = get_data(processor, mid_data_path, "train_aug.json", "train", ent2id, labels, args) 294 | else: 295 | train_data = get_data(processor, mid_data_path, "train.json", "train", ent2id, labels, args) 296 | save_file(os.path.join(mid_data_path,"clue_{}_cut.txt".format(args.max_seq_len)), train_data, id2ent) 297 | dev_data = get_data(processor, mid_data_path, "dev.json", "dev", ent2id, labels, args) 298 | # test_data = get_data(processor, mid_data_path, "test.json", "test", ent2id, labels, args) 299 | elif dataset == "addr": 300 | args.data_dir = './data/addr' 301 | args.max_seq_len = 64 302 | 303 | labels_path = os.path.join(args.data_dir, 'mid_data', 'labels.json') 304 | with open(labels_path, 'r') as fp: 305 | labels = json.load(fp) 306 | 307 | ent2id_path = os.path.join(args.data_dir, 'mid_data') 308 | with open(os.path.join(ent2id_path, 'nor_ent2id.json'), encoding='utf-8') as f: 309 | ent2id = json.load(f) 310 | id2ent = {v: k for k, v in ent2id.items()} 311 | 312 | mid_data_path = os.path.join(args.data_dir, 'mid_data') 313 | processor = NerProcessor(cut_sent=True, cut_sent_len=args.max_seq_len) 314 | 315 | if use_aug: 316 | train_data = get_data(processor, mid_data_path, "train_aug.json", "train", ent2id, labels, args) 317 | else: 318 | train_data = get_data(processor, mid_data_path, "train.json", "train", ent2id, labels, args) 319 | save_file(os.path.join(mid_data_path,"clue_{}_cut.txt".format(args.max_seq_len)), train_data, id2ent) 320 | dev_data = get_data(processor, mid_data_path, "dev.json", "dev", ent2id, labels, args) 321 | # test_data = get_data(processor, mid_data_path, "test.json", "test", ent2id, labels, args) 322 | elif dataset == "attr": 323 | args.data_dir = './data/attr' 324 | args.max_seq_len = 128 325 | 326 | labels_path = os.path.join(args.data_dir, 'mid_data', 'labels.json') 327 | with open(labels_path, 'r') as fp: 328 | labels = json.load(fp) 329 | 330 | ent2id_path = os.path.join(args.data_dir, 'mid_data') 331 | with open(os.path.join(ent2id_path, 'nor_ent2id.json'), encoding='utf-8') as f: 332 | ent2id = json.load(f) 333 | id2ent = {v: k for k, v in ent2id.items()} 334 | 335 | mid_data_path = os.path.join(args.data_dir, 'mid_data') 336 | processor = NerProcessor(cut_sent=True, cut_sent_len=args.max_seq_len) 337 | 338 | if use_aug: 339 | train_data = get_data(processor, mid_data_path, "train_aug.json", "train", ent2id, labels, args) 340 | else: 341 | train_data = get_data(processor, mid_data_path, "train.json", "train", ent2id, labels, args) 342 | save_file(os.path.join(mid_data_path,"clue_{}_cut.txt".format(args.max_seq_len)), train_data, id2ent) 343 | dev_data = get_data(processor, mid_data_path, "dev.json", "dev", ent2id, labels, args) 344 | # test_data = get_data(processor, mid_data_path, "test.json", "test", ent2id, labels, args) 345 | 346 | elif dataset == "sighan2005": 347 | args.data_dir = './data/sighan2005' 348 | args.max_seq_len = 512 349 | 350 | labels_path = os.path.join(args.data_dir, 'mid_data', 'labels.json') 351 | with open(labels_path, 'r') as fp: 352 | labels = json.load(fp) 353 | 354 | ent2id_path = os.path.join(args.data_dir, 'mid_data') 355 | with open(os.path.join(ent2id_path, 'nor_ent2id.json'), encoding='utf-8') as f: 356 | ent2id = json.load(f) 357 | id2ent = {v: k for k, v in ent2id.items()} 358 | 359 | mid_data_path = os.path.join(args.data_dir, 'mid_data') 360 | processor = NerProcessor(cut_sent=True, cut_sent_len=args.max_seq_len) 361 | 362 | train_data = get_data(processor, mid_data_path, "train.json", "train", ent2id, labels, args) 363 | save_file(os.path.join(mid_data_path, "clue_{}_cut.txt".format(args.max_seq_len)), train_data, id2ent) 364 | dev_data = get_data(processor, mid_data_path, "test.json", "dev", ent2id, labels, args) 365 | # test_data = get_data(processor, mid_data_path, "test.json", "test", ent2id, labels, args) 366 | 367 | elif dataset == "gdcq": 368 | args.data_dir = './data/gdcq' 369 | args.max_seq_len = 70 370 | 371 | labels_path = os.path.join(args.data_dir, 'mid_data', 'labels.json') 372 | with open(labels_path, 'r') as fp: 373 | labels = json.load(fp) 374 | 375 | ent2id_path = os.path.join(args.data_dir, 'mid_data') 376 | with open(os.path.join(ent2id_path, 'nor_ent2id.json'), encoding='utf-8') as f: 377 | ent2id = json.load(f) 378 | id2ent = {v: k for k, v in ent2id.items()} 379 | 380 | mid_data_path = os.path.join(args.data_dir, 'mid_data') 381 | processor = NerProcessor(cut_sent=True, cut_sent_len=args.max_seq_len) 382 | 383 | train_data = get_data(processor, mid_data_path, "train.json", "train", ent2id, labels, args) 384 | save_file(os.path.join(mid_data_path, "clue_{}_cut.txt".format(args.max_seq_len)), train_data, id2ent) 385 | dev_data = get_data(processor, mid_data_path, "dev.json", "dev", ent2id, labels, args) 386 | # test_data = get_data(processor, mid_data_path, "test.json", "test", ent2id, labels, args) 387 | -------------------------------------------------------------------------------- /data/cner/aug_data/TITLE.txt: -------------------------------------------------------------------------------- 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 | 证券教室丛书之一的《投资者维权21讲》的作者 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 | 清华MBA教育20年20人 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 | EMBA商法教员 161 | 综合分公司会计主管 162 | 集团专务 163 | 营销部片区经理 164 | 交易部副总经理 165 | 家用空调事业部财务部总监 166 | 投资部经理 167 | 医学生物学高级工程师 168 | 研究部副主任 169 | 客户资源中心总经理 170 | 冶金研究室主任 171 | 组织科干事 172 | 人事与董事管理部干部一处处长 173 | 工会主席 174 | 秘书处秘书 175 | 企划室主管 176 | 行长助理 177 | 副局级审计员 178 | 工程部主管 179 | 信用卡和消费金融业务的首席执行官 180 | 资产经营部投资经营处处长 181 | 仪表自动化工程师 182 | 市场总监 183 | 第四届董事会董事 184 | 总裁办主任 185 | 正连职教官 186 | 高级研究员 187 | 大学教授 188 | 资产经营处处长 189 | 财务专家 190 | 黄冈工业系统企管干部 191 | 生产经理 192 | 汽车南站站长 193 | 保卫处副处长 194 | 投资信贷科工程师 195 | 综合事务部总经理 196 | 高级政工师 197 | 生产处室副主任 198 | 审核委员会主席 199 | 晋华宫矿党办室副主任 200 | 供应科科长 201 | 事务部副总经理 202 | 法学教授 203 | 资产管理总监 204 | 第五届董事会独立董事 205 | 劳动模范 206 | 财务部经理 207 | 筹建处综合管理部负责人 208 | 审计部经理 209 | 外资办综合组负责人 210 | 会计主管 211 | 科研办副主任 212 | 信息化部部长 213 | 研究发展部副部长 214 | 高级统计师 215 | 国家一级结构注册工程师 216 | 金融投资与地产协会会长 217 | 非执行独立董事 218 | 校长 219 | 投资管理处处长 220 | 芜湖改革开放30周年纪念勋章 221 | 宣传部部长 222 | 注册会员 223 | 软件工程师 224 | 第二届董事会董事 225 | C4烯烃催化裂解制丙烯项目部技术负责人 226 | 企业策划与管理部总经理 227 | 执行董事 228 | 资料员 229 | 化验员 230 | 系副主任 231 | 独立监事 232 | 中华人民共和国律师 233 | 注册资产评估师 234 | 数据科技董事长 235 | 注册化工师 236 | 铝行业市场高级分析师 237 | 船长 238 | 计划经理 239 | 全球研究发展部副总裁 240 | 原料室经理 241 | 运营管理办公室主任 242 | 资产监管部总经理 243 | 干事 244 | 芜湖市突出贡献的创新型人才 245 | 项目主管 246 | 芜湖市首届优秀中国特色社会主义事业建设者 247 | 地电副主任 248 | 香港执业资深会计师 249 | 东方创业监事 250 | 法律顾问 251 | 局长 252 | 一级人力资源师 253 | 债权管理部经理 254 | 外事办主任 255 | 加工事业一部总经理 256 | 主管会计 257 | 工会办公室主任 258 | 项目数据分析师 259 | 销售事业部总经理 260 | 组长 261 | 副理事长 262 | 国际业务部总经理 263 | 质量保证部经理 264 | 监事会职工代表监事 265 | 科协秘书 266 | 综合计划科科长 267 | 农业经济师 268 | 党委办公室副主任 269 | 执行委员 270 | 行政办副主任 271 | 注册审计师 272 | 安全管理中心总监 273 | 知青 274 | 监察室副主任科员 275 | 人事处工资科科长 276 | 生产部经理 277 | 安徽省优秀青年企业家 278 | 财务处副科长 279 | PMIMember 280 | 总帐主管 281 | 财务股帐务、成本、核价负责人 282 | 品牌规划中心总监 283 | 总经理专项助理 284 | 经营管理部部长 285 | 科技处长 286 | 博导 287 | 副代表 288 | 总经办副主任 289 | 市场经营部主任 290 | 党委常委 291 | 战勤科长 292 | 瑞康配送监事 293 | 特邀研究员 294 | 调度员 295 | 供应科统计员 296 | 副司长 297 | 理财顾问 298 | 财务管理国家一级 299 | E服务行销中心总经理 300 | 常务副总经理 301 | 总规划师 302 | 秘书处处长 303 | 人事部部长 304 | 物资装备部部长 305 | 企业财务信息化专家成员 306 | 组织部副部长 307 | 销售经理 308 | 副主任 309 | 中国注册税务师 310 | 养殖事业四部副总经理 311 | 创办人 312 | 文员 313 | 安徽省优秀民营科技企家 314 | 第二届董事会独立董事 315 | 党支书记 316 | 法务管理 317 | 第二届和第三届董事会独立董事 318 | 业务发展资深副总裁 319 | 专题组长 320 | 建筑设计研究院建筑师 321 | 技术中心经理 322 | 政治部宣传干事 323 | 存储增值事业部总经理 324 | 大班长 325 | 电容器制造工艺员 326 | 支行副行长 327 | 高级程序员 328 | 副省长 329 | 运行主管 330 | 家电行业管理部主任 331 | 总办主任 332 | 副主任科员 333 | 国际业务部副总经理 334 | 办公厅主任 335 | 公司计划资金部总经理 336 | 全军优秀企业家 337 | 董事长助理 338 | 总裁助理 339 | 博士生女导师 340 | 成本控制室成本主管 341 | 资产管理部总经理 342 | 小家电事业部销售财务经理 343 | 部门总经理助理 344 | 药剂室工程师 345 | 国际注册内部审计师 346 | 系统信息产品一部总经理 347 | 行长 348 | 技师 349 | 党政办公室秘书科长 350 | 投资银行总部总经理助理 351 | 立法咨询专家 352 | 信息部主任 353 | 排长 354 | 投资银行部主管 355 | 支部书记 356 | 舟桥旅正营职参谋 357 | 高级工程经理 358 | 电信行业总经理 359 | 连政治指导员 360 | 管理者代表 361 | 计划财务部总经理助理 362 | 新能源发电事业部总经理 363 | 投行部总经理 364 | 企业发展部经理 365 | 首席审计官 366 | 企业银行部总经理 367 | 队长 368 | 特级工程师 369 | 财务资产部经理 370 | 高级律师 371 | 社保基金理事会主任 372 | 党委秘书 373 | 财经管理部长 374 | 电缆车间主任 375 | 专家组副组长 376 | 总经济师 377 | 副院长 378 | 付总经理 379 | 审计委员会主任 380 | 常务副理事长 381 | 第二经营部副经理 382 | 上海经营部副总经理 383 | 专家委员会副主任 384 | 五合一事业部副总经理 385 | 产业发展部部长 386 | 技术总经理 387 | 监管部负责人 388 | 主编 389 | 审计员 390 | 行政财务管理部经理 391 | 电解车间工段长 392 | 董事总经理 393 | 自动化室工程师 394 | 中近东南非事业部主担 395 | 采购部主管工程师 396 | 资产监管部总经理助理 397 | 鞍山市人大代表 398 | 团委副书记 399 | 通讯编辑 400 | 经营管理部副主任 401 | 常务董事 402 | 副秘书长 403 | 土木与建筑教授 404 | 会计部经理 405 | 园林工程师 406 | 注册律师 407 | 执行总编 408 | 富乐车站站长 409 | 财务科主办会计 410 | 出口援助物资招标评审专家 411 | 英国执业律师 412 | 稽核监督局处长 413 | 监察室纪检处长 414 | 助理经济师 415 | 技术部经理 416 | 高级经营师 417 | 市场营销总监 418 | 电子所所长 419 | 二级业务主管 420 | 经营总监 421 | 新闻发言人 422 | 普通合伙人 423 | 综管部部长 424 | 商场部门经理 425 | B.B.S. 426 | 计财处副处长 427 | 机动能源科副科长 428 | 计划企管部部长 429 | 工程部副经理 430 | 导师 431 | 局长办公室外事秘书 432 | 战略规划部部长 433 | 主办 434 | 水利工程项目经理部会计主管 435 | 气体室副主任 436 | 第二届监事会负责人 437 | 第六届董事会董事 438 | 一届董事会董事 439 | 第四届、第五届监事会监事 440 | 财务科副科长 441 | 商务部经理 442 | 采购事业部总经理 443 | 财务部副总经理 444 | 审计风险部总经理 445 | 计划财务部主任 446 | 董秘 447 | 社会学部委员 448 | 财务副总监 449 | 战略投资部经理 450 | 销售助理 451 | 深圳市政府特殊津贴技术专家 452 | 项目工程师 453 | 监事会监事 454 | 业务发展部银行卡业务组组长 455 | 研发处副总 456 | 财务管理系主任 457 | 药理教研室讲师 458 | 高级会员 459 | 职工监事 460 | 市场营销部总经理 461 | 运营和技术部门的负责人 462 | 四川经济社会发展重大问题对策研究中心秘书长 463 | 音响事业部总经理助理 464 | 副科级纪检员 465 | 第一届委员会民营经济组组长 466 | 合成车间党支部书记 467 | 西餐部经理 468 | 行政副总监 469 | 应用金融系主任 470 | 主席助理 471 | 集团发展改革中心副主任 472 | 研发系统产品开发中心主任 473 | 纪检组长 474 | 城市处处长 475 | 超市事业部财务部长助理 476 | 教育处干部 477 | 正司局级巡视员 478 | 财务会计 479 | 法务顾问 480 | 机电产品进出口办公室主任 481 | 董事局副主席 482 | 兼任教授 483 | 经理助理 484 | 审计处副处长 485 | 两办主任 486 | 工艺员 487 | 内部审计师 488 | 常务委员 489 | 财务处成本科副科长 490 | 制成车间主任 491 | 知识产权管理 492 | 审计处处长 493 | 财务部总监助理 494 | 质检科长 495 | 站长 496 | 党工委书记 497 | 业务部部长 498 | 股东代表 499 | 企划部经理 500 | 人力资源总监 501 | 第八、九届成员 502 | 财务管理部负责人 503 | 生产部部长 504 | 清产核资专家成员 505 | 企划本部本部长 506 | 高级策划师 507 | 东区销售与市场总经理 508 | 股份制办公室副主任 509 | 副总 510 | 合成车间技术员 511 | 省经建投业务员 512 | 车间副主任 513 | 技术部工艺员 514 | 工会副主席 515 | 产权发展部主任 516 | 股份制改造办公室主任 517 | 生产计划处处长 518 | 剑桥CFO 519 | 并购重组审核委员会委员 520 | 南京总经理 521 | 系统产品事业部总经理 522 | 人力资源部培训经理 523 | 项目管理专家 524 | 财务中心副总经理 525 | 常务副总裁 526 | 安徽省工会财务先进个人 527 | 决策咨询委员 528 | 监审室主任 529 | 审计师 530 | 总工程师 531 | 项目指挥部计划处副处长 532 | 国家有突出贡献中青年专家 533 | 会计 534 | 副厅长 535 | 退服中心副主任 536 | 市场分析师 537 | 资产保全处处长助理 538 | 信贷主管 539 | 计划发展部经理 540 | 副班长 541 | 气体应用业务主管 542 | CAM工程师 543 | 监事职工代表监事 544 | 安徽省先进女职工标兵称号 545 | 本地化部部门经理 546 | 校党委副书记 547 | 执业药师 548 | 投资发展部部长 549 | 生产运营部部长 550 | 职工董事 551 | 国际部编辑 552 | 融资中心清理小组组长 553 | 投资发展科科长 554 | 人力资源部总经理 555 | 编委会主任 556 | 工交处副处长 557 | 计划统计办公室主任 558 | 进出口部副经理 559 | 电气工程师 560 | 事业部总经理 561 | 市场科副科长 562 | 总调度长 563 | 运行管理部部长 564 | 机械工程师 565 | 第三、四届常务副会长 566 | 金融事业部部长 567 | 第九届广东省人大代表 568 | 高级编辑 569 | 党办副主任 570 | 业务助理 571 | 机械高级工程师 572 | 地球科学系主任 573 | 投资管理部总经理助理 574 | 制造中心总监 575 | 资产财务处处长 576 | 团委书记 577 | 资产管理部副总经理 578 | 科技处副处长 579 | 亚太区副总裁 580 | 副主委 581 | 铜镍处处长 582 | 会长 583 | 非执行董事 584 | 驻新加坡首席代表 585 | 网站专栏作者 586 | 财务部副经理 587 | 生产总监 588 | 审计二部审计员 589 | 稽查部调研员 590 | 第六、七届董事会董事 591 | 证券部副部长 592 | 无损检测高级检验员 593 | 部队干部 594 | 三总师室主任 595 | 厂办副主任 596 | 财务副股长 597 | 部门总经理 598 | 党委组织部部长 599 | 员工 600 | 合伙人 601 | 注册评估师 602 | 顾问 603 | 研究总监 604 | 审计部副主任 605 | 业务经理 606 | 统计师 607 | 专职监事 608 | 高级合伙人 609 | 审计部副部长 610 | 一级建造师 611 | 安监局局长 612 | 电脑事业部副总经理 613 | 运营总监 614 | 二车间副主任 615 | 机电车间技术员 616 | 摩托车本部本部长 617 | 董事长办公室处长 618 | 董事会办公室副主任 619 | 第六监事会监事 620 | 营运部总裁 621 | 肾脏病血液净化中心主任 622 | 财务分析主管 623 | 主任 624 | 人力资源部部长 625 | 电器设计室主管工程师 626 | 项目部副经理 627 | 亚太区总裁 628 | 计划财务部主管会计 629 | 财务综合会计 630 | 人事处处长 631 | 学员 632 | 代理总经理 633 | 上市科经理 634 | 职工代表 635 | 理事长 636 | 财务部主管会计 637 | 实际控制人 638 | 电子所助理工程师 639 | 人事部工资处副处长 640 | 新闻中心主任 641 | 外贸部副经理 642 | 盛泽负责人 643 | 上尉军衔 644 | 审计部审计专员 645 | 副处级 646 | 第三届监事会职工代表监事 647 | 党委委员 648 | 调研员 649 | 技术干部 650 | 党群工作部副主任 651 | 书记 652 | 咨询顾问 653 | 广告中心主任 654 | 特邀工作专家 655 | 非官方委员 656 | 财务经营部科长 657 | 无损检测助理工程师 658 | 镇长 659 | 注册咨询(投资)工程师 660 | 市场开发部经理 661 | 科技兴市功臣 662 | 党委工作部主任 663 | 计划科科长 664 | 江西省宜春市袁州区人大常委 665 | 审计教研室副主任 666 | 审计部负责人 667 | 投资部高级经理 668 | 固网销售负责人 669 | 国际注册金融分析师 670 | 党委书记 671 | 寿险运营中心总经理 672 | 党员 673 | 营销中心主任 674 | 财务负责人 675 | 主任委员 676 | 高级经理 677 | 教研室主任 678 | 专家学术委员会顾问 679 | 研究室主任 680 | 连长 681 | 销售部副理 682 | 电营销管理部经理 683 | 精密质保部副部长 684 | 纪检书记 685 | 科技质量管理部部长 686 | 注册会计师 687 | 证券部主任 688 | 工程建设项目指挥长 689 | 常委 690 | 进口部经理 691 | 服务专刊部主任 692 | 厂长经理 693 | 晋华宫矿党办公室秘书 694 | GMP监督 695 | 销售部副总裁 696 | 质量处副处长 697 | 投资经营处副处长 698 | 专职副主任 699 | 数据中心主任 700 | 销售科科长 701 | 综合计划科副科长 702 | 质检部经理 703 | 会计中级 704 | 法律审计室主任 705 | 信用管理师 706 | 新闻干事 707 | 无线交换产品线副总经理 708 | SIFM 709 | 应用系统业务部业务管理专员 710 | 车间技术员 711 | 经营规划总部总部长 712 | 进口科科长 713 | 监事 714 | 采购部经理 715 | 代厂长 716 | CEO 717 | 第一届监事会监事 718 | 车间主任 719 | 第五届董事会董事 720 | 职工代表监事 721 | 投资管理部副经理 722 | 资金计划处副处长 723 | 行政副总裁 724 | 淮委 725 | 四川省人大代表 726 | 副研 727 | 质量工程师 728 | 监察部部长 729 | 首席投资官 730 | 审计室主任 731 | 常务副市长 732 | 首席经济学家 733 | 财会处处长 734 | ACCA中心主任 735 | 高级畜牧师 736 | 办公室副主任 737 | 战略管理顾问 738 | 院党委委员 739 | 常务副总 740 | 货代部经理 741 | 第十一届、第十二届全国人大代表 742 | 技术和产品开发工作负责人 743 | 军械师 744 | 秘书科长 745 | 策划发展部经理 746 | 企划部部长 747 | 院士 748 | 广州土地开发项目部经理 749 | 资产管理事业部总经理 750 | 供销处主办会计 751 | 第四届董事会独立董事 752 | 会员 753 | 蛇形管车间主任 754 | 处长 755 | 企业发展研究所副所长 756 | 委员 757 | 检修管理科长 758 | 组织部部长助理 759 | 高级国际商务师 760 | 事业部副总经理 761 | 证券部部长 762 | 区长 763 | 所工会主席 764 | 审计部长 765 | 特许秘书 766 | 战略统筹部副总经理 767 | 审计评估部经理 768 | 应用技术工程师 769 | 助理研究员 770 | 技术科主管 771 | 投行部经理 772 | 专家评审 773 | 人事处长 774 | 区域总经理 775 | 劳资员 776 | 技术中心副主任 777 | 人事部工资处任科员 778 | 监审部部长 779 | 党委办公室主任 780 | 注册税务师 781 | 助理巡视员 782 | 理事会副主任 783 | 副科长 784 | 二车间助理工程师 785 | 政协委员 786 | 三峡枢纽工程稽查组组长 787 | 外经处副处长 788 | 副书记 789 | 教务处处长 790 | 团政治处宣传股长 791 | 课长 792 | 财务公司董事 793 | 工程技术应用研究员 794 | 会计学首席教授 795 | 化验室技术员 796 | 单位负责人 797 | 专职教师 798 | 产品总经理 799 | 总裁 800 | 会长助理 801 | 局长助理 802 | 战略及业务发展董事 803 | 董事锯片部部长 804 | 首席执行官 805 | 供应部副主任 806 | 主施工 807 | 科技处处长 808 | 嘉兴市人大代表 809 | 审计部项目经理 810 | 电子工程博士后 811 | 财务部负责人 812 | 人力资源部副总监 813 | 财务主办 814 | 审计总部副总经理 815 | 企业发展部副部长 816 | 二级教授 817 | 机关总部党委书记 818 | 研发中心常务副主任 819 | 信用卡事业部干事 820 | 中国区副总裁 821 | 财务总监 822 | 博士后导师 823 | 科技部主任 824 | 计统员 825 | 会计员 826 | 汽车系教授 827 | 人力资源中心经理 828 | 计划财务部总经理 829 | 注册项目管理专家 830 | 工段长 831 | 二车间调度员 832 | 研究部研究员 833 | 中国律师资格 834 | 生产制造部部长 835 | 规划发展部项目经理 836 | 会计专业硕士(MPAcc)教育中心副主任 837 | 监事会召集人 838 | 综合管理部副总经理 839 | 出纳员 840 | 实业管理部高级主管 841 | 外部董事 842 | 计划与财务部副部长 843 | 多元产业发展部部长 844 | 国家注册一级建造师 845 | 第三、第四、第五届董事会副董事长 846 | 亚太区质量经理 847 | 计划信息处副处长 848 | 采购咨询专家 849 | 晋华宫矿副矿长 850 | 党委副书记 851 | 综合部主任 852 | 法律室主任 853 | 地区销售经理 854 | 基层工作处副科长 855 | 稽核审计部总经理 856 | 法人 857 | 党组书记 858 | 行政人事部部长 859 | 人事部副经理 860 | 党支部书记 861 | 中国区大众气体业务总经理 862 | 研究员级高级工程师 863 | 商务部部长 864 | 营销管理部部长 865 | 资产管理部分析师 866 | 注册财务管理师 867 | 工厂长 868 | 董事会秘书办公室及法律事务部法律顾问 869 | 纪检办主任 870 | 筹建办主任 871 | 副译审 872 | 研发处处长 873 | 特聘教授 874 | 会计核算基础达标考核评委 875 | 干果外贸部经理 876 | 资产管理部经理 877 | 主任策划师 878 | 政治处干部 879 | 财务经理 880 | 美国注册金融分析师 881 | 培训部教员 882 | 设计室主任 883 | 国际业务总部助理总经理 884 | 资产并购部总监 885 | 投资总监 886 | 工会办公室副主任 887 | 金融系主任 888 | 生活福利处处长助理 889 | 仓管员 890 | 经理 891 | 主任医师 892 | 四届监事会股东监事 893 | 投资银行部高级经理 894 | 单证员 895 | 咨询委员 896 | 高级工程师 897 | 主席 898 | 芜湖市第二届优秀中国特色社会主义事业建设者 899 | 产业发展事业部副总裁 900 | 总裁办公室主任 901 | 团险部副经理 902 | 第六届、第七届董事会董事 903 | PMP 904 | 编审 905 | 学术委员会副主任 906 | 劳动标准研究室副主任 907 | 技术总顾问 908 | 代表 909 | 总经理助理 910 | 分行信贷管理部经理 911 | 副校长 912 | 纺织商场办公室主任 913 | 业务科副科长 914 | 党纪书记 915 | 资深会员 916 | 投资银行部执行副总经理 917 | 执行人 918 | 组织部代理副部长 919 | 项目设备部副部长 920 | 纪委副书记 921 | 注册财务总监 922 | 生产管理部部长 923 | 办公室秘书 924 | 专职研究人员 925 | 成本会计 926 | 董事会薪酬与考核委员会主任委员 927 | 总会计师 928 | 成员 929 | 肿瘤科科主任 930 | 生产技术部主任 931 | 副总调度长 932 | 应用研究处处长 933 | 执业注册会计师 934 | 董事长 935 | 总经理办公室主任 936 | 第四届监事会监事 937 | 荣誉会员 938 | 研究部总经理 939 | 车间党支部副书记 940 | 公司秘书资格 941 | 选矿工艺室副主任 942 | 商务总经理 943 | 电算化组组长 944 | 投资经理 945 | 董事会秘书 946 | 第七届监事会监事 947 | 财务部会计 948 | 企业及投资银行行政总裁 949 | 办公室主任 950 | 学生 951 | 静冈制作所所长 952 | 运销处副处长 953 | 正高级工程师 954 | PMC经理 955 | 外销经理 956 | 生产处副处长 957 | 20周年突出贡献奖获得者 958 | 信贷部总经理 959 | 开发工程师 960 | 人事部业务副主办 961 | 助理工程师 962 | 司长 963 | 副总工程师 964 | 会计师 965 | 策划部主任工程师 966 | 投资发展部副部长 967 | 基金经理 968 | 综合管理部总经理助理 969 | 高级管理咨询师 970 | 策划部经理 971 | 资产部副经理 972 | 项目管理处处长 973 | 关联人 974 | 生产调度员 975 | 资深投资总监 976 | 财务部部长助理 977 | 矿务局局长 978 | 党群部副主任 979 | 区域经理 980 | 稽核局银行一处、二处副处长 981 | 资产建管部部长 982 | 党组成员 983 | 规划建设处处长 984 | 中国事业室主管 985 | 办公室干事 986 | 业务主管 987 | 软件学院院长 988 | 第七届理事会副会长 989 | 国际商务师 990 | 副系主任 991 | 新北洋监事 992 | 总建筑师 993 | 特邀检察员 994 | 行政廉政监督员 995 | 综合管理部经理 996 | 第二、三届董事会独立董事 997 | 技术科技术员 998 | 第六届董事会独立董事 999 | VM发动机项目指挥部财务总监 1000 | 技改办主任 1001 | 资产监管部副总经理 1002 | 财务部长 1003 | 第二届副理事长 1004 | 科技发展部部长 1005 | 发动机室主任 1006 | "金融硕士"兼职导师 1007 | 管理四部总经理 1008 | 任教 1009 | 研究员 1010 | 所长助理 1011 | 经济学教授 1012 | 办公室调研科科长 1013 | 血糖事业部总经理 1014 | 自动化仪表高级工程师 1015 | 住宅科科长 1016 | 政治处干事 1017 | 技术质量科科长 1018 | 清理整顿办公室副主任 1019 | 董事会董事长 1020 | 营林处处长 1021 | 下派监事会工作部总经理 1022 | 大长山岛分公司经理 1023 | 副处级巡视员 1024 | 第一届董事会董事 1025 | 教员 1026 | 学术委员会主席 1027 | 首席人力资源官 1028 | 胶囊生产线设备维护员 1029 | 物业本部副本部长 1030 | 财务管理国际最高级 1031 | 政研体改部处长 1032 | 巡视员 1033 | 分梳运转班班长 1034 | 律师 1035 | 销售副经理 1036 | 发展部经理 1037 | 记者 1038 | 证券特许注册会计师 1039 | 司令部参谋 1040 | 禽蛋部副经理 1041 | 正高职高级工程师 1042 | 负责人 1043 | 名誉会长 1044 | 发展规划部总经理 1045 | 中队长 1046 | 营政治教导员 1047 | 硕士导师 1048 | 经营室室长 1049 | 工人 1050 | 计划部、证券部职员 1051 | 副总会计 1052 | 董事会秘书助理 1053 | 常务副指挥长 1054 | 所学术委员 1055 | 董事局主席 1056 | 副总经济师 1057 | 三届监事会监事 1058 | 客座教授 1059 | 一级高级法官 1060 | 审计法规部主任 1061 | 董事 1062 | 劳资综合管理室主任 1063 | 组织科科长 1064 | 副大队长 1065 | 市场部经理 1066 | 主编助理 1067 | 法律部经理 1068 | 人事科长 1069 | 业务开发部总经理助理 1070 | 干部 1071 | 渠道发展董事长 1072 | 财务科科长 1073 | 综合部经理 1074 | 政策法规所所长 1075 | 教研室副主任 1076 | 党组副书记 1077 | 见习技术员 1078 | 人力资源部总监 1079 | 执行副总 1080 | ERP项目组长 1081 | 教授委员会主任 1082 | 实验室主任助理 1083 | 计财部经理 1084 | 人力行政中心总监 1085 | 进出口贸易部常务副经理 1086 | 科研所所长 1087 | 常务理事 1088 | 会计学副教授 1089 | 园林科科长 1090 | 厂部副厂长 1091 | 集团总会计师 1092 | 科员 1093 | 人事董事部副主任 1094 | 工会副主任 1095 | 银行国际部顾问 1096 | 研究中心副经理 1097 | 主任法律助理 1098 | 创新业务部高级副经理 1099 | 副总编 1100 | 注册资产管理师 1101 | 第一、第二届监事会监事 1102 | 综合处处长 1103 | 证券部长 1104 | 专业会员 1105 | 院长 1106 | 中国工程院院士 1107 | 主任会计师 1108 | 信息总监 1109 | 助工 1110 | 计财科会计 1111 | 总监 1112 | 糖尿病事业部总经理 1113 | 城市经济研究室副主任 1114 | 高级总监 1115 | 常务副主任 1116 | 工程师 1117 | 涉外价格司进出口处副处长 1118 | 房地产系主任 1119 | 副所长 1120 | 四车间书记 1121 | 总部财务处主办会计 1122 | 营执行官 1123 | 厂党委委员 1124 | 风险管理部总经理 1125 | 博士生导师 1126 | 专家委员会主任 1127 | 投资策划部主任 1128 | 材料会计 1129 | 独立非执行董事 1130 | 管理学部委员 1131 | 综合员 1132 | 监事会副主席 1133 | 下属财务经理 1134 | 综合办主任 1135 | 企划室主担 1136 | 第二、三届董事会董事 1137 | 项目经理 1138 | 设备管理员 1139 | 第一届、第二届、第三届董事会董事 1140 | 飞机分党组成员 1141 | 组织部长 1142 | 亚洲区高级理论应用工程师 1143 | 文艺辅导员 1144 | 发展部部长 1145 | 会计学教授 1146 | 人力资源部副部长 1147 | 干部培训科科长 1148 | 监事会主席 1149 | 贸易经济系副主任 1150 | 本地化工程师 1151 | 皮管委副主任 1152 | 人力资源部人事主管 1153 | 外派监事会主席 1154 | 资深副总 1155 | 正团职副主任 1156 | 中药处主任科员 1157 | 工控部经理 1158 | 企业策划与管理部副总经理 1159 | 晋华宫矿矿办室主任 1160 | 计财处处长 1161 | 管理财务部部长 1162 | 计划企管部主任 1163 | 第一副厂长 1164 | 贷款项目评估员 1165 | 特约研究员 1166 | 常务副厂长 1167 | 综合办公室主任 1168 | 机关党委副书记 1169 | 纪委委员 1170 | 筹委会副主任 1171 | 主办会计 1172 | 法规稽查处处长 1173 | 政工干事 1174 | 财务司二处 1175 | 管理合伙人 1176 | 设备处财务科副科长 1177 | 研究部主任研究员 1178 | 工艺科长 1179 | 本公司 1180 | 副总工 1181 | 财务监管部总经理 1182 | 副总会计师 1183 | 亚太区执行副总裁 1184 | 高级项目管理师 1185 | 人事教育处副处长 1186 | 采卤车间副主任 1187 | 技术部技术员 1188 | 文书 1189 | 政策研究室主任 1190 | 设备部经理 1191 | 运营中心副总经理 1192 | 综合产业部主任 1193 | 董事长秘书 1194 | 辽宁省丹东市副市长 1195 | 首席财务官 1196 | 董事会第一、二届董事长 1197 | 办公室主管 1198 | 财务部副主任 1199 | 行政人事总监 1200 | 法律事务室处长 1201 | 战略投资部副主任 1202 | 合资格会计师 1203 | 技术质量主管 1204 | 管理学硕士生导师 1205 | 上校军衔 1206 | 监察处处长 1207 | 薪酬与考核委员会委员 1208 | 设备副主任 1209 | 财务部主任 1210 | 行政事务部部长 1211 | 矿业经理 1212 | 研究人员 1213 | 合伙人律师 1214 | 副总监 1215 | 北站分场经营部经理 1216 | 财务部副部长 1217 | 原料药事业部总裁 1218 | 国际内部审计师 1219 | 市场与营销总监 1220 | 第七届理事会副理事长 1221 | 仲裁员 1222 | 三届监事会股东监事 1223 | 事业群协理 1224 | 高级管理人员 1225 | 副教授 1226 | 工商所所长 1227 | 副研究员 1228 | 财务副总 1229 | 业务部副部长 1230 | 机修车间工人 1231 | 运销公司副经理 1232 | 计量室设备员 1233 | 民主党派 1234 | 财政专业 1235 | 通程商业公司审计部部长 1236 | 采购部总经理 1237 | 审计室副主任 1238 | 综合管理部部长 1239 | 人事部副总经理 1240 | 副董事长 1241 | 副处长 1242 | 证券事务代表 1243 | 高级审计师 1244 | 中国法律专家 1245 | 应收账款催收办公室主任 1246 | 内部审计部经理 1247 | 生产主管 1248 | 教育部跨世纪人才计划 1249 | 高级技师 1250 | 生产副总经理 1251 | 战略研究部总经理 1252 | 评审专家 1253 | 财务科长 1254 | 电教中心总编 1255 | 财务管理 1256 | 副场长 1257 | 院总会计师 1258 | 产品评估部经理 1259 | 工商管理研究生导师 1260 | MBA硕士生导师 1261 | 外部监事 1262 | 技术科科长 1263 | 物质供应处副处长 1264 | 证券部经理 1265 | 经济顾问 1266 | 教授研究员级高级工程师 1267 | 生产材料控制科主管 1268 | 汽车北站副站长 1269 | 外贸部经理 1270 | 审计部部长 1271 | 技术室副主任 1272 | 技术总监 1273 | 第二届监事会监事 1274 | 太平绅士 1275 | 北京市海淀区十五届人大代表 1276 | 总飞行师 1277 | 第一届董事会董事会秘书 1278 | 干果业务部经理 1279 | 财务管理部部长 1280 | 海外事业部副总经理 1281 | 人事处副处长 1282 | 小型机部软件工程师 1283 | 理论教育干部 1284 | 我国第一台微机保护研制者 1285 | 报社社长 1286 | 生产处长 1287 | 总经理 1288 | 第三研究室副主任 1289 | 主任助理 1290 | 廊坊发展董事长 1291 | 会计科副科长 1292 | 木工部经理 1293 | 审计委员会秘书长 1294 | 审计监察部经理 1295 | 亚洲区总经理 1296 | 投资部总监 1297 | 主任律师 1298 | 内审司副司长 1299 | 博士后管理办公室主任 1300 | 美国注册会计师 1301 | 设备管理部部长 1302 | 第三届监事会监事 1303 | 法律顾问室主任 1304 | 二级律师 1305 | 市场营销系主任 1306 | 治理与证券业务经理 1307 | 设计所副所长 1308 | 片剂车间主任 1309 | 国际业务部经理 1310 | 执业律师 1311 | 项目管理研究中心主任 1312 | 938分厂党支部书记 1313 | 财务处核算主管 1314 | 代理厂长 1315 | 金融系教授 1316 | 科长 1317 | 工程部经理 1318 | 高级会计师 1319 | 项目物资处技术员 1320 | 总法律顾问 1321 | 第一届、第二届董事会独立董事 1322 | 组织部部长 1323 | 法务审计部副经理 1324 | 项目部副总经理 1325 | 针织部副经理 1326 | 研究所所长 1327 | 预决算处处长 1328 | 第二届独立董事 1329 | 财务主管 1330 | 计划财务部高级主管 1331 | 销售处技术员 1332 | 投资经营部副部长 1333 | 主管工程师 1334 | 副主任会计师 1335 | 基建科、财务科会计 1336 | 力源应用服务董事 1337 | 人力资源部处长 1338 | 厂长 1339 | 设总 1340 | 生产机动部主任 1341 | 财务部总经理 1342 | 审计部主任 1343 | 秘书 1344 | 专家学术委员会副主任 1345 | 技术科长 1346 | 评委 1347 | 高级物流师 1348 | 立法小组成员 1349 | 捆扎事业部总经理 1350 | 资产经营部副主任 1351 | 股改部副经理 1352 | 企业规划部副总经理 1353 | 常务副会长 1354 | 安徽省优秀军转干部 1355 | 董事会秘书室主任 1356 | 常务副站长 1357 | 业务一部总经理 1358 | 技术委员会主任 1359 | 办事员 1360 | 战士 1361 | 财审部主任助理 1362 | 中国注册资产评估师 1363 | 司法会计鉴定人 1364 | 统计员 1365 | 英国及香港执业会计师 1366 | 财务处科长 1367 | 粮油食品事业部副总经理 1368 | 副总经理 1369 | 团副政委 1370 | 秘书长 1371 | 教授级高级工程师 1372 | 企业管理专业教授 1373 | 董事副总裁 1374 | 常务副院长 1375 | 副部长 1376 | 计财科副科长 1377 | 硕士生导师 1378 | 局长秘书 1379 | 科级组织员 1380 | 专家组专家 1381 | 副主任委员 1382 | 第一届监事会负责人 1383 | 生产制造部经理 1384 | 评估师 1385 | 工委会主席 1386 | 营销总监 1387 | 大队长 1388 | 锯片事业部技术科工程师 1389 | 工会专职干事 1390 | 投资部副总经理 1391 | 资金部经理 1392 | 监事长 1393 | 购物广场男装商场商品部主管 1394 | 会计顾问处副主任科员 1395 | 企业管理处处长 1396 | 监事会办公室副主任 1397 | 厅长 1398 | 企业管理处副处长 1399 | 财务部综合分析组主管 1400 | 国际业务部业务主任 1401 | 副总裁 1402 | 股权管理一部项目经理 1403 | 摩托车部副总经理 1404 | 质量检查员 1405 | 副司局级助理巡视员 1406 | 英女皇颁授荣誉奖章 1407 | 广鹿分公司经理 1408 | 投资发展部项目经理 1409 | 香港注册税务师 1410 | 教授 1411 | 注册咨询工程师 1412 | 经济学博士后 1413 | 质量管理部部长 1414 | 教师 1415 | 研究部副总经理 1416 | 系主任 1417 | 法律专业人士 1418 | 董事会秘书长 1419 | 董事经理 1420 | 投资经营部资产经营处副处长 1421 | 营长 1422 | 工业企业出纳 1423 | 企业管理与市场营销学系系主任 1424 | 会计系主任 1425 | 晋华宫矿工人 1426 | 第一工程管理处施工员 1427 | 地方立法咨询专家库成员 1428 | 资金运营部高级副总裁 1429 | 教授级高级会计师 1430 | 管理咨询部高级经理 1431 | 电视台台长 1432 | 战略投资总监 1433 | 大中华区销售总经理 1434 | 西北地区经理 1435 | 审计 1436 | 医师 1437 | 财务处处长 1438 | 资产证券部部长 1439 | 法律审计处处长 1440 | 博士后 1441 | 河北省人大代表 1442 | 企划科科长 1443 | 正处级 1444 | 总审计师 1445 | 第十届全国政协委员 1446 | 商贸管理总部总经理 1447 | 评估员 1448 | 论证发起人 1449 | 北方销售区总经理 1450 | 风险管理部高级业务经理 1451 | 内控审计部总监 1452 | 技术中心主任 1453 | 锯片事业部技术科科长 1454 | 技术部副部长 1455 | 独立董事 1456 | 行政总监 1457 | 事业部常务副总经理 1458 | 商贸财务处办事员 1459 | 主任编辑 1460 | 经济学副教授 1461 | 董事会独立非执行董事 1462 | 贸易中心财务部副经理 1463 | 植保室主任 1464 | 政法委书记 1465 | 亚太区消费金融业务和银行卡业务总裁 1466 | 技术员 1467 | 财务部部长 1468 | 金融教材编委会委员 1469 | 指挥长 1470 | 财务处会计 1471 | 战略发展部部长 1472 | 融资部董事 1473 | 金融学教授 1474 | 财务部经理助理 1475 | 技术支持工程师 1476 | 安全中心总监 1477 | 个人金融部副经理 1478 | 亚太区首席执行官 1479 | 中共预备党员 1480 | 运营总裁 1481 | CDM项目办公室主任 1482 | 证券投资部部长 1483 | 顾问机构总经理 1484 | 助教 1485 | 锯片事业部部长 1486 | 访问学者 1487 | 生产机动部部长 1488 | 副会长 1489 | 名誉所长 1490 | 咨询专家 1491 | 兼职律师 1492 | 铝业务处业务经理 1493 | 财会处副处长 1494 | 财务科会计 1495 | 监察室副主任 1496 | 质量总监 1497 | 超市事业部副总经理 1498 | 正处级秘书 1499 | 分党组成员 1500 | 生产处处长 1501 | 财务部助理 1502 | 一司银行二处处长 1503 | 拉美运营和技术部门的负责人 1504 | 购物广场女装商场商品部主管 1505 | 会议处主任科员 1506 | 战略策划部经理 1507 | 组织宣传股干事 1508 | 质量处处长 1509 | 工程技术部经理 1510 | 第三届董事会董事 1511 | 会士 1512 | 规划与市场部主任 1513 | 董事会秘书处副主任 1514 | 主任科员 1515 | 第三届董事会成员 1516 | 经济师 1517 | 稽核总部经理 1518 | 工程中心主任 1519 | 部门副总经理 1520 | 国际经贸处副处长 1521 | 发展规划局局长 1522 | 综合管理部主管 1523 | 销售部经理 1524 | 信贷部经理 1525 | 研发部电视设计工程师 1526 | 下属企业劳资主管 1527 | 安徽省芜湖市人大代表 1528 | 华北销售区经理 1529 | 项目负责人 1530 | 裸线车间主任 1531 | 行政科科长 1532 | 会计学硕士生导师 1533 | 董事会办公室主任 1534 | 副主席 1535 | 冻干车间筹建组组长 1536 | 建立现代企业制度办公室主任 1537 | 讲师 1538 | 新产品开发部总监 1539 | 研发部经理 1540 | 企管办主任 1541 | 博士指导委员会委员 1542 | 语文教研员 1543 | 兼职教授 1544 | 首席战略官 1545 | 外办主任 1546 | 财务总监助理 1547 | 董事局执行董事 1548 | 初级会计师 1549 | 物流部经理 1550 | 纪检监察审计部副部长 1551 | 总经办主任 1552 | 宣传部副部长 1553 | 生产业务部部长助理 1554 | 公共及国际业务总经理 1555 | 大校 1556 | 企业管理访问学者 1557 | 财务处副处长 1558 | 审计法规处处长助理 1559 | 研究生 1560 | 政工师 1561 | 人力资源主管 1562 | 第六、七、八届监事会主席 1563 | 热管车间工段长 1564 | 宣传干事 1565 | 副行长 1566 | 机动能源部主任 1567 | 营销中心副主任 1568 | 学术委员会主任 1569 | 部长 1570 | 注册纳税筹划师 1571 | 国家注册咨询工程师(投资) 1572 | 生物工程系主任 1573 | 财务预算部部长 1574 | 销售总经理 1575 | 稽核司副处长 1576 | 首席分析师 1577 | 资深合伙人 1578 | 营运总裁 1579 | 开发部主任 1580 | 注册房地产估价师 1581 | 管理系党支部书记 1582 | ISO/TC122/SC4工作组国际专家 1583 | 发行部高级经理 1584 | 法律部主任 1585 | 审核(审计)委员会委员 1586 | 法律办主任 1587 | 风电事业部总经理 1588 | 编辑 1589 | 顾问委员会主任 1590 | 企管部部长 1591 | 执行总裁 1592 | 投资部项目经理 1593 | 首席代表 1594 | 高级软件工程师 1595 | 机务科计划员 1596 | 市场部部长 --------------------------------------------------------------------------------