[信息抽取]基于ERNIE3.0的多对多信息抽取算法:属性关系抽取
[信息抽取]基于ERNIE3.0的多对多信息抽取算法:属性关系抽取
实体关系,实体属性抽取是信息抽取的关键任务;实体关系抽取是指从一段文本中抽取关系三元组,实体属性抽取是指从一段文本中抽取属性三元组;信息抽取一般分以下几种情况一对一,一对多,多对一,多对多的情况:
一对一:“张三男汉族硕士学历”含有一对一的属性三元组(张三,民族,汉族)。
一对多:“华扬联众数字技术股份有限公司于2017年8月2日在上海证券交易所上市”,含有一对多的属性三元组(华扬联众数字技术股份有限公司,上市时间,2017年8月2日)和(华扬联众数字技术股份有限公司,上市地点,上海证券交易所上市)
多对一:“上海森焱软件有限公司和上海欧提软件有限公司的注册资本均为100万人民币”,含有多对一的属性三元组(上海森焱软件有限公司,注册资本,100万人民币)和(上海欧提软件有限公司,注册资本,100万人民币)
多对多:“大华种业稻麦种子加工36.29万吨、销售37.5万吨;苏垦米业大米加工22.02万吨、销售24.86万吨”,含有多对多的属性三元组(大华种业,稻麦种子产量,36.29万吨)和(苏垦米业,大米加工产量,22.02万吨)
代码结构如下:
├── data
│ ├── entity_attribute_data
│ │ ├── dev_data
│ │ │ └── dev.json
│ │ ├── predict_data
│ │ │ └── predict.json
│ │ ├── test_data
│ │ │ └── test.json
│ │ └── train_data
│ │ └── train.json
│ └── entity_relation_data
│ ├── dev_data
│ │ └── dev.json
│ ├── predict_data
│ │ └── predict.json
│ ├── test_data
│ │ └── test.json
│ └── train_data
│ └── train.json
├── data_set_reader
│ └── ie_data_set_reader.py
├── dict
│ ├── entity_attribute_label_map.json
│ └── entity_relation_label_map.json
├── examples
│ ├── many_to_many_ie_attribute_ernie_fc_ch_infer.json
│ ├── many_to_many_ie_attribute_ernie_fc_ch.json
│ ├── many_to_many_ie_relation_ernie_fc_ch_infer.json
│ └── many_to_many_ie_relation_ernie_fc_ch.json
├── inference
│ ├── custom_inference.py
│ └── __init__.py
├── model
│ ├── ernie_fc_ie_many_to_many.py
│ └── __init__.py
├── run_infer.py
├── run_trainer.py
└── trainer
├── custom_dynamic_trainer.py
├── custom_trainer.py
└── __init__.py
1.数据集简介
这里提供三份已标注的数据集:属性抽取数据集(demo示例数据集)、关系抽取数据集(demo示例数据集)、DuIE2.0(全量数据集)。
属性抽取训练集、测试集、验证集和预测集分别存放在./data/entity_attribute_data目录下的train_data、test_data、dev_data和predict_data文件夹下,对应的示例标签词表存放在./dict目录下。
关系抽取训练集、测试集、验证集和预测集分别存放在./data/entity_relation_data目录下的train_data、test_data、dev_data和predict_data文件夹下,对应的示例标签词表存放在./dict目录下。
DuIE2.0数据集已经上传到“数据集中”也进行解压
注:数据集(包含词表)均为utf-8格式。
Demo示例数据集(属性抽取数据集、关系抽取数据集)
demo示例数据集中属性抽取数据集与关系抽取数据集的结构一样,他们都只包含少量数据集,可用于快速开始模型的训练与预测。
训练集/测试集/的数据格式相同,每个样例分为两个部分文本和对应标签
{"text": "倪金德,1916年生,奉天省营口(今辽宁省营口市)人", "spo_list": [{"predicate": "出生日期", "subject": [0, 3], "object": [4, 9]}, {"predicate": "出生地", "subject": [0, 3], "object": [11, 16]}]}
{"text": "基本介绍克里斯蒂娜·塞寇丽(Christina Sicoli)身高163cm,在加拿大安大略出生和长大,毕业于伦道夫学院", "spo_list": [{"predicate": "毕业院校", "subject": [4, 13], "object": [55, 60]}]}
预测集只有一个key("text"):
{"text": "倪金德,1916年生,奉天省营口(今辽宁省营口市)人"}
{"text": "基本介绍克里斯蒂娜·塞寇丽(Christina Sicoli)身高163cm,在加拿大安大略出生和长大,毕业于伦道夫学院"}
标签词表:标签列表是一个json字符串,key是标签值,value是标签对应id,示例词表采用BIO标注,B表示关系,分为主体(S)与客体(O),如下所示:
{
"O": 0,
"I": 1,
"B-毕业院校@S": 2,
"B-毕业院校@O": 3,
"B-出生地@S": 4,
"B-出生地@O": 5,
"B-祖籍@S": 6,
"B-祖籍@O": 7,
"B-国籍@S": 8,
"B-国籍@O": 9,
"B-出生日期@S": 10,
"B-出生日期@O": 11
}
注意:O, I对应的ID必须是0, 1,B-XXX@O对应的id需要必须为B-XXX@S对应的id+1(B-XXX@s须为偶数,B-XXX@O须为奇数)
DuIE2.0数据集
DuIE2.0是业界规模最大的中文关系抽取数据集,其schema在传统简单关系类型基础上添加了多元复杂关系类型,此外其构建语料来自百度百科、百度信息流及百度贴吧文本,全面覆盖书面化表达及口语化表达语料,能充分考察真实业务场景下的关系抽取能力。
DuIE2.0数据集的格式与本框架所需要的文本输入格式不一致,需要进行转化成demo示例数据集的格式才能使用,具体转化步骤如下:下载数据集到 ./data/DuIE2.0 文件夹中,并解压
进入./data/DuIE2.0目录
运行./data/DuIE2.0/convert_data.py 脚本
{'text': '《司马迁之人格与风格\u3000道教徒的诗人李白及其痛苦》是李长之代表作品,共收录了两本著作,《司马迁之人格与风格》,是中国第一部透过西方文学批评视角全面审视、评价司马迁及其《史记》的学术专著', 'spo_list': [{'predicate': '作者', 'object_type': {'@value': '人物'}, 'subject_type': '图书作品', 'object': {'@value': '李长之'}, 'subject': '司马迁之人格与风格\u3000道教徒的诗人李白及其痛苦'}, {'predicate': '作者', 'object_type': {'@value': '人物'}, 'subject_type': '图书作品', 'object': {'@value': '李长之'}, 'subject': '司马迁之人格与风格 道教徒的诗人李白及其痛苦'}]}
《司马迁之人格与风格 道教徒的诗人李白及其痛苦》是李长之代表作品,共收录了两本著作,《司马迁之人格与风格》,是中国第一部透过西方文学批评视角全面审视、评价司马迁及其《史记》的学术专著 * 司马迁之人格与风格 道教徒的诗人李白及其痛苦
2.网络模型选择(文心大模型)
文心预置的可用于生成任务的模型源文件在/home/aistudio/model/ernie_fc_ie_many_to_many.py
网络名称(py文件的类型) | 简介 | 支持类型 |
---|---|---|
ErnieFcIe(ernie_fc_ie_many_to_many.py) | ErnieFcIe多对多信息抽取任务模型源文件,可加载ERNIE2.0-Base、ERNIE2.0-large、ERNIE3.0-Base、ERNIE3.0-x-Base、ERNIE3.0-Medium | 通用信息抽取Finetune任务 |
ERNIE预训练模型下载:文心提供的ERNIE预训练模型的参数文件和配置文件在 /home/aistudio/models_hub目录下,使用对应的sh脚本,即可拉取对应的模型、字典、必要环境等文件。
简单罗列可能会用的模型:
模型名称 | 下载脚本 | 备注 |
---|---|---|
ERNIE1.0-m-Base | Text | ERNIE-M:通过将跨语言语义与单语语料库对齐来增强多语言表示 |
ERNIE1.0-gen-Base | Text | ERNIE-GEN:用于自然语言生成的增强型多流预训练和微调框架 |
ERNIE2.0-Base | Text | |
ERNIE2.0-large | Text | |
ERNIE3.0-Base | Text | |
ERNIE3.0-x-Base | Text | |
ERNIE3.0-Medium | Text | 下载并解压后得到对应模型的参数、字典和配置 |
简单介绍以下几个不常用模型:
ERNIE-GEN 是面向生成任务的预训练-微调框架,首次在预训练阶段加入span-by-span 生成任务,让模型每次能够生成一个语义完整的片段。在预训练和微调中通过填充式生成机制和噪声感知机制来缓解曝光偏差问题。此外, ERNIE-GEN 采样多片段-多粒度目标文本采样策略, 增强源文本和目标文本的关联性,加强了编码器和解码器的交互。
ERNIE-GEN base 模型和 ERNIE-GEN large 模型。 预训练数据使用英文维基百科和 BookCorpus,总共16GB。此外,我们还发布了基于 430GB 语料(数据描述见ERNIE-GEN Appendix A.1)预训练的ERNIE-GEN large 模型。
- ERNIE-GEN base (lowercased | 12-layer, 768-hidden, 12-heads, 110M parameters)
- ERNIE-GEN large (lowercased | 24-layer, 1024-hidden, 16-heads, 340M parameters)
- ERNIE-GEN large with 430G (lowercased | 24-layer, 1024-hidden, 16-heads, 340M parameters)
微调任务:在五个典型生成任务上与当前效果最优的生成预训练模型(UniLM、MASS、PEGASUS、BART、T5等)进行对比, 包括生成式摘要 (Gigaword 和 CNN/DailyMail), 问题生成(SQuAD), 多轮对话(Persona-Chat) 和生成式多轮问答(CoQA)。
https://github.com/PaddlePaddle/ERNIE/blob/repro/ernie-gen/README.zh.md
ERNIE-M 是面向多语言建模的预训练-微调框架。为了突破双语语料规模对多语言模型的学习效果限制,提升跨语言理解的效果,我们提出基于回译机制,从单语语料中学习语言间的语义对齐关系的预训练模型 ERNIE-M,显著提升包括跨语言自然语言推断、语义检索、语义相似度、命名实体识别、阅读理解在内的 5 种典型跨语言理解任务效果。
飞桨发布了 ERNIE-M base 多语言模型和 ERNIE-M large 多语言模型。
- ERNIE-M base (12-layer, 768-hidden, 12-heads)
- ERNIE-M large (24-layer, 1024-hidden, 16-heads)
下游任务:在自然语言推断,命名实体识别,阅读理解,语义相似度以及跨语言检索等任务上选取了广泛使用的数据集进行模型效果验证,并且与当前效果最优的模型(XLM、Unicoder、XLM-R、INFOXLM、VECO、mBERT等)进行对比。
https://github.com/PaddlePaddle/ERNIE/blob/repro/ernie-m/README_zh.md
3.训练&预测
3.1 属性抽取模型训练&预测
以属性抽取数据集的训练为例:
训练的配置文件:
配置文件:./examples/many_to_many_ie_attribute_ernie_fc_ch.json
{
"dataset_reader": {
"train_reader": {
"name": "train_reader",
"type": "IEReader",
"fields": [],
"config": {
"data_path": "./data/entity_attribute_data/train_data/",
"shuffle": false,
"batch_size": 2,
"epoch": 5,
"sampling_rate": 1.0,
"need_data_distribute": true,
"need_generate_examples": false,
"extra_params": {
"vocab_path": "./models_hub/ernie_3.0_base_ch_dir/vocab.txt", #选择对应预训练模型的词典路径,在models_hub路径下
"label_map_config": "./dict/entity_attribute_label_map.json",
"num_labels": 12,
"max_seq_len": 512,
"do_lower_case":true,
"in_tokens":false,
"tokenizer": "FullTokenizer"
}
}
},
"test_reader": {
"name": "test_reader",
"type": "IEReader",
"fields": [],
"config": {
"data_path": "./data/entity_attribute_data/test_data/",
"shuffle": false,
"batch_size": 2,
"epoch": 1,
"sampling_rate": 1.0,
"need_data_distribute": false,
"need_generate_examples": false,
"extra_params": {
"vocab_path": "./models_hub/ernie_3.0_base_ch_dir/vocab.txt", #选择对应预训练模型的词典路径,在models_hub路径下
"label_map_config": "./dict/entity_attribute_label_map.json",
"num_labels": 12,
"max_seq_len": 512,
"do_lower_case":true,
"in_tokens":false,
"tokenizer": "FullTokenizer"
}
}
}
},
"model": {
"type": "ErnieFcIe",
"is_dygraph":1,
"num_labels":12,
"optimization": {
"learning_rate": 5e-05,
"use_lr_decay": true,
"warmup_steps": 0,
"warmup_proportion": 0.1,
"weight_decay": 0.01,
"use_dynamic_loss_scaling": false,
"init_loss_scaling": 128,
"incr_every_n_steps": 100,
"decr_every_n_nan_or_inf": 2,
"incr_ratio": 2.0,
"decr_ratio": 0.8
},
"embedding": {
"config_path": "./models_hub/ernie_3.0_base_ch_dir/ernie_config.json" #选择对应预训练模型的配置文件路径,在models_hub路径下
}
},
"trainer": {
"type": "CustomDynamicTrainer",
"PADDLE_PLACE_TYPE": "gpu",
"PADDLE_IS_FLEET": 0,
"train_log_step": 10,
"use_amp": true,
"is_eval_dev": 0,
"is_eval_test": 1,
"eval_step": 50,
"save_model_step": 100,
"load_parameters": "",
"load_checkpoint": "",
"pre_train_model": [
{
"name": "ernie_3.0_base_ch",
"params_path": "./models_hub/ernie_3.0_base_ch_dir/params" #选择对应预训练模型的参数路径,在models_hub路径下
}
],
"output_path": "./output/ie_attribute_ernie_3.0_base_fc_ch", #输出路径
"extra_param": {
"meta":{
"job_type": "entity_attribute_extraction"
}
}
}
}
# 基于示例的数据集,可以运行以下命令在训练集(train.txt)上进行模型训练,并在测试集(test.txt)上进行验证;
# 训练属性抽取
%cd /home/aistudio
!python run_trainer.py --param_path ./examples/many_to_many_ie_attribute_ernie_fc_ch.json
# 训练运行的日志会自动保存在./log/test.log文件中;
# 训练中以及结束后产生的模型文件会默认保存在./output/目录下,其中save_inference_model/文件夹会保存用于预测的模型文件,save_checkpoint/文件夹会保存用于热启动的模型文件
部分结果展示:
INFO: 11-30 15:19:47: custom_dynamic_trainer.py:85 * 139681516312320 current learning rate: 2e-07
DEBUG: 11-30 15:19:48: ernie_fc_ie_many_to_many.py:234 * 139681516312320 phase = training precision = 1.0 recall = 1.0 f1 = 1.0 step = 2500 time_cost = 0.5210211277008057 loss = [0.00099489]
INFO: 11-30 15:19:48: custom_dynamic_trainer.py:85 * 139681516312320 current learning rate: 0.0
DEBUG: 11-30 15:19:48: ernie_fc_ie_many_to_many.py:261 * 139681516312320 phase = test precision = 0.958 recall = 0.976 f1 = 0.967 time_cost = 0.4507319927215576
INFO: 11-30 15:19:48: custom_dynamic_trainer.py:138 * 139681516312320 eval step = 14
INFO: 11-30 15:19:48: custom_dynamic_trainer.py:103 * 139681516312320 Final test result:
DEBUG: 11-30 15:19:49: ernie_fc_ie_many_to_many.py:261 * 139681516312320 phase = test precision = 0.958 recall = 0.976 f1 = 0.967 time_cost = 0.44904589653015137
INFO: 11-30 15:19:49: custom_dynamic_trainer.py:138 * 139681516312320 eval step = 14
使用预置网络进行预测的方式为使用./run_infer.py入口脚本,通过--param_path参数来传入./examples/目录下的json配置文件。
预测分为以下几个步骤:
基于示例的数据集,可以运行以下命令在预测集(predict.txt)上进行预测:
预测运行的日志会自动保存在./output/predict_result.txt文件中。
以属性抽取数据集的预测为例:
预测的配置文件
配置文件:./examples/many_to_many_ie_attribute_ernie_fc_ch_infer.json
在配置文件./examples/many_to_many_ie_attribute_ernie_fc_ch_infer.json中需要更改 inference.inference_model_path 为上面训练过程中所保存的预测模型的路径
{
"dataset_reader": {
"predict_reader": {
"name": "predict_reader",
"type": "IEReader",
"fields": [],
"config": {
"data_path": "./data/entity_attribute_data/predict_data/",
"shuffle": false,
"batch_size": 2,
"epoch": 1,
"sampling_rate": 1.0,
"extra_params": {
"vocab_path": "../../models_hub/ernie_3.0_base_ch_dir/vocab.txt",
"label_map_config": "./dict/entity_attribute_label_map.json",
"num_labels": 12,
"max_seq_len": 512,
"do_lower_case":true,
"in_tokens":false,
"tokenizer": "FullTokenizer",
"need_data_distribute": false,
"need_generate_examples": true
}
}
}
},
"inference": {
"output_path": "./output/predict_result.txt", #输出文件路径
"label_map_config": "./dict/entity_attribute_label_map.json",
"PADDLE_PLACE_TYPE": "gpu",
"inference_model_path": "./output/ie_attribute_ernie_3.0_base_fc_ch/save_inference_model/inference_step_1000", #加载推理模型
"extra_param": {
"meta": {
"job_type": "information_extraction"
}
}
}
}
3.2 关系抽取模型训练&预测
# 训练关系抽取
!python run_trainer.py --param_path ./examples/many_to_many_ie_relation_ernie_fc_ch.json
# 训练运行的日志会自动保存在./log/test.log文件中;
# 训练中以及结束后产生的模型文件会默认保存在./output/目录下,其中save_inference_model/文件夹会保存用于预测的模型文件,save_checkpoint/文件夹会保存用于热启动的模型文件
部分结果展示:
DEBUG: 11-30 16:09:37: ernie_fc_ie_many_to_many.py:261 * 140264317826816 phase = test precision = 0.953 recall = 0.968 f1 = 0.96 time_cost = 0.7550814151763916
INFO: 11-30 16:09:37: custom_dynamic_trainer.py:138 * 140264317826816 eval step = 50
INFO: 11-30 16:09:41: dynamic_trainer.py:170 * 140264317826816 save path: ./output/ie_relation_ernie_3.0_medium/save_inference_model/inference_step_2500
INFO: 11-30 16:09:42: custom_dynamic_trainer.py:103 * 140264317826816 Final test result:
DEBUG: 11-30 16:09:43: ernie_fc_ie_many_to_many.py:261 * 140264317826816 phase = test precision = 0.953 recall = 0.968 f1 = 0.96 time_cost = 0.883291482925415
INFO: 11-30 16:09:43: custom_dynamic_trainer.py:138 * 140264317826816 eval step = 50
部分结果:
"text": "杨力革,男,汉族,1966年4月生,湖南益阳人,1987年7月参加工作,1992年10月入党,在职研究生学历(2004年7月新疆自治区党委党校领导干部研究生班工商管理专业毕业)",
"spo_list": [
{
"predicate": "出生地",
"subject": [
0,
3
],
"object": [
18,
22
]
},
{
"predicate": "出生日期",
"subject": [
0,
3
],
"object": [
9,
16
]
}
]
4.总结
本项目讲解了基于ERNIE信息抽取技术,对属性和关系的抽取涉及多对多抽取,主要是使用可ERNIEKIT组件,整体效果非常不错,当然追求小样本学习的可以参考之前UIE项目或者去官网看看paddlenlp最新的更新,对训练和部署进行了提速。
模型 | 任务 | precision | recall | f1 |
---|---|---|---|---|
ernie_3.0_medium | 属性抽取 | 0.958 | 0.976 | 0.967 |
ernie_3.0_medium | 关系抽取 | 0.953 | 0.968 | 0.96 |
[信息抽取]基于ERNIE3.0的多对多信息抽取算法:属性关系抽取的更多相关文章
- 编译可在Nexus5上运行的CyanogenMod13.0 ROM(基于Android6.0)
编译可在Nexus5上运行的CyanogenMod13.0 ROM (基于Android6.0) 作者:寻禹@阿里聚安全 前言 下文中无特殊说明时CM代表CyanogenMod的缩写. 下文中说的“设 ...
- mybatis整合spring 之 基于接口映射的多对一关系
转载自:http://my.oschina.net/huangcongmin12/blog/83731 mybatis整合spring 之 基于接口映射的多对一关系. 项目用到俩个表,即studen ...
- 基于AFNetworking3.0网络封装
概述 对于开发人员来说,学习网络层知识是必备的,任何一款App的开发,都需要到网络请求接口.很多朋友都还在使用原生的NSURLConnection一行一行地写,代码到处是,这样维护起来更困难了. 对于 ...
- iOS_SN_基于AFNetworking3.0网络封装
转发文章,原地址:http://www.henishuo.com/base-on-afnetworking3-0-wrapper/?utm_source=tuicool&utm_medium= ...
- 基于vue2.0的一个豆瓣电影App
1.搭建项目框架 使用vue-cli 没安装的需要先安装 npm intall -g vue-cli 使用vue-cli生成项目框架 vue init webpack-simple vue-movie ...
- WmS详解(二)之如何理解Window和窗口的关系?基于Android7.0源码
上篇博客(WmS详解(一)之token到底是什么?基于Android7.0源码)中我们简要介绍了token的作用,这里涉及到的概念非常多,其中出现频率最高的要数Window和窗口这一对搭档了,那么我们 ...
- PoiDemo【Android将表单数据生成Word文档的方案之二(基于Poi4.0.0)】
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 使用Poi实现android中根据模板文件生成Word文档的功能.这里的模板文件是doc文件.如果模板文件是docx文件的话,请阅读 ...
- BaiduSpeechDemo【百度语音SDK集成】(基于v3.0.8.1)
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 上一篇集成的是V3.0.7.3版本的SDK<BaiduSpeechDemo[百度语音SDK集成](基于v3.0.7.3)> ...
- IdentityServer4之SSO(基于OAuth2.0、OIDC)单点登录、登出
IdentityServer4之SSO(基于OAuth2.0.OIDC)单点登录.登出 准备 五个Web站点: 1.localhost:5000 : 认证服务器.2 ...
- WmS具体解释(二)之怎样理解Window和窗体的关系?基于Android7.0源代码
上篇博客(WmS具体解释(一)之token究竟是什么?基于Android7.0源代码)中我们简要介绍了token的作用,这里涉及到的概念非常多,当中出现频率最高的要数Window和窗体这一对搭档了,那 ...
随机推荐
- UEC++ 多线程(一) FRunnable
虚幻官方文档:https://docs.unrealengine.com/5.0/en-US/API/Runtime/Core/HAL/FRunnable/ FRunnable "runna ...
- Docker 与 Containerd 并用配置
描述: 事实上,Docker 和 Containerd 是可以同时使用的,只不过 Docker 默认使用的 Containerd 的命名空间不是 default,而是 moby,此处为了更方便我们学习 ...
- 使用metricbeat监控system和nginx
下载并解压缩metricbeat metricbeat.yml配置文件设置: setup.kibana: host: "192.168.75.21:5601" output.ela ...
- Logstash:为 Logstash 日志启动索引生命周期管理
文章转载自:https://elasticstack.blog.csdn.net/article/details/110816948
- Python实现改进后的Bi-RRT算法实例
Python实现改进后的Bi-RRT算法实例 1.背景说明 以下代码是参照上海交通大学海洋工程国家重点实验室<基于改进双向RRT的无人艇局部路径规划算法研究>的算法思想实现的. 2.算法流 ...
- AcWing 最短Hamilton距离 (状压DP)
题目描述 给定一张 n 个点的带权无向图,点从 0∼n−1 标号,求起点 0 到终点 n−1 的最短 Hamilton 路径. Hamilton 路径的定义是从 0 到 n−1 不重不漏地经过每个点恰 ...
- cudaMemcpy cudaMalloc
cudaMemcpy有四种类型:HostToHost, DeviceToHost, HostToDevice, DeviceToDevices 现在我有两个指针:h_ptr, d_ptr,分别指向ho ...
- 齐博x1标签实例:标签的嵌套用法,调用聚合数据
齐博标签非常强大,可以让不懂程序的你,轻松就能实现所见即所得. 下面跟大家讲解一下,最复杂的运用, 同时使用了union 动态变量参数 与 分页处理标签 比如下面这张图,不仅仅想调用圈子,还想同时调用 ...
- HDFS追加数据报错解决办法
主要的两个错误,今天晚上一直轮着报: 第一个 2022-10-25 21:37:11,901 WARN hdfs.DataStreamer: DataStreamer Exception java.i ...
- iOS- 最全的真机测试教程
想要上架的同学请看:<iOS-最全的App上架教程> 因为最近更新了Xcode 8 ,证书的创建都大同小异,只是在Xcode 8中的设置有一些变化,我就在下面补充,如有什么疑问,请联系 ...