ToD-BERT the Paper

数据集

不同的数据集可以帮助模型达到不同的熟练效果

  • MetaLWOZ 预测数据

ToD-BERT怎么训练的?

  1. mlm
  2. contrastive function 两者都有误差,因此才可以被训练。 空间结构能够捕获差异,发现细微结构。

在服务器上运行ToD-BERT训练

  1. 进入服务器,激活环境source activate todbert_env
  2. 进入/media/HD1/dche/ToD-BERT文件夹cd /media/HD1/dche/ToD-BERT
  3. 查看GPU资源占用情况nvidia-smi,然后选择目前占用情况较低的一张GPU进行训练即可
  4. 运行训练shell脚本文件CUDA_VISIBLE_DEVICES=0 ./run_tod_lm_pretraining.sh 0 bert bert-base-uncased save/pretrain/ToD-BERT-MLM --only_last_turn --data_path ./../dialog_datasets。根据第三步选择的几号卡,就把对应的0改成几,此处默认单卡训练。如果一切正常的话,再读入数据集数据后,就会开始训练了,有进度条出现就Ok了。常见的没跑起来的情况是CUDA out of memory。

ToD-BERT本地调用

  1. 将ToD-BERT模型下载至本地
  2. 包含ToD-BERT所需的python包,并定义模型路径
    import torch
    from transformers import *
    
    BERT = <path_to_the_downloaded_tod-bert>  # 注意此处的路径要使用从根目录开始的绝对路径,而非从用户~目录开始的相对路径。
    model_class, tokenizer_class, config_class = BertModel, BertTokenizer, BertConfig
    tokenizer = tokenizer_class.from_pretrained(BERT)
    tod_bert = model_class.from_pretrained(BERT)
    
  3. 使用ToD-BERT文档中的示例
    # Encode text 
    input_text = "[CLS] [SYS] Hello, what can I help with you today? [USR] Find me a cheap restaurant nearby the north town."
    input_tokens = tokenizer.tokenize(input_text)
    story = torch.Tensor(tokenizer.convert_tokens_to_ids(input_tokens)).long()
    
    if len(story.size()) == 1: 
        story = story.unsqueeze(0) # batch size dimension
    
    if torch.cuda.is_available(): 
        tod_bert = tod_bert.cuda()
        story = story.cuda()
    
    with torch.no_grad():
        input_context = {"input_ids": story, "attention_mask": (story > 0).long()}
        hiddens = tod_bert(**input_context)[0] 
    

计算ToD-BERT推理时间延迟

如何正确地计算

深度学习中如何正确地measure inference time

问题:

  1. 在进行多batch训练或推理的时候,batch1被送进GPU后,CPU由于异步执行,不再等待batch1在GPU内执行完毕,而是直接对batch2进行预处理,此时若使用python的time库,停止计算时间的代码将在GPU执行完毕前被执行,导致时长计算错误。
  2. GPU在不工作时将关掉许多硬件模块,在调用GPU时需要重新初始化(GPU预热),占用大量时间,导致时间测算错误。

解决方法:

  1. 在真正需要的example前运行几个example,使得GPU不再处于省电模式。
  2. 使用tr.cuda.event,在GPU上测量时间
  3. 使用函数torch.cuda.synchronize(),使得CPU和GPU工作在同步执行模式。

在服务器上进行inference并计算inference时间

  1. run_tod_lm_pretraining.sh文件中修改batch size = 1:

    gpu=$1
    model_type=$2
    bert_dir=$3
    output_dir=$4
    add1=$5
    add2=$6
    add3=$7
    add4=$8
    add5=$9
    
    # ./run_tod_lm_pretraining.sh 0 bert bert-base-uncased save/pretrain/ToD-BERT-MLM --only_last_turn
    # ./run_tod_lm_pretraining.sh 0 bert bert-base-uncased save/pretrain/ToD-BERT-JNT --only_last_turn --add_rs_loss
    
    CUDA_VISIBLE_DEVICES=3 python my_tod_pretraining.py \
        --task=usdl \
        --model_type=${model_type} \
        --model_name_or_path=${bert_dir} \
        --output_dir=${output_dir} \
        --do_train \
        --do_eval \
        --mlm \
        --do_lower_case \
        --evaluate_during_training \
        --save_steps=2500 --logging_steps=1000 \
        --per_gpu_train_batch_size=1 --per_gpu_eval_batch_size=1 \
        ${add1} ${add2} ${add3} ${add4} ${add5}
    
  2. 使用上文办法,在my_tod_pretraining.py中引入计时相关语句:

    ## with only MLM loss
    else: 
        starter, ender = torch.cuda.Event(enable_timing=True), torch.cuda.Event(enable_timing=True)
    
         inputs = batch["context"].clone()
        if args.mlm:
            inputs, labels = mask_tokens(inputs, tokenizer, args)
            inputs = inputs.to(args.device)
            labels = labels.to(args.device)
    
            starter.record()
    
            outputs = model(inputs,
                            masked_lm_labels=labels,
                            attention_mask=inputs>0)
    
            ender.record()
            # WAIT FOR GPU SYNC
            torch.cuda.synchronize()
            curr_time = starter.elapsed_time(ender)
            print(curr_time)
    
  3. 由于训练时间较长,使用tmux命令:tmux new -s inference_time_measure,进入tmux回话后还需要重新激活虚拟环境。

    \(base) dialogue@amax-13:/media/HD1/dche/ToD-BERT$ CUDA_VISIBLE_DEVICES=0 ./run_tod_lm_pretraining.sh 0 bert bert-base-uncased save/prtrain/ToD-BERT-MLM --only_last_turn --data_path ./../dialog_datasets
    Traceback (most recent call last):
      File "/media/HD1/dche/ToD-BERT/my_tod_pretraining.py", line 16, in <module>
        import numpy as np
    ModuleNotFoundError: No module named 'numpy'
    (base) dialogue@amax-13:/media/HD1/dche/ToD-BERT$ conda info --env
    # conda environments:
    #
    base                  *  /media/HD1/dche/miniconda3
    sum_env                  /media/HD1/dche/miniconda3/envs/sum_env
    tod_bert                 /media/HD1/dche/miniconda3/envs/tod_bert
                             /media/HD1/miniconda3
    
    (base) dialogue@amax-13:/media/HD1/dche/ToD-BERT$ conda activate tod_bert
    (tod_bert) dialogue@amax-13:/media/HD1/dche/ToD-BERT$ CUDA_VISIBLE_DEVICES=0 ./run_tod_lm_pretraining.sh 0 bert bert-base-uncased save/pretrain/ToD-BERT-MLM --only_last_turn --data_path ./../dialog_datasets
    
  4. 进行训练,观察输出结果 CUDA_VISIBLE_DEVICES=0 ./run_tod_lm_pretraining.sh 0 bert bert-base-uncased save/pretrain/ToD-BERT-MLM --only_last_turn --data_path ./../dialog_datasets

  5. 训练过程中可以使用crtl+b d从会话中分离

    (tod_bert) dialogue@amax-13:/media/HD1/dche/ToD-BERT$ tmux new -s inference_time_measure
    [detached (from session inference_time_measure)]
    (tod_bert) dialogue@amax-13:/media/HD1/dche/ToD-BERT$ 
    
  6. 可以查看当前的tmux会话并连接

    (tod_bert) dialogue@amax-13:/media/HD1/dche/ToD-BERT$ tmux ls
    inference_time_measure: 1 windows (created Sun Nov 21 23:26:48 2021) [134x33]
    zym1: 1 windows (created Sun Nov 21 18:34:03 2021) [148x45]
    zym2: 1 windows (created Sun Nov 21 18:34:44 2021) [113x12]
    (tod_bert) dialogue@amax-13:/media/HD1/dche/ToD-BERT$ tmux attach -t inference_time_measure
    
  7. 为了便于记录inference time,可以将bash命令中的输出全部写入txt文件,script -a 1.txt,则之后shell中所有文字都将被记录在1.txt中。