为了账号安全,请及时绑定邮箱和手机立即绑定

在家搭建自己的专注于网络安全的AI开发、训练和微调实验室

这是ChatGPT对问题“基于你对我的了解,描绘出我目前的生活画面”的回答,附上笑脸:

随着AI应用的发展越来越快,商业平台如OpenAI、Gemini以及其他许多大型语言模型版本正在提供覆盖数千个领域的高级功能。然而,对于我们这些网络安全爱好者而言,这些平台提供的深入知识远远不够满足我们的需求。它们通常只分享来自公开渠道的浅显信息或学术资料。

这就是为什么最近几个月,我决定将我在准备23个成功完成的认证时整理的笔记用于训练一个选定模型,创建一个符合我需求的精调版本的模型。这个想法促使我进行了深入的研究,我想与大家分享在这个过程中我获得的见解和知识。

现在让我们直接开始工作吧,因为虽然信息随处可见,但很少有讨论技术上的进展。

如何在Hugging Face上选模型

Hugging Face 是一个提供开源工具、数据集和众多模型的平台,这些模型用于自然语言处理(NLP)和人工智能(AI)领域中的各种任务。它使用户能够轻松地开发、训练和使用各种 AI 模型。其最强大的功能之一是 Transformers 库。这个由 Hugging Face 开发的库是一个强大的开源 Python 库,专用于自然语言处理任务。它允许轻松地使用预训练模型,例如 BERT、GPT、T5 和 LLaMA,并对文本分类、翻译和摘要等任务进行了优化。凭借其简单的 API 结构,它使用户能够轻松下载和集成模型,进行微调,甚至开发自己的应用程序。

这个链接指向了Hugging Face的模型页面: https://huggingface.co/models

你可以从Hugging Face上的数千个库中挑选。选择模型时要注意两个关键点:一是它与你所使用的部署环境是否兼容,二是它与你打算训练的模型是否兼容。

注意:由于VMware Workstation和VirtualBox不支持GPU透传,你无法在虚拟机中使用你的GPU。因此,你应该在你的主机系统上安装Docker。或者,你可以尝试使用Hyper-V或ESXi。

制作 Docker 图像:

我们来创建一个Dockerfile基于Ubuntu来构建Docker镜像,然后在这个镜像中安装PyTorch。

    FROM nvidia/cuda:11.8.0-cudnn8-runtime-ubuntu20.04  

    RUN apt-get update && apt-get install -y \  
        python3 \  
        python3-pip \  
        wget \  
        && rm -rf /var/lib/apt/lists/*  

    # 安装 PyTorch, torchvision 和 torchaudio 库(支持 CUDA)
    RUN pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118  

    WORKDIR /workspace  

    CMD ["bash"]

让我们如下处理 Dockerfile

使用以下命令构建和运行PyTorch GPU容器:

docker build -t pytorch-gpu .  # 构建一个名为pytorch-gpu的docker镜像

docker run --gpus all -it --name pytorch-gpu-container pytorch-gpu  # 使用所有GPU资源运行名为pytorch-gpu-container的pytorch-gpu镜像

我们来看看(PyTorch)是否安装成功。

运行 `nvidia-smi` 命令检查NVIDIA显卡状态,

运行 `python3 -c "import torch; print(torch.cuda.is_available())"` 检查CUDA是否可用。

现在我们可以一步一步地选择、加载并微调来自Hugging Face的LLM模型,使用虚拟化。为了高效地利用处理器资源,你可以用virtualenvconda来实现。

选项1

pip install virtualenv    # 这将安装一个虚拟环境管理工具
virtualenv llm_env        # 创建一个名为llm_env的虚拟环境

source llm_env/bin/activate  # 在Linux或Mac上运行此命令。在Windows上,应使用llm_env\\Scripts\\activate

选项2:第二个选项

Python 还提供了 venv 模块,可以用来创建虚拟环境,。如果你不想使用 virtualenv,也可以选择使用这个 venv 模块。

在命令行中运行以下命令来创建虚拟环境:

python3 -m venv llm_env

然后使用以下命令激活环境:

source llm_env/bin/activate

这会激活虚拟环境
Huggingface 模型选择与 Token(令牌)

选择Hugging Face上的一个模型后,注册一个账户并生成一个token。接着,使用此token从你的机器的bash终端访问Hugging Face,然后拉取你的模型。

运行命令 huggingface-cli 登录


    从transformers库导入AutoModelForCausalLM 和 AutoTokenizer

    model_name = "MODEL_NAME"  
    token = "<your_token>"   

    model = AutoModelForCausalLM.from_pretrained(model_name, use_auth_token=token)  
    tokenizer = AutoTokenizer.from_pretrained(model_name, use_auth_token=token)
让我们安装库

自从我们激活了虚拟环境之后,我们将安装一些仅在这个虚拟环境中可用的库,

使用pip安装transformers、datasets和torch库

pip install transformers datasets torch

安装特定版本的torch库

pip install torch==2.4.0+cu124

使用pip进行升级安装transformers库

pip install --upgrade transformers
测试模型功能
    input_text = "Merhaba, ben bir dil modeliyim ve size nasıl yardımcı olabilirim?"  

    # 分词处理输入文本  
    inputs = tokenizer(input_text, return_tensors="pt")  

    # 生成输出文本  
    outputs = model.generate(inputs["input_ids"], max_length=50)  

    # 将生成的输出解码回文本  
    generated_text = tokenizer.decode(outputs[0], skip_special_tokens=True)  

    # 打印生成的文本内容  
    print(generated_text)

用数据集来训练

要对模型进行微调,我们可以使用Hugging Face的Trainer类工具。在微调过程中,我们需要一个合适的训练数据集和适当的配置来完成微调。

例如,让我们使用IMDb数据集。对于更高级的测试数据集,比如WikiText。

    从datasets库导入load_dataset.  

    dataset = load_dataset("imdb").  # 加载IMDb数据集  

    train_dataset = dataset["train"].  # 训练数据集  
    eval_dataset = dataset["test"].  # 评估数据集

比如说,我们来用 meta-llama/Llama-3.1-8B-Instruct 模型。

注意:要访问Meta提供的模型,请在Hugging Face上提交请求!

from transformers import AutoModelForSequenceClassification, AutoTokenizer  

model_name = "meta-llama/Llama-3.1-8B-Instruct"  

model = AutoModelForSequenceClassification.from_pretrained(model_name, num_labels=2)  
tokenizer = AutoTokenizer.from_pretrained(model_name)

在这里,我们从transformers库中导入AutoModelForSequenceClassification和AutoTokenizer。然后,我们使用特定的模型名称初始化模型和分词器。

现在,让我们为RTX 3080编写一个适合的分词函数。在进行数据分词时,最重要的考虑因素之一是批次大小和分词长度这两个方面。对于像RTX 3080这样的显卡,在对大型数据集进行分词时,使用较大的批次大小和较长的分词长度可能导致内存过载。

    def tokenize_function(examples):  

        # 我们通过设置 padding 和 truncation 参数来统一每个示例的长度。  
        return tokenizer(  
            examples["text"],           # 我们对 "text" 字段中的文本进行分词处理  
            padding="max_length",       # 我们将所有文本填充至最大长度  
            truncation=True,            # 我们截断过长的文本  
            max_length=512,             # 最大长度(通常在 512-1024 之间,适用于 RTX 3080 显卡)  
        )
  • **max_length**:设定每个文本的标记长度为固定值。对于大规模数据集,通常设定此值为一个合理的数值,例如512或1024,以优化内存使用。

  • **padding="max_length"**:将每个文本填充至max_length,确保所有标记化的文本长度一致。

  • **truncation=True**:将超出指定max_length的文本截断。

我们将使用map函数来对您的数据集进行标记化处理。该函数会批量处理并为每个样本进行标记化。

  • **batched=True**:允许分批进行分词操作,一次处理多个示例,这可以提高处理速度。
  • **num_proc=4**:启用CPU核心的并行处理,减少处理时间。选择合适的值以避免内存溢出错误,特别是在使用RTX 3080这样的GPU时更为重要。
    train_dataset = train_dataset.map(tokenize_function, batched=True, num_proc=4)  # 使用4个核心进行并行处理
    eval_dataset = eval_dataset.map(tokenize_function, batched=True, num_proc=4)    # 使用4个核心进行并行处理

为了使分词过程更高效,你可能需要将 per_device_train_batch_sizeper_device_eval_batch_size 参数的值降低。如果你的 GPU VRAM 较低时,将这些值设为 4 或更低可能会有帮助。

    从transformers库导入TrainingArguments,

    training_args = TrainingArguments(  
        output_dir="./results",  # 结果输出目录
        evaluation_strategy="epoch",  # 设置评估策略为每个epoch评估一次
        logging_dir="./logs",  # 日志文件输出目录
        logging_steps=5,  # 每5步记录一次
        learning_rate=2e-5,  # 学习率设置为2e-5
        per_device_train_batch_size=4,  # 每个设备的训练批次大小为4
        per_device_eval_batch_size=4,  # 每个设备的评估批次大小为4
        num_train_epochs=3,  # 训练总epoch数为3
        weight_decay=0.01,  # 权重衰减设置为0.01
        fp16=True, # 使用半精度浮点数
        gradient_accumulation_steps=4,  # 梯度累积步数设置为4
    )

如果你碰到填充令牌错误,

    if tokenizer.pad_token is None:  
        tokenizer.pad_token = tokenizer.eos_token  

    inputs = tokenizer(input_text, return_tensors="pt", padding=True, truncation=True)  

    inputs["attention_mask"] = inputs["attention_mask"].to(model.device)  

    if model.config.pad_token_id is None:  
        model.config.pad_token_id = model.config.eos_token_id  

    # 生成输出  
    outputs = model.generate(inputs["input_ids"], attention_mask=inputs["attention_mask"], max_length=50)  

    # 将输出解码为文本  
    generated_text = tokenizer.decode(outputs[0], skip_special_tokens=True)  

    # 打印文本  
    print(generated_text)

咱们开始训练吧,

    # 创建一个训练师对象
    trainer = Trainer(  
        model=model,  
        args=training_args,  
        train_dataset=训练数据集,    
        eval_dataset=评估数据集,      
    )  

    trainer.train()
实践方法、小技巧、常见错误和解决方法
    torch.OutOfMemoryError: CUDA 缺少内存。以下尝试分配 64.00 MiB。   
    GPU 0 总容量为 23.64 GiB,其中 20.81 MiB 空闲。   
    进程 2131856 占用了 23.62 GiB 内存。在分配的内存中,   
    23.24 GiB 由 PyTorch 分配,1.11 MiB 由 PyTorch 预留但未分配。   
    如果预留但未分配的内存较大,可以试着设置 PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True 来避免内存碎片。    
    有关内存管理的文档(见 https://pytorch.org/docs/stable/notes/cuda.html#environment-variables)

在这种情况下,可以减少批量大小。

训练参数设置如下:输出目录为 './results',评估策略为 'epoch',学习率为 2e-5,每设备训练批大小为 2,每设备评估批大小为 2,训练周期数为 3,权重衰减为 0.01。

梯度累积

而不是减小批量大小,我们可以使用梯度累积来用小批量进行训练,同时模拟大批量的效果。

    training_args = TrainingArguments(  
        output_dir="./results",  
        eval_strategy="轮次",  
        learning_rate=2e-5,  
        per_device_train_batch_size=2,  
        per_device_eval_batch_size=2,  
        num_train_epochs=3,  
        weight_decay=0.01,  
        gradient_accumulation_steps=8,    
    )
FP16 训练(半精度的训练)

通过使用mixed_precision训练,我们可以使用低精度数字。这可以显著降低内存使用,同时提升性能。

    training_args = TrainingArguments(  
        output_dir="./results",  # 输出目录 (chūchú mùlù)
        eval_strategy="epoch",  # 评估策略 (píngguǎn lüèshē)
        learning_rate=2e-5,  # 学习率 (xuéxí lǜ)
        per_device_train_batch_size=8,  # 每设备训练批量 (měi shèbèi xùnliàn piányì)
        per_device_eval_batch_size=8,  # 每设备评估批量 (měi shèbèi píngguǎn piányì)
        num_train_epochs=3,  # 训练周期数 (xùnliàn zhuīqi yǔnshù)
        weight_decay=0.01,  # 权重衰减 (zhòngqián shuāijiǎn)
        fp16=True,  # 半精度浮点数 (bàn jīdù fúdiǎnshù)
    )
使用 Trainer 进行日志记录和指标追踪
    training_args = TrainingArguments(  
        output_dir="./results",  
        eval_strategy="epoch",  
        logging_dir="./logs",    
        logging_steps=5,    
        per_device_train_batch_size=8,  
        num_train_epochs=3,  
    )

注:上述代码定义了一个TrainingArguments对象,用于设置模型训练的相关参数,包括输出目录、评估策略、日志目录、日志步骤、每个设备的训练批次大小以及训练的总轮数。

用 TensorBoard 监控
    从transformers导入Trainer, TrainingArguments模块

    # 初始化训练参数并设置训练器
    training_args = TrainingArguments(  
        output_dir="./results",  
        logging_dir="./logs",    
        logging_steps=10,  
    )  

    trainer = Trainer(  
        model=model,  
        args=training_args,  
        train_dataset=train_dataset,  
        eval_dataset=eval_dataset,  
    )  

    trainer.train()  # 训练器启动训练

    %load_ext tensorboard  
    %tensorboard --logdir ./logs
保存训练成果。
trainer.save_model()  # 保存模型
tokenizer.save_pretrained("./results")  # 保存分词器到指定文件夹
检查训练状况
    # 查看训练过程中的步数(当前训练步数)
    print(trainer.state.global_step)

    # 查看当前的epoch(当前训练周期)
    print(trainer.state.epoch)
点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消