コード例 #1
0
def generate_trained_model_path(trained_model_dir: str,
                                trained_model_name: str):
    """
    传入模型保存文件夹,和训练后模型名称,按照日期生成模型保存文件夹,并生成模型保存路径,返回模型保存路径
    :param trained_model_dir: (str)模型保存文件夹
    :param trained_model_name: (str)模型名称
    :return: trained_model_path(str)模型保存路径
    :raise:ValueError 文件夹不存在或者模型命名不以.h5结尾
    """
    # 判断保存训练后模型的文主文件夹是否存在,不存在则报错
    if not os.path.exists(trained_model_dir) or not os.path.isdir(
            trained_model_dir):
        logger.error(f"{trained_model_dir} is wrong!")
        raise ValueError
    # 模型不以.h5结尾则报错
    if not trained_model_name.endswith(".h5"):
        logger.error(f"{trained_model_name} must end with .h5")
        raise ValueError
    # 按照当前时间年月日生成文件夹,构建训练后模型的保存位置
    trained_model_dir = cat_path(
        trained_model_dir,
        time.strftime('%Y-%m-%d', time.localtime(time.time())))
    trained_model_path = cat_path(trained_model_dir, trained_model_name)
    # 如果文件夹不存在则生成
    if not os.path.exists(trained_model_dir):
        os.mkdir(trained_model_dir)

    return trained_model_path
コード例 #2
0
def load_rnn_models(model_dir):
    """
    加载模型文件目录下的模型
    Args:
      model_dir: 模型文件所在目录

    Returns:
      模型的 encoder, decoder
    """
    encoder = load_model(cat_path(model_dir, 'encoder.h5'), compile=False)
    decoder = load_model(cat_path(model_dir, 'decoder.h5'), compile=False)
    return encoder, decoder
コード例 #3
0
    def on_epoch_end(self, epoch, logs=None):
        """
        选择所有训练次数中,f1最大时的模型
        :param epoch: 训练次数

        return None
        """
        score_summary = self.evaluate()
        if score_summary > self.best:
            logger.info(f'{score_summary} better than old: {self.best}')
            self.best = score_summary
            encoder_path = cat_path(self.model_dir, 'encoder.h5')
            decoder_path = cat_path(self.model_dir, 'decoder.h5')
            self.encoder.save(encoder_path)
            self.decoder.save(decoder_path)
コード例 #4
0
def test_extract_model_train():
    """
    调用事件抽取模块训练函数,测试训练流程是否成功
    :return: status
    """
    # 训练后模型路径
    trained_model_path = cat_path(extract_train_config.trained_model_dir,
                                  f"extract_model_{0}_{0}")
    # 模型训练
    model_train(version="0",
                model_id="0",
                all_steps=10,
                trained_model_dir=extract_train_config.trained_model_dir,
                data_dir=extract_train_config.supplement_data_dir,
                maxlen=extract_train_config.maxlen,
                epoch=1,
                batch_size=extract_train_config.batch_size,
                max_learning_rate=extract_train_config.learning_rate,
                min_learning_rate=extract_train_config.min_learning_rate,
                model_type="roberta")
    # 判断是否有模型生成
    assert os.path.exists(trained_model_path) == True
    # 将生成的模型删除
    os.remove(trained_model_path)
    logger.info(f"event_extract_train demo is OK!")

    return {"status": "success"}
コード例 #5
0
def get_data(train_data_path: str, dev_data_path: str,
             supplement_data_dir: str):
    """
    传入训练集、验证集、补充数据路径,读取并解析json数据,将补充数据补充到训练集中,返回解析后的数据
    :param train_data_path:(str)训练集路径
    :param dev_data_path:(str)验证集路径
    :param supplement_data_dir:(str)补充数据保存路径
    :return:train_data(list), dev_data(list)
    """
    if not valid_file(train_data_path):
        logger.error(f"训练数据{train_data_path} 路径错误!")
    elif not valid_file(dev_data_path):
        logger.error(f"验证数据{dev_data_path} 路径错误!")
    elif not os.path.exists(supplement_data_dir) or os.path.isfile(
            supplement_data_dir):
        logger.error(f"补充数据集{supplement_data_dir} 文件夹路径错误!")

    # 加载训练数据集
    train_data = read_json(train_data_path)
    # 加载验证集
    dev_data = read_json(dev_data_path)

    # 加载补充数据
    file_list = os.listdir(supplement_data_dir)
    supplement_data = []
    for file in file_list:
        supplement_data_path = cat_path(supplement_data_dir, file)
        supplement_data.extend(read_json(supplement_data_path))
    train_data.extend(supplement_data)

    return train_data, dev_data
コード例 #6
0
def load_vec_data(cameo: str):
    """
    传入事件cameo号,到cameo号对应的列表中加载所有事件短句向量
    :param cameo:(str)事件cameo号
    :return:data(dict){事件id:向量}
    :raise:TypeError FileNotFoundError
    """
    # 需要读取向量的文件路径
    read_file_path = cat_path(pre_config.vec_data_dir, f"{cameo}.npy")

    data = {}
    # 判断文件是否存在,不存在则返回空值
    if not os.path.exists(read_file_path):
        return data
    # 如果字典文件缺失则报错
    elif not os.path.exists(pre_config.cameo2id_path):
        logger.error("cameo映射事件向量的字典文件缺失!")
        raise FileNotFoundError

    else:
        # cameo2id 字典 {cameo:[]}
        cameo2id = comm.read_cameo2id(pre_config.cameo2id_path)

        # 读取文件中的向量
        x = comm.read_np(read_file_path)

        for key, value in zip(cameo2id[cameo], x):
            data[key] = value

        return data
コード例 #7
0
 def __init__(self,
              mode,
              data,
              vec_data,
              vector_id_dict_dir,
              batch_size,
              shuffle=True):
     """
     构造方法,传入类的实例变量
     :param mode: (str) 数据模式 train dev test
     :param data: (list) 传入的数据列表
     :param vec_data: (dict) 所有的{id:[vec]}
     :param vector_id_dict_dir: (str) 向量id保存字典文件夹
     :param batch_size: (int)批量大小
     :param shuffle: (bool)是否打乱
     """
     self.mode = mode
     self.data = data
     self.vec_data = vec_data
     self.vector_id_dict_dir = vector_id_dict_dir
     self.batch_size = batch_size
     self.shuffle = shuffle
     # 数据的步数
     self.steps = len(self.data) // self.batch_size
     if len(self.data) % self.batch_size != 0:
         self.steps += 1
     # 保存数据对应id字典的文件名称
     dict_name = f"{self.mode}_dict.json"
     # 字典保存路径
     dict_path = cat_path(vector_id_dict_dir, dict_name)
     # 获取字典
     with open(dict_path, "r", encoding="utf-8") as f:
         self.data_dict = f.read()
         self.data_dict = json.loads(self.data_dict)
コード例 #8
0
def test_model(version,
               model_id,
               trained_model_dir="",
               data_dir=extract_train_config.supplement_data_dir,
               maxlen=160):
    """
    进行模型训练的主函数,搭建模型,加载模型数据,根据传入的参数进行模型测试,测试模型是否达标
    :param data_dir: 补充数据的文件夹路径
    :param trained_model_dir: 训练后模型存放路径
    :param maxlen: 最大长度
    :param version: 模型版本号
    :param model_id: 模型id
    :return: status, F1, precision, recall, corpus_num
    """
    # 训练后模型路径
    if version and model_id:
        trained_model_path = cat_path(trained_model_dir,
                                      f"extract_model_{version}_{model_id}")
    else:
        trained_model_path = extract_pred_config.event_extract_model_path

    # 获取训练集、验证集
    train_data, dev_data = get_data(extract_train_config.train_data_path,
                                    extract_train_config.dev_data_path,
                                    data_dir)
    # 搭建模型
    trigger_model, object_model, subject_model, loc_model, time_model, negative_model, train_model = build_model(
    )

    with SESS.as_default():
        with SESS.graph.as_default():
            # 构造callback模块的评估类
            evaluator = Evaluate(dev_data, maxlen, trained_model_path,
                                 trigger_model, object_model, subject_model,
                                 loc_model, time_model, negative_model,
                                 train_model)

            # 重载模型参数
            train_model.load_weights(trained_model_path)
            # 将验证集预测结果保存到文件中,暂时注释掉
            f1, precision, recall = evaluator.evaluate()

            assert f1 >= 0.8
            assert precision >= 0.8
            assert recall >= 0.8

            logger.info(f"f1:{f1}, precision:{precision}, recall:{recall}")
            logger.info(f"model is OK!")

    return {
        "status": "success",
        "version": version,
        "model_id": model_id,
        "results": {
            "f1": f1,
            "precison": precision,
            "recall": recall
        }
    }
コード例 #9
0
def gen_relation(relation, articles_dir, use_db=False):
    articles_content = get_articles_content(articles_dir, use_db)
    rst_articles_pos, rst_articles_neg = extract_articles_relation(
        articles_content, relation, 10000)
    relation_name = relation.__name__.split('.')[-1]
    ner_pos_fp = cat_path(ALGOR_PRETRAIN_ROOT, 'relation_key_extract',
                          f'ner_{relation_name}_pos.txt')
    ner_neg_fp = cat_path(ALGOR_PRETRAIN_ROOT, 'relation_key_extract',
                          f'ner_{relation_name}_neg.txt')
    save_ner_data(rst_articles_pos, rst_articles_neg, 1000, ner_pos_fp,
                  ner_neg_fp)
    classify_pos_fp = cat_path(ALGOR_PRETRAIN_ROOT, 'relation_extract',
                          f'classify_{relation_name}_pos.txt')
    classify_neg_fp = cat_path(ALGOR_PRETRAIN_ROOT, 'relation_extract',
                          f'classify_{relation_name}_neg.txt')
    save_classify_data(rst_articles_pos, rst_articles_neg, 1000, classify_pos_fp,
                  classify_neg_fp)
コード例 #10
0
def execute(raw_dir, target_dir):
    """
    传入原始标注数据文件夹路径和解析后文件存放的路径,按照时间生成json文件名称,将解析好的数据保存到目标文件夹
    :param raw_dir: 存放原始标注数据的文件夹
    :param target_dir: 存放解析后数据的文件夹
    :return: status--解析状态, corpus_num--数据量
    """
    # 存放所有解析后的数据
    all_datas = []
    # 语料中的句子数量
    all_sentence_num = 0
    # 语料中的事件数量
    all_event_num = 0

    try:
        # 判断数据路径是否正确
        if valid_dir(raw_dir):
            # 判断目标文件夹路径是否存在,不存在则创建
            if not valid_dir(target_dir):
                os.makedirs(target_dir)
            file_name = f"{time.strftime('%Y-%m-%d', time.localtime(time.time()))}.json"
            target_file_path = cat_path(target_dir, file_name)
            # 获取文件夹下所有文件的名称
            file_names = os.listdir(raw_dir)
            file_names = list(
                set(file_name.split(".")[0] for file_name in file_names))
            # 遍历文件进行解析
            for file_name in tqdm(file_names):
                file_path = os.path.join(raw_dir, file_name)
                # 判断两个文件是否都同时存在
                if valid_file(f"{file_path}.ann") and valid_file(
                        f"{file_path}.txt"):

                    # 解析文件获取事件和文件中的句子以及事件数量
                    data, sentence_num, event_num = data_process(file_path)
                    all_datas.extend(data)
                    all_sentence_num += sentence_num
                    all_event_num += event_num

            logger.info(f"总共有句子:{all_sentence_num},总共有事件:{all_event_num}")
            # 将解析后的数据保存到目标文件
            save_json(all_datas, target_file_path)

            return {
                "status": "success",
                "results": {
                    "sentences": all_sentence_num,
                    "events": all_event_num
                }
            }

        else:
            logger.error(f"存放原始标注数据的文件夹:{raw_dir}没有找到")
            raise FileNotFoundError
    except:
        trace = traceback.format_exc()
        logger.error(trace)
        return {"status": "failed", "results": trace}
コード例 #11
0
def load_cnn_model(model_dir):
    """
    加载模型文件目录下的模型
    Args:
      model_dir: 模型文件所在目录

    Returns:
      模型的 encoder, decoder
    """
    model = load_model(cat_path(model_dir, 'cnn_model.h5'), compile=False)
    return model
コード例 #12
0
    def on_epoch_end(self, epoch, logs=None):
        """
        选择所有训练次数中,f1最大时的模型
        :param epoch: 训练次数

        return None
        """
        score_summary = self.evaluate()
        if score_summary > self.best:
            logger.info(f'{score_summary} better than old: {self.best}')
            self.best = score_summary
            model_path = cat_path(self.model_dir, 'cnn_model.h5')
            self.model.save(model_path, include_optimizer=True)
コード例 #13
0
def train(batch_size, epochs, latent_dim, array_x, array_y, array_yin,
          model_sub_dir):
    """
    训练模型并保存模件
    Args:
      array_x: encoder 的输入序列
      array_y: deocder 的输出序列
      array_yin: decoder 的 inference 序列
      model_sub_dir: 存放此次训练所生成的模型的目录
    """
    # x的shape是[样本数, encoder输入长度(即滞后期), 特征数]
    # y的shape是[样本数, decoder输出长度(即预测天数), 输出事件类别个数]
    n_input = array_x.shape[2]
    n_output = array_y.shape[2]
    model, encoder, decoder = build_models(latent_dim, n_input, n_output)
    model.fit([array_x, array_yin],
              array_y,
              batch_size=batch_size,
              epochs=epochs,
              verbose=2)
    encoder_path = cat_path(model_sub_dir, 'encoder.h5')
    decoder_path = cat_path(model_sub_dir, 'decoder.h5')
    encoder.save(encoder_path)
    decoder.save(decoder_path)
コード例 #14
0
def load_vec_data(vector_data_dir: str):
    """
    传入向量数据保存的文件夹,加载所有的向量数据到内存中。
    :param vector_data_dir: (str)向量数据保存的文件夹
    :return: vec_data(dict)向量数据字典
    :raise:ValueError 保存向量的文件夹路径不是文件夹或者不存在
    """
    if not os.path.exists(vector_data_dir) or os.path.isfile(vector_data_dir):
        logger.error(f"{vector_data_dir}向量保存文件夹错误!")
        raise ValueError
    # 将所有向量加载到内存中
    vec_data = {}
    file_list = os.listdir(vector_data_dir)
    for file in file_list:
        vec_data["{}".format(file)] = np.load(cat_path(vector_data_dir, file))

    return vec_data
コード例 #15
0
def apply_pca(pca_n, pca_dir, data, reload=False):
    """
    对输入数据进行pca降维
    Args:
      pca_n: 降维后维度
      pca_dir: pca模型所在目录
      data: 数据表数据
      reload: 是否加载已存在的pca模型文件

    Returns:
      降维操作后的数据
    """
    pca_fp = cat_path(pca_dir, f"{pca_n}fit_pca")
    if reload:
        data_pca = joblib.load(pca_fp).transform(data)
    else:
        pca = PCA(n_components=pca_n)
        data_pca = pca.fit_transform(data)
        joblib.dump(pca, pca_fp)
    return data_pca
コード例 #16
0
def measure():
    """
    调用相似度模型,对测试集数据进行相似度计算,返回测试集相似度计算结果。
    :return: test_model_pred(lsit)测试集相似度列表
    """
    # 测试集模式
    mode = "dev"
    # 测试集数据保存字典
    dict_name = f"{mode}_dict.json"
    dict_path = cat_path(search_config.vector_id_dict_dir, dict_name)

    # 加载字典
    with open(dict_path, "r", encoding="utf-8") as f:
        dev_dict = f.read()
        dev_dict = json.loads(dev_dict)

    test_model_pred = []
    for i in range(len(DEV_DATA)):
        x1 = DEV_DATA[i].split("\t")[0]
        x2 = DEV_DATA[i].split("\t")[1]
        # 测试数据在字典中的键,与保存是规则相同
        key = str(i // 10000)
        # 获取测试数据在字典列表中的下标,用于到向量列表中去索引对应的句子向量
        x1_id = dev_dict[key].index(x1)
        x2_id = dev_dict[key].index(x2)

        # 验证集向量保存位置
        file_name = f"{mode}_{key}.npy"
        # 获取句子向量
        x1 = VECTOR_DATA[file_name][x1_id]
        x2 = VECTOR_DATA[file_name][x2_id]
        # 计算两个句子的相似度[[0.1,0.9]]
        x = MATCH_MODEL.predict([np.array([x1]), np.array([x2])])
        # 将相似度保存到列表中
        test_model_pred.append(np.argmax(x))

    return test_model_pred
コード例 #17
0
def generate_vec(mode: str, data: list, tokenizer, bert_model,
                 vector_data_dir: str, vector_id_dict_dir: str):
    """
    传入保存模式、数据、分词器、模型对象、向量保存文件夹路径、向量保存索引文件夹
    :param mode: (str)数据模式 train dev test
    :param data: (list) 数据列表 sentence sentence2 label
    :param tokenizer: 分字器
    :param bert_model: bert模型对象
    :param vector_data_dir: (str)向量保存文件夹
    :param vector_id_dict_dir: (str)事件{cameo:[id]}保存文件夹
    :return: None
    """
    # 下标列表
    idxs = list(range(len(data)))
    # 数据字典
    data_dict = {}
    # 保存向量的列表
    X = []

    for j, i in tqdm(enumerate(idxs)):
        d = data[i]
        # 匹配样本的两个句子
        text_01 = d.split("	")[0]
        text_02 = d.split("	")[1]
        # 按照句子对的数量保存索引,每10000个句子对保存成一个文件
        # 每个向量文件对应一个索引列表,以j//10000为键,以句子列表为值
        data_dict.setdefault(j // 10000, [])
        # 如果短句不在字典中,则将短句保存到字典中,并将向量化的短句保存到向量文件中
        if text_01 not in data_dict[j // 10000]:
            # 将短句保存到字典中
            data_dict[j // 10000].append(text_01)
            # 将短句向量化并保存到向量列表中
            x1_1, x1_2 = tokenizer.encode(first_text=text_01)
            x1 = bert_model.model.predict([np.array([x1_1]),
                                           np.array([x1_2])])[0][0]

            X.append(x1)
        # 同上
        if text_02 not in data_dict[j // 10000]:
            data_dict[j // 10000].append(text_02)
            x2_1, x2_2 = tokenizer.encode(first_text=text_02)
            x2 = bert_model.model.predict([np.array([x2_1]),
                                           np.array([x2_2])])[0][0]

            X.append(x2)

        # 如果达到10000或者最后一个批次则将向量保存,置空变量再次循环
        if (j + 1) % 10000 == 0 or (j + 1) == len(data):
            X = np.array(X)
            file_name = "{}_{}.npy".format(mode, j // 10000)
            file_path = cat_path(vector_data_dir, file_name)
            np.save(file_path, X)
            X = []

    # 最后将字典文件保存
    dict_name = "{}_dict.json".format(mode)
    dict_path = cat_path(vector_id_dict_dir, dict_name)

    with open(dict_path, "w", encoding="utf-8") as f:
        content = json.dumps(data_dict, ensure_ascii=False, indent=4)
        f.write(content)
コード例 #18
0
def __train_over_hyperparameters_RNN(data, dates, events_set, events_p_oh,
                                     event_model: EventModel):
    """
    提供训练模型服务, 遍历不同超参数的组合来训练模型. 先对降维维度遍历, 再对encoder输入长度遍历,
    产生的子模型数量为降维维度遍历个数与encoder输入长度遍历个数之积. 随encoder输入长度, 降维维度的增加,
    模型训练时间会变长. epoch越大, 模型训练时间越长
    Args:
      data: 模型目录
      dates: 模型目录
      events_set: 模型目录
      events_p_oh: 模型目录
      event_model: EventModel实体类

    Returns:
      训练完成的模型文件所在目录列表
      模型名称列表
      每个模型对应的 decoder 输出序列列表. 不同的模型由于输入序列长度不同导致输出序列不同
      每个模型对应的超参数列表
    """
    logger.info('<RNN>开始训练模型')

    # 每次训练生成一个对应的目录
    new_model_dir = cat_path(base_model_dir, guid())
    if not os.path.exists(new_model_dir):
        os.makedirs(new_model_dir)
    pca_dir = new_model_dir
    sub_model_dirs = []
    sub_model_names = []
    lag_dates = []
    pcas = []
    outputs_list = []
    params_list = []
    # 先进行降维,对于PCA降维来说它始终只有固定的降维组合,若先对滞后期的选择的话,会导致出现N个重复的降维组合
    for i in range(event_model.dr_min, event_model.dr_max,
                   event_model.size):  # 各种降维选择
        values_pca = preprocess.apply_pca(i, pca_dir, data)
        # 基于页面选择的开始日期、结束日期的整个范围中每一天作为一个基准日期,在该基准日期往前推max_input_len至min_input_len天
        # 的范围内每次间隔5天(10、15、20天)拉取数据训练模型。
        for j in range(event_model.delay_min_day, event_model.delay_max_day,
                       5):  # 滞后期的选择
            logger.info(f"<RNN> Current value: 滞后期={j}, pca={i}")
            lag_dates.append(j)
            pcas.append(i)
            sub_model_name = f'{event_model.model_name}-{j}-{event_model.days}-{i}'
            sub_model_names.append(sub_model_name)
            sub_model_path = cat_path(new_model_dir, sub_model_name)
            if not os.path.exists(sub_model_path):
                os.makedirs(sub_model_path)
            sub_model_dirs.append(sub_model_path)
            # flag 表示样本是否可用
            array_x, array_y, array_yin = gen_samples(
                values_pca, events_p_oh, j, event_model.days, dates,
                event_model.tran_start_date, event_model.tran_end_date)
            outputs_list.append(array_y)
            params_list.append([j, event_model.days, i])

            train_model_rnn.train(event_model.train_batch_no,
                                  event_model.epoch, event_model.neure_num,
                                  array_x, array_y, array_yin, sub_model_path,
                                  values_pca, events_p_oh, j, event_model.days,
                                  dates, event_model.evaluation_start_date,
                                  event_model.evaluation_end_date, events_set)

    logger.info('<RNN>训练完成, 模型存入数据库')

    detail_ids = pgsql.model_train_done_rnn(event_model.model_id, lag_dates,
                                            pcas, sub_model_dirs,
                                            sub_model_names, outputs_list,
                                            events_set, new_model_dir)

    return sub_model_dirs, params_list, detail_ids, new_model_dir
コード例 #19
0
def __predict_by_sub_models(data, dates, event_predict_array: list,
                            pred_start_date, num_classes, task_id, model_type):
    """
    使用各个子模型进行预测。
    Args:
      data: 预测输入数据
      dates: 数据表日期列表
      event_predict_array: array. EventPredict实体类,封装预测时需要用到的信息
      pred_start_date: 开始预测日期, 即此日期后均有预测结果
      num_classes: 事件类别数量
      task_id: 由页面传入

    Returns:
      preds_one: 所有子模型预测结果, 每天为输入数据预测的后一天结果, 如果最后一个样本没有历史预测结果,
          则最后一个样本的预测结果全部保留.
          shape(最后样本有历史预测结果): (子模型数, 未预测的样本数),
          或shape(最后样本无历史预测结果): (子模型数, 未预测的样本数 + output_len - 1)
      preds_all: 所有子模型预测结果, 每天为输入数据预测的多天结果. shape: (子模型数, 未预测的样本数, 预测天数)
      dates_pred_one: preds_one 对应的预测日期, shape 与 preds_one 相同
      dates_pred_all: preds_all 对应的预测日期, shape 与 preds_all 相同
      dates_pred_data: preds_one 对应的数据结束日期, shape 与 preds_one 相同
      pred_detail_ids: 预测的子模型 detail_id 列表, 去掉了已预测的子模型
      last_date_data_pred: 预测所用数据最后一天日期
      model_type: string.模型类型,对应代码项为ModelType
    """
    preds_one = []
    preds_all = []
    dates_pred_one = []
    dates_pred_all = []
    dates_pred_data = []
    pred_detail_ids = []
    last_date_data_pred = None
    for event_predict in event_predict_array:
        sub_model = event_predict.model_name
        logger.info(f'正在使用模型{sub_model}进行预测')
        input_len = event_predict.lag_date
        detail_id = event_predict.detail_id

        if ModelType.CNN.value == model_type:
            output_len = cnn_day
            inputs_data, output_dates = pp.gen_inputs_by_pred_start_date(
                data, input_len, dates, pred_start_date)
        elif ModelType.RNN.value == model_type:
            # 预测天数指的是模型可以预测n天,而不是预测开始日期+n天。假设预测开始日期为6月1日,则模型从6月1日起,每次预测n天
            # 直到今天的日期,且对重复预测的处理是使用最新的预测。
            output_len = event_predict.days
            values_pca = pp.apply_pca(event_predict.pca,
                                      event_predict.model_dir, data, True)
            inputs_data, output_dates = pp.gen_inputs_by_pred_start_date(
                values_pca, input_len, dates, pred_start_date)
        else:
            raise RuntimeError(f"Unsupport model type <{model_type}>")

        # 取样本数据中最大的日期,再往后推1天  TODO dates[-1]要求日期必须升序排序
        max_output_date = datetime.strptime(
            dates[-1], date_formatter).date() + timedelta(1)
        output_dates.append(max_output_date)  # 此时output_dates不包含预测第一天后日期
        dates_data = [
            datetime.strptime(output_dates[0], date_formatter).date() -
            timedelta(1)
        ]
        dates_data.extend([
            datetime.strptime(out_put_date, date_formatter).date()
            for out_put_date in output_dates[:-1]
        ])
        last_date_data_pred = dates_data[-1]
        predicted_detail_id_dates = pgsql.query_predicted_rsts(
            detail_id, pred_start_date, task_id)
        predicted_dates = predicted_detail_id_dates.get(
            detail_id)  # type of list of str
        if predicted_dates is None:
            latest_date_predicted = False
            predicted_dates_to_delete = []
        else:
            predicted_dates = sorted(
                [pp.parse_date_str(d) for d in predicted_dates])
            predicted_dates_to_delete = predicted_dates[-output_len + 1:]
            predicted_dates = predicted_dates[:-output_len + 1]  # 截取只预测一天的预测结果
            max_predicted_date = predicted_dates[-1]
            zipped_unpredicted = [[
                d, i, dd
            ] for d, i, dd in zip(output_dates, inputs_data, dates_data)
                                  if d not in predicted_dates]
            if not zipped_unpredicted:
                logger.info(f'{sub_model}所有日期已预测, 跳过')
                continue

            output_dates, inputs_data, dates_data, = zip(*zipped_unpredicted)
            output_dates = list(output_dates)
            inputs_data = list(inputs_data)
            dates_data = list(dates_data)
            if max_predicted_date == max_output_date:
                latest_date_predicted = True
            else:
                latest_date_predicted = False

        # 预测日期, 包含第一天以后日期
        dates_pred_all_model = [[(dd + timedelta(t))
                                 for t in range(1, output_len + 1)]
                                for dd in dates_data]

        sub_model_dir = cat_path(event_predict.model_dir, sub_model)
        if ModelType.RNN.value == model_type:
            encoder, decoder = load_rnn_models(sub_model_dir)
            pred = predict_sample_rnn(encoder, decoder, inputs_data,
                                      output_len, num_classes)
        elif ModelType.CNN.value == model_type:
            model = load_cnn_model(sub_model_dir)
            pred = predict_sample_cnn(model, inputs_data)

        pred_one = [p[0] for p in pred]  # 在预测到最后一天之前的每一天预测的结果都只有第一天可用
        if not latest_date_predicted:
            pred_one.extend(pred[-1][1:])
            # 此时output_dates添加第一天以后日期
            output_dates.extend(
                [max_output_date + timedelta(d) for d in range(1, output_len)])
            dates_data.extend([dates_data[-1]] * (output_len - 1))
            if predicted_dates_to_delete:
                pgsql.delete_predicted_dates(detail_id,
                                             predicted_dates_to_delete)

        pred_detail_ids.append(detail_id)
        preds_one.append(pred_one)
        preds_all.append(pred)
        dates_pred_one.append(output_dates)
        dates_pred_data.append(dates_data)
        dates_pred_all.append(dates_pred_all_model)

    return preds_one, preds_all, dates_pred_one, dates_pred_all, dates_pred_data, pred_detail_ids, last_date_data_pred
コード例 #20
0
    :return:
    """
    rst_articles_pos = []
    rst_articles_neg = []
    neg_num = 0
    for content in tqdm(articles_content):
        content = remove_white_space(content)
        rsts, rsts_neg, neg_num = extract_article_relation(content, relation,
                                                           neg_num,
                                                           neg_capacity)
        rst_articles_pos.extend(rsts)
        rst_articles_neg.extend(rsts_neg)
    return rst_articles_pos, rst_articles_neg


articles_db_path = cat_path(ALGOR_PRETRAIN_ROOT, 'articles.txt')


def get_db_articles():
    """
    获取数据库中爬取的文章内容. 如果有本地的内容文件, 则从本地读取, 否则从数据库读取,
    并将过滤后的结果存到本地文件
    :return:
    """
    if os.path.exists(articles_db_path):
        articles_zh = json.loads(readfile(articles_db_path))
        return articles_zh

    articles = get_articles_from_db()
    articles_zh = filter_db_articles(articles)
    save_content(json.dumps(articles_zh, ensure_ascii=False), articles_db_path)
コード例 #21
0
def model_train(version,
                model_id,
                trained_model_dir="",
                data_dir="",
                all_steps=0,
                maxlen=160,
                epoch=40,
                batch_size=8,
                max_learning_rate=5e-5,
                min_learning_rate=1e-5,
                model_type="roberta"):
    """
    进行模型训练的主函数,搭建模型,加载模型数据,根据传入的参数进行模型训练
    :param version: 模型版本
    :param model_id: 模型编号
    :param data_dir: 补充数据的文件夹路径
    :param trained_model_dir: 训练后模型存放路径
    :param all_steps: 模型训练步数
    :param maxlen: 最大长度
    :param epoch: 循环次数
    :param batch_size: 批次大小
    :param max_learning_rate: 最大学习率
    :param min_learning_rate: 最小学习率
    :param version: 模型版本号
    :param model_id: 模型id
    :param model_type: 预训练模型类型,现在不用,后期会用到,
    :return: status, F1, precision, recall, corpus_num
    """
    try:
        # 补充数据文件夹更换
        if data_dir:
            extract_train_config.supplement_data_dir = data_dir
        # 判断训练后模型路径是否存在
        if not os.path.exists(trained_model_dir):
            os.makedirs(trained_model_dir)
        # 训练后模型路径
        trained_model_path = cat_path(trained_model_dir,
                                      f"extract_model_{version}_{model_id}")

        # 获取训练集、验证集
        train_data, dev_data = get_data(extract_train_config.train_data_path,
                                        extract_train_config.dev_data_path,
                                        data_dir)
        # 搭建模型
        trigger_model, object_model, subject_model, loc_model, time_model, negative_model, train_model = build_model(
        )
        # 构造训练数据生成器
        train_d = DataGenerator(TOKENIZER, maxlen, train_data, batch_size)

        with SESS.as_default():
            with SESS.graph.as_default():
                # 构造callback模块的评估类
                evaluator = Evaluate(dev_data, maxlen, trained_model_path,
                                     trigger_model, object_model,
                                     subject_model, loc_model, time_model,
                                     negative_model, train_model,
                                     max_learning_rate, min_learning_rate)
                # 如果训练数据小于5000,则设置内部循环步数1000次为一个循环,否则集使用训练数据个数/batch_size计算得到的步数
                if all_steps:
                    pass
                elif len(train_data) < 5000:
                    all_steps = 1000
                else:
                    all_steps = train_d.__len__()

                # 构造对抗攻击训练
                adversarial_training(train_model, 'Embedding-Token', 0.1)

                # 模型训练
                train_model.fit_generator(train_d.__iter__(),
                                          steps_per_epoch=all_steps,
                                          epochs=epoch,
                                          callbacks=[evaluator])
                # 重载模型参数
                train_model.load_weights(trained_model_path)
                # 将验证集预测结果保存到文件中,暂时注释掉
                f1, precision, recall = evaluator.evaluate()
                logger.info(f"f1:{f1}, precision:{precision}, recall:{recall}")

        return {
            "status": "success",
            "version": version,
            "model_id": model_id,
            "results": {
                "f1": f1,
                "precison": precision,
                "recall": recall
            },
            "corpus_num": {
                "train_data": len(train_data),
                "dev_data": len(dev_data)
            }
        }
    except:
        trace = traceback.format_exc()
        logger.error(trace)
        return {"status": "failed", "results": trace}
コード例 #22
0
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Author: Mr Fan
# @Time: 2020年06月09
"""
事件状态模型训练需要的参数以就文件保存路径

"""
import feedwork.AppinfoConf as appconf
from feedwork.utils.FileHelper import cat_path
from jdqd.common.event_emm.model_utils import generate_trained_model_path

# 训练后模型保存路径
trained_model_dir = "event_extract/event_state_trained_model"
trained_model_dir = cat_path(appconf.ALGOR_MODULE_ROOT, trained_model_dir)
# 训练后模型名称
trained_model_name = "state_model.h5"
# 训练后模型路径
trained_model_path = generate_trained_model_path(trained_model_dir,
                                                 trained_model_name)
# 训练集数据保存路径
train_data_path = "event_extract/data/event_state_data/raw_data/train_data.json"
train_data_path = cat_path(appconf.ALGOR_PRETRAIN_ROOT, train_data_path)
# 测试集数据保存路径
dev_data_path = "event_extract/data/event_state_data/raw_data/dev_data.json"
dev_data_path = cat_path(appconf.ALGOR_PRETRAIN_ROOT, dev_data_path)
# 补充数据保存文件夹
supplement_data_dir = "event_extract/data/event_state_data/supplement"
supplement_data_dir = cat_path(appconf.ALGOR_PRETRAIN_ROOT,
                               supplement_data_dir)
# 模型状态 下标 字典
コード例 #23
0
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Author: Mr Fan
# @Time: 2020年06月11
from feedwork.utils.FileHelper import cat_path
import feedwork.AppinfoConf as appconf

# 模型类型
model_type = "bert"
# 模型参数
config_path = 'chinese_roberta_wwm_ext_L-12_H-768_A-12/bert_config.json'
config_path = cat_path(appconf.ALGOR_PRETRAIN_ROOT, config_path)
# 初始化模型路径
checkpoint_path = 'chinese_roberta_wwm_ext_L-12_H-768_A-12/bert_model.ckpt'
checkpoint_path = cat_path(appconf.ALGOR_PRETRAIN_ROOT, checkpoint_path)
# 模型字典路径
dict_path = 'chinese_roberta_wwm_ext_L-12_H-768_A-12/vocab.txt'
dict_path = cat_path(appconf.ALGOR_PRETRAIN_ROOT, dict_path)
コード例 #24
0
# -*- coding:utf-8 -*-
# @Author: Mr Fan
# @Time: 2020年06月09
"""
传递事件抽取预测模块需要的所有参数
"""
import feedwork.AppinfoConf as appconf
from feedwork.utils.FileHelper import cat_path

# 模型类型
model_type = "bert"
# 字符串最大长度
maxlen = 160
# 事件抽取模型路径
event_extract_model_path = "event_extract/model/extract_model.h5"
event_extract_model_path = cat_path(appconf.ALGOR_PRETRAIN_ROOT, event_extract_model_path)
# 事件状态判断模型路径
event_state_model_path = "event_extract/model/state_model.h5"
event_state_model_path = cat_path(appconf.ALGOR_PRETRAIN_ROOT, event_state_model_path)
# 事件类别模型路径
event_cameo_model_path = "event_extract/model/cameo_model.h5"
event_cameo_model_path = cat_path(appconf.ALGOR_PRETRAIN_ROOT, event_cameo_model_path)
# bert模型参数json文件路径
bert_config_path = "chinese_roberta_wwm_ext_L-12_H-768_A-12/bert_config.json"
bert_config_path = cat_path(appconf.ALGOR_PRETRAIN_ROOT, bert_config_path)
# bert模型字典保存的路径
dict_path = "chinese_roberta_wwm_ext_L-12_H-768_A-12/vocab.txt"
dict_path = cat_path(appconf.ALGOR_PRETRAIN_ROOT, dict_path)
# 小牛翻译的key
user_key = "b3d33c84a6291b89524e1a759064032a"
# 小牛翻译的网址
コード例 #25
0
# @Time: 2020年06月09
"""
事件归并模型训练所有的参数和文件路径

"""
import feedwork.AppinfoConf as appconf
from feedwork.utils.FileHelper import cat_path

# 批量大小
batch_size = 8
# 最大最小学习率
learning_rate = 5e-5
min_learning_rate = 1e-5
# 训练集路径
train_data_path = "event_search/train/data/datav06/train.txt"
train_data_path = cat_path(appconf.ALGOR_PRETRAIN_ROOT, train_data_path)
# 验证集路径
dev_data_path = "event_search/train/data/datav06/dev.txt"
dev_data_path = cat_path(appconf.ALGOR_PRETRAIN_ROOT, dev_data_path)
# 测试集路径
test_data_path = "event_search/train/data/datav06/test.txt"
test_data_path = cat_path(appconf.ALGOR_PRETRAIN_ROOT, test_data_path)
# 训练后的模型路径
trained_model_path = "event_search/trained_model/match_model.h5"
trained_model_path = cat_path(appconf.ALGOR_MODULE_ROOT, trained_model_path)
# 转化后的向量路径
vector_data_path = "event_search/train/data/vector_data"
vector_data_path = cat_path(appconf.ALGOR_MODULE_ROOT, vector_data_path)
# 存储转化样本的字典
vector_id_dict_dir = "event_search/train/data/"
vector_id_dict_dir = cat_path(appconf.ALGOR_MODULE_ROOT, vector_id_dict_dir)
コード例 #26
0
# @Time: 2020年06月09
"""
匹配模型训练需要的所有参数和模型路径

"""
import feedwork.AppinfoConf as appconf
from feedwork.utils.FileHelper import cat_path

# 训练批次大小
batch_size = 8
# 循环
epoch = 5
# dropout
drop_out_rate = 0.1
# 字符串最大长度
maxlen = 512
# 学习率
learning_rate = 5e-5
# 最小学习率
min_learning_rate = 1e-5
# 训练数据集路径
train_data_path = "event_match/data/second_train/train.txt"
train_data_path = cat_path(appconf.ALGOR_PRETRAIN_ROOT, train_data_path)
dev_data_path = "event_match/data/second_train/dev.txt"
dev_data_path = cat_path(appconf.ALGOR_PRETRAIN_ROOT, dev_data_path)
test_data_path = "event_match/data/second_train/test.txt"
test_data_path = cat_path(appconf.ALGOR_PRETRAIN_ROOT, test_data_path)
# 训练后模型保存路径
trained_model_path = "event_match/model/trained_model/match_model.h5"
trained_model_path = cat_path(appconf.ALGOR_MODULE_ROOT, trained_model_path)
コード例 #27
0
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Author: Mr Fan
# @Time: 2020年06月09
"""
事件提取中匹配模型预测模块需要的所有参数以及文件路径

"""
import feedwork.AppinfoConf as appconf
from feedwork.utils.FileHelper import cat_path

# 模型批量大小
batch_size = 1
# 字符串最大长度
maxlen = 512
# 事件类别模型路径
match_model_path = "event_match/model/trained_model/match_model_05.h5"
match_model_path = cat_path(appconf.ALGOR_PRETRAIN_ROOT, match_model_path)
# 事件列表地址
allevent_path = "event_match/data/allevent"
allevent_path = cat_path(appconf.ALGOR_PRETRAIN_ROOT, allevent_path)
# 摘要句子数量
abstract_n = 3
コード例 #28
0
def execute_delete(event_id: str):
    """
    删除模块的主控程序,读取cameo2id,然后查看事件id是否存在字典中,并进行删除。
    :return: None
    :raise: FileNotFoundError
    """
    if not os.path.exists(pre_config.cameo2id_path) or not os.path.isfile(
            pre_config.cameo2id_path):
        logger.error(f"{pre_config.cameo2id_path} miss, can not exec delete!")
        raise FileNotFoundError
    # 读取保存事件{cameo:[event_id]}字典
    cameo2id = comm.read_cameo2id(pre_config.cameo2id_path)

    # 判断事件是否在向量库中,如果存在则设置为1,并读取对应的向量并将其删除
    status = 0
    for cameo in list(cameo2id.keys()):

        if event_id in cameo2id[cameo]:
            status += 1
            # 读取向量的文件地址
            read_file_path = cat_path(pre_config.vec_data_dir, f"{cameo}.npy")
            # 保存向量时的路径,只是比上边缺少了.npy,函数会自动补齐
            save_file_path = cat_path(pre_config.vec_data_dir, cameo)
            # 读取cameo保存的向量文件
            x = comm.read_np(read_file_path)

            # 删除向量
            temp = np.delete(x, list(cameo2id[cameo]).index(event_id), axis=0)
            # 删除列表中的事件id
            cameo2id[cameo].remove(event_id)

            # 将更新后的文件重新保存
            # cameo对应的向量没有删除完,cameo2id[cameo]也没有删完
            if temp.shape[0] and cameo2id[cameo]:
                comm.save_cameo2id(cameo2id, pre_config.cameo2id_path)
                # 将向量保存到文件中
                comm.save_np(save_file_path, temp)
                # 跳出循环
                break

            # cameo对应的向量已经置空了,且cameo对应的列表也空了
            elif not temp.shape[0] and not cameo2id[cameo]:
                # 将向量文件删除
                os.remove(read_file_path)
                # 删除cameo在字典中的键
                del cameo2id[cameo]
                # 判断字典是否为空
                if len(cameo2id):
                    # 字典不为空则重新保存
                    comm.save_cameo2id(cameo2id, pre_config.cameo2id_path)
                else:
                    # 字典空了,则删除字典文件
                    os.remove(pre_config.cameo2id_path)
                # 跳出循环
                break

            # 说明向量表和字典不匹配,一个已经清空,而另一个没有清空,此时需要手动将对应的cameo删除
            else:
                logger.error(
                    "vector file does not match cameo2id, please delete file manually!"
                )
                raise ValueError

    return status
コード例 #29
0
# -*- coding: utf-8 -*-
"""
Created on Tue Jun  9 16:18:41 2020

@author: 12894
"""
"""
关系触发词抽取模型训练需要的所有参数以及文件路径

"""
import feedwork.AppinfoConf as appconf
from feedwork.utils.FileHelper import cat_path

# 关系触发词抽取模型路径
relation_key_extract_model_path = "relation_key_extract/relation_key_extract.h5"
relation_key_extract_model_path = cat_path(appconf.ALGOR_PRETRAIN_ROOT,
                                           relation_key_extract_model_path)
# 模型参数
config_path = 'chinese_L-12_H-768_A-12/bert_config.json'
config_path = cat_path(appconf.ALGOR_PRETRAIN_ROOT, config_path)
# 初始化模型路径
checkpoint_path = 'chinese_L-12_H-768_A-12/bert_model.ckpt'
checkpoint_path = cat_path(appconf.ALGOR_PRETRAIN_ROOT, checkpoint_path)
# 模型字典路径
dict_path = 'chinese_L-12_H-768_A-12/vocab.txt'
dict_path = cat_path(appconf.ALGOR_PRETRAIN_ROOT, dict_path)
# 训练后模型保存路径
trained_model_dir = "relation_key_extract_model"
trained_model_dir = cat_path(appconf.ALGOR_MODULE_ROOT, trained_model_dir)
# 训练后模型名称
trained_model_name = "relation_key_extract.h5"
# 训练集数据保存路径
コード例 #30
0
def save_vec_data(cameo: str, event_id: str, main_vec):
    """
    传入事件cameo、事件id、事件短句向量,将向量保存到文件中,临时保存,后期改写为保存到数据库中,
    将事件id存放到以cameo为键的字典中{cameo:[event_id], }
    :param cameo: (str)事件cameo号
    :param event_id: (str)事件编号
    :param main_vec: (ndarray)事件向量
    :return: None
    :raise:字典文件缺失/ 向量文件文件缺失 FileNotFoundError 事件id重复 ValueError 传入类型错误 TypeError
    """
    if not isinstance(cameo, str):
        logger.error("cameo编号格式错误!")
        raise TypeError
    if not isinstance(event_id, str):
        logger.error("事件编号格式错误!")
        raise TypeError

    # 读取向量时的路径
    read_file_path = cat_path(pre_config.vec_data_dir, f"{cameo}.npy")
    # 保存向量时的路径,只是比上边缺少了.npy,函数会自动补齐
    save_file_path = cat_path(pre_config.vec_data_dir, cameo)

    # 判断字典文件是否存在, 不存在这就是第一个向量
    if not os.path.exists(pre_config.cameo2id_path):
        cameo2id = {cameo: [event_id]}
        # 将字典保存
        comm.save_cameo2id(cameo2id, pre_config.cameo2id_path)

        # 将向量保存到文件中
        comm.save_np(save_file_path, np.array([main_vec]))

    # 如果字典文件存在,而向量文件不存在,则说明这是这个cameo的第一个向量
    elif not os.path.exists(read_file_path):
        # cameo2id 字典 {cameo:[]}
        cameo2id = comm.read_cameo2id(pre_config.cameo2id_path)
        # 将事件id添加到字典中
        cameo2id[cameo] = [event_id]
        # 将向量保存到文件中
        comm.save_np(save_file_path, np.array([main_vec]))

        # 写入文件中
        comm.save_cameo2id(cameo2id, pre_config.cameo2id_path)

    # 如果向量文件存在,而字典文件不存在,则报错,字典文件缺失
    elif not os.path.exists(pre_config.cameo2id_path):
        logger.error("字典文件缺失!")
        raise FileNotFoundError

    # 如果字典和向量都存在,则正常添加向量和事件id,并保存
    else:
        # cameo2id 字典 {cameo:[]}
        cameo2id = comm.read_cameo2id(pre_config.cameo2id_path)

        # 如果事件id不在字典中,则进行保存向量和添加id索引的操作
        if event_id not in cameo2id.setdefault(cameo, []):
            # 将事件id保存到cameo2id字典中
            cameo2id[cameo].append(event_id)

            # 读取向量文件
            x = comm.read_np(read_file_path)
            # 将向量拼接进去
            temp = np.vstack([x, np.array([main_vec])])
            # 将向量保存到文件中
            comm.save_np(save_file_path, temp)

            # 写入文件中
            comm.save_cameo2id(cameo2id, pre_config.cameo2id_path)

        # 事件id已经存在了,说明输入的id重复了,则报错,不进行保存操作。
        else:
            logger.error("事件id重复!")
            raise ValueError