【Python】科研代码学习:九 parser,argparse,HfArgumentParser

本文介绍了Python内置的parser和argparse库,以及HuggingFace的HfArgumentParser,对比了它们在构建用户友好命令行接口时的使用和特点,重点讲解了add_argument和parse_args的方法以及高级应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【Python】科研代码学习:九 parser,argparse,HfArgumentParser

parser

  • 首先了解一下,parser 是干什么的
    parser,解析器,可以让人轻松编写用户友好的命令行接口
    主要从 sys.argv 识别解析用户给出的参数,方面这些参数后续 .py 文件中的操作
  • parserpython 直接支持使用的库,使用
import parser

即可导入使用

  • 但是现在使用 parser 的人越来越少了,为什么呢?

argparser

import argparser
  • 然后看一下,argparser 主要是通过实例化一个 ArgumentParser 类来做各种操作的:
parser = argparse.ArgumentParser(
                    prog='ProgramName',
                    description='What the program does',
                    epilog='Text at the bottom of help')
  • 顺便看下源码,以及构造参数
    prog:描述项目名
    description:描述项目作用
    epilog:在参数帮助信息之后显示的文本
    在这里插入图片描述

add_argument 添加参数

  • 还是看最重要的方法吧
    首先是为解析器添加参数
    在这里插入图片描述
  • 首先需要知道 位置参数,选项参数 这两者的区别,这相当于调用一个函数时的参数提供: f(12,b=5),前面就是位置参数,后面是选项参数
    选项参数有短选项参数 -f 和长选项 --foo,他们表示相同的含义,只不过约定俗成,短选项参数为一个 - 后接一个字母,据说特殊情况也可以接多个。但比如 -abc,一般我们就认为它使用了三个短选项参数,即 -a -b -c 的简写
  • 如果输入参数是以 - 开头,则识别为选项参数,否则其他都识别为位置参数。
parser.add_argument('filename')           # 位置参数
parser.add_argument('-c', '--count')      # 选项参数,其中 -c 和 --count 是一个含义
parser.add_argument('-v', '--verbose',
                    action='store_true')
parser.add_argument('--foo', help='foo help') # 只提供长选项参数

parse_args 解析参数

  • 有如下几种解析参数的方式
  • 第一种:通过 cmd 中,或者 .sh 中,提供参数:
OUTPUT_DIR=${1:-"./llama-2-7b-oscar-ft"}
export HF_DATASETS_CACHE=".cache/huggingface_cache/datasets"
export TRANSFORMERS_CACHE=".cache/models/"

# random port between 30000 and 50000
port=$(( RANDOM % (50000 - 30000 + 1 ) + 30000 ))
accelerate launch --main_process_port ${port} --config_file configs/deepspeed_train_config.yaml \
     run_llmmt.py \
    --model_name_or_path meta-llama/Llama-2-7b-hf \
    --oscar_data_path oscar-corpus/OSCAR-2301 \
    --oscar_data_lang en,ru,cs,zh,is,de \
    --interleave_probs "0.17,0.22,0.14,0.19,0.08,0.2" \
    --streaming \
    --max_steps 600000 \
    --do_train \
..... 太长省略

然后在 .py 文件中,直接调用

args = parser.parse_args()

※ 然后就可以随意使用其中的参数啦

print(args.seed)
print(args.do_train)
  • 第二种:提供字符串列表作为参数,而不是上面的空参数
    他这里有选项参数 --foo 和位置参数 bar
    第一个只提供了 ['BAR'],默认作为位置参数,所以有 bar='BAR'
    第二个提供了 ['BAR', '--foo', 'FOO'],第一个为位置参数,所以有 bar='BAR' 第二个选项参数 --foo 设置为 FOO
    第三个,只提供了选项参数,报错,因为位置参数是都需要提供的
    在这里插入图片描述
  • 当然也可以给一整个字符串,然后 .split() 也是同理的,但这个更接近于 cmd / sh 的格式
    在这里插入图片描述

add_argument 高级应用

  • 核心就是上面两个方法,这两个都明白之后,就可以看能做什么高级操作了
  • action
    如果设置 action='store_const',那么使用 const=xxx 来设置存储的常数。这样调用 --foo 的话,最终foo=42,不然 foo=None
    如果设置 action='store_true',那么如果有提供该参数,该参数值变为 true,没提供该参数的话该参数值为 falsestore_false 同理
    在这里插入图片描述
  • action='apend' 的话,那么设定该参数是一个列表,我就可以提供多次该参数值,比如这里 --foo 1 --foo 2,那么 foo=['1','2'] 的列表了
  • action='append_const' 的话,相当于是 constappend 的一个混合,同理。
  • action='count' 的话,会返回调用该参数的次数
    在这里插入图片描述
  • nargs 可以设定该参数的接受参数个数
    比如 ('--foo', nargs=2),表示 --foo 后面需要接受俩参数,即 --foo a b
    可以设置为 nargs='?' ,表示可以接受1个或0个。0个的时候会调用 default 的值
    可以设置为 nargs='*' ,表示可以接受任意数量个参数。
    可以设置为 nargs='+' ,表示可以接受1个或更多参数。
    在这里插入图片描述
    在这里插入图片描述
  • 可以使用 type 设定接受参数的数据类型,例子有:
    在这里插入图片描述
  • 可以使用 choices=[...] 设定,该参数值是给定列表中的一个选项。否则报错。
    在这里插入图片描述
  • 可以设定 required=True 表示该参数必须提供,否则报错。
    在这里插入图片描述
  • 可以设定 help='str...' ,表示该参数的作用介绍
    可以使用格式 %(var)s 就可以显示变量的值,比如 %(prog)s 或者 %(default)s
    在这里插入图片描述

HfArgumentParser

from transformers import HfArgumentParser
  • 然后是怎么使用,这一段几乎大部分使用到它都会有的代码
    一开始会去初始化 模型配置、数据配置和训练配置的参数
    接下来,通过判断 sys.argv ,观察是通过 .json 传递参数(加载对应的json_file),还是通过 cmd / sh 里提供配置参数(解析成 dataclass)
    然后传递到 model_args, data_args, training_args 三个变量中去
from utils.arguments import ModelArguments, DataTrainingArguments
from transformers import (
    HfArgumentParser,
    TrainingArguments,
    default_data_collator,
)
from transformers import HfArgumentParser
def main():
    # See all possible arguments in src/transformers/training_args.py
    # or by passing the --help flag to this script.
    # We now keep distinct sets of args, for a cleaner separation of concerns.
    
    parser = HfArgumentParser((ModelArguments, DataTrainingArguments, TrainingArguments))
    if len(sys.argv) == 2 and sys.argv[1].endswith(".json"):
        # If we pass only one argument to the script and it's the path to a json file,
        # let's parse it to get our arguments.
        model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1]))
    else:
        model_args, data_args, training_args = parser.parse_args_into_dataclasses()
  • 最后就是通过这些参数,进行调用咯。这里给了一些代码例子
tokenizer = load_tokenizer(data_args, model_args, training_args, logger)
train_datasets, eval_datasets, test_datasets = preprocess_cpo_data(train_raw_data, valid_raw_data, test_raw_data, pairs, tokenizer, shots_eval_dict, data_args, training_args, model_args)
model = load_model(data_args, model_args, training_args, tokenizer, logger) 

trainer = CPOTrainer(
    model,
    args=training_args,
    beta=model_args.cpo_beta,
    train_dataset=train_datasets,
    eval_dataset=eval_datasets,
    tokenizer=tokenizer,
    max_prompt_length=data_args.max_source_length,
    max_length=data_args.max_source_length+data_args.max_new_tokens,
    callbacks=[SavePeftModelCallback] if model_args.use_peft else None,
)


# Training
if training_args.do_train:
    checkpoint = None
    if training_args.resume_from_checkpoint is not None:
        checkpoint = training_args.resume_from_checkpoint
    
    trainer.train(resume_from_checkpoint=checkpoint)

    trainer.save_state()
    if model_args.use_peft:
        if torch.distributed.get_rank() == 0:
            model.save_pretrained(training_args.output_dir) 
    else:
        trainer.save_model()  # Saves the tokenizer too for easy upload
python根据需求完成一个TXT解析器的简单开发 一 修改说明: 需求一: 一开始说要解析UECapabilityInfo 消息里的supportedBandCombination-r10 这个IE里的CA组合转化成易阅读的表现形式. 我以为一组CA组合就是一组: bandEUTRA-r10 ca-BandwidthClassUL-r10 ca-BandwidthClassDL-r10 supportedMIMO-CapabilityDL-r10 功能实现: 有效信息筛选:于是就用循环把UECapabilityInformation的数据里每一行作为一个元素放到list里面 然后用bandEUTRA-r10作为一组CA的识别信息、在筛选出同组ca-BandwidthClassUL-r10、ca-BandwidthClassDL-r10、supportedMIMO-CapabilityDL-r10的信息,添加保存到字符串中,然后再把字符串作为元素添加到list中去。最后遍历list的元素写入目标文件 需求二: 然后收到反馈CA组合的理解是错误的。一组CA组合应该是以大括号作为识别的,里面可能包含多组: bandEUTRA-r10: ca-BandwidthClassUL-r10 ca-BandwidthClassDL-r10 supportedMIMO-CapabilityDL-r10 CA组合识别原理:在查看UECapabilityInformation内的CA组合后 发现CA组合内第一个 bandEUTRA-r10因为比其他bandEUTRA-r10多了一层的CA组合的大括号,所以如果给每一行增加索引的话就会发现除了第一个bandEUTRA-r10,其他bandEUTRA-r10到上一个supportedMIMO-CapabilityDL-r10的距离都是一样的,为了减少复杂度,我删除了所有’{’,这样所有除了所有CA组合第一个bandEUTRA-r10往上第四行是’}’其他bandEUTRA-r10的往上第四行都是supportedMIMO-CapabilityDL-r10 功能实现: 添加索引:便利时用了for enumerate()循环,这样便利时可以在循环时,自动为每个元素生成索引 CA组合识别:在识别到bandEUTRA-r10时,增加一个判断if datalist1[index-4].startswith(),如果bandEUTRA-r10的往上第四行是supportedMIMO-CapabilityDL-r10说明同组CA未结束,把筛选的有效信息强制类型转换后添加在上个元素末尾,反之则说明是个新的CA组合,往列表里添加一个新的元素。 需求三: 之后收到反馈CA组合虽然识别了,但是排序不行,需要按照CA组合支持的band进行排序 功能实现: 排序:于是我在识别完CA组合后,增加了一个循环和count(),用CA组合里的’-’给它们归类 比如1AA,11A,21AA是一类;1A-1A,2A-1AA,3A-1A是一类 在用一个中间变量保存开头的band的数字,一个类中把开头支持band的数字字母相同的CA组合归为一行 比如1A-21A,1A-22A一类1AA-2AA 1AA-3AA为一类 需求四: 之后收到反馈,CA组合分类不能只按照开头比较分类,不然一但数据多了会对查阅带来极大不便,应该按照每组CA组合中bandEUTRA-r10的值进行判断,比如1AA-2AA,1A-2AA和1AA-2A应该归在同一行 实现原理:首先我想的是按位比较数字,但是因为字母的数量不稳定,数字的位置不一定对应,然后我就想把数字全部提取出来作为索引,在相应的索引后面添加同组元素,用dict来实现排序。难点就在于从字符串中提取数字。后来在python的正则表达式中找到相关的处理函数compile()(设置匹配对象类型)和findall()(找到所有匹配对象并以list返回)。 功能实现: 第二次排序:在上次的排序中我保留了分类和从小到大的排序。方便提取索引时,索引也是从小到大。每遍历一个元素(CA组合有效信息),就compile()和findall(),从该元素中提取数字组合(在compile()的参数中添加()就能够使提取的内容成为一组数据),然后通过dict自带函数setdefault()添加索引,并可以设置索引值为list类型(dict类型的索引的值不可变,但如果类型为list,list的内容可以进行改动),避免重复索引,在本次遍历中完成将元素添加到索引值对应的list中去 需求五: 之后对程序进行测试,在测试test2时发现layers增加了fourlayers类型后,用来代表layers的数字2和4会影响分类结果。比如1AA(2)-1AA(2)和1A(4)-1A(2)会被归为两类。 test1:当CA组合的格式为xx-xx-xx-xx-xx(最长可识别为五位元素的组合,再长就需要修改代码) test2:当CA组合包含fourLayers test3:当CA组合缺失某种格式比如xx-xx时发现layers增加了fourlayers 功能实现: : 解除layers对排序的影响:用II 和 IV替代2,4来表示layers,测试后不影响阅读与分类 二、整体程序架构: 1.通过循环和自带的startswith()先将每组CA组合的有效信息识别 2.通过sorted()函数将所有CA组合从小到大排列 3.通过count()函数将所有CA组合根据格式不同分类 4.通过循环和正则表达式的split()对所有CAlist数据进行处理(用split处理只是防止出现不必要的错误) 5.通过循环和正则表达式compile()和findall()识别所有CA组合中数字,并将同一组合中的数字合为一个元素(在同一循环,用这个数字的元素作为一个dict的索引),用dict自带的setdefault()进行Key的添加顺便设置Key的值为list,避免Key重复,在用append把当前Key的字符串,添加到Key对应值的list中去 6.最后对dict整体遍历,将每一个Key的值输出到文本中去。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值