目录
2.输入python检测当前环境下python是否可用,如有以下输出则正常:
3.输入pip检测环境内的pip指令是否能正常使用,如有列出指令则正常:
2.下载 tinyshakespeare 数据集,使用 GPT-2 Tokenizer 对其进行标记分割。
3.运行脚本文件,使用 OpenAI 发布的 GPT-2 权重进行初始化然后微调,以便在c语言中加载。
1.在项目根目录下,打开终端或命令提示符,创建一个名为build的新目录并进入运行:
2. 运行CMake来配置项目并生成构建系统(如Makefile或其他适合你平台的构建文件):
前言
本文旨在记录初学者在探索Karpathy大佬的llm.c项目时配置本地环境的过程和粗略的解决方法,并且更进一步的探索llm.c的文件架构和一些代码内容,以期使用cmake的方式完成对llm.c在linux上运行和在windows下相同的可执行内容。以上内容皆以llm.c给出的cpu版本为例。(因笔者未系统学习过深度学习,所以本文不多涉及具体原理)
项目部署的环境如下:
Nvidia独立显卡+驱动(driver)
Ubuntu22.04(wsl)
Visual Studio Code
windows11命令行(powershell)
一、环境配置
1.下载源代码
github原项目地址https://github.com/karpathy/llm.c
依次点击code->Download ZIP,下载并解压到合适目录
2.工具检查
1.输入wsl进入linux子系统
2.输入python3检测当前环境下python是否可用,如有以下输出则正常:
输入exit()退出
若无正常输出则检查是否安装python以及环境变量是否添加正常。
3.输入pip检测环境内的pip指令是否能正常使用,如有列出指令则正常:
若python环境内的pip不可用或正好缺失则指令安装:python get-pip.py
报错:利用指令安装出现错误E: Package 'python3-pip' has no installation candidate
解决:命令行输入sudo apt-get update(更新软件源)
tip:更换pip软件源教程
如果不更换国内源或者其它源,有些依赖包会下载十分缓慢以致失败,这对我们的项目基本运行非常不利,在这里简单给出换源方法:
1.在主目录创建.pip文件夹:sudo mkdir .pip
2.进入./pip文件夹 :cd .pip
3. 创建pip.conf文件 :sudo touch pip.conf
4.修改配置文件conf方法一:使用vim 打开文件修改(推荐,i编辑,esc进入命令模式,输入:进入末行模式,wq保存退出)
方法二: sudo gedit pip.conf 打开文件(不推荐,因为大多数白板Ubuntu没有gedit需要sudo apt-get install gedit 下载文件编辑器gedit)
具体内容可以搜索网络上的各种国内源复制粘贴到配置文件pip.conf中
二、项目运行
在llm.c项目目录进入命令行:
1.下载依赖
输入pip install -r requirements.txt 安装依赖;
(报错1:ERROR: Package ‘xxx‘ requires a different Python: 3.8.10 not in ‘>=3.9‘ 意为该包需要更高版本的python 解决:从官网寻找所需版本的包安装或直接在命令行输入sudo pip install --upgrade python==3.x.x ,其中,将"3.x.x"替换为想要安装的Python版本号即可)
等待依赖自行安装完成即可
2.下载 tinyshakespeare 数据集,使用 GPT-2 Tokenizer 对其进行标记分割。
运行:python3 prepro_tinyshakespeare.py
也可以使用给出的另一数据集tinystories.py
结果如下
得到两个二进制文件,验证集以及数据集
3.运行脚本文件,使用 OpenAI 发布的 GPT-2 权重进行初始化然后微调,以便在c语言中加载。
作用:生成gpt2_124M.bin gpt2_124M_debug_state.bin gpt2_tokenizer.bin (在这里用到的主要是gpt2_123M) 1) 包含用于在 C 中加载的原始模型权重的文件,2) ,它还包含更多调试状态:输入、目标、logits 和 loss(可用于调试和单元测试), 最后 3) 它存储 GPT-2 分词器的词汇表,将令牌 ID 转换为 UTF-8 编码字符串片段的字节序列。
运行: python3 train_gpt2.py
注:可能会报异常多的错误,主要是“OSError: We couldn't connect to 'https://huggingface.co' to load this file, couldn't find it in the cached files and it looks like gpt2 is not the path to a directory containing a file named config.json”大意为网络连接失败导致的无法从huggingface下载预定义的gpt2模型.;解决办法:打开train_gpt2.py文件,在导包后加一段代码os.environ["HF_ENDPOINT"] = "https://hf-mirror.com" )tip:HF_ENDPOINT 该变量是 HF 相关库官方支持的一个环境变量,设置后,相关库会尊重该变量指定的主机名,替换 huggingface.co 域名进行模型、数据集的下载和上传,从而做到无需修改python的transformers代码,即可利用上镜像站来加载模型。
运行结果参考:
4.初始化并检测
运行make train_gpt2fp32cu 用gpt2_124M.bin 中的模型权重进行初始化编译,加载训练脚本,自动检测系统上是否有 OpenMP 可用,这对于以非常低的代码复杂性成本加快代码速度非常有帮助。
运行结果参考:
由于我们在这里使用的是cpu版本的代码,因此没有使用项目中的cuda相关包和代码
5.开始训练
运行: OMP_NUM_THREADS=8 ./train_gpt2 (即线程数为8,依据自己的cpu调整)进行训练
参考结果:
附言:
作者在项目中还给出了和pytorch进行比对的简单测试代码
运行:make test_gpt2 ./test_gpt2
三、文件分析
对llm.c项目部分文件进行简单概括,主要是根目录下的文件
- cudnn_att.cpp:所有和cudnn相关的函数都在这个文件中,每次使用时就不需要再次编译。
-
prepro_tinyshakespeare.py 与 prepro_tinystories.py:
都是从github或huggingface上获取数据集然后用GPT-2 tokenizer进行分割标记,
重要的是会生成两个二进制文件 xxx_val.bin 和 xxx.train.bin 。(下图为tinyshakesperare)
-
train_gpt2.py:初始化权重,为在c环境下训练做预处理,从huggingface加载GPT-2(124M)模型权重,生成三个二进制文件gpt2_124M.bin(原始的模型权重)gpt2_124M_debug_state.bin(在原有基础上加上调试状态量),gpt2_tokenizer.bin(存储GPT-2标记器的词汇表,将标记id转换为UTF-8编码字符串片段的字节序列)根目录的Makefile中写了检查OpenMP可用性的代码
-
train_gpt2.c (直接在纯c中训练,CPU版本训练)头文件:除常规头文件外,需引入根目录下utils.h头文件(utils.h: 定义一系列宏xxxCheck以用相应的C标准库函数并检查其返回码。如果报错便会打印调试信息并退出。)和tokenizer.h头文件(tokenizer.h: 定义GPT-2分词器。且仅支持解码,即:标记(整数)->字符串,也需引入utils.h)如图:此外还有openmp主函数: 上一步骤python脚本加载了GPT-2(124M)原始权重并将其保存为了检查点,先从这一检查点构建gpt-2 模型
从前面的二进制文件(xxx_val.bin,xxx_train.bin)构建数据集的加载。即使用tiny_shakespeare和 tiny_stories(这里的代码是以tiny_shakespeare为例)
构建分词器(同由python脚本生成),加载 gpt2_tokenizer.bin二进制文件
之后就是训练部分
train_gpt2_fp32.cu(原理与.c文件大致相同但添加了cuda内核,用GPU加速训练,fp32精度内核训练)
train_gpt2.cu(同上为GPU训练代码,但是使用混合精度)
杂项:profile_gpt2.cu:用于在训练中分析CUDA内核 (引入train_gpt2.cu)
头文件:
-
dataloader.h: 实现了一个分布式训练环境下的数据加载器。它负责从文件中加载数据,支持分布式处理,每个进程处理数据的不同部分。
-
rand.h: 包含了 Mersenne Twister 随机数生成器的实现,这是一个与 PyTorch 中使用的随机数生成器数值相同的实现。它用于在模型训练中生成随机数,例如初始化权重或在训练过程中进行随机抽样。
-
tokenizer.h: 定义了 GPT-2 的解码器。这个文件负责将整数代表的 tokens 转换为字符串,这是模型生成文本的重要部分。目前只支持解码,不支持编码。
-
utils.h: 提供了一系列实用函数和宏,用于文件操作和错误检查。这些工具函数在整个项目中被广泛使用,以简化文件读写操作并确保操作的正确性。
四、cmake编译llm.c
1.准备CMakeLists.txt文件
在llm.c项目的根目录下,创建一个名为CMakeLists.txt
的文件,将以下内容复制粘贴
cmake_minimum_required(VERSION 3.10)
project(llm_c_project LANGUAGES C)
# 设置C语言标准
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)
# 查找并链接OpenMP
find_package(OpenMP)
if(OpenMP_C_FOUND)
link_libraries(OpenMP::OpenMP_C)
endif()
# 查找Python解释器,并确保所有Python依赖都被安装
find_package(Python3 REQUIRED Interpreter)
add_custom_target(install_python_deps
COMMAND ${Python3_EXECUTABLE} -m pip install -r "${PROJECT_SOURCE_DIR}/requirements.txt"
COMMENT "Installing Python dependencies"
)
# 添加编译器优化和警告标志
add_compile_options(-Wall -Wextra -pedantic -Ofast)
# 指定源文件
set(SOURCE_FILES
train_gpt2.c
)
# 添加执行文件
add_executable(llm_c_project ${SOURCE_FILES})
# 链接数学库
target_link_libraries(llm_c_project m)
# 自定义目标:预处理数据
add_custom_target(preprocess
COMMAND ${Python3_EXECUTABLE} "${PROJECT_SOURCE_DIR}/prepro_tinyshakespeare.py"
COMMENT "Preprocessing TinyShakespeare dataset"
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
)
# 自定义目标:下载并初始化GPT-2模型
add_custom_target(prepare_model
COMMAND ${Python3_EXECUTABLE} "${PROJECT_SOURCE_DIR}/train_gpt2.py"
COMMENT "Preparing GPT-2 model weights"
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
)
# 添加依赖关系:prepare_model 依赖于 preprocess
add_dependencies(prepare_model preprocess)
# 添加依赖关系:主项目依赖于模型准备、数据预处理和Python依赖安装
add_dependencies(llm_c_project install_python_deps prepare_model)
2.运行CMake生成构建系统
1.在项目根目录下,打开终端或命令提示符,创建一个名为build
的新目录并进入运行:
mkdir build
cd build
2. 运行CMake来配置项目并生成构建系统(如Makefile或其他适合你平台的构建文件):
cmake ..
3.构建项目
构建完成,可以运行生成的可执行文件来测试项目是否按预期工作:
./llm_c_project
报错2: Error opening model file
原因:模型文件在根目录,而如果直接在生成可执行文件的build文件夹下运行,会查找不到gpt-2model的路径。
解决方案:改为在根目录运行
cd ..
./build/llm_c_project
运行结果参考 :
总结
本文仅提供了运行llm.c的环境配置解决和在linux下的cmake编译实现方案,原理部分未多提及,文中提供的编译实现方案可略微拓展llm.c这一轻量型语言模型工具在api方面的开发,希望能为后续的如交互式文本生成,智能聊天等项目迭代提供一些可能的帮助。