├── image ├── canva1s.png ├── sendpix0.jpg ├── 030AB2157517DB02D70CC2FDC2A1E3F3.png ├── 04E09FF3345D1E188923369CE589C67F.jpg ├── 0944A8F05FC21CA12A13448AAC56EFE3.png ├── 1EE91DC06D18692773CF3DD13572D682.png ├── 20B149B170CA50162362F5682B4282C0.png ├── 3E178AF03E21C7B60BA4A77BEC0A77E4.png ├── 4C077E3221DCC324718E1EE2C7BC1A00.jpg ├── 718EC6C51639765F9A21CEE1CBE1089A.png ├── 7DC52A21FAFFF8093729E0E0D40E3DE5.jpg ├── 94B48DAD50D8098702354CDBCED084F5.png ├── 98A3DC28322429BBE766B70D26CCB375.jpg ├── 9DD2ABB55806CB9F5B9C558E8AEB673B.png └── AD5984B2236009053E5AD80325AC0B69.png ├── data ├── 文本处理_不带词频统计.py ├── cvs处理.py └── 文本预处理_带词频统计.py ├── GPT_test ├── 词向量印刻.py ├── GPT模型_测试.py ├── GPT单元.py ├── 取训练数据.py └── 测试_ROCStories.py ├── GPT_train ├── 词向量印刻.py ├── 预训练.py ├── GPT模型.py ├── ROCStories_训练.py ├── 取训练数据.py ├── 生成midspore训练数据.py └── GPT单元.py └── readme.md /image/canva1s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FengQuanLi/GPT_Mindspore/HEAD/image/canva1s.png -------------------------------------------------------------------------------- /image/sendpix0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FengQuanLi/GPT_Mindspore/HEAD/image/sendpix0.jpg -------------------------------------------------------------------------------- /image/030AB2157517DB02D70CC2FDC2A1E3F3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FengQuanLi/GPT_Mindspore/HEAD/image/030AB2157517DB02D70CC2FDC2A1E3F3.png -------------------------------------------------------------------------------- /image/04E09FF3345D1E188923369CE589C67F.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FengQuanLi/GPT_Mindspore/HEAD/image/04E09FF3345D1E188923369CE589C67F.jpg -------------------------------------------------------------------------------- /image/0944A8F05FC21CA12A13448AAC56EFE3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FengQuanLi/GPT_Mindspore/HEAD/image/0944A8F05FC21CA12A13448AAC56EFE3.png -------------------------------------------------------------------------------- /image/1EE91DC06D18692773CF3DD13572D682.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FengQuanLi/GPT_Mindspore/HEAD/image/1EE91DC06D18692773CF3DD13572D682.png -------------------------------------------------------------------------------- /image/20B149B170CA50162362F5682B4282C0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FengQuanLi/GPT_Mindspore/HEAD/image/20B149B170CA50162362F5682B4282C0.png -------------------------------------------------------------------------------- /image/3E178AF03E21C7B60BA4A77BEC0A77E4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FengQuanLi/GPT_Mindspore/HEAD/image/3E178AF03E21C7B60BA4A77BEC0A77E4.png -------------------------------------------------------------------------------- /image/4C077E3221DCC324718E1EE2C7BC1A00.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FengQuanLi/GPT_Mindspore/HEAD/image/4C077E3221DCC324718E1EE2C7BC1A00.jpg -------------------------------------------------------------------------------- /image/718EC6C51639765F9A21CEE1CBE1089A.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FengQuanLi/GPT_Mindspore/HEAD/image/718EC6C51639765F9A21CEE1CBE1089A.png -------------------------------------------------------------------------------- /image/7DC52A21FAFFF8093729E0E0D40E3DE5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FengQuanLi/GPT_Mindspore/HEAD/image/7DC52A21FAFFF8093729E0E0D40E3DE5.jpg -------------------------------------------------------------------------------- /image/94B48DAD50D8098702354CDBCED084F5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FengQuanLi/GPT_Mindspore/HEAD/image/94B48DAD50D8098702354CDBCED084F5.png -------------------------------------------------------------------------------- /image/98A3DC28322429BBE766B70D26CCB375.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FengQuanLi/GPT_Mindspore/HEAD/image/98A3DC28322429BBE766B70D26CCB375.jpg -------------------------------------------------------------------------------- /image/9DD2ABB55806CB9F5B9C558E8AEB673B.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FengQuanLi/GPT_Mindspore/HEAD/image/9DD2ABB55806CB9F5B9C558E8AEB673B.png -------------------------------------------------------------------------------- /image/AD5984B2236009053E5AD80325AC0B69.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FengQuanLi/GPT_Mindspore/HEAD/image/AD5984B2236009053E5AD80325AC0B69.png -------------------------------------------------------------------------------- /data/文本处理_不带词频统计.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | 4 | def 存(段,文件号,j): 5 | 临2 = {} 6 | if ('¶' in 段) or ('å' in 段): 7 | 8 | print(段, "--------------------") 9 | 段 = '' 10 | 11 | else: 12 | 临2["id"] = j 13 | 临2["input"] = 段 14 | 15 | json.dump(临2, 文件号, ensure_ascii=False) 16 | 文件号.write('\n') 17 | 18 | 19 | def txt文本_到训练数据(dirname, 文件号,文本长度=667): 20 | result = [] # 所有的文件 21 | 22 | j = 0 23 | i = 0 24 | 临 = '' 25 | 计数 = 0 26 | 小计=0 27 | 段 = '' 28 | 29 | for maindir, subdir, file_name_list in os.walk(dirname): 30 | 31 | for filename in file_name_list: 32 | 33 | apath = os.path.join(maindir, filename) # 合并成一个完整路径 34 | print(apath) 35 | f = open(apath, "r", encoding='utf8') 36 | str1 = f.read() 37 | for s in str1: 38 | 39 | if (u'\u0041' <= s <= u'\u005a') or (u'\u0061' <= s <= u'\u007a') : 40 | if 临 == '': 41 | 42 | 临 = s 43 | else: 44 | 临 = 临 + s 45 | 46 | 47 | else: 48 | if 临 == '': 49 | 段 = 段 + s 50 | if s != ' ': 51 | 小计 = 小计 + 1 52 | if 小计 == 文本长度: 53 | 存(段, 文件号, j) 54 | 小计=0 55 | j=j+1 56 | 段 = '' 57 | 58 | 59 | 计数 = 计数 + 1 60 | else: 61 | 62 | 段 = 段 + 临 63 | if 临!= ' ': 64 | 小计 = 小计 + 1 65 | if 小计 == 文本长度: 66 | 存(段, 文件号, j) 67 | 小计=0 68 | j=j+1 69 | 段='' 70 | 71 | 计数 = 计数 + 1 72 | 段 = 段 + s 73 | if s!=' ': 74 | 小计 = 小计 + 1 75 | if 小计 == 文本长度: 76 | 存(段, 文件号, j) 77 | 小计=0 78 | j=j+1 79 | 段 = '' 80 | 81 | 临 = '' 82 | 计数 = 计数 + 1 83 | 84 | if 计数 % 100000 == 0 : 85 | print(计数) 86 | 段 = '' 87 | 临 = '' 88 | 89 | return "临2" 90 | 91 | 92 | 93 | with open("./新生成的训练数据/XXX训练材料.json", "w", encoding="utf8") as f: 94 | json数据 = txt文本_到训练数据("./再训练txt", f) 95 | print(json数据) 96 | -------------------------------------------------------------------------------- /GPT_test/词向量印刻.py: -------------------------------------------------------------------------------- 1 | import mindspore.common.dtype as mstype 2 | from mindspore.common.tensor import Tensor 3 | from mindspore.ops import operations as P 4 | from mindspore.common.parameter import Parameter 5 | import mindspore.nn as nn 6 | import mindspore 7 | import numpy as np 8 | class Embedding2(nn.Cell): 9 | """ 10 | 从mindspore的源码nn.Embedding抄过来的,做了细微的改动。 11 | 可用numpy的随机数种子生成固定的参数以便对比研究。 12 | """ 13 | def __init__(self, vocab_size, embedding_size, use_one_hot=False, embedding_table='normal', dtype=mstype.float32): 14 | super(Embedding2, self).__init__() 15 | self.vocab_size = vocab_size 16 | self.embedding_size = embedding_size 17 | self.use_one_hot = use_one_hot 18 | np.random.seed(1) # 可以生成固定参数以便对比研究,不需要固定参数注释掉此行就可。 19 | self.embedding_table = Parameter(Tensor(np.random.uniform(0, 1, (vocab_size, embedding_size)),mindspore.float32), 20 | name='embedding_table') 21 | 22 | self.dtype = dtype 23 | self.expand = P.ExpandDims() 24 | self.reshape_flat = P.Reshape() 25 | self.shp_flat = (-1,) 26 | self.gather = P.GatherV2() 27 | self.one_hot = P.OneHot() 28 | self.on_value = Tensor(1.0, self.dtype) 29 | self.off_value = Tensor(0.0, self.dtype) 30 | self.array_mul = P.MatMul() 31 | self.reshape = P.Reshape() 32 | self.get_shp = P.Shape() 33 | 34 | def construct(self, ids): 35 | extended_ids = self.expand(ids, -1) 36 | out_shape = self.get_shp(ids) + (self.embedding_size,) 37 | flat_ids = self.reshape_flat(extended_ids, self.shp_flat) 38 | 39 | if self.use_one_hot: 40 | one_hot_ids = self.one_hot(flat_ids, self.vocab_size, self.on_value, self.off_value) 41 | output_for_reshape = self.array_mul(one_hot_ids, self.embedding_table) 42 | else: 43 | output_for_reshape = self.gather(self.embedding_table, flat_ids, 0) 44 | 45 | output = self.reshape(output_for_reshape, out_shape) 46 | return output 47 | 48 | def extend_repr(self): 49 | s = 'vocab_size={}, embedding_size={},' \ 50 | 'use_one_hot={}, ' \ 51 | 'embedding_table={}, dtype={}'.format( 52 | self.vocab_size, 53 | self.embedding_size, 54 | self.use_one_hot, 55 | self.embedding_table, 56 | self.dtype) 57 | return s 58 | 59 | class 词向量印刻(nn.Cell): 60 | """ 61 | Embedding的另一个马甲,训练的时候刻上去,用的时候印出来。 62 | """ 63 | def __init__(self, 词库总数, 向量维度): 64 | super(词向量印刻, self).__init__() 65 | self.d_model = 向量维度 66 | self.embed = Embedding2(词库总数, 向量维度) 67 | 68 | def construct(self, 词编号集): 69 | return self.embed(词编号集) 70 | 71 | -------------------------------------------------------------------------------- /GPT_train/词向量印刻.py: -------------------------------------------------------------------------------- 1 | import mindspore.common.dtype as mstype 2 | from mindspore.common.tensor import Tensor 3 | from mindspore.ops import operations as P 4 | from mindspore.common.parameter import Parameter 5 | import mindspore.nn as nn 6 | import mindspore 7 | import numpy as np 8 | class Embedding2(nn.Cell): 9 | """ 10 | 从mindspore的源码nn.Embedding抄过来的,做了细微的改动。 11 | 可用numpy的随机数种子生成固定的参数以便对比研究。 12 | """ 13 | def __init__(self, vocab_size, embedding_size, use_one_hot=False, embedding_table='normal', dtype=mstype.float32): 14 | super(Embedding2, self).__init__() 15 | self.vocab_size = vocab_size 16 | self.embedding_size = embedding_size 17 | self.use_one_hot = use_one_hot 18 | np.random.seed(1) # 可以生成固定参数以便对比研究,不需要固定参数注释掉此行就可。 19 | self.embedding_table = Parameter(Tensor(np.random.uniform(0, 1, (vocab_size, embedding_size)),mindspore.float32), 20 | name='embedding_table') 21 | 22 | self.dtype = dtype 23 | self.expand = P.ExpandDims() 24 | self.reshape_flat = P.Reshape() 25 | self.shp_flat = (-1,) 26 | self.gather = P.GatherV2() 27 | self.one_hot = P.OneHot() 28 | self.on_value = Tensor(1.0, self.dtype) 29 | self.off_value = Tensor(0.0, self.dtype) 30 | self.array_mul = P.MatMul() 31 | self.reshape = P.Reshape() 32 | self.get_shp = P.Shape() 33 | 34 | def construct(self, ids): 35 | extended_ids = self.expand(ids, -1) 36 | out_shape = self.get_shp(ids) + (self.embedding_size,) 37 | flat_ids = self.reshape_flat(extended_ids, self.shp_flat) 38 | 39 | if self.use_one_hot: 40 | one_hot_ids = self.one_hot(flat_ids, self.vocab_size, self.on_value, self.off_value) 41 | output_for_reshape = self.array_mul(one_hot_ids, self.embedding_table) 42 | else: 43 | output_for_reshape = self.gather(self.embedding_table, flat_ids, 0) 44 | 45 | output = self.reshape(output_for_reshape, out_shape) 46 | return output 47 | 48 | def extend_repr(self): 49 | s = 'vocab_size={}, embedding_size={},' \ 50 | 'use_one_hot={}, ' \ 51 | 'embedding_table={}, dtype={}'.format( 52 | self.vocab_size, 53 | self.embedding_size, 54 | self.use_one_hot, 55 | self.embedding_table, 56 | self.dtype) 57 | return s 58 | 59 | class 词向量印刻(nn.Cell): 60 | """ 61 | Embedding的另一个马甲,训练的时候刻上去,用的时候印出来。 62 | """ 63 | def __init__(self, 词库总数, 向量维度): 64 | super(词向量印刻, self).__init__() 65 | self.d_model = 向量维度 66 | self.embed = Embedding2(词库总数, 向量维度) 67 | 68 | def construct(self, 词编号集): 69 | return self.embed(词编号集) 70 | 71 | -------------------------------------------------------------------------------- /GPT_train/预训练.py: -------------------------------------------------------------------------------- 1 | from mindspore.train.callback import ModelCheckpoint, CheckpointConfig, LossMonitor, TimeMonitor 2 | from mindspore.train import Model 3 | from mindspore.nn.metrics import Accuracy 4 | import mindspore.dataset as mds 5 | from mindspore import context, nn 6 | from mindspore.train.serialization import load_checkpoint, load_param_into_net 7 | from GPT模型 import 输出函数_GPT 8 | import os.path 9 | from 生成midspore训练数据 import 数据预处理_json到minecord 10 | def create_dataset(base_path, batch_size, num_epochs): 11 | path = base_path 12 | dataset = mds.MindDataset(path, columns_list=["input", "output"], num_parallel_workers=4) 13 | dataset = dataset.shuffle(buffer_size=dataset.get_dataset_size()) 14 | dataset = dataset.batch(batch_size=batch_size, drop_remainder=True) 15 | dataset = dataset.repeat(count=num_epochs) 16 | return dataset 17 | #注意!!这里的训练的文本长度为666 这在数据预处理时已经定了,可利用预处理的代码重定文本长度。预处理的代码和数据放在一起。 18 | #以下是模型参数 19 | 文本长度 = 666 # 固定长度就不用每次训练都生成mask 20 | 丢弃率 = 0.0 21 | 词库总数 = 50001 # 组成是UTF8单字符和部分英文字母组合请务必保留此数,如需更改则需要重改json查询表并重新生成训练数据 22 | 向量维度 = 768 23 | 层数 = 12 24 | 头数 = 12 25 | 26 | 27 | #________________________以下是Adam优化算法的参数 28 | 学习率 = 6.25e-5 29 | beta1 = 0.9 30 | beta2=0.98 31 | eps=1e-09 32 | 33 | # 预训练一轮就可以有较好效果,训练两轮效果略好,两轮以上没有试过。 34 | # 约3600万字符集的训练材料单显卡(GTX1660)batch_size=2训练一轮约12小时。 35 | # 每一步耗时约1.5秒 36 | epoch = 1 37 | batch_size = 2 38 | #预训练数据路径="../data/checkpoint/预训练/checkpoint_english_2-1_27821.ckpt" 39 | 40 | if os.path.isfile("../data/mindrecord/训练材料_英语3.minecord.db") and os.path.isfile("..data/mindrecord/训练材料_英语3.minecord"): 41 | print("发现mindrecord类型训练数据,直接加载训练。") 42 | dataset = create_dataset("../data/mindrecord/训练材料_英语3.minecord", batch_size, 1) 43 | else: 44 | print("未发现mindrecord类型训练数据,正在生成,请稍等......") 45 | 数据预处理_json到minecord() 46 | dataset = create_dataset("../data/mindrecord/训练材料_英语3.minecord", batch_size, 1) 47 | 48 | device_target = "GPU" 49 | context.set_context(mode=context.GRAPH_MODE, device_target=device_target) 50 | network = 输出函数_GPT(词库总数, 向量维度, 层数, 头数, 丢弃率, 文本长度) 51 | # if os.path.isfile(预训练数据路径) : 52 | # print("正在加载预训练参数") 53 | # param_dict = load_checkpoint(预训练数据路径) 54 | # load_param_into_net(network, param_dict) 55 | net_loss = nn.SoftmaxCrossEntropyWithLogits(is_grad=False, sparse=True, reduction="mean") 56 | net_opt = nn.Adam(network.trainable_params(), learning_rate=学习率, beta1=beta1, beta2=beta2, eps=eps) 57 | time_cb = TimeMonitor(data_size=dataset.get_dataset_size()) 58 | config_ck = CheckpointConfig(save_checkpoint_steps=200, keep_checkpoint_max=1) 59 | ckpoint_cb = ModelCheckpoint(prefix="checkpoint_english", directory="../data/checkpoint/预训练/", config=config_ck) 60 | model = Model(network, net_loss, net_opt, {'acc': Accuracy()}) 61 | print("开始训练——训练一轮约12小时。时间较长........") 62 | model.train(epoch=epoch, train_dataset=dataset, callbacks=[time_cb, ckpoint_cb, LossMonitor()], 63 | dataset_sink_mode=False) -------------------------------------------------------------------------------- /GPT_train/GPT模型.py: -------------------------------------------------------------------------------- 1 | from mindspore import Tensor, nn 2 | import mindspore 3 | import numpy as np 4 | import mindspore.ops.operations as P 5 | from 词向量印刻 import 词向量印刻 6 | from GPT单元 import 解码层, 全连接层 7 | 8 | 9 | def 创建_上三角_遮罩(尺寸): 10 | 上三角_遮罩= np.triu(np.ones((1, 尺寸, 尺寸)), k=1) 11 | 上三角_遮罩= (上三角_遮罩 != 0) 12 | return 上三角_遮罩 13 | 14 | 15 | def 创建_遮罩(目标_数组,头数): 16 | 17 | if 目标_数组 is not None: 18 | 目标_遮罩 = (目标_数组 != -1) 19 | 目标_遮罩 = 目标_遮罩[:, None, :] 20 | 尺寸 = 目标_数组.shape[1] 21 | 上三角_遮罩 = 创建_上三角_遮罩(尺寸) 22 | 目标_遮罩 = 目标_遮罩 & 上三角_遮罩 23 | 目标_遮罩 = 目标_遮罩.astype('float32') 24 | 目标_遮罩=目标_遮罩*(-1e9) 25 | 目标_遮罩=目标_遮罩[:, None, :, :] 26 | 目标_遮罩=[目标_遮罩 for i in range(头数)] 27 | 目标_遮罩=np.concatenate(目标_遮罩, axis=1) 28 | else: 29 | 目标_遮罩 = None 30 | return 目标_遮罩 31 | 32 | 33 | class 多层解码(nn.Cell): 34 | def __init__(self, 词库总数, 向量维度, 层数, 头数, 丢弃率,辞数,最大长度=1024): 35 | super(多层解码, self).__init__() 36 | self.N = 层数 37 | self.embed = 词向量印刻(词库总数, 向量维度) 38 | self.embedP = 词向量印刻(最大长度, 向量维度) 39 | self.decoders = nn.CellList([解码层(向量维度, 头数, 丢弃率) for i in range(层数)]) 40 | self.norm = nn.LayerNorm((向量维度,), epsilon=1e-6) 41 | a = [i for i in range(辞数)] 42 | b = np.array(a).reshape(1, 辞数) 43 | self.po = Tensor(b, mindspore.int32) 44 | self.dropout = nn.Dropout(1 - 丢弃率) 45 | 46 | def construct(self, 输入, 输入_遮罩): 47 | x = self.embed(输入) 48 | x = x + self.embedP(self.po) 49 | x = self.dropout(x) 50 | for i in range(self.N): 51 | x = self.decoders[i](x, 输入_遮罩) 52 | x = self.norm(x) 53 | return x 54 | 55 | class 输出函数_GPT(nn.Cell): 56 | def __init__(self, 词库总数, 向量维度, 层数, 头数, 丢弃率,辞数=666): 57 | super(输出函数_GPT, self).__init__() 58 | self.Transformer = Transformer(词库总数, 向量维度, 层数, 头数, 丢弃率,辞数) 59 | 输入 = np.ones((1, 辞数)) 60 | MAKS1 = 创建_遮罩(输入, 12) 61 | self.MAKS1 = Tensor(MAKS1) 62 | 63 | def construct(self, 输入): 64 | 输出 = self.Transformer(输入, self.MAKS1) 65 | return 输出 66 | 67 | def 前向(self, 输入, 输入_遮罩=None): 68 | 输出 = self.Transformer(输入, 输入_遮罩) 69 | return 输出 70 | 71 | 72 | class Transformer(nn.Cell): 73 | def __init__(self, 词库总数, 向量维度, 层数, 头数, 丢弃率, 辞数): 74 | super(Transformer, self).__init__() 75 | 76 | self.d_model = 向量维度 77 | self.trg_vocab = 词库总数 78 | self.decoder = 多层解码(词库总数, 向量维度, 层数, 头数, 丢弃率, 辞数) 79 | self.out = 全连接层(向量维度, 词库总数) 80 | self.shape = P.Shape() 81 | self.reshape = P.Reshape() 82 | 83 | def construct(self, 输入, 输入_遮罩): 84 | bs = self.shape(输入)[0] 85 | d_output = self.decoder(输入, 输入_遮罩) 86 | d_output = self.reshape(d_output, (-1, self.d_model)) 87 | output = self.out(d_output) 88 | 输出 = self.reshape(output, (bs, -1, self.trg_vocab)) 89 | return 输出 90 | 91 | -------------------------------------------------------------------------------- /GPT_train/ROCStories_训练.py: -------------------------------------------------------------------------------- 1 | from mindspore.train.callback import ModelCheckpoint, CheckpointConfig, LossMonitor, TimeMonitor 2 | from mindspore.train import Model 3 | from mindspore.nn.metrics import Accuracy 4 | import mindspore.dataset as mds 5 | from mindspore import context, nn 6 | from GPT模型 import 输出函数_GPT 7 | import os.path 8 | from mindspore.train.serialization import load_checkpoint, load_param_into_net 9 | from 生成midspore训练数据 import json到minecord 10 | def create_dataset(base_path, batch_size, num_epochs): 11 | path = base_path 12 | dataset = mds.MindDataset(path, columns_list=["input", "output"], num_parallel_workers=4) 13 | dataset = dataset.shuffle(buffer_size=dataset.get_dataset_size()) 14 | dataset = dataset.batch(batch_size=batch_size, drop_remainder=True) 15 | dataset = dataset.repeat(count=num_epochs) 16 | return dataset 17 | #注意!!这里的训练的文本长度为666 这在数据预处理时已经定了,可利用预处理的代码重定文本长度。预处理的代码和数据放在一起。 18 | #以下是模型参数 19 | 文本长度 = 666 # 固定长度就不用每次训练都生成mask 20 | 丢弃率 = 0.0 21 | 词库总数 = 50001 # 组成是UTF8单字符和部分英文字母组合请务必保留此数,如需更改则需要重改json查询表并重新生成训练数据 22 | 向量维度 = 768 23 | 层数 = 12 24 | 头数 = 12 25 | 26 | 27 | #________________________以下是Adam优化算法的参数 28 | 学习率 = 6.25e-5 29 | beta1 = 0.9 30 | beta2=0.98 31 | eps=1e-09 32 | 33 | 34 | # 每一步耗时约1.5秒 35 | epoch = 3 36 | batch_size = 2 37 | 原始文件路径 = '../data/ROCStories_训练和测试/ROCStories/ROCStories_dev.json' 38 | 过渡文件路径 = '../data/ROCStories_训练和测试/ROCStories/ROCStories_dev.npz' 39 | 最终文件名 = 'ROCStories_dev' 40 | 预训练数据路径='../data/checkpoint/ROCStories/checkpoint_ROCStories-1_5227.ckpt' #请确保有预训练的文件 41 | if os.path.isfile("../data/mindrecord/"+最终文件名+".minecord.db") and os.path.isfile("..data/mindrecord/"+最终文件名+".minecord"): 42 | print("发现mindrecord类型训练数据,直接加载训练。") 43 | dataset = create_dataset("../data/mindrecord/"+最终文件名+".minecord", batch_size, 1) 44 | else: 45 | print("未发现mindrecord类型训练数据,正在生成,请稍等......") 46 | 47 | json到minecord(原始文件路径, 过渡文件路径, 最终文件名) 48 | dataset = create_dataset("../data/mindrecord/"+最终文件名+".minecord", batch_size, 1) 49 | 50 | device_target = "GPU" 51 | context.set_context(mode=context.GRAPH_MODE, device_target=device_target) 52 | network = 输出函数_GPT(词库总数, 向量维度, 层数, 头数, 丢弃率, 文本长度) 53 | if os.path.isfile(预训练数据路径): 54 | 55 | param_dict = load_checkpoint(预训练数据路径) 56 | load_param_into_net(network, param_dict) 57 | net_loss = nn.SoftmaxCrossEntropyWithLogits(is_grad=False, sparse=True, reduction="mean") 58 | net_opt = nn.Adam(network.trainable_params(), learning_rate=学习率, beta1=beta1, beta2=beta2, eps=eps) 59 | time_cb = TimeMonitor(data_size=dataset.get_dataset_size()) 60 | config_ck = CheckpointConfig(save_checkpoint_steps=200, keep_checkpoint_max=1) 61 | ckpoint_cb = ModelCheckpoint(prefix="checkpoint_" + 最终文件名, directory="../data/checkpoint/"+最终文件名, config=config_ck) 62 | model = Model(network, net_loss, net_opt, {'acc': Accuracy()}) 63 | print("开始训练单步时长1.5秒") 64 | model.train(epoch=epoch, train_dataset=dataset, callbacks=[time_cb, ckpoint_cb, LossMonitor()], 65 | dataset_sink_mode=False) -------------------------------------------------------------------------------- /GPT_test/GPT模型_测试.py: -------------------------------------------------------------------------------- 1 | from mindspore import Tensor, nn 2 | import mindspore 3 | import numpy as np 4 | import mindspore.ops.operations as P 5 | from 词向量印刻 import 词向量印刻 6 | from GPT单元 import 解码层, 全连接层 7 | 8 | 9 | def 创建_上三角_遮罩(尺寸): 10 | 上三角_遮罩= np.triu(np.ones((1, 尺寸, 尺寸)), k=1) 11 | 上三角_遮罩= (上三角_遮罩 != 0) 12 | return 上三角_遮罩 13 | 14 | 15 | def 创建_遮罩(目标_数组,头数): 16 | 17 | if 目标_数组 is not None: 18 | 目标_遮罩 = (目标_数组 != -1) 19 | 目标_遮罩 = 目标_遮罩[:, None, :] 20 | 尺寸 = 目标_数组.shape[1] 21 | 上三角_遮罩 = 创建_上三角_遮罩(尺寸) 22 | 目标_遮罩 = 目标_遮罩 & 上三角_遮罩 23 | 目标_遮罩 = 目标_遮罩.astype('float32') 24 | 目标_遮罩=目标_遮罩*(-1e9) 25 | 目标_遮罩=目标_遮罩[:, None, :, :] 26 | 目标_遮罩=[目标_遮罩 for i in range(头数)] 27 | 目标_遮罩=np.concatenate(目标_遮罩, axis=1) 28 | else: 29 | 目标_遮罩 = None 30 | return 目标_遮罩 31 | 32 | 33 | class 多层解码(nn.Cell): 34 | def __init__(self, 词库总数, 向量维度, 层数, 头数, 丢弃率,辞数,最大长度=1024): 35 | super(多层解码, self).__init__() 36 | self.N = 层数 37 | self.embed = 词向量印刻(词库总数, 向量维度) 38 | self.embedP = 词向量印刻(最大长度, 向量维度) 39 | self.decoders = nn.CellList([解码层(向量维度, 头数, 丢弃率) for i in range(层数)]) 40 | self.norm = nn.LayerNorm((向量维度,), epsilon=1e-6) 41 | a = [i for i in range(辞数)] 42 | b = np.array(a).reshape(1, 辞数) 43 | self.po = Tensor(b, mindspore.int32) 44 | self.dropout = nn.Dropout(1 - 丢弃率) 45 | 46 | def construct(self, 输入, 输入_遮罩): 47 | x = self.embed(输入) 48 | 长=P.Shape()(x)[1] 49 | a = [i for i in range(长)] 50 | b = np.array(a).reshape(1, 长) 51 | po = Tensor(b, mindspore.int32) 52 | x = x + self.embedP(po) 53 | x = self.dropout(x) 54 | for i in range(self.N): 55 | x = self.decoders[i](x, 输入_遮罩) 56 | x = self.norm(x) 57 | return x 58 | 59 | class 输出函数_GPT(nn.Cell): 60 | def __init__(self, 词库总数, 向量维度, 层数, 头数, 丢弃率,辞数=666): 61 | super(输出函数_GPT, self).__init__() 62 | self.Transformer = Transformer(词库总数, 向量维度, 层数, 头数, 丢弃率,辞数) 63 | 输入 = np.ones((1, 辞数)) 64 | MAKS1 = 创建_遮罩(输入, 12) 65 | self.MAKS1 = Tensor(MAKS1) 66 | 67 | def construct(self, 输入): 68 | 输出 = self.Transformer(输入, self.MAKS1) 69 | return 输出 70 | 71 | def 前向(self, 输入, 输入_遮罩=None): 72 | 输出 = self.Transformer(输入, 输入_遮罩) 73 | return 输出 74 | 75 | 76 | class Transformer(nn.Cell): 77 | def __init__(self, 词库总数, 向量维度, 层数, 头数, 丢弃率, 辞数): 78 | super(Transformer, self).__init__() 79 | 80 | self.d_model = 向量维度 81 | self.trg_vocab = 词库总数 82 | self.decoder = 多层解码(词库总数, 向量维度, 层数, 头数, 丢弃率, 辞数) 83 | self.out = 全连接层(向量维度, 词库总数) 84 | self.shape = P.Shape() 85 | self.reshape = P.Reshape() 86 | 87 | def construct(self, 输入, 输入_遮罩): 88 | bs = self.shape(输入)[0] 89 | d_output = self.decoder(输入, 输入_遮罩) 90 | d_output = self.reshape(d_output, (-1, self.d_model)) 91 | output = self.out(d_output) 92 | 输出 = self.reshape(output, (bs, -1, self.trg_vocab)) 93 | return 输出 94 | 95 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # GPT学习 2 | 本模型主要参考了[SamLynnEvans Transformer](https://github.com/SamLynnEvans/Transformer) 的源码,其次参考了[graykode gpt-2-Pytorch](https://github.com/graykode/gpt-2-Pytorch/tree/master/GPT2) 3 | 的源码。 4 | 此模型把上文所提Transformer模型的解码部份分离出来 把Relu换成了Gelu,把位置编码方式换成可训练的。 5 | 同时完成了pytorch和mindspore的搭建,这里只上传mindspore的。 6 | 7 | 理论上GTP这个模型时可以同时处理多种语言的,但处理多种语言会使得模型变得非常庞大而超出我这可怜的GTX1660的能力范围。不过令人可喜的是以现在的硬件条件依然可以勉强完成参数 8 | 约1亿的模型训练,训练的方式是先在约1亿字符的语料库上预训练再根据具体任务再训练。 9 | 而训练的结果,虽然并不十分完美,但已经给了我很大的惊喜。 10 | 11 | 如图: 12 | 文本生成《西游记》 13 | 14 | ![西游记](image/7DC52A21FAFFF8093729E0E0D40E3DE5.jpg) 15 | ![西游记](https://scienhere.com/image/7DC52A21FAFFF8093729E0E0D40E3DE5.jpg) 16 | --- 17 | 18 | 19 | 文本生成《红楼梦》 20 | 21 | ![红楼梦](image/98A3DC28322429BBE766B70D26CCB375.jpg) 22 | ![红楼梦](https://scienhere.com/image/98A3DC28322429BBE766B70D26CCB375.jpg) 23 | --- 24 | 文本生成《二十四史——陈书》 25 | 26 | ![陈书1](image/4C077E3221DCC324718E1EE2C7BC1A00.jpg) 27 | ![陈书1](https://scienhere.com/image/4C077E3221DCC324718E1EE2C7BC1A00.jpg) 28 | 29 | 30 | ![陈书2](image/04E09FF3345D1E188923369CE589C67F.jpg) 31 | ![陈书2](https://scienhere.com/image/04E09FF3345D1E188923369CE589C67F.jpg) 32 | 33 | 34 | 😏感觉这个文言文水平比我好多了, 35 | 36 | 总的感觉是这个模型对于字词和语法都有较好把握,但对于其中的内在联系却没有学习到,比如唐僧自称老孙。 37 | 38 | # 基于mindspore搭建GPT模型的尝试 39 | mindspore模型是为了参加一个基于mindspore的比赛而搭建,这里并不提供训练文本。 40 | 41 | 42 | 预训练可以是新闻、书籍、代码之类的训练语料,但是语料的长度并没有明确限定。我看见的GPT3中公布的语料样例中有3.9兆大小的文本,以英文为主包含了其它语言,内容各式各样。 43 | 我这里用的是666*2的语料长度每666个字或词作为一个Batch Size。训练方式如图: 44 | ![GPT预训练流程简图](image/AD5984B2236009053E5AD80325AC0B69.png) 45 | 46 | - [ ] :注意:在GPT模型的预训练过程中并不只是完成由"我爱北京天安门"预测一个",", 47 | 而且通过适当的mask遮罩并行完成了"我"到"爱"的预测,以及 "我爱"到"北"的预测....如此类推。 48 | 目前用了大约含有3600万单词的数据集训练了4轮,我估计数据集偏小。 49 | 50 | 预训练和再训练脚本图: 51 | 52 | ![预训练和再训练脚本图](image/1EE91DC06D18692773CF3DD13572D682.png) 53 | 54 | 模型相关参数已经写入训练脚本 55 | 56 | ![相关参数](image/sendpix0.jpg) 57 | 58 | 59 | ### 再训练(微调) 60 | 61 | 相比于GPT3这样的庞大模型,GPT1这样规模的模型必须通过再训练微调参数来实现具体语言任务。具体到当前的任务ROCStories 62 | 通过下载此训练集观察可以发现此数据集的训练集和测试集有一个重要的不同,训练集最后只有一项符合前文的正例,没有不符合前文的 63 | 负例。我的做法是在整个训练集随机选取一句话作为负例,再构造成如下形式,图: 64 | ![再训练文本](image/030AB2157517DB02D70CC2FDC2A1E3F3.png) 65 | 再将这样一种构造的文本和与预训练一样的方式进行训练。 66 | 67 | - [ ] :综合说来,这里再训练和预训练的方法是一样的。不同的是:再训练时,新构造了一种特殊的文本结构来达到GPT网络完成具体任务的目的。 68 | 69 | 70 | ### 测试 71 | 测试过程是一段测试材料一个Batch 72 | 73 | 最后的分支(Batch Size)的大小在这里为(666*3/每支大小) 74 | 这里不用担心材料长短不齐的mask问题。测试材料的格式样例如下,相比原csv格式作了调整。 75 | 76 | {"input": "Sara had lost her cat.She was so sad!She put up signs all over the neighborhood.Then a wonderful thing happened.|Sarah broke her leg.|Somebody found her cat.&", "labe": "2"} 77 | {"input": "Kelly was playing her new Mario game.She had been playing it for weeks.She was playing for so long without beating the level.Finally she beat the last level.|Kelly was mad about that.|Kelly was so happy to finally beat it.&", "labe": "2"} 78 | 79 | 如上面两段测试材料这里只关心&后的输出,具体看测试脚本。 80 | 81 | ![测试代码位置](image/3E178AF03E21C7B60BA4A77BEC0A77E4.png) 82 | 83 | 测试完成会生成测试报告如图: 84 | ![测试报告图](image/718EC6C51639765F9A21CEE1CBE1089A.png) 85 | 86 | ### 分析 87 | 我认为 虽然此模型和网上流行的GPT模型不完全同,但我认为造成和目标精度(85%。有人用openAI的预训练模型做到了87%以上)差距巨大的一个可能原因是 88 | 训练材料偏少。GPT_1的论文中说是用了7000本书。以每本书10万词算,有7亿词的训练材料。另一个可能原因是再训练时实现目标任务方式增加了模型的判断难度。 89 | 具体是什么原因需要进行验证才能最终定论。 90 | -------------------------------------------------------------------------------- /data/cvs处理.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import os 3 | import json 4 | import numpy as np 5 | def _rocstories(path,txtpath): 6 | with open(path, encoding='utf_8') as f: 7 | with open(txtpath, 'w', encoding='utf-8') as f2: 8 | f = csv.reader(f) 9 | s1='' 10 | lf=list(f) 11 | for i, line in enumerate(lf): 12 | if i > 0: 13 | s = line[1:5] 14 | for i in s: 15 | s1=s1+i 16 | 17 | c1 = line[5] 18 | c2 = line[6] 19 | y=int(line[-1]) 20 | 21 | if y==1: 22 | 组1 = '#' +s1 + '|' + c1 + '|' + c2 + '&' + str(1) 23 | 24 | 25 | else: 26 | 27 | 组1 = '#' +s1 + '|' + c1 + '|' + c2 + '&' + str(2) 28 | 29 | s1='' 30 | f2.write(组1+ '\n') 31 | 32 | for i, line in enumerate(lf): 33 | if i > 0: 34 | s = line[1:5] 35 | for i in s: 36 | s1=s1+i 37 | 38 | c1 = line[5] 39 | c2 = line[6] 40 | y=int(line[-1]) 41 | 42 | if y==1: 43 | 44 | 组2 = '#' +s1 + '|' + c2 + '|' + c1 + '&' + str(2) 45 | 46 | else: 47 | 48 | 49 | 组2 = '#' +s1 + '|' + c2 + '|' + c1 + '&' + str(1) 50 | s1='' 51 | f2.write(组2+ '\n') 52 | 53 | return y 54 | 55 | def _rocstories3(path,txtpath): 56 | with open(path, encoding='utf_8') as f: 57 | with open(txtpath, 'w', encoding='utf-8') as f2: 58 | f = csv.reader(f) 59 | s1='' 60 | x1=3 61 | x2=3 62 | lf=list(f) 63 | 64 | for i, line in enumerate(lf): 65 | if i > 0: 66 | s = line[2:6] 67 | for ss in s: 68 | s1=s1+ss 69 | 70 | c1 = line[6] 71 | x1=np.random.randint(1,len(lf)) 72 | x2 = np.random.randint(2, 7) 73 | c2 = lf[x1][x2] 74 | x2 = np.random.randint(1, 3) 75 | if x2==1: 76 | 77 | 组1 = '#' +s1 + '|' + c1 + '|' + c2 + '&' + str(1) 78 | else: 79 | 组1 = '#' +s1 + '|' + c2 + '|' + c1 + '&' + str(2) 80 | s1='' 81 | f2.write(组1+ '\n') 82 | 83 | return x1 84 | 85 | 86 | def _rocstories_test(path,txtpath): 87 | with open(path, encoding='utf_8') as f: 88 | with open(txtpath, 'w', encoding='utf-8') as f2: 89 | f = csv.reader(f) 90 | s1='' 91 | 字典={} 92 | 93 | for i, line in enumerate(list(f)): 94 | if i > 0: 95 | s = line[1:5] 96 | for i in s: 97 | s1=s1+i 98 | 99 | c1 = line[5] 100 | c2 = line[6] 101 | y=int(line[-1]) 102 | 103 | 104 | 组1 = s1 + '|' + c1 + '|' + c2 + '&' 105 | 字典['input']=组1 106 | 字典['labe']=str(y) 107 | s1='' 108 | 109 | json.dump(字典, f2, ensure_ascii=False) 110 | f2.write('\n') 111 | 112 | return y 113 | 114 | 路径="./csvdata/cloze_test_test__spring2016 - cloze_test_ALL_test.csv" 115 | 116 | 路径json="./ROCStories_训练和测试/ROCStories/ROCStories_spring2016_test.json" 117 | #_rocstories(路径,路径json) 118 | _rocstories_test(路径,路径json) 119 | -------------------------------------------------------------------------------- /GPT_train/取训练数据.py: -------------------------------------------------------------------------------- 1 | import json 2 | import numpy as np 3 | 4 | def 读出引索(词_数表路径, 数_词表路径): 5 | with open(词_数表路径, encoding='utf-8') as f: 6 | 词_数表= json.load(f) 7 | 8 | with open(数_词表路径, encoding='utf-8') as f: 9 | 数_词表 = json.load(f) 10 | return 词_数表, 数_词表 11 | 12 | def 生成训练用numpy数组_A(输入表单, 词_数表, numpy数组路径): 13 | """ 14 | 将预处理过的文本转化为numpy数组并保存并用于训练。 15 | """ 16 | 表_1 = [] 17 | 表_2 = [] 18 | i=0 19 | 临='' 20 | for 表单 in 输入表单: 21 | 表_3=[] 22 | for 字符 in 表单: 23 | if (u'\u0041' <= 字符 <= u'\u005a') or (u'\u0061' <= 字符 <= u'\u007a'): 24 | if 临 == '': 25 | 26 | 临 = 字符 27 | else: 28 | 临 = 临 + 字符 29 | else: 30 | 31 | if 临 == '': 32 | 33 | if 字符 in 词_数表: 34 | 表_3.append(词_数表[字符]) 35 | else: 36 | 表_3.append(14991) 37 | else: 38 | if 临 in 词_数表: 39 | 表_3.append(词_数表[临]) 40 | else: 41 | 表_3.append(14991) 42 | 临='' 43 | if 字符 in 词_数表: 44 | 表_3.append(词_数表[字符]) 45 | else: 46 | 表_3.append(14991) 47 | if 临!='': 48 | if 临 in 词_数表: 49 | 表_3.append(词_数表[临]) 50 | else: 51 | 表_3.append(14991) 52 | 临 = '' 53 | 54 | 55 | if len(表_3)!=667: 56 | #表_1.append(np.array(表_3[0:-1])) 57 | #表_2.append(np.array(表_3[1:])) 58 | print(表_3) 59 | else: 60 | 61 | 表_1.append(np.array(表_3[0:-1])) 62 | 表_2.append(np.array(表_3[1:])) 63 | if i % 1000 == 0: 64 | print("数据转化为numpy数组完成度百分比{}".format(i/len(输入表单)*100)) 65 | i = i + 1 66 | print("数据转化为numpy数组完成。") 67 | 68 | 69 | 输入np = np.array(表_1) 70 | 输出np = np.array(表_2) 71 | np.savez(numpy数组路径, 输出np=输出np, 输入np=输入np) 72 | 73 | def 读取训练数据_A(路径): 74 | 输入表单 = [] 75 | with open(路径, encoding='utf-8') as f: 76 | while True: 77 | 行 = f.readline() 78 | if not 行: 79 | break 80 | json_行 = json.loads(行) 81 | 82 | 内容 = json_行['input'] 83 | 输入表单.append(内容) 84 | 85 | return 输入表单 86 | def 生成训练用numpy数组_B(输入表单, 词_数表, numpy数组路径): 87 | """ 88 | 将预处理过的文本转化为numpy数组并保存并用于训练。 89 | """ 90 | 表_1 = [] 91 | 表_2 = [] 92 | i=0 93 | 临='' 94 | for 表单 in 输入表单: 95 | 表_3=[] 96 | for 字符 in 表单: 97 | if (u'\u0041' <= 字符 <= u'\u005a') or (u'\u0061' <= 字符 <= u'\u007a'): 98 | if 临 == '': 99 | 100 | 临 = 字符 101 | else: 102 | 临 = 临 + 字符 103 | else: 104 | 105 | if 临 == '': 106 | 107 | if 字符.lower() in 词_数表: 108 | if 字符 != ' ': 109 | 表_3.append(词_数表[字符.lower()]) 110 | else: 111 | 表_3.append(49999) 112 | else: 113 | if 临.lower() in 词_数表: 114 | if 临 != ' ': 115 | 表_3.append(词_数表[临.lower()]) 116 | else: 117 | 表_3.append(49999) 118 | 临='' 119 | if 字符.lower() in 词_数表: 120 | if 字符 != ' ': 121 | 表_3.append(词_数表[字符.lower()]) 122 | else: 123 | 表_3.append(49999) 124 | if 临!='': 125 | if 临.lower() in 词_数表: 126 | if 临 != ' ': 127 | 表_3.append(词_数表[临.lower()]) 128 | else: 129 | 表_3.append(49999) 130 | 临 = '' 131 | 132 | 133 | if len(表_3)!=667: 134 | #表_1.append(np.array(表_3[0:-1])) 135 | #表_2.append(np.array(表_3[1:])) 136 | print(表_3) 137 | else: 138 | 139 | 表_1.append(np.array(表_3[0:-1])) 140 | 表_2.append(np.array(表_3[1:])) 141 | if i % 1000 == 0: 142 | print("数据转化为numpy数组完成度百分比{}".format(i/len(输入表单)*100)) 143 | i = i + 1 144 | print("数据转化为numpy数组完成。") 145 | 146 | 147 | 输入np = np.array(表_1) 148 | 输出np = np.array(表_2) 149 | np.savez(numpy数组路径, 输出np=输出np, 输入np=输入np) -------------------------------------------------------------------------------- /GPT_train/生成midspore训练数据.py: -------------------------------------------------------------------------------- 1 | from 取训练数据 import 读取训练数据_A, 读出引索, 生成训练用numpy数组_A,生成训练用numpy数组_B 2 | import os.path 3 | import numpy as np 4 | from mindspore.mindrecord import FileWriter 5 | 6 | def 数据预处理_json到minecord(): 7 | 8 | 路径 = "../data/训练材料_英语3.json" 9 | 输入表单 = 读取训练数据_A(路径) 10 | 词_数表路径 = "../data/词_数50000.json" 11 | 数_词表路径 = "../data/数_词50000.json" 12 | 13 | if os.path.isfile(词_数表路径) and os.path.isfile(数_词表路径): 14 | 词_数表, 数_词表 = 读出引索(词_数表路径, 数_词表路径) 15 | 16 | 17 | numpy数组路径 = "../data/训练材料_英语3.npz" 18 | if os.path.isfile(numpy数组路径): 19 | npz文件 = np.load(numpy数组路径, allow_pickle=True) 20 | 输出np, 输入np = npz文件["输出np"], npz文件["输入np"] 21 | else: 22 | 23 | 生成训练用numpy数组_B(输入表单, 词_数表, numpy数组路径) #汉语用A英语用B 24 | npz文件 = np.load(numpy数组路径, allow_pickle=True) 25 | 输出np, 输入np = npz文件["输出np"], npz文件["输入np"] 26 | 27 | if os.path.isfile(numpy数组路径): 28 | npz文件 = np.load(numpy数组路径) 29 | 输出np, 输入np = npz文件["输出np"], npz文件["输入np"] 30 | else: 31 | print("训练用numpy数组不存在") 32 | 数据_表 = [] 33 | print("正在打包numpy数组为mindspore所需json格式......") 34 | for i in range(输入np.shape[0]): 35 | 36 | 输入_分 = 输入np[i:i+1, :] 37 | 输入_分 = 输入_分.reshape(-1) 38 | 输出_分 = 输出np[i:i+1, :] 39 | 输出_分 = 输出_分.reshape(-1) 40 | 数据_json = {"id": i, "input": 输入_分.astype(np.int32), "output": 输出_分.astype(np.int32)} 41 | 数据_表.append(数据_json) 42 | 43 | 纲要_json = {"id": {"type": "int32"}, 44 | "input": {"type": "int32", "shape": [-1]}, 45 | "output": {"type": "int32", "shape": [-1]}} 46 | if os.path.isfile("../data/mindrecord/训练材料_英语3.minecord.db"): 47 | os.remove("../data/mindrecord/训练材料_英语3.minecord.db") 48 | if os.path.isfile("../data/mindrecord/训练材料_英语3.minecord"): 49 | os.remove("../data/mindrecord/训练材料_英语3.minecord") 50 | print("写入mindspore格式需要预留约10G内存") 51 | print("正在写入mindspore格式......") 52 | writer = FileWriter("../data/mindrecord/训练材料_英语3.minecord", shard_num=1) 53 | writer.add_schema(纲要_json, "nlp_1") 54 | writer.add_index(["id"]) 55 | writer.write_raw_data(数据_表) 56 | writer.commit() 57 | print("写入mindspore格式完成。") 58 | else: 59 | print('词_数表路径或数_词表路径不存在') 60 | def json到minecord(路径,numpy路径,最终文件名): 61 | 62 | #路径 = "../data/预训练数据.json" 63 | 输入表单 = 读取训练数据_A(路径) 64 | 词_数表路径 = "../data/词_数50000.json" 65 | 数_词表路径 = "../data/数_词50000.json" 66 | 67 | if os.path.isfile(词_数表路径) and os.path.isfile(数_词表路径): 68 | 词_数表, 数_词表 = 读出引索(词_数表路径, 数_词表路径) 69 | 70 | 71 | 72 | numpy数组路径 = numpy路径 73 | if os.path.isfile(numpy数组路径): 74 | npz文件 = np.load(numpy数组路径, allow_pickle=True) 75 | 输出np, 输入np = npz文件["输出np"], npz文件["输入np"] 76 | else: 77 | 78 | 生成训练用numpy数组_B(输入表单, 词_数表, numpy数组路径) 79 | npz文件 = np.load(numpy数组路径, allow_pickle=True) 80 | 输出np, 输入np = npz文件["输出np"], npz文件["输入np"] 81 | 82 | if os.path.isfile(numpy数组路径): 83 | npz文件 = np.load(numpy数组路径) 84 | 输出np, 输入np = npz文件["输出np"], npz文件["输入np"] 85 | else: 86 | print("训练用numpy数组不存在") 87 | 数据_表 = [] 88 | print("正在打包numpy数组为mindspore所需json格式......") 89 | for i in range(输入np.shape[0]): 90 | 91 | 输入_分 = 输入np[i:i+1, :] 92 | 输入_分 = 输入_分.reshape(-1) 93 | 输出_分 = 输出np[i:i+1, :] 94 | 输出_分 = 输出_分.reshape(-1) 95 | 数据_json = {"id": i, "input": 输入_分.astype(np.int32), "output": 输出_分.astype(np.int32)} 96 | 数据_表.append(数据_json) 97 | 98 | 纲要_json = {"id": {"type": "int32"}, 99 | "input": {"type": "int32", "shape": [-1]}, 100 | "output": {"type": "int32", "shape": [-1]}} 101 | if os.path.isfile("../data/mindrecord/"+最终文件名+".minecord.db"): 102 | os.remove("../data/mindrecord/"+最终文件名+".minecord.db") 103 | if os.path.isfile("../data/mindrecord/"+最终文件名+".minecord"): 104 | os.remove("../data/mindrecord/"+最终文件名+".minecord") 105 | print("正在写入mindspore格式......") 106 | writer = FileWriter("../data/mindrecord/"+最终文件名+".minecord", shard_num=1) 107 | writer.add_schema(纲要_json, "nlp_1") 108 | writer.add_index(["id"]) 109 | writer.write_raw_data(数据_表) 110 | writer.commit() 111 | print("写入mindspore格式完成。") 112 | 113 | else: 114 | 115 | print('词_数表路径或数_词表路径不存在') -------------------------------------------------------------------------------- /data/文本预处理_带词频统计.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | 4 | def 存(段,文件号,j): 5 | 临2 = {} 6 | if ('¶' in 段) or ('å' in 段): 7 | 8 | print(段, "--------------------") 9 | 段 = '' 10 | 11 | else: 12 | 临2["id"] = j 13 | 临2["input"] = 段 14 | 15 | json.dump(临2, 文件号, ensure_ascii=False) 16 | 文件号.write('\n') 17 | 18 | 19 | def txt文本_到训练数据(dirname, 文件号,文本长度=667): 20 | result = [] # 所有的文件 21 | 22 | j = 0 23 | i = 0 24 | 临 = '' 25 | 计数 = 0 26 | 小计=0 27 | 段 = '' 28 | 标号_到_字符 = {} 29 | 字符_到_标号 = {} 30 | 字符_到_词频 = {} 31 | 标号_字符 = [] 32 | for maindir, subdir, file_name_list in os.walk(dirname): 33 | 34 | for filename in file_name_list: 35 | 36 | apath = os.path.join(maindir, filename) # 合并成一个完整路径 37 | print(apath) 38 | f = open(apath, "r", encoding='utf8') 39 | str1 = f.read() 40 | for s in str1: 41 | 42 | if (u'\u0041' <= s <= u'\u005a') or (u'\u0061' <= s <= u'\u007a') : 43 | if 临 == '': 44 | 45 | 临 = s 46 | else: 47 | 临 = 临 + s 48 | 49 | 50 | else: 51 | if 临 == '': 52 | 段 = 段 + s 53 | 小计=小计+1 54 | if 小计 == 文本长度: 55 | 存(段, 文件号, j) 56 | 小计=0 57 | j=j+1 58 | 段 = '' 59 | if s not in 标号_字符: 60 | 标号_字符.append(s) 61 | 字符_到_标号[s] = i 62 | 标号_到_字符[i] = s 63 | 字符_到_词频[s] = 1 64 | i = i + 1 65 | else: 66 | 字符_到_词频[s]=字符_到_词频[s]+1 67 | 68 | 计数 = 计数 + 1 69 | else: 70 | 71 | 段 = 段 + 临 72 | 小计 = 小计 + 1 73 | if 小计 == 文本长度: 74 | 存(段, 文件号, j) 75 | 小计=0 76 | j=j+1 77 | 段='' 78 | if 临 not in 标号_字符: 79 | 标号_字符.append(临) 80 | 字符_到_标号[临] = i 81 | 标号_到_字符[i] = 临 82 | 字符_到_词频[临] =1 83 | i = i + 1 84 | else: 85 | 数=字符_到_词频[临] + 1 86 | # if 数>100: 87 | # print(临," 这个词的词频为{}".format(数)) 88 | 字符_到_词频[临]=数 89 | 计数 = 计数 + 1 90 | 段 = 段 + s 91 | 小计 = 小计 + 1 92 | if 小计 == 文本长度: 93 | 存(段, 文件号, j) 94 | 小计=0 95 | j=j+1 96 | 段 = '' 97 | if s not in 标号_字符: 98 | 标号_字符.append(s) 99 | 字符_到_标号[s] = i 100 | 标号_到_字符[i] = s 101 | 字符_到_词频[s] = 1 102 | i = i + 1 103 | else: 104 | 字符_到_词频[s]=字符_到_词频[s]+1 105 | 临 = '' 106 | 计数 = 计数 + 1 107 | 108 | if 计数 % 100000 == 0 and i != 0: 109 | print(i, 标号_到_字符[i - 1], filename,计数) 110 | 段 = '' 111 | 临 = '' 112 | print(标号_到_字符[1], 标号_到_字符[111], len(标号_到_字符)) 113 | with open("./新生成的训练数据/词_数表路径.json", 'w', encoding='utf-8') as f: 114 | json.dump(字符_到_标号, f, ensure_ascii=False) 115 | with open("./新生成的训练数据/数_词表路径.json", 'w', encoding='utf-8') as f: 116 | json.dump(标号_到_字符, f, ensure_ascii=False) 117 | with open("./新生成的训练数据/字符_到_词频.json", 'w', encoding='utf-8') as f: 118 | json.dump(字符_到_词频, f, ensure_ascii=False) 119 | return "临2" 120 | 121 | ##################################### 122 | #基本处理原则是: 123 | #【1】按一定字符长度把要处理的文本切割成块 124 | #【2】把所有连续英语字母当作一个字符 125 | #【3】同时采集词频和生成查询表 126 | ##################################### 127 | 128 | 129 | 130 | with open("./新生成的训练数据/XXX训练材料.json", "w", encoding="utf8") as f: 131 | json数据 = txt文本_到训练数据("./TXT", f) 132 | print(json数据) 133 | -------------------------------------------------------------------------------- /GPT_test/GPT单元.py: -------------------------------------------------------------------------------- 1 | import mindspore.ops.operations as P 2 | import mindspore.nn as nn 3 | import mindspore 4 | from mindspore import Tensor 5 | import numpy as np 6 | 7 | class 前向传播网络(nn.Cell): 8 | """ 9 | 与transformer不同的是把激活Relu换替换为Gelu。 10 | """ 11 | def __init__(self, 输入_接口, 输出_接口=2048, 丢弃率=0.1): 12 | super(前向传播网络, self).__init__() 13 | self.linear_1 = 全连接层(输入_接口, 输出_接口) 14 | self.gelu = P.Gelu() 15 | self.linear_2 = 全连接层(输出_接口, 输入_接口) 16 | self.Dropout = nn.Dropout(1-丢弃率) 17 | 18 | def construct(self, x): 19 | x = self.linear_1(x) 20 | x = self.gelu(x) 21 | x = self.Dropout(x) 22 | x = self.linear_2(x) 23 | return x 24 | 25 | 26 | class 多头_注意力(nn.Cell): 27 | """ 28 | 核心中的核心值得进一步研究。 29 | 30 | """ 31 | def __init__(self, 头数, 尺寸, 丢弃率=0.1): 32 | super(多头_注意力, self).__init__() 33 | self.d_model = 尺寸 34 | self.d_k = 尺寸 // 头数 35 | self.d_k_Tensor = Tensor(尺寸 // 头数, mindspore.float32) 36 | self.h = 头数 37 | self.q_linear = 全连接层(尺寸, 尺寸) 38 | self.v_linear = 全连接层(尺寸, 尺寸) 39 | self.k_linear = 全连接层(尺寸, 尺寸) 40 | self.dropout = nn.Dropout(1-丢弃率) 41 | self.out = 全连接层(尺寸, 尺寸) 42 | self.reshape = P.Reshape() 43 | self.transpose = P.Transpose() 44 | self.shape = P.Shape() 45 | 46 | self.batch_matmul = P.BatchMatMul() 47 | self.add = P.TensorAdd() 48 | self.transpose = P.Transpose() 49 | self.sqrt = P.Sqrt() 50 | self.softmax = P.Softmax(-1) 51 | 52 | def construct(self, 输入, 遮罩=None): 53 | bs = self.shape(输入)[0] 54 | 查询向量 = self.reshape(self.q_linear(self.reshape(输入, (-1, self.d_model))), (bs, -1, self.h, self.d_k)) 55 | 键向量 = self.reshape(self.k_linear(self.reshape(输入, (-1, self.d_model))), (bs, -1, self.h, self.d_k)) 56 | 值向量 = self.reshape(self.v_linear(self.reshape(输入, (-1, self.d_model))), (bs, -1, self.h, self.d_k)) 57 | 58 | 查询向量 = self.transpose(查询向量, (0, 2, 1, 3)) 59 | 键向量 = self.transpose(键向量, (0, 2, 1, 3)) 60 | 值向量 = self.transpose(值向量, (0, 2, 1, 3)) 61 | #----------------------------------------------------------------- 62 | 键向量_转置 = self.transpose(键向量, (0, 1, 3, 2)) 63 | 关连度 = self.batch_matmul(查询向量, 键向量_转置) 64 | 关连度 = 关连度 / self.sqrt(self.d_k_Tensor) 65 | 66 | if 遮罩 is not None: 67 | 关连度 = self.add(关连度, 遮罩) # 遮罩目前来看很重要,否则训练不出理想结果 68 | 关连度 = self.softmax(关连度) 69 | 关连度 = self.dropout(关连度) # 粗暴丢弃似乎并非一个好方法 70 | 输出 = self.batch_matmul(关连度, 值向量) 71 | 72 | #----------------------------------------------------------------- 73 | 输出 = self.transpose(输出, (0, 2, 1, 3)) 74 | 输出 = self.reshape(输出, (-1, self.d_model)) 75 | 输出 = self.out(输出) 76 | 输出 = self.reshape(输出, (bs, -1, self.d_model)) 77 | return 输出 78 | 79 | class 解码层(nn.Cell): 80 | """ 81 | GPT核心是transformer的解码部分作细微改动而成。 82 | 83 | """ 84 | def __init__(self, 尺寸, 头数, 丢弃率=0.1): 85 | super(解码层, self).__init__() 86 | self.norm_1 = nn.LayerNorm((尺寸,), epsilon=1e-6) 87 | self.d_model = 尺寸 88 | self.norm_3 = nn.LayerNorm((尺寸,), epsilon=1e-6) 89 | 90 | self.dropout_1 = nn.Dropout(1-丢弃率) 91 | self.dropout_3 = nn.Dropout(1-丢弃率) 92 | 93 | self.attn_1 = 多头_注意力(头数, 尺寸, 丢弃率=丢弃率) 94 | self.ff = 前向传播网络(尺寸, 丢弃率=丢弃率) 95 | self.reshape = P.Reshape() 96 | self.shape = P.Shape() 97 | 98 | def construct(self, 输入, 目标_遮罩): 99 | x = self.norm_1(输入) 100 | x = self.attn_1(x, 目标_遮罩) 101 | x = self.dropout_1(x) 102 | x = 输入 + x 103 | x1 = self.norm_3(x) 104 | bs = self.shape(x1)[0] 105 | x1 = self.reshape(x1, (-1, self.d_model)) 106 | x1 = self.ff(x1) 107 | x1 = self.reshape(x1, (bs, -1, self.d_model)) 108 | 输出 = x + self.dropout_3(x1) 109 | return 输出 110 | 111 | class 全连接层(nn.Cell): 112 | """ 113 | 替代mindspore的nn.Dense。 114 | 可用numpy的随机数种子生成固定的参数以便对比研究。 115 | """ 116 | def __init__(self, 输入_接口, 输出_接口): 117 | super(全连接层, self).__init__() 118 | np.random.seed(1) # 可以生成固定参数以便对比研究,不需要固定参数注释掉此行就可。 119 | self.weight = mindspore.Parameter(Tensor(np.random.uniform(-1/np.sqrt(输入_接口), 1/np.sqrt(输入_接口),(输入_接口, 输出_接口)), mindspore.float32), "w") 120 | self.bias = mindspore.Parameter(Tensor(np.random.uniform(-1/np.sqrt(输入_接口), 1/np.sqrt(输入_接口),输出_接口), mindspore.float32), "b") 121 | self.MatMul=P.MatMul() 122 | 123 | def construct(self, x): 124 | 输出=self.MatMul(x, self.weight) 125 | 输出=输出+self.bias 126 | return 输出 -------------------------------------------------------------------------------- /GPT_train/GPT单元.py: -------------------------------------------------------------------------------- 1 | import mindspore.ops.operations as P 2 | import mindspore.nn as nn 3 | import mindspore 4 | from mindspore import Tensor 5 | import numpy as np 6 | 7 | class 前向传播网络(nn.Cell): 8 | """ 9 | 与transformer不同的是把激活Relu换替换为Gelu。 10 | """ 11 | def __init__(self, 输入_接口, 输出_接口=2048, 丢弃率=0.1): 12 | super(前向传播网络, self).__init__() 13 | self.linear_1 = 全连接层(输入_接口, 输出_接口) 14 | self.gelu = P.Gelu() 15 | self.linear_2 = 全连接层(输出_接口, 输入_接口) 16 | self.Dropout = nn.Dropout(1-丢弃率) 17 | 18 | def construct(self, x): 19 | x = self.linear_1(x) 20 | x = self.gelu(x) 21 | x = self.Dropout(x) 22 | x = self.linear_2(x) 23 | return x 24 | 25 | 26 | class 多头_注意力(nn.Cell): 27 | """ 28 | 核心中的核心值得进一步研究。 29 | 30 | """ 31 | def __init__(self, 头数, 尺寸, 丢弃率=0.1): 32 | super(多头_注意力, self).__init__() 33 | self.d_model = 尺寸 34 | self.d_k = 尺寸 // 头数 35 | self.d_k_Tensor = Tensor(尺寸 // 头数, mindspore.float32) 36 | self.h = 头数 37 | self.q_linear = 全连接层(尺寸, 尺寸) 38 | self.v_linear = 全连接层(尺寸, 尺寸) 39 | self.k_linear = 全连接层(尺寸, 尺寸) 40 | self.dropout = nn.Dropout(1-丢弃率) 41 | self.out = 全连接层(尺寸, 尺寸) 42 | self.reshape = P.Reshape() 43 | self.transpose = P.Transpose() 44 | self.shape = P.Shape() 45 | 46 | self.batch_matmul = P.BatchMatMul() 47 | self.add = P.TensorAdd() 48 | self.transpose = P.Transpose() 49 | self.sqrt = P.Sqrt() 50 | self.softmax = P.Softmax(-1) 51 | 52 | def construct(self, 输入, 遮罩=None): 53 | bs = self.shape(输入)[0] 54 | 查询向量 = self.reshape(self.q_linear(self.reshape(输入, (-1, self.d_model))), (bs, -1, self.h, self.d_k)) 55 | 键向量 = self.reshape(self.k_linear(self.reshape(输入, (-1, self.d_model))), (bs, -1, self.h, self.d_k)) 56 | 值向量 = self.reshape(self.v_linear(self.reshape(输入, (-1, self.d_model))), (bs, -1, self.h, self.d_k)) 57 | 58 | 查询向量 = self.transpose(查询向量, (0, 2, 1, 3)) 59 | 键向量 = self.transpose(键向量, (0, 2, 1, 3)) 60 | 值向量 = self.transpose(值向量, (0, 2, 1, 3)) 61 | #----------------------------------------------------------------- 62 | 键向量_转置 = self.transpose(键向量, (0, 1, 3, 2)) 63 | 关连度 = self.batch_matmul(查询向量, 键向量_转置) 64 | 关连度 = 关连度 / self.sqrt(self.d_k_Tensor) 65 | 66 | if 遮罩 is not None: 67 | 关连度 = self.add(关连度, 遮罩) # 遮罩目前来看很重要,否则训练不出理想结果 68 | 关连度 = self.softmax(关连度) 69 | 关连度 = self.dropout(关连度) # 粗暴丢弃似乎并非一个好方法 70 | 输出 = self.batch_matmul(关连度, 值向量) 71 | 72 | #----------------------------------------------------------------- 73 | 输出 = self.transpose(输出, (0, 2, 1, 3)) 74 | 输出 = self.reshape(输出, (-1, self.d_model)) 75 | 输出 = self.out(输出) 76 | 输出 = self.reshape(输出, (bs, -1, self.d_model)) 77 | return 输出 78 | 79 | class 解码层(nn.Cell): 80 | """ 81 | GPT核心是transformer的解码部分作细微改动而成。 82 | 83 | """ 84 | def __init__(self, 尺寸, 头数, 丢弃率=0.1): 85 | super(解码层, self).__init__() 86 | self.norm_1 = nn.LayerNorm((尺寸,), epsilon=1e-6) 87 | self.d_model = 尺寸 88 | self.norm_3 = nn.LayerNorm((尺寸,), epsilon=1e-6) 89 | 90 | self.dropout_1 = nn.Dropout(1-丢弃率) 91 | self.dropout_3 = nn.Dropout(1-丢弃率) 92 | 93 | self.attn_1 = 多头_注意力(头数, 尺寸, 丢弃率=丢弃率) 94 | self.ff = 前向传播网络(尺寸, 丢弃率=丢弃率) 95 | self.reshape = P.Reshape() 96 | self.shape = P.Shape() 97 | 98 | def construct(self, 输入, 目标_遮罩): 99 | x = self.norm_1(输入) 100 | x = self.attn_1(x, 目标_遮罩) 101 | x = self.dropout_1(x) 102 | x = 输入 + x 103 | x1 = self.norm_3(x) 104 | bs = self.shape(x1)[0] 105 | x1 = self.reshape(x1, (-1, self.d_model)) 106 | x1 = self.ff(x1) 107 | x1 = self.reshape(x1, (bs, -1, self.d_model)) 108 | 输出 = x + self.dropout_3(x1) 109 | return 输出 110 | 111 | class 全连接层(nn.Cell): 112 | """ 113 | 替代mindspore的nn.Dense。 114 | 可用numpy的随机数种子生成固定的参数以便对比研究。 115 | """ 116 | def __init__(self, 输入_接口, 输出_接口): 117 | super(全连接层, self).__init__() 118 | np.random.seed(1) # 可以生成固定参数以便对比研究,不需要固定参数注释掉此行就可。 119 | self.weight = mindspore.Parameter(Tensor(np.random.uniform(-1/np.sqrt(输入_接口), 1/np.sqrt(输入_接口),(输入_接口, 输出_接口)), mindspore.float32), "w") 120 | self.bias = mindspore.Parameter(Tensor(np.random.uniform(-1/np.sqrt(输入_接口), 1/np.sqrt(输入_接口),输出_接口), mindspore.float32), "b") 121 | self.MatMul=P.MatMul() 122 | 123 | def construct(self, x): 124 | 输出=self.MatMul(x, self.weight) 125 | 输出=输出+self.bias 126 | return 输出 -------------------------------------------------------------------------------- /GPT_test/取训练数据.py: -------------------------------------------------------------------------------- 1 | import json 2 | import numpy as np 3 | 4 | def 读出引索(词_数表路径, 数_词表路径): 5 | with open(词_数表路径, encoding='utf-8') as f: 6 | 词_数表= json.load(f) 7 | 8 | with open(数_词表路径, encoding='utf-8') as f: 9 | 数_词表 = json.load(f) 10 | return 词_数表, 数_词表 11 | 12 | def 生成训练用numpy数组_A(输入表单, 词_数表, numpy数组路径): 13 | """ 14 | 将预处理过的文本转化为numpy数组并保存并用于训练。 15 | """ 16 | 表_1 = [] 17 | 表_2 = [] 18 | i=0 19 | 临='' 20 | for 表单 in 输入表单: 21 | 表_3=[] 22 | for 字符 in 表单: 23 | if (u'\u0041' <= 字符 <= u'\u005a') or (u'\u0061' <= 字符 <= u'\u007a'): 24 | if 临 == '': 25 | 26 | 临 = 字符 27 | else: 28 | 临 = 临 + 字符 29 | else: 30 | 31 | if 临 == '': 32 | 33 | if 字符 in 词_数表: 34 | 表_3.append(词_数表[字符]) 35 | else: 36 | 表_3.append(14991) 37 | else: 38 | if 临 in 词_数表: 39 | 表_3.append(词_数表[临]) 40 | else: 41 | 表_3.append(14991) 42 | 临='' 43 | if 字符 in 词_数表: 44 | 表_3.append(词_数表[字符]) 45 | else: 46 | 表_3.append(14991) 47 | if 临!='': 48 | if 临 in 词_数表: 49 | 表_3.append(词_数表[临]) 50 | else: 51 | 表_3.append(14991) 52 | 临 = '' 53 | 54 | 55 | if len(表_3)!=667: 56 | #表_1.append(np.array(表_3[0:-1])) 57 | #表_2.append(np.array(表_3[1:])) 58 | print(表_3) 59 | else: 60 | 61 | 表_1.append(np.array(表_3[0:-1])) 62 | 表_2.append(np.array(表_3[1:])) 63 | if i % 1000 == 0: 64 | print("数据转化为numpy数组完成度百分比{}".format(i/len(输入表单)*100)) 65 | i = i + 1 66 | print("数据转化为numpy数组完成。") 67 | 68 | 69 | 输入np = np.array(表_1) 70 | 输出np = np.array(表_2) 71 | np.savez(numpy数组路径, 输出np=输出np, 输入np=输入np) 72 | 73 | def 读取训练数据_A(路径): 74 | 输入表单 = [] 75 | with open(路径, encoding='utf-8') as f: 76 | while True: 77 | 行 = f.readline() 78 | if not 行: 79 | break 80 | json_行 = json.loads(行) 81 | 82 | 内容 = json_行['input'] 83 | 输入表单.append(内容) 84 | 85 | return 输入表单 86 | def 生成测试用numpy数组_A(输入表单, 词_数表): 87 | 表_3 = [] 88 | 临 = '' 89 | 90 | for 字符 in 输入表单: 91 | if 字符 in 词_数表: 92 | if (u'\u0041' <= 字符 <= u'\u005a') or (u'\u0061' <= 字符 <= u'\u007a'): 93 | if 临 == '': 94 | 95 | 临 = 字符 96 | else: 97 | 临 = 临 + 字符 98 | else: 99 | 100 | if 临 == '': 101 | 102 | if 字符 in 词_数表: 103 | 表_3.append(词_数表[字符]) 104 | else: 105 | 表_3.append(14991) 106 | else: 107 | if 临 in 词_数表: 108 | 表_3.append(词_数表[临]) 109 | else: 110 | 表_3.append(14991) 111 | 临 = '' 112 | if 字符 in 词_数表: 113 | 表_3.append(词_数表[字符]) 114 | else: 115 | 表_3.append(14991) 116 | 输入np = np.array(表_3) 117 | return (输入np) 118 | def 生成测试用numpy数组_B(输入表单, 词_数表): 119 | 表_3 = [] 120 | 临 = '' 121 | 122 | for 字符 in 输入表单: 123 | if 字符.lower() in 词_数表: 124 | if (u'\u0041' <= 字符 <= u'\u005a') or (u'\u0061' <= 字符 <= u'\u007a'): 125 | if 临 == '': 126 | 127 | 临 = 字符 128 | else: 129 | 临 = 临 + 字符 130 | else: 131 | 132 | if 临 == '': 133 | 134 | if 字符.lower() in 词_数表: 135 | if 字符.lower() != ' ': 136 | 表_3.append(词_数表[字符.lower()]) 137 | else: 138 | 表_3.append(49999) 139 | else: 140 | if 临.lower() in 词_数表: 141 | if 临.lower() != ' ': 142 | 143 | 表_3.append(词_数表[临.lower()]) 144 | else: 145 | 表_3.append(49999) 146 | 临 = '' 147 | if 字符.lower() in 词_数表: 148 | if 字符.lower() != ' ': 149 | 150 | 表_3.append(词_数表[字符.lower()]) 151 | else: 152 | 表_3.append(49999) 153 | 输入np = np.array(表_3) 154 | return (输入np) -------------------------------------------------------------------------------- /GPT_test/测试_ROCStories.py: -------------------------------------------------------------------------------- 1 | import json 2 | from 取训练数据 import 生成测试用numpy数组_A, 读出引索, 生成测试用numpy数组_B 3 | import os.path 4 | from mindspore.train.serialization import load_checkpoint, load_param_into_net 5 | from mindspore import context, Tensor 6 | import mindspore 7 | import numpy as np 8 | import mindspore.ops.operations as P 9 | from GPT模型_测试 import 创建_遮罩, 输出函数_GPT 10 | context.set_context(mode=context.PYNATIVE_MODE, device_target="GPU") 11 | def 单步测试(单元_捆, 词_数表, 数_词表, network): 12 | 枝数=len(单元_捆) 13 | for i in range(枝数): 14 | if i==0: 15 | 测试_捆 = 单元_捆[i]["待测数组"] 16 | else: 17 | 测试_捆 = np.vstack((测试_捆, 单元_捆[i]["待测数组"] )) 18 | 19 | 20 | 21 | MAKS1 = 创建_遮罩(测试_捆, 12) 22 | MAKS1 = Tensor(MAKS1) 23 | 累加 = Tensor(测试_捆, mindspore.int32) 24 | 结果_A = network.前向(累加, MAKS1) 25 | softmax = P.Softmax(-1) 26 | 成功数=0 27 | 和报='' 28 | for i in range(枝数): 29 | 30 | 结果 = 结果_A[i:i+1, -1-单元_捆[i]["标差"], :] 31 | 结果 = softmax(结果) 32 | 结果 = 结果.asnumpy() 33 | 34 | 结果 = np.argmax(结果, -1) 35 | 返回 ,简报= 生成测试简报(数_词表, 结果, 单元_捆[i]) 36 | 和报=和报+简报+"\n" 37 | if 返回==True: 38 | 成功数=成功数+1 39 | 40 | # torch.cat([a, b], dim=0) 41 | #累加 = 累加.cpu().numpy() 42 | 43 | return 成功数,枝数 ,和报 44 | def 生成测试简报(数_词表,数据, 单元): 45 | 临 = 数据 46 | 欲打印=[数_词表[str(临[i])] for i in range(临.size)] 47 | 打印="" 48 | for i in range(len(欲打印)): 49 | 打印=打印+欲打印[i] 50 | 51 | 52 | 标签=list(单元['标准结果'])[0] 53 | if 标签==打印: 54 | 简报="成功 ——预测:" + 打印 + "-标准回答:" + 单元['标准结果'] + " 题目:" + 单元["待测目标"] 55 | return True,简报 56 | else: 57 | 简报="失败 ——预测:"+打印+"-标准回答:"+单元['标准结果']+" 题目:"+单元["待测目标"] 58 | return False,简报 59 | 60 | 丢弃率 = 0.0 61 | 词库总数 = 50001 62 | 向量维度 = 768 63 | 层数 = 12 64 | 头数 = 12 65 | 文件名 = 'ROCStories_dev' 66 | #模型数据文件夹="../data/checkpoint/"+文件名+"/" 67 | 测试报告路径="../data/ROCStories_训练和测试/测试报告_ROCStories.txt" 68 | 测试题目路径="../data/ROCStories_训练和测试/ROCStories/ROCStories_spring2016_test.json" 69 | 词_数表路径 = "../data/词_数50000.json" 70 | 数_词表路径 = "../data/数_词50000.json" 71 | 模型数据路径='' 72 | # for maindir, subdir, file_name_list in os.walk(模型数据文件夹): 73 | # 74 | # for filename in file_name_list: 75 | # print(filename[-4:]) 76 | # if filename[-4:]=='ckpt': 77 | # 模型数据路径=模型数据文件夹+filename 78 | 79 | 模型数据路径='../data/checkpoint/ROCStories_dev/checkpoint_ROCStories_test.ckpt' 80 | if os.path.isfile(模型数据路径) and os.path.isfile(测试题目路径): 81 | 82 | network = 输出函数_GPT(词库总数, 向量维度, 层数, 头数, 丢弃率) 83 | param_dict = load_checkpoint(模型数据路径) 84 | load_param_into_net(network, param_dict) 85 | 86 | 87 | if os.path.isfile(词_数表路径) and os.path.isfile(数_词表路径): 88 | 词_数表, 数_词表 = 读出引索(词_数表路径, 数_词表路径) 89 | else: 90 | #写出词标号引索(总表单, 词_数表路径, 数_词表路径) # 生成标号——字符相互查找的字典 91 | #词_数表, 数_词表 = 读出引索(词_数表路径, 数_词表路径) 92 | print('词_数表路径或数_词表路径不存在') 93 | 路2=测试题目路径 94 | 总计数=0 95 | 成功数=0 96 | with open(路2, encoding="utf8") as f甲: 97 | 测试数组_临=[] 98 | 总辞数=0 99 | 最大辞数=0 100 | 枝数=0 101 | while True: 102 | 行=f甲.readline() 103 | if not 行: 104 | break 105 | js=json.loads(行) 106 | 107 | 测试文本 = js["input"] 108 | 109 | 110 | 测试_表单 = list(测试文本) 111 | 待测数组 = 生成测试用numpy数组_B(测试_表单, 词_数表).reshape(1, -1) 112 | #js["labe"] 113 | 待测单元={} 114 | 待测单元["待测目标"]=js["input"] 115 | 待测单元["标准结果"] =js["labe"] 116 | 待测单元["待测数组"] = 待测数组 117 | 待测单元["目标长度"]=待测数组.shape[1] 118 | 测试数组_临.append(待测单元) 119 | 120 | 测试数组_临 = sorted(测试数组_临, key=lambda x: x["目标长度"], reverse=True) 121 | 122 | 游标=0 123 | 测试总_捆=[] 124 | 置到尾部=False 125 | while True: 126 | 标长=测试数组_临[游标]["目标长度"] 127 | 单元数 = 666*3//标长 128 | 单元_捆=[] 129 | for i in range(单元数): 130 | if 游标+i==len(测试数组_临)-1: 131 | 置到尾部=True 132 | if 标长==测试数组_临[游标+i]["目标长度"]: 133 | 测试数组_临[游标 + i]["标差"]=0 134 | 单元_捆.append(测试数组_临[游标+i]) 135 | else: 136 | 标差=标长-测试数组_临[游标 + i]["目标长度"] 137 | 测试数组_临[游标 + i]["标差"] = 标差 138 | 补丁 = np.ones((1,标差))*50001 139 | 测试数组_临[游标 + i]["待测数组"]=np.hstack((测试数组_临[游标 + i]["待测数组"], 补丁)) 140 | 抽样=测试数组_临[游标 + i]["待测数组"] 141 | 单元_捆.append(测试数组_临[游标 + i]) 142 | if 置到尾部==True: 143 | break 144 | 游标 = 游标 + 单元数 145 | 测试总_捆.append(单元_捆) 146 | if 置到尾部 == True: 147 | break 148 | 成功数_总,枝数_总 =0,0 149 | with open(测试报告路径, 'w', encoding='utf8') as f_乙: 150 | 151 | for i in range(len(测试总_捆)): 152 | 153 | 成功数,枝数 ,和报=单步测试(测试总_捆[i], 词_数表, 数_词表, network) 154 | 成功数_总=成功数_总+成功数 155 | 枝数_总=枝数_总+枝数 156 | f_乙.write(和报) 157 | print("完成度{:.2f}%".format((i+1)*100/len(测试总_捆))) 158 | 尾报 = "成功率:{:.2f}".format(成功数_总 / 枝数_总 * 100) +"%测试总数:" + str(枝数_总) + "\n" 159 | 160 | f_乙.write(尾报) 161 | else: 162 | print('没有发现模型参数!或测试题目') 163 | 164 | print("成功率:{:.2f}".format(成功数_总 / 枝数_总 * 100) , 枝数_总,"测试报告在:"+测试报告路径) 165 | --------------------------------------------------------------------------------