{ "cells": [ { "cell_type": "markdown", "id": "96fe094792f58dd", "metadata": { "collapsed": false }, "source": "### Bert NER 实体抽取任务" }, { "metadata": { "ExecuteTime": { "end_time": "2024-05-04T00:58:02.895669Z", "start_time": "2024-05-04T00:57:57.087195Z" } }, "cell_type": "code", "source": [ "# 导入库\n", "import os\n", "import json\n", "import torch\n", "import pandas as pd\n", "from transformers import BertTokenizerFast\n", "from torch.utils.data import random_split" ], "id": "4e550f849189dddc", "outputs": [], "execution_count": 1 }, { "metadata": { "ExecuteTime": { "end_time": "2024-05-04T00:58:03.208869Z", "start_time": "2024-05-04T00:58:02.897660Z" } }, "cell_type": "code", "source": "from utils import BertNerModel", "id": "356a053dd45cc273", "outputs": [], "execution_count": 2 }, { "metadata": { "ExecuteTime": { "end_time": "2024-05-04T00:58:03.224827Z", "start_time": "2024-05-04T00:58:03.210824Z" } }, "cell_type": "code", "source": [ "# 设置量\n", "count = None # 训练量 None 为所有" ], "id": "ad119d35690af359", "outputs": [], "execution_count": 3 }, { "cell_type": "code", "id": "8dcccc45da68749f", "metadata": { "collapsed": false, "ExecuteTime": { "end_time": "2024-05-04T00:58:03.286621Z", "start_time": "2024-05-04T00:58:03.228777Z" } }, "source": [ "# 判断GPU\n", "use_cuda = torch.cuda.is_available()\n", "use_cuda" ], "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "execution_count": 4 }, { "cell_type": "code", "id": "ba07c141b60de27f", "metadata": { "collapsed": false, "ExecuteTime": { "end_time": "2024-05-04T00:58:13.503308Z", "start_time": "2024-05-04T00:58:03.287621Z" } }, "source": [ "# 读取文件\n", "# 训练集\n", "train_data = []\n", "# 遍历当前dataset文件夹下文件\n", "current_directory = os.getcwd() + '\\\\data_set'\n", "for file_name in os.listdir(current_directory):\n", " # 拼接文件的完整路径\n", " file_path = os.path.join(current_directory, file_name)\n", " # 检查是否为文件\n", " if os.path.isfile(file_path):\n", " with open(file_path, 'r', encoding='utf-8') as f:\n", " for i in f:\n", " train_data.append(json.loads(i))\n", "# 转换为pandas引用\n", "train_data = pd.DataFrame(train_data)" ], "outputs": [], "execution_count": 5 }, { "cell_type": "code", "source": [ "if not count is None:\n", " train_data = train_data.head(count)" ], "metadata": { "collapsed": false, "ExecuteTime": { "end_time": "2024-05-04T00:58:13.519266Z", "start_time": "2024-05-04T00:58:13.506301Z" } }, "id": "4b0b50a97cb77f2c", "outputs": [], "execution_count": 6 }, { "cell_type": "code", "id": "dbf7e0655d319da7", "metadata": { "collapsed": false, "ExecuteTime": { "end_time": "2024-05-04T00:58:13.550183Z", "start_time": "2024-05-04T00:58:13.521262Z" } }, "source": [ "train_data.head(5)" ], "outputs": [ { "data": { "text/plain": [ " text \\\n", "0 交行14年用过,半年准备提额,却直接被降到1K,半年期间只T过一次三千,其它全部真实消费,第... \n", "1 单标我有了,最近visa双标返现活动好 \n", "2 建设银行提额很慢的…… \n", "3 孙女士在原恒泰农村合作银行存入50万元,同年9月又存款50万元。2014年,恒泰农村合作银行... \n", "4 我的怎么显示0.25费率,而且不管分多少期都一样费率,可惜只有69k \n", "\n", " labels \n", "0 [B-BANK, I-BANK, O, O, O, O, O, O, O, O, O, O,... \n", "1 [B-PRODUCT, I-PRODUCT, O, O, O, O, O, O, B-PRO... \n", "2 [B-BANK, I-BANK, I-BANK, I-BANK, B-COMMENTS_N,... \n", "3 [O, O, O, O, O, B-BANK, I-BANK, I-BANK, I-BANK... \n", "4 [O, O, O, O, O, O, O, O, O, O, B-COMMENTS_N, I... " ], "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
textlabels
0交行14年用过,半年准备提额,却直接被降到1K,半年期间只T过一次三千,其它全部真实消费,第...[B-BANK, I-BANK, O, O, O, O, O, O, O, O, O, O,...
1单标我有了,最近visa双标返现活动好[B-PRODUCT, I-PRODUCT, O, O, O, O, O, O, B-PRO...
2建设银行提额很慢的……[B-BANK, I-BANK, I-BANK, I-BANK, B-COMMENTS_N,...
3孙女士在原恒泰农村合作银行存入50万元,同年9月又存款50万元。2014年,恒泰农村合作银行...[O, O, O, O, O, B-BANK, I-BANK, I-BANK, I-BANK...
4我的怎么显示0.25费率,而且不管分多少期都一样费率,可惜只有69k[O, O, O, O, O, O, O, O, O, O, B-COMMENTS_N, I...
\n", "
" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "execution_count": 7 }, { "metadata": { "ExecuteTime": { "end_time": "2024-05-04T00:58:19.113339Z", "start_time": "2024-05-04T00:58:13.552180Z" } }, "cell_type": "code", "source": [ "# 增加新标签\n", "def add_new_lable(lable: list) -> list:\n", " compare_lable = lable[1:] + ['O']\n", " count = 0\n", " for i, j in zip(lable, compare_lable):\n", " if i[0] == 'I' and j == 'O':\n", " lable[count] = 'E' + i[1:]\n", " count += 1\n", " return lable\n", "\n", "train_data['labels'] = train_data['labels'].apply(add_new_lable)" ], "id": "5b03d12714b45347", "outputs": [], "execution_count": 8 }, { "metadata": { "ExecuteTime": { "end_time": "2024-05-04T00:58:32.947178Z", "start_time": "2024-05-04T00:58:19.114338Z" } }, "cell_type": "code", "source": [ "# 替换标签\n", "def change_basic_lable(lable: list) -> list:\n", " r_l =[i.split('.')[0] for i in lable]\n", " return [i if i[0] != 'S' else 'B' + i[1:] for i in r_l]\n", "\n", "train_data['labels'] = train_data['labels'].apply(change_basic_lable)" ], "id": "49f644953db48653", "outputs": [], "execution_count": 9 }, { "metadata": { "ExecuteTime": { "end_time": "2024-05-04T00:58:32.962140Z", "start_time": "2024-05-04T00:58:32.949174Z" } }, "cell_type": "code", "source": "train_data.head(5)", "id": "a699748ab7ffea01", "outputs": [ { "data": { "text/plain": [ " text \\\n", "0 交行14年用过,半年准备提额,却直接被降到1K,半年期间只T过一次三千,其它全部真实消费,第... \n", "1 单标我有了,最近visa双标返现活动好 \n", "2 建设银行提额很慢的…… \n", "3 孙女士在原恒泰农村合作银行存入50万元,同年9月又存款50万元。2014年,恒泰农村合作银行... \n", "4 我的怎么显示0.25费率,而且不管分多少期都一样费率,可惜只有69k \n", "\n", " labels \n", "0 [B-BANK, E-BANK, O, O, O, O, O, O, O, O, O, O,... \n", "1 [B-PRODUCT, E-PRODUCT, O, O, O, O, O, O, B-PRO... \n", "2 [B-BANK, I-BANK, I-BANK, I-BANK, B-COMMENTS_N,... \n", "3 [O, O, O, O, O, B-BANK, I-BANK, I-BANK, I-BANK... \n", "4 [O, O, O, O, O, O, O, O, O, O, B-COMMENTS_N, E... " ], "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
textlabels
0交行14年用过,半年准备提额,却直接被降到1K,半年期间只T过一次三千,其它全部真实消费,第...[B-BANK, E-BANK, O, O, O, O, O, O, O, O, O, O,...
1单标我有了,最近visa双标返现活动好[B-PRODUCT, E-PRODUCT, O, O, O, O, O, O, B-PRO...
2建设银行提额很慢的……[B-BANK, I-BANK, I-BANK, I-BANK, B-COMMENTS_N,...
3孙女士在原恒泰农村合作银行存入50万元,同年9月又存款50万元。2014年,恒泰农村合作银行...[O, O, O, O, O, B-BANK, I-BANK, I-BANK, I-BANK...
4我的怎么显示0.25费率,而且不管分多少期都一样费率,可惜只有69k[O, O, O, O, O, O, O, O, O, O, B-COMMENTS_N, E...
\n", "
" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "execution_count": 10 }, { "metadata": { "ExecuteTime": { "end_time": "2024-05-04T00:58:32.978098Z", "start_time": "2024-05-04T00:58:32.964134Z" } }, "cell_type": "code", "source": "len(train_data)", "id": "293089e6a0661b19", "outputs": [ { "data": { "text/plain": [ "581738" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "execution_count": 11 }, { "cell_type": "code", "source": [ "# 切分数据集\n", "train_split, test_split = random_split(train_data.values, [0.7, 0.3])\n", "train_split, test_split = pd.DataFrame(list(train_split), columns=list(train_data.columns)), pd.DataFrame(list(test_split), columns=list(train_data.columns))" ], "metadata": { "collapsed": false, "ExecuteTime": { "end_time": "2024-05-04T00:58:36.137397Z", "start_time": "2024-05-04T00:58:32.980092Z" } }, "id": "5c1b76f5cbeae3b0", "outputs": [], "execution_count": 12 }, { "cell_type": "code", "source": [ "test_split.head()" ], "metadata": { "collapsed": false, "ExecuteTime": { "end_time": "2024-05-04T00:58:36.168309Z", "start_time": "2024-05-04T00:58:36.140384Z" } }, "id": "d9fda96d7eb8fb3", "outputs": [ { "data": { "text/plain": [ " text \\\n", "0 据中新网能源频道了解,截至1月8日,卓创资讯监测原油变化率为-0.65%,依此变化率累加上次... \n", "1 虽然我们城市化现在每年以一个百分点的速度在这个,这个城市化的规模在扩张, \n", "2 回想起它的味道,比小樱桃还要可口!它那“大大”的核还可以用作竹枪的子弹,竹枪是用细细的竹枝做... \n", "3 2017新款厚底凉鞋女夏松糕底韩版休闲百搭真皮罗马欧洲站摇摇鞋潮 \n", "4 根据连续不间断对梁体和立柱位移的监测数据表明,目前桥梁各重要监控指标稳定,未见病害进一步发展趋势。 \n", "\n", " labels \n", "0 [O, O, O, O, O, O, O, O, O, O, O, O, O, B-T, I... \n", "1 [O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, ... \n", "2 [O, O, O, B-Thing, O, O, O, O, O, O, B-Thing, ... \n", "3 [O, O, O, O, O, O, O, O, B-HCCX, E-HCCX, O, O,... \n", "4 [O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, ... " ], "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
textlabels
0据中新网能源频道了解,截至1月8日,卓创资讯监测原油变化率为-0.65%,依此变化率累加上次...[O, O, O, O, O, O, O, O, O, O, O, O, O, B-T, I...
1虽然我们城市化现在每年以一个百分点的速度在这个,这个城市化的规模在扩张,[O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, ...
2回想起它的味道,比小樱桃还要可口!它那“大大”的核还可以用作竹枪的子弹,竹枪是用细细的竹枝做...[O, O, O, B-Thing, O, O, O, O, O, O, B-Thing, ...
32017新款厚底凉鞋女夏松糕底韩版休闲百搭真皮罗马欧洲站摇摇鞋潮[O, O, O, O, O, O, O, O, B-HCCX, E-HCCX, O, O,...
4根据连续不间断对梁体和立柱位移的监测数据表明,目前桥梁各重要监控指标稳定,未见病害进一步发展趋势。[O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, ...
\n", "
" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "execution_count": 13 }, { "cell_type": "code", "source": [ "# 提取所有的labels类型\n", "labels = []\n", "for i in train_data.labels:\n", " for k in i:\n", " if k not in labels:\n", " labels.append(k)\n", "labels" ], "metadata": { "collapsed": false, "ExecuteTime": { "end_time": "2024-05-04T00:58:46.249289Z", "start_time": "2024-05-04T00:58:36.170304Z" } }, "id": "a1cbd4f9e9a0325e", "outputs": [ { "data": { "text/plain": [ "['B-BANK',\n", " 'E-BANK',\n", " 'O',\n", " 'B-COMMENTS_N',\n", " 'E-COMMENTS_N',\n", " 'B-COMMENTS_ADJ',\n", " 'E-COMMENTS_ADJ',\n", " 'B-PRODUCT',\n", " 'E-PRODUCT',\n", " 'I-PRODUCT',\n", " 'I-COMMENTS_N',\n", " 'I-BANK',\n", " 'I-COMMENTS_ADJ',\n", " 'B-product_name',\n", " 'I-product_name',\n", " 'B-time',\n", " 'I-time',\n", " 'E-time',\n", " 'B-person_name',\n", " 'I-person_name',\n", " 'E-person_name',\n", " 'E-product_name',\n", " 'B-org_name',\n", " 'I-org_name',\n", " 'E-org_name',\n", " 'B-location',\n", " 'I-location',\n", " 'E-location',\n", " 'B-company_name',\n", " 'I-company_name',\n", " 'E-company_name',\n", " 'B-GPE',\n", " 'I-GPE',\n", " 'E-GPE',\n", " 'B-PER',\n", " 'I-PER',\n", " 'E-PER',\n", " 'B-LOC',\n", " 'I-LOC',\n", " 'E-LOC',\n", " 'B-ORG',\n", " 'I-ORG',\n", " 'E-ORG',\n", " 'B-body',\n", " 'E-body',\n", " 'I-body',\n", " 'B-symp',\n", " 'E-symp',\n", " 'I-symp',\n", " 'B-chec',\n", " 'E-chec',\n", " 'I-chec',\n", " 'B-dise',\n", " 'I-dise',\n", " 'E-dise',\n", " 'B-cure',\n", " 'I-cure',\n", " 'E-cure',\n", " 'B-身体部位',\n", " 'I-身体部位',\n", " 'B-检查和检验',\n", " 'E-检查和检验',\n", " 'I-检查和检验',\n", " 'E-身体部位',\n", " 'B-症状和体征',\n", " 'E-症状和体征',\n", " 'I-症状和体征',\n", " 'B-疾病和诊断',\n", " 'I-疾病和诊断',\n", " 'E-疾病和诊断',\n", " 'B-治疗',\n", " 'I-治疗',\n", " 'E-治疗',\n", " 'B-解剖部位',\n", " 'E-解剖部位',\n", " 'B-手术',\n", " 'I-手术',\n", " 'E-手术',\n", " 'B-影像检查',\n", " 'E-影像检查',\n", " 'I-解剖部位',\n", " 'B-药物',\n", " 'E-药物',\n", " 'I-药物',\n", " 'B-实验室检验',\n", " 'I-实验室检验',\n", " 'E-实验室检验',\n", " 'I-影像检查',\n", " 'B-name',\n", " 'I-name',\n", " 'E-name',\n", " 'B-address',\n", " 'E-address',\n", " 'B-organization',\n", " 'E-organization',\n", " 'B-game',\n", " 'I-game',\n", " 'E-game',\n", " 'I-address',\n", " 'B-scene',\n", " 'I-scene',\n", " 'E-scene',\n", " 'B-book',\n", " 'I-book',\n", " 'E-book',\n", " 'I-organization',\n", " 'B-company',\n", " 'I-company',\n", " 'E-company',\n", " 'B-position',\n", " 'E-position',\n", " 'I-position',\n", " 'B-government',\n", " 'I-government',\n", " 'E-government',\n", " 'B-movie',\n", " 'I-movie',\n", " 'E-movie',\n", " 'B-bod',\n", " 'I-bod',\n", " 'E-bod',\n", " 'B-dis',\n", " 'I-dis',\n", " 'E-dis',\n", " 'B-sym',\n", " 'I-sym',\n", " 'E-sym',\n", " 'B-pro',\n", " 'I-pro',\n", " 'E-pro',\n", " 'B-ite',\n", " 'I-ite',\n", " 'E-ite',\n", " 'B-mic',\n", " 'I-mic',\n", " 'E-mic',\n", " 'B-dep',\n", " 'E-dep',\n", " 'B-dru',\n", " 'I-dru',\n", " 'E-dru',\n", " 'I-dep',\n", " 'B-equ',\n", " 'I-equ',\n", " 'E-equ',\n", " 'B-Time',\n", " 'I-Time',\n", " 'E-Time',\n", " 'B-Person',\n", " 'B-Location',\n", " 'I-Location',\n", " 'E-Location',\n", " 'E-Person',\n", " 'B-Thing',\n", " 'E-Thing',\n", " 'B-Metric',\n", " 'E-Metric',\n", " 'I-Person',\n", " 'I-Thing',\n", " 'B-Organization',\n", " 'I-Organization',\n", " 'E-Organization',\n", " 'I-Metric',\n", " 'B-Abstract',\n", " 'I-Abstract',\n", " 'E-Abstract',\n", " 'B-Physical',\n", " 'I-Physical',\n", " 'E-Physical',\n", " 'B-Term',\n", " 'I-Term',\n", " 'E-Term',\n", " 'B-ABstract',\n", " 'I-ABstract',\n", " 'E-ABstract',\n", " 'B-HCCX',\n", " 'E-HCCX',\n", " 'I-HCCX',\n", " 'B-MISC',\n", " 'E-MISC',\n", " 'B-HPPX',\n", " 'E-HPPX',\n", " 'I-HPPX',\n", " 'I-MISC',\n", " 'B-XH',\n", " 'I-XH',\n", " 'E-XH',\n", " 'B-EQU',\n", " 'I-EQU',\n", " 'E-EQU',\n", " 'B-TIME',\n", " 'E-TIME',\n", " 'I-TIME',\n", " 'B-FAC',\n", " 'I-FAC',\n", " 'E-FAC',\n", " 'B-Symptom',\n", " 'E-Symptom',\n", " 'B-Medical_Examination',\n", " 'E-Medical_Examination',\n", " 'I-Medical_Examination',\n", " 'B-Drug',\n", " 'I-Drug',\n", " 'E-Drug',\n", " 'B-Drug_Category',\n", " 'I-Drug_Category',\n", " 'E-Drug_Category',\n", " 'I-Symptom',\n", " 'B-Operation',\n", " 'E-Operation',\n", " 'I-Operation',\n", " 'B-NAME',\n", " 'I-NAME',\n", " 'E-NAME',\n", " 'B-CONT',\n", " 'I-CONT',\n", " 'E-CONT',\n", " 'B-EDU',\n", " 'I-EDU',\n", " 'E-EDU',\n", " 'B-TITLE',\n", " 'I-TITLE',\n", " 'E-TITLE',\n", " 'B-RACE',\n", " 'E-RACE',\n", " 'B-PRO',\n", " 'I-PRO',\n", " 'E-PRO',\n", " 'I-RACE',\n", " 'B-T',\n", " 'I-T',\n", " 'E-T']" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "execution_count": 14 }, { "cell_type": "code", "source": [ "# 转换标签字典\n", "label_dict = {i: j for i,j in zip(labels, range(len(labels)))}\n", "label_dict" ], "metadata": { "collapsed": false, "ExecuteTime": { "end_time": "2024-05-04T00:58:46.265245Z", "start_time": "2024-05-04T00:58:46.250285Z" } }, "id": "da46e04a666a54d9", "outputs": [ { "data": { "text/plain": [ "{'B-BANK': 0,\n", " 'E-BANK': 1,\n", " 'O': 2,\n", " 'B-COMMENTS_N': 3,\n", " 'E-COMMENTS_N': 4,\n", " 'B-COMMENTS_ADJ': 5,\n", " 'E-COMMENTS_ADJ': 6,\n", " 'B-PRODUCT': 7,\n", " 'E-PRODUCT': 8,\n", " 'I-PRODUCT': 9,\n", " 'I-COMMENTS_N': 10,\n", " 'I-BANK': 11,\n", " 'I-COMMENTS_ADJ': 12,\n", " 'B-product_name': 13,\n", " 'I-product_name': 14,\n", " 'B-time': 15,\n", " 'I-time': 16,\n", " 'E-time': 17,\n", " 'B-person_name': 18,\n", " 'I-person_name': 19,\n", " 'E-person_name': 20,\n", " 'E-product_name': 21,\n", " 'B-org_name': 22,\n", " 'I-org_name': 23,\n", " 'E-org_name': 24,\n", " 'B-location': 25,\n", " 'I-location': 26,\n", " 'E-location': 27,\n", " 'B-company_name': 28,\n", " 'I-company_name': 29,\n", " 'E-company_name': 30,\n", " 'B-GPE': 31,\n", " 'I-GPE': 32,\n", " 'E-GPE': 33,\n", " 'B-PER': 34,\n", " 'I-PER': 35,\n", " 'E-PER': 36,\n", " 'B-LOC': 37,\n", " 'I-LOC': 38,\n", " 'E-LOC': 39,\n", " 'B-ORG': 40,\n", " 'I-ORG': 41,\n", " 'E-ORG': 42,\n", " 'B-body': 43,\n", " 'E-body': 44,\n", " 'I-body': 45,\n", " 'B-symp': 46,\n", " 'E-symp': 47,\n", " 'I-symp': 48,\n", " 'B-chec': 49,\n", " 'E-chec': 50,\n", " 'I-chec': 51,\n", " 'B-dise': 52,\n", " 'I-dise': 53,\n", " 'E-dise': 54,\n", " 'B-cure': 55,\n", " 'I-cure': 56,\n", " 'E-cure': 57,\n", " 'B-身体部位': 58,\n", " 'I-身体部位': 59,\n", " 'B-检查和检验': 60,\n", " 'E-检查和检验': 61,\n", " 'I-检查和检验': 62,\n", " 'E-身体部位': 63,\n", " 'B-症状和体征': 64,\n", " 'E-症状和体征': 65,\n", " 'I-症状和体征': 66,\n", " 'B-疾病和诊断': 67,\n", " 'I-疾病和诊断': 68,\n", " 'E-疾病和诊断': 69,\n", " 'B-治疗': 70,\n", " 'I-治疗': 71,\n", " 'E-治疗': 72,\n", " 'B-解剖部位': 73,\n", " 'E-解剖部位': 74,\n", " 'B-手术': 75,\n", " 'I-手术': 76,\n", " 'E-手术': 77,\n", " 'B-影像检查': 78,\n", " 'E-影像检查': 79,\n", " 'I-解剖部位': 80,\n", " 'B-药物': 81,\n", " 'E-药物': 82,\n", " 'I-药物': 83,\n", " 'B-实验室检验': 84,\n", " 'I-实验室检验': 85,\n", " 'E-实验室检验': 86,\n", " 'I-影像检查': 87,\n", " 'B-name': 88,\n", " 'I-name': 89,\n", " 'E-name': 90,\n", " 'B-address': 91,\n", " 'E-address': 92,\n", " 'B-organization': 93,\n", " 'E-organization': 94,\n", " 'B-game': 95,\n", " 'I-game': 96,\n", " 'E-game': 97,\n", " 'I-address': 98,\n", " 'B-scene': 99,\n", " 'I-scene': 100,\n", " 'E-scene': 101,\n", " 'B-book': 102,\n", " 'I-book': 103,\n", " 'E-book': 104,\n", " 'I-organization': 105,\n", " 'B-company': 106,\n", " 'I-company': 107,\n", " 'E-company': 108,\n", " 'B-position': 109,\n", " 'E-position': 110,\n", " 'I-position': 111,\n", " 'B-government': 112,\n", " 'I-government': 113,\n", " 'E-government': 114,\n", " 'B-movie': 115,\n", " 'I-movie': 116,\n", " 'E-movie': 117,\n", " 'B-bod': 118,\n", " 'I-bod': 119,\n", " 'E-bod': 120,\n", " 'B-dis': 121,\n", " 'I-dis': 122,\n", " 'E-dis': 123,\n", " 'B-sym': 124,\n", " 'I-sym': 125,\n", " 'E-sym': 126,\n", " 'B-pro': 127,\n", " 'I-pro': 128,\n", " 'E-pro': 129,\n", " 'B-ite': 130,\n", " 'I-ite': 131,\n", " 'E-ite': 132,\n", " 'B-mic': 133,\n", " 'I-mic': 134,\n", " 'E-mic': 135,\n", " 'B-dep': 136,\n", " 'E-dep': 137,\n", " 'B-dru': 138,\n", " 'I-dru': 139,\n", " 'E-dru': 140,\n", " 'I-dep': 141,\n", " 'B-equ': 142,\n", " 'I-equ': 143,\n", " 'E-equ': 144,\n", " 'B-Time': 145,\n", " 'I-Time': 146,\n", " 'E-Time': 147,\n", " 'B-Person': 148,\n", " 'B-Location': 149,\n", " 'I-Location': 150,\n", " 'E-Location': 151,\n", " 'E-Person': 152,\n", " 'B-Thing': 153,\n", " 'E-Thing': 154,\n", " 'B-Metric': 155,\n", " 'E-Metric': 156,\n", " 'I-Person': 157,\n", " 'I-Thing': 158,\n", " 'B-Organization': 159,\n", " 'I-Organization': 160,\n", " 'E-Organization': 161,\n", " 'I-Metric': 162,\n", " 'B-Abstract': 163,\n", " 'I-Abstract': 164,\n", " 'E-Abstract': 165,\n", " 'B-Physical': 166,\n", " 'I-Physical': 167,\n", " 'E-Physical': 168,\n", " 'B-Term': 169,\n", " 'I-Term': 170,\n", " 'E-Term': 171,\n", " 'B-ABstract': 172,\n", " 'I-ABstract': 173,\n", " 'E-ABstract': 174,\n", " 'B-HCCX': 175,\n", " 'E-HCCX': 176,\n", " 'I-HCCX': 177,\n", " 'B-MISC': 178,\n", " 'E-MISC': 179,\n", " 'B-HPPX': 180,\n", " 'E-HPPX': 181,\n", " 'I-HPPX': 182,\n", " 'I-MISC': 183,\n", " 'B-XH': 184,\n", " 'I-XH': 185,\n", " 'E-XH': 186,\n", " 'B-EQU': 187,\n", " 'I-EQU': 188,\n", " 'E-EQU': 189,\n", " 'B-TIME': 190,\n", " 'E-TIME': 191,\n", " 'I-TIME': 192,\n", " 'B-FAC': 193,\n", " 'I-FAC': 194,\n", " 'E-FAC': 195,\n", " 'B-Symptom': 196,\n", " 'E-Symptom': 197,\n", " 'B-Medical_Examination': 198,\n", " 'E-Medical_Examination': 199,\n", " 'I-Medical_Examination': 200,\n", " 'B-Drug': 201,\n", " 'I-Drug': 202,\n", " 'E-Drug': 203,\n", " 'B-Drug_Category': 204,\n", " 'I-Drug_Category': 205,\n", " 'E-Drug_Category': 206,\n", " 'I-Symptom': 207,\n", " 'B-Operation': 208,\n", " 'E-Operation': 209,\n", " 'I-Operation': 210,\n", " 'B-NAME': 211,\n", " 'I-NAME': 212,\n", " 'E-NAME': 213,\n", " 'B-CONT': 214,\n", " 'I-CONT': 215,\n", " 'E-CONT': 216,\n", " 'B-EDU': 217,\n", " 'I-EDU': 218,\n", " 'E-EDU': 219,\n", " 'B-TITLE': 220,\n", " 'I-TITLE': 221,\n", " 'E-TITLE': 222,\n", " 'B-RACE': 223,\n", " 'E-RACE': 224,\n", " 'B-PRO': 225,\n", " 'I-PRO': 226,\n", " 'E-PRO': 227,\n", " 'I-RACE': 228,\n", " 'B-T': 229,\n", " 'I-T': 230,\n", " 'E-T': 231}" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "execution_count": 15 }, { "cell_type": "code", "source": [ "# 数据集构建\n", "class Dataset(torch.utils.data.Dataset):\n", " def __init__(self, df: pd.DataFrame, label_dict: dict):\n", " \"\"\"\n", " 数据集初始化\n", " :param: df 数据集标签\n", " :param: label_dict lable字典\n", " \"\"\"\n", " self.labels = None\n", " self.text = None\n", " self.df_label = None\n", " self.df_text = None\n", " self.label_all_tokens = None\n", " self.bert_token_model = None\n", " self.bert_length = None\n", " self.settings_init()\n", " self.df = df\n", " self.label_dict = label_dict\n", " self.tokenizer = BertTokenizerFast.from_pretrained(self.bert_token_model, do_lower_case=True)\n", " self.data_prepare()\n", " \n", " def settings_init(self):\n", " \"\"\"\n", " 设置 \n", " \"\"\"\n", " self.bert_length = 128 # bert统一长度设置\n", " self.bert_token_model = 'bert-base-chinese' # bert tokenizer 基于的模型, 最好基于本地\n", " self.label_all_tokens = True # 子词延续标签 True为子词提供相同标签 False为用-100做标签\n", " self.df_text = 'text' # 文本列名称\n", " self.df_label = 'labels' # 标签列名称\n", " \n", " def data_prepare(self):\n", " \"\"\"\n", " 数据预处理\n", " \"\"\"\n", " self.text = [self.tokenizer(i, padding='max_length', truncation=True, max_length=self.bert_length, return_tensors='pt') for i in self.df[self.df_text].values.tolist()]\n", " self.labels = [self.labels_id_together(j, k) for j, k in zip(self.text, self.df[self.df_label].values.tolist())]\n", " \n", " def labels_id_together(self, tk, labels: list) -> list :\n", " \"\"\"\n", " 对齐数据集 lables与新ids\n", " :param tk: 字段tokenize后标签\n", " :param labels: 标签\n", " :return: 转换后的lables标签\n", " \"\"\"\n", " word_ids = tk.word_ids()\n", " label_ids = []\n", " k = None\n", " step = 0\n", " for i in word_ids:\n", " if i is None:\n", " label_ids.append(-100)\n", " step += 1\n", " elif step == 0:\n", " label_ids.append(self.label_dict[labels[i]])\n", " k = i\n", " step += 1\n", " else:\n", " if self.label_all_tokens:\n", " label_ids.append(self.label_dict[labels[i]])\n", " else:\n", " if k == i:\n", " label_ids.append(-100)\n", " else:\n", " label_ids.append(self.label_dict[labels[i]])\n", " step += 1\n", " k = i\n", " return label_ids\n", " \n", " def __len__(self):\n", " return len(self.labels)\n", " \n", " def get_batch_text(self, idx):\n", " return self.text[idx]\n", " \n", " def get_batch_label(self, idx):\n", " return torch.LongTensor(self.labels[idx])\n", " \n", " def __getitem__(self, idx):\n", " return self.get_batch_text(idx), self.get_batch_label(idx)" ], "metadata": { "collapsed": false, "ExecuteTime": { "end_time": "2024-05-04T00:58:46.297164Z", "start_time": "2024-05-04T00:58:46.267240Z" } }, "id": "ea9bab41704b4921", "outputs": [], "execution_count": 16 }, { "cell_type": "code", "source": [ "from tqdm import tqdm\n", "from torch.optim.adamw import AdamW\n", "from torch.utils.data import DataLoader\n", "\n", "learning_rate = 5e-5\n", "epochs = 10\n", "batch_size = 256\n", "\n", "def train_loop(model, df_train, df_val):\n", " # 定义训练和验证集数据\n", " train_dataset = Dataset(df_train, label_dict)\n", " val_dataset = Dataset(df_val, label_dict)\n", " # 批量获取训练和验证集数据\n", " train_dataloader = DataLoader(train_dataset, num_workers=0, batch_size=batch_size, shuffle=True)\n", " val_dataloader = DataLoader(val_dataset, num_workers=0, batch_size=batch_size, shuffle=True)\n", " # 判断是否使用GPU,如果有,尽量使用,可以加快训练速度\n", " use_cuda = torch.cuda.is_available()\n", " device = torch.device(\"cuda\" if use_cuda else \"cpu\")\n", " # 定义优化器\n", " optimizer = AdamW(model.parameters(), lr=learning_rate)\n", "\n", " if use_cuda:\n", " model = model.cuda()\n", " \n", " # 开始训练循环\n", " best_acc = None\n", " best_loss = None\n", " best_val_loss = None\n", " best_val_acc = None\n", " best_model = None\n", " acc_list = []\n", " for epoch_num in range(epochs):\n", "\n", " total_acc_train = 0\n", " total_loss_train = 0\n", " # 训练模型S\n", " # 按批量循环训练模型\n", " for train_data, train_label in tqdm(train_dataloader):\n", " # 从train_data中获取mask和input_id\n", " train_label = train_label[0].to(device)\n", " mask = train_data['attention_mask'][0].to(device)\n", " input_id = train_data['input_ids'][0].to(device)\n", " # 梯度清零!!\n", " optimizer.zero_grad()\n", " # 输入模型训练结果:损失及分类概率\n", " loss, logits = model(input_id, mask, train_label)\n", " # 过滤掉特殊token及padding的token\n", " logits_clean = logits[0][train_label != -100]\n", " label_clean = train_label[train_label != -100]\n", " # 获取最大概率值\n", " predictions = logits_clean.argmax(dim=1)\n", " # 计算准确率\n", " acc = (predictions == label_clean).float().mean()\n", " total_acc_train += acc\n", " total_loss_train += loss.item()\n", " # 反向传递\n", " loss.backward()\n", " # 参数更新\n", " optimizer.step()\n", " # 模型评估\n", " model.eval()\n", "\n", " total_acc_val = 0\n", " total_loss_val = 0\n", " for val_data, val_label in val_dataloader:\n", " # 批量获取验证数据\n", " val_label = val_label[0].to(device)\n", " mask = val_data['attention_mask'][0].to(device)\n", " input_id = val_data['input_ids'][0].to(device)\n", " # 输出模型预测结果\n", " loss, logits = model(input_id, mask, val_label)\n", " # 清楚无效token对应的结果\n", " logits_clean = logits[0][val_label != -100]\n", " label_clean = val_label[val_label != -100]\n", " # 获取概率值最大的预测\n", " predictions = logits_clean.argmax(dim=1)\n", " # 计算精度\n", " acc = (predictions == label_clean).float().mean()\n", " total_acc_val += acc\n", " total_loss_val += loss.item()\n", "\n", " val_accuracy = total_acc_val / len(df_val)\n", " val_loss = total_loss_val / len(df_val)\n", " model_loss = total_loss_train / len(df_train)\n", " model_acc = total_acc_train / len(df_train)\n", "\n", " print(\n", " f'''Epochs: {epoch_num + 1} | \n", " Loss: {total_loss_train / len(df_train): .3f} | \n", " Accuracy: {total_acc_train / len(df_train): .3f} |\n", " Val_Loss: {total_loss_val / len(df_val): .3f} | \n", " Val_Accuracy: {total_acc_val / len(df_val): .3f}''')\n", " \n", " # 单次选优模型\n", " if best_model is None:\n", " best_loss = model_loss\n", " best_acc = model_acc\n", " best_val_loss = val_loss\n", " best_val_acc = val_accuracy\n", " best_model = model\n", " elif best_loss < model_loss and best_val_loss < val_loss:\n", " best_loss = model_loss\n", " best_acc = model_acc\n", " best_val_loss = val_loss\n", " best_val_acc = val_accuracy\n", " best_model = model\n", " \n", " # acc信息写入\n", " acc_list.append([epoch_num, model_loss, model_acc, val_loss, val_accuracy])\n", " return best_model, acc_list\n" ], "metadata": { "collapsed": false, "ExecuteTime": { "end_time": "2024-05-04T00:58:46.327082Z", "start_time": "2024-05-04T00:58:46.299156Z" } }, "id": "c12880f22af0ca8f", "outputs": [], "execution_count": 17 }, { "metadata": { "ExecuteTime": { "end_time": "2024-05-04T02:59:32.402667Z", "start_time": "2024-05-04T00:58:46.331069Z" } }, "cell_type": "code", "source": [ "model = BertNerModel(labels)\n", "model, info = train_loop(model, train_split, test_split)" ], "id": "1af8c7475035fe2", "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Some weights of BertForTokenClassification were not initialized from the model checkpoint at bert-base-chinese and are newly initialized: ['classifier.bias', 'classifier.weight']\n", "You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.\n", "100%|██████████| 1591/1591 [10:54<00:00, 2.43it/s]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epochs: 1 | \n", " Loss: 0.003 | \n", " Accuracy: 0.003 |\n", " Val_Loss: 0.003 | \n", " Val_Accuracy: 0.003\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "100%|██████████| 1591/1591 [10:54<00:00, 2.43it/s]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epochs: 2 | \n", " Loss: 0.002 | \n", " Accuracy: 0.003 |\n", " Val_Loss: 0.002 | \n", " Val_Accuracy: 0.003\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "100%|██████████| 1591/1591 [11:34<00:00, 2.29it/s]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epochs: 3 | \n", " Loss: 0.002 | \n", " Accuracy: 0.003 |\n", " Val_Loss: 0.002 | \n", " Val_Accuracy: 0.003\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "100%|██████████| 1591/1591 [10:36<00:00, 2.50it/s]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epochs: 4 | \n", " Loss: 0.002 | \n", " Accuracy: 0.003 |\n", " Val_Loss: 0.002 | \n", " Val_Accuracy: 0.003\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "100%|██████████| 1591/1591 [10:43<00:00, 2.47it/s]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epochs: 5 | \n", " Loss: 0.002 | \n", " Accuracy: 0.003 |\n", " Val_Loss: 0.002 | \n", " Val_Accuracy: 0.003\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "100%|██████████| 1591/1591 [11:39<00:00, 2.27it/s]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epochs: 6 | \n", " Loss: 0.002 | \n", " Accuracy: 0.003 |\n", " Val_Loss: 0.002 | \n", " Val_Accuracy: 0.003\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "100%|██████████| 1591/1591 [12:20<00:00, 2.15it/s]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epochs: 7 | \n", " Loss: 0.002 | \n", " Accuracy: 0.003 |\n", " Val_Loss: 0.002 | \n", " Val_Accuracy: 0.003\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "100%|██████████| 1591/1591 [11:25<00:00, 2.32it/s]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epochs: 8 | \n", " Loss: 0.002 | \n", " Accuracy: 0.003 |\n", " Val_Loss: 0.002 | \n", " Val_Accuracy: 0.003\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "100%|██████████| 1591/1591 [11:27<00:00, 2.32it/s]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epochs: 9 | \n", " Loss: 0.002 | \n", " Accuracy: 0.003 |\n", " Val_Loss: 0.002 | \n", " Val_Accuracy: 0.003\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "100%|██████████| 1591/1591 [10:59<00:00, 2.41it/s]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epochs: 10 | \n", " Loss: 0.002 | \n", " Accuracy: 0.003 |\n", " Val_Loss: 0.002 | \n", " Val_Accuracy: 0.003\n" ] } ], "execution_count": 18 }, { "cell_type": "code", "source": [ "torch.save(model.state_dict(), 'bert-model.pth')" ], "metadata": { "collapsed": false, "ExecuteTime": { "end_time": "2024-05-04T02:59:32.951202Z", "start_time": "2024-05-04T02:59:32.404662Z" } }, "id": "69b2fdb529e60fdd", "outputs": [], "execution_count": 19 }, { "cell_type": "code", "source": [ "# 保存labels\n", "with open('labels.txt', 'w') as f:\n", " for label in labels:\n", " f.writelines(label + '\\n')" ], "metadata": { "collapsed": false, "ExecuteTime": { "end_time": "2024-05-04T02:59:32.966165Z", "start_time": "2024-05-04T02:59:32.953195Z" } }, "id": "fd668538dc137ade", "outputs": [], "execution_count": 20 }, { "cell_type": "code", "source": [ "import matplotlib.pyplot as plt\n", "\n", "# [epoch_num, model_loss, model_acc, val_loss, val_accuracy]\n", "\n", "\n", "x = [i[0] for i in info]\n", "y1 = [float(i[1]) for i in info]\n", "y2 = [float(i[2]) for i in info]\n", "y3 = [float(i[3]) for i in info]\n", "y4 = [float(i[4]) for i in info]\n", "\n", "plt.plot(x, y1, color='r', label='loss')\n", "plt.plot(x, y2, color='g', label='acc')\n", "plt.plot(x, y3, color='b', label='val_loss')\n", "plt.plot(x, y4, color='k', label='val_acc')\n", "plt.xlim((0,1))\n", "%matplotlib inline\n", "plt.show()" ], "metadata": { "collapsed": false, "ExecuteTime": { "end_time": "2024-05-04T02:59:34.526025Z", "start_time": "2024-05-04T02:59:32.968156Z" } }, "id": "d8c16f36d9431367", "outputs": [ { "data": { "text/plain": [ "
" ], "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlEAAAGdCAYAAAAyviaMAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAABSa0lEQVR4nO3de1xUdf4/8Be3mQEvg0bOgKGQhpppFAZBGpIUrQiyl6x2V1nX0nbd/dXXdjdtU9orrtq3vvq1tZu6u/nNdLsoipaRl1JAQ8xrrBe8oA5mxaAmIDPv3x+nmeHIIMwRmAFez8fjPGY4n8855zOccF6d8zmfj5+ICIiIiIjII/7ebgARERFRR8QQRURERKQBQxQRERGRBgxRRERERBowRBERERFpwBBFREREpAFDFBEREZEGDFFEREREGgR6uwEdjd1ux5kzZ9CjRw/4+fl5uzlERETUAiKCCxcuICIiAv7+rXMNiSHKQ2fOnEFkZKS3m0FEREQanDp1CjfddFOr7IshykM9evQAoJyEnj17erk1RERE1BLV1dWIjIx0fo+3BoYoDzlu4fXs2ZMhioiIqINpza447FhOREREpAFDFBEREZEGDFFEREREGjBEEREREWnAEEVERESkAUMUERERkQYMUUREREQaaApRixcvRlRUFAwGAxISErBz585r1l+9ejUGDx4Mg8GAYcOGIT8/X1UuIpgzZw7Cw8MRHByM1NRUHD58WFUnMzMT/fr1g8FgQHh4OCZOnIgzZ844y48fPw4/P79GS1FRkUdtISIiImoJj0PU22+/jRkzZiAnJwe7d+/G7bffjrS0NJw7d85t/R07duDRRx/FlClTUFpaiqysLGRlZWH//v3OOvPmzcPChQuxZMkSFBcXo1u3bkhLS0NNTY2zTkpKClatWoWysjK88847OHr0KH70ox81Ot5HH32Es2fPOpe4uDiP2kJERETUEn4iIp5skJCQgLvuugv/+7//C0CZkDcyMhK//vWvMXPmzEb1H374YVy6dAnr1q1zrrv77rsRGxuLJUuWQEQQERGBp59+Gr/5zW8AAFarFSaTCcuXL8cjjzzith1r165FVlYWamtrERQUhOPHjyM6OhqlpaWIjY11u01zbWmJ6upqGI1GWK1WjlhORETUQbTF97dHV6Lq6upQUlKC1NRU1w78/ZGamorCwkK32xQW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Hh7OAHUdtJyLb7/9tlFQcoRb4TS27arVvrs96/Pe+a1cuVL0er0sX75cDh48KFOnTpXQ0FCxWCwiIjJx4kSZOXOms/727dslMDBQFixYIIcOHZKcnBwOcdBKPD0Xc+fOFZ1OJ//+97/l7NmzzuXChQve+gidhqfn4mp8Oq/1eHouTp48KT169JBf/epXUlZWJuvWrZM+ffrIn//8Z299hE7D03ORk5MjPXr0kLfeekuOHTsmH374oQwYMEAmTJjgrY/QaVy4cEFKS0ultLRUAMh///d/S2lpqZw4cUJERGbOnCkTJ0501ncMcfDb3/5WDh06JIsXL+YQB61l0aJF0q9fP9HpdBIfHy9FRUXOsuTkZMnOzlbVX7VqlcTExIhOp5OhQ4fK+vXr27nFnZcn56J///4CoNGSk5PT/g3vhDz9u2iIIap1eXouduzYIQkJCaLX6+Xmm2+Wv/zlL1JfX9/Ore6cPDkXV65ckeeff14GDBggBoNBIiMj5Ze//KV888037d/wTmbz5s1u//13/P6zs7MlOTm50TaxsbGi0+nk5ptvlmXLlnl8XD8RXkMkIiIi8hT7RBERERFpwBBFREREpAFDFBEREZEGDFFEREREGjBEEREREWnAEEVERESkAUMUERERkQYMUUREREQaMEQRERERacAQRURERKQBQxQRERGRBgxRRERERBr8f/TiguRCYmrOAAAAAElFTkSuQmCC" }, "metadata": {}, "output_type": "display_data" } ], "execution_count": 21 }, { "metadata": { "ExecuteTime": { "end_time": "2024-05-04T02:59:34.541951Z", "start_time": "2024-05-04T02:59:34.527987Z" } }, "cell_type": "code", "source": "", "id": "a1f0ed25b0e7353b", "outputs": [], "execution_count": 21 } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.18" } }, "nbformat": 4, "nbformat_minor": 5 }