train_gpt2_fp32.cu - main

llm.c/test_gpt2_fp32.cu at master · karpathy/llm.c (github.com)

源码

// ----------------------------------------------------------------------------
// main training loop
int main(int argc, char *argv[]) {// read in the (optional) command line argumentsconst char* input_dataset_prefix = "data/tiny_shakespeare"; // or e.g. data/TinyStoriesconst char* output_log_file = NULL;int B = 4; // batch sizeint T = 1024; // sequence length maxfloat learning_rate = 3e-4f;int val_loss_every = 20; // every how many steps do we eval validation loss?int val_max_batches = 20; // how many batches max do we eval for validation loss?int sample_every = 20; // every how many steps to do inference?int genT = 64; // number of steps of inference we will dofor (int i = 1; i < argc; i+=2) {if (i + 1 >= argc) { error_usage(); } // must have arg after flagif (argv[i][0] != '-') { error_usage(); } // must start with dashif (strlen(argv[i]) != 2) { error_usage(); } // must be -x (one dash, one letter)// read in the argsif (argv[i][1] == 'i') { input_dataset_prefix = argv[i+1]; }else if (argv[i][1] == 'o') { output_log_file = argv[i+1]; }else if (argv[i][1] == 'b') { B = atoi(argv[i+1]); }else if (argv[i][1] == 't') { T = atoi(argv[i+1]); }else if (argv[i][1] == 'l') { learning_rate = atof(argv[i+1]); }else if (argv[i][1] == 'v') { val_loss_every = atoi(argv[i+1]); }else if (argv[i][1] == 'm') { val_max_batches = atoi(argv[i+1]); }else if (argv[i][1] == 's') { sample_every = atoi(argv[i+1]); }else if (argv[i][1] == 'g') { genT = atoi(argv[i+1]); }else { error_usage(); }}printf("+-----------------------+----------------------------------------------------+\n");printf("| Parameter             | Value                                              |\n");printf("+-----------------------+----------------------------------------------------+\n");printf("| input dataset prefix  | %-50s |\n", input_dataset_prefix);printf("| output log file       | %-50s |\n", output_log_file == NULL ? "NULL" : output_log_file);printf("| batch size B          | %-50d |\n", B);printf("| sequence length T     | %-50d |\n", T);printf("| learning rate         | %-50f |\n", learning_rate);printf("| val_loss_every        | %-50d |\n", val_loss_every);printf("| val_max_batches       | %-50d |\n", val_max_batches);printf("| sample_every          | %-50d |\n", sample_every);printf("| genT                  | %-50d |\n", genT);printf("+-----------------------+----------------------------------------------------+\n");// set up the deviceint deviceIdx = 0;cudaCheck(cudaSetDevice(deviceIdx));cudaDeviceProp deviceProp;cudaGetDeviceProperties(&deviceProp, deviceIdx);// setup cuBLAS and cuBLASLtcublasCheck(cublasCreate(&cublas_handle));cublasCheck(cublasLtCreate(&cublaslt_handle));// TF32 precision is equivalent to torch.set_float32_matmul_precision('high')int enable_tf32 = deviceProp.major >= 8 ? 1 : 0;cublas_compute_type = enable_tf32 ? CUBLAS_COMPUTE_32F_FAST_TF32 : CUBLAS_COMPUTE_32F;cublasMath_t cublas_math_mode = enable_tf32 ? CUBLAS_TF32_TENSOR_OP_MATH : CUBLAS_DEFAULT_MATH;cublasCheck(cublasSetMathMode(cublas_handle, cublas_math_mode));cudaCheck(cudaMalloc(&cublaslt_workspace, cublaslt_workspace_size));printf("| device                | %-50s |\n", deviceProp.name);printf("| TF32                  | %-50s |\n", enable_tf32 ? "enabled" : "disabled");printf("+-----------------------+----------------------------------------------------+\n");// build the GPT-2 model from a checkpointGPT2 model;gpt2_build_from_checkpoint(&model, "gpt2_124M.bin");printf("| max_sequence_length T | %-50d |\n", model.config.max_seq_len);printf("| vocab_size V          | %-50d |\n", model.config.vocab_size);printf("| padded_vocab_size Vp  | %-50d |\n", model.config.padded_vocab_size);printf("| num_layers L          | %-50d |\n", model.config.num_layers);printf("| num_heads NH          | %-50d |\n", model.config.num_heads);printf("| channels C            | %-50d |\n", model.config.channels);printf("| num_parameters        | %-50zu |\n", model.num_parameters);printf("+-----------------------+----------------------------------------------------+\n");// build DataLoaders for both train and valchar train_tokens_filename[128];char val_tokens_filename[128];assert(strlen(input_dataset_prefix) < 100); // being bit lazy here, make sure we don't overflowsprintf(train_tokens_filename, "%s_train.bin", input_dataset_prefix);sprintf(val_tokens_filename, "%s_val.bin", input_dataset_prefix);DataLoader train_loader;dataloader_init(&train_loader, train_tokens_filename, B, T);DataLoader val_loader;dataloader_init(&val_loader, val_tokens_filename, B, T);int train_num_batches = train_loader.num_batches; // let's do 1 epoch by default for nowint val_num_batches = train_loader.num_batches < val_max_batches ? train_loader.num_batches : val_max_batches;printf("| train_num_batches     | %-50d |\n", train_num_batches);printf("| val_num_batches       | %-50d |\n", val_num_batches);printf("+-----------------------+----------------------------------------------------+\n");// print model parameter allocations from gpt2_build_from_checkpoint down here to not mess up our table aboveprintf("allocated %d MiB for model parameters\n", (int)round(model.num_parameters * sizeof(float) / (1024 * 1024)));// set up the LoggerLogger logger;logger_init(&logger, output_log_file);// build the TokenizerTokenizer tokenizer;tokenizer_init(&tokenizer, "gpt2_tokenizer.bin");// some memory for generating samples from the modelunsigned long long rng_state = 1337;int* gen_tokens = (int*)mallocCheck(B * T * sizeof(int));float* cpu_logits = (float*)mallocCheck(model.config.vocab_size * sizeof(float));// trainstruct timespec start, end;double total_sum_iteration_time_s = 0.0;for (int step = 0; step <= train_num_batches; step++) {int last_step = step == train_num_batches;// once in a while estimate the validation lossif (step % val_loss_every == 0 || last_step) {float val_loss = 0.0f;dataloader_reset(&val_loader);for (int i = 0; i < val_num_batches; i++) {dataloader_next_batch(&val_loader);gpt2_forward(&model, val_loader.inputs, val_loader.targets, B, T);val_loss += model.mean_loss;}val_loss /= val_num_batches;printf("val loss %f\n", val_loss);logger_log_val(&logger, step, val_loss);}// once in a while do model inference to print generated textif (step > 0 && step % sample_every == 0 || last_step) {// fill up gen_tokens with the GPT2_EOT, which kicks off the generationfor(int i = 0; i < B * T; ++i) {gen_tokens[i] = GPT2_EOT;}// now sample from the model autoregressivelyprintf("generating:\n---\n");for (int t = 1; t < genT; t++) {// note that inference is very wasteful here because for each token// we re-calculate the forward pass for all of (B,T) positions from scratch// but the inference here is just for sanity checking anyway// and we can maybe optimize a bit more later, with careful testsgpt2_forward(&model, gen_tokens, NULL, B, T);// furthermore, below we're only using b=0 (i.e. the first row) of all B rows// we're in principle running B "inference streams" in parallel here// only using position 0 because it's a bit faster (copy less probs from GPU -> CPU)// get the V-dimensional vector probs[0, t-1, :]float* logits = model.acts.output + (t - 1) * model.config.padded_vocab_size;// move probs back to CPU and sample (note we only move the first vocab_size logits, ignoring the padding)cudaCheck(cudaMemcpy(cpu_logits, logits, model.config.vocab_size * sizeof(float), cudaMemcpyDeviceToHost));float coin = random_f32(&rng_state);int next_token = sample_softmax(cpu_logits, model.config.vocab_size, coin);gen_tokens[t] = next_token;// print the generated token, either using the Tokenizer or a fallbackif (tokenizer.init_ok) {const char* token_str = tokenizer_decode(&tokenizer, next_token);safe_printf(token_str);} else {// fall back to printing the token idprintf("%d ", next_token);}fflush(stdout);}printf("\n---\n");}// bit confusing: we want to make sure to eval and sample on 0th iteration// but also after the very last iteration. so we loop for step <= train_num_batches// instead of just < train_num_batches (one extra due to <=), only to do// the validation/sampling one last time, and then we break right here as we're done.if (last_step) { break; }// do a training stepclock_gettime(CLOCK_MONOTONIC, &start);dataloader_next_batch(&train_loader);gpt2_forward(&model, train_loader.inputs, train_loader.targets, B, T);gpt2_zero_grad(&model);gpt2_backward(&model);gpt2_update(&model, learning_rate, 0.9f, 0.999f, 1e-8f, 0.0f, step+1);cudaCheck(cudaDeviceSynchronize()); // finish all CUDA work to get correct precise timingsclock_gettime(CLOCK_MONOTONIC, &end);double time_elapsed_s = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1e9;total_sum_iteration_time_s += time_elapsed_s;int tokens_per_second = (B * T) / time_elapsed_s;printf("step %4d/%d: train loss %f (%f ms, %d tok/s)\n", step + 1, train_num_batches, model.mean_loss, time_elapsed_s * 1000, tokens_per_second);logger_log_train(&logger, step, model.mean_loss);}// add a total average, for optimizations that are only mild improvementsprintf("total average iteration time: %f ms\n", total_sum_iteration_time_s / train_num_batches * 1000);// freedataloader_free(&train_loader);dataloader_free(&val_loader);tokenizer_free(&tokenizer);gpt2_free(&model);free(cpu_logits);free(gen_tokens);cudaCheck(cudaFree(cublaslt_workspace));cublasCheck(cublasDestroy(cublas_handle));cublasCheck(cublasLtDestroy(cublaslt_handle));logger_free(&logger);return 0;
}

注释

#include <stdio.h>      // 引入标准输入输出头文件
#include <stdlib.h>     // 引入标准库头文件,提供动态内存分配、随机数生成等功能
#include <math.h>       // 引入数学库头文件,提供数学计算函数
#include <time.h>       // 引入时间库头文件,提供时间相关函数
#include <assert.h>     // 引入断言库头文件,提供断言功能
#include <string.h>     // 引入字符串库头文件,提供字符串操作函数
// 其他相关头文件省略,可能包括 cuda 相关头文件和自定义的模型、数据加载库头文件
int main(int argc, char *argv[]) {// 从命令行参数中读取(可选)参数,如果没有提供给出默认值const char* input_dataset_prefix = "data/tiny_shakespeare"; // 数据集前缀,默认为 "data/tiny_shakespeare"const char* output_log_file = NULL;  // 输出日志文件路径,默认为空int B = 4; // 批次大小,默认为 4int T = 1024; // 序列最大长度,默认为 1024float learning_rate = 3e-4f; // 学习率,默认为 0.0003int val_loss_every = 20; // 每多少步计算一次验证集损失,默认为 20 步int val_max_batches = 20; // 计算验证集损失的最大批次数,默认为 20int sample_every = 20; // 每多少步进行一次模型推理生成文本,默认为 20 步int genT = 64; // 推理时的步数,默认为 64// 根据命令行参数设定变量的值for (int i = 1; i < argc; i+=2) {if (i + 1 >= argc) { error_usage(); } // 检查参数是否成对出现if (argv[i][0] != '-') { error_usage(); } // 检查参数标志是否以短横线开头if (strlen(argv[i]) != 2) { error_usage(); } // 检查参数标志格式是否正确(-x 格式)// 解析命令行参数并设定相关变量的值if (argv[i][1] == 'i') { input_dataset_prefix = argv[i+1]; }else if (argv[i][1] == 'o') { output_log_file = argv[i+1]; }else if (argv[i][1] == 'b') { B = atoi(argv[i+1]); }else if (argv[i][1] == 't') { T = atoi(argv[i+1]); }else if (argv[i][1] == 'l') { learning_rate = atof(argv[i+1]); }else if (argv[i][1] == 'v') { val_loss_every = atoi(argv[i+1]); }else if (argv[i][1] == 'm') { val_max_batches = atoi(argv[i+1]); }else if (argv[i][1] == 's') { sample_every = atoi(argv[i+1]); }else if (argv[i][1] == 'g') { genT = atoi(argv[i+1]); }else { error_usage(); }}// 打印出设置的参数值printf("+-----------------------+----------------------------------------------------+\n");// 将正文翻译为表格,忽略了具体细节...// 设置 cuda 设备,和创建 cuBLAS 句柄等 cuda 相关操作/* ... 一系列 CUDA 和 cuBLAS 相关设置,这里省略了详细代码 ... */// 使用检查点构建 GPT-2 模型GPT2 model;gpt2_build_from_checkpoint(&model, "gpt2_124M.bin");// 再次打印模型配置的参数值/* ... 省略了具体代码 ... */// 为训练集和验证集创建 DataLoader 对象char train_tokens_filename[128];char val_tokens_filename[128];assert(strlen(input_dataset_prefix) < 100); // 确保路径长度不会溢出sprintf(train_tokens_filename, "%s_train.bin", input_dataset_prefix); // 生成训练集文件路径sprintf(val_tokens_filename, "%s_val.bin", input_dataset_prefix); // 生成验证集文件路径DataLoader train_loader;dataloader_init(&train_loader, train_tokens_filename, B, T); // 初始化训练 DataLoaderDataLoader val_loader;dataloader_init(&val_loader, val_tokens_filename, B, T); // 初始化验证 DataLoaderint train_num_batches = train_loader.num_batches; // 训练批次总数,默认为1轮(epoch)// 根据实际训练数据批次和设定的最大验证批次数确定验证时使用的批次数int val_num_batches = train_loader.num_batches < val_max_batches ? train_loader.num_batches : val_max_batches;// 继续打印出与数据加载器相关的参数值/* ... 省略了具体代码 ... */// 输出模型参数空间分配情况/* ... 省略了具体代码 ... */// 设置日志记录器Logger logger;logger_init(&logger, output_log_file);// 构建 TokenizerTokenizer tokenizer;tokenizer_init(&tokenizer, "gpt2_tokenizer.bin");// 创建内存空间以生成模型样本unsigned long long rng_state = 1337; // 设置随机数生成器的初始状态int* gen_tokens = (int*)mallocCheck(B * T * sizeof(int)); // 动态分配生成 token 的内存float* cpu_logits = (float*)mallocCheck(model.config.vocab_size * sizeof(float)); // 动态分配在 CPU 上的 logits 空间// 训练过程开始struct timespec start, end; // 创建两个 timespec 结构体用于记录时间double total_sum_iteration_time_s = 0.0; // 总迭代时间for (int step = 0; step <= train_num_batches; step++) {int last_step = step == train_num_batches; // 判断是否为最后一步// 定期计算验证集的损失if (step % val_loss_every == 0 || last_step) {/* ... 省略了具体代码 ... */}// 每隔一定步数执行模型推理,打印生成的文本if (step > 0 && step % sample_every == 0 || last_step) {/* ... 省略了具体代码 ... */}// 在循环最后一次迭代后立即退出;前面的 val_loss_every 和 sample_every 块中的代码在最后一步也会执行if (last_step) { break; }// 执行一个训练步骤clock_gettime(CLOCK_MONOTONIC, &start); // 记录开始时间dataloader_next_batch(&train_loader); // 获取下一个训练批次/* ... 省略了执行前向传播、反向传播、参数更新等具体代码 ... */cudaCheck(cudaDeviceSynchronize()); // 等待 CUDA 操作完成以确保时间精确clock_gettime(CLOCK_MONOTONIC, &end); // 记录结束时间/* ... 省略了计算本次迭代所需时间、打印迭代结果等代码 ... */}// 输出平均迭代时间/* ... 省略了具体代码 ... */// 清理资源,释放分配的内存和 CUDA、cuBLAS 资源/* ... 省略了清理数据加载器、tokenizer、GPT-2 模型、日志记录器等资源的代码 ... */return 0; // 主函数返回 0,代表程序正常退出
}	

上述代码涵盖了一个典型的深度学习训练过程,包括参数解析、配置设置、模型构建、训练数据准备、日志记录、模型训练与验证、以及资源清理等环节。代码注释以简要解释每部分的主要目的和某些实现细节,便于理解程序执行流程。当然,实际实现中,函数 error_usagegpt2_build_from_checkpointdataloader_initmallocChecklogger_inittokenizer_initgpt2_forwardgpt2_zero_gradgpt2_backwardgpt2_updatecudaCheckcublasDestroylogger_free, 等的具体实现细节被省略了,这些都是特定于具体的程序库或框架的函数调用。

这个函数是一个CUDA程序,它是专门为Nvidia GPU写的,并利用了如CUDA、cuBLAS和cuBLASLt这样的Nvidia专有技术。为了将这个程序转换为能够在AMD GPU上运行的代码,你需要使用AMD提供的相应工具和库,特别是ROCm (Radeon Open Compute) 平台,它是AMD GPU上的开源计算平台。
ROCm提供了与CUDA相似的功能,例如HIP (Heterogeneous-compute Interface for Portability) 是一个可用于将CUDA代码转换为可在AMD GPU上运行的代码的工具。它包含了hipify程序,该程序可以将CUDA代码转换为HIP代码。HIP代码能够在Nvidia和AMD GPU上运行。
此外,AMD GPU也有自己的数学库,如rocBLAS,这是cuBLAS的AMD等价物。然而,请注意,即使有这些工具和库,将代码从CUDA迁移到ROCm也不是一件简单的事情,可能需要手动调整和修改代码以确保性能和功能上的最佳兼容。
以下是一些关键步骤,简要概述了如何开始将这个特定的CUDA代码转换为运行于AMD GPU的代码:
1. 使用HIP转换语法:将CUDA语法手动转换为HIP语法,或使用hipify工具自动进行。语句如`cudaMalloc`,`cudaMemcpy`之类的需要被转换为`hipMalloc`,`hipMemcpy`等。
2. 替换库调用:将CUDA专有的库调用,如cuBLAS,替换为ROCm的rocBLAS库调用。例如,`cublasCreate()`需要更改为`rocblas_create_handle()`等。
3. 调整构建配置:修改编译和链接配置,从使用nvcc编译器和CUDA库切换到使用hipcc编译器和ROCm库。
4. 调试和优化:转换完成后,通常需要大量的测试,调试和性能优化来确保转换后的程序可以正确且有效地在AMD硬件上运行。
5. 验证结果:确保程序的输出和行为与CUDA版本一致。
此过程可以是复杂且费时的,而且并不总是能够一对一直接转换,尤其是对于高度优化的代码段,可能需要有深入理解的CUDA和ROCm平台的专业知识来确保有效转换。
针对你的问题,如果你不熟悉这些操作或库,在进行上述步骤之前,最好研究ROCm官方文档和相关的社区资源,或者考虑寻求经验丰富的开发者的帮助。

The code you've provided is written to run on an Nvidia GPU using CUDA and cuBLAS libraries, which are specific to Nvidia's hardware. To run this code on an AMD GPU, you will need to replace these with AMD's GPU computing APIs, which are primarily ROCm (Radeon Open Compute) and its libraries such as rocBLAS for BLAS operations.
Here are the general steps you would need to follow to translate this code from CUDA/Nvidia to ROCm/AMD:
1. Environment Setup: Make sure you have the ROCm platform and its associated libraries installed on your system.
2. Finding Corresponding ROCm Libraries and Functions**:
   - Replace cublas function calls with rocblas function calls.
   - Replace CUDA kernel launches with HIP kernel launches.
   - Other CUDA-specific functions will need to be mapped to their equivalent ROCm functions (e.g., CUDA's memory management functions to ROCm's memory management functions).
   - If you’re using cuDNN for deep learning primitives, you would replace those with MIOpen when working with ROCm.
3. Code Conversion:
   - Use the hipify-perl script provided by ROCm to convert the CUDA code to HIP code. HIP is a C++ Runtime API and Kernel Language that allows developers to create portable code that can run on AMD and Nvidia GPUs with minimal or no changes. The hipify-perl script can automatically translate CUDA API calls to their HIP equivalents where a direct mapping exists.
   - Manual adjustments may be necessary for sections of the code that the hipify script cannot convert automatically, or where the script's automatic conversion is not suitable.
4. Memory Management:
   - Review and replace CUDA memory management calls (cudaMalloc, cudaMemcpy, etc.) with their HIP equivalents (hipMalloc, hipMemcpy, etc.).
5. Kernel Launches:
   - Replace CUDA kernel launches with HIP kernel launches. The syntax is very similar, but make sure that you review each launch to ensure it translates correctly.
6. Build System Changes:
   - Update your build system to use hipcc (the HIP compiler) instead of nvcc (the CUDA compiler). This may require changes in your makefiles or build scripts.
7. Testing and Optimization:
   - Rigorous testing is necessary to ensure that the translated code works correctly on AMD hardware.
   - After ensuring correctness, you can profile and optimize the code for AMD GPU architecture.
8. Consider Libraries and Language Features Unavailable in ROCm**:
   - CUDA might have certain features that do not have direct equivalents in HIP. For instance, you might encounter differences in warp/wavefront behavior, shared memory usage, or atomic operations.
Here is an example of how you might start transitioning a simple CUDA memory allocation and copy to its HIP equivalent:

// CUDA example:
cudaMalloc(&devicePtr, size);
cudaMemcpy(devicePtr, hostPtr, size, cudaMemcpyHostToDevice);// HIP equivalent:
hipMalloc(&devicePtr, size);
hipMemcpy(devicePtr, hostPtr, size, hipMemcpyHostToDevice);

Remember, transitioning between GPU ecosystems involves not only translating the API calls but also understanding the nuances and differences between the hardware architectures, as they may have implications on the performance and correctness of your translated code. 

1. 环境配置:确保在您的系统上安装了ROCm平台及其相关的库。
2. 匹配对应的ROCm库和函数:
   - 将`cublas`函数调用替换为`rocblas`函数调用。
   - 将CUDA核函数启动替换为HIP核函数启动。
   - 将其他特定于CUDA的函数映射到ROCm的等效函数(例如,CUDA的内存管理函数到ROCm的内存管理函数)。
   - 如果您使用的是cuDNN进行深度学习,那么在ROCm中您应该用MIOpen代替。
3. 代码转换:
   - 使用ROCm提供的`hipify-perl`脚本将CUDA代码转换为HIP代码。HIP是一个可让开发者创建可在AMD和Nvidia GPU上运行的可移植代码的C++运行时API和内核语言。`hipify-perl`脚本可以自动将CUDA API调用翻译成他们的HIP等价物。
   - 对于hipify脚本无法自动转换的代码部分,或脚本的自动转换不合适的部分,可能需要手动调整。
4. 内存管理:
   - 审查并替换CUDA内存管理调用(`cudaMalloc`, cudaMemcpy等)为HIP等价物(`hipMalloc`, hipMemcpy等)。
5. 核函数启动:
   - 将CUDA核函数启动替换为HIP核函数启动。语法非常相似,但确保审查每个启动以确保正确地转换。
6. 构建系统变更:
   - 将构建系统更新为使用`hipcc`(HIP编译器)替代`nvcc`(CUDA编译器)。这可能需要更改makefile或构建脚本。
7. 测试和优化:
   - 需要进行严格的测试,以确保翻译后的代码在AMD硬件上能够正确运行。
   - 确保正确后,您可以对代码进行性能分析和针对AMD GPU架构的优化。
8. 考虑ROCm中不可用的库和语言特性:
   - CUDA可能拥有某些没有直接等价物的特性。例如,您可能会遇到线程束/波前行为、共享内存使用或原子操作方面的差异。
以下是一个简单的将CUDA内存分配和复制转换为HIP等价物的示例:

// CUDA例子:
cudaMalloc(&devicePtr, size);
cudaMemcpy(devicePtr, hostPtr, size, cudaMemcpyHostToDevice);// HIP等价的代码:
hipMalloc(&devicePtr, size);
hipMemcpy(devicePtr, hostPtr, size, hipMemcpyHostToDevice);

请注意,转移GPU生态系统不仅仅涉及转换API调用,还需要理解不同硬件架构的细微差别,因为它们可能会影响您转换代码的性能和正确性。 

解释

这段代码是一个C++程序,主要用于训练一个GPT-2(一种生成式预训练Transformer模型)模型。我会为你解释代码的主要部分:

  1. 命令行参数处理:

    • 程序接受一系列的命令行参数,用于配置训练过程。例如,input_dataset_prefix指定输入数据集的前缀,output_log_file用于记录日志的文件等。
    • 如果参数不符合预期的格式或缺失,程序会调用error_usage()函数(该函数在代码中未给出)来输出错误信息并退出。
  2. CUDA和cuBLAS初始化:

    • 使用cudaSetDevice设置要使用的CUDA设备。
    • 获取设备属性,并创建cuBLAS句柄。cuBLAS是NVIDIA提供的一个数学库,用于在CUDA上进行基本线性代数运算。
    • 根据CUDA设备的能力决定是否启用TF32(一种加速数学运算的浮点格式)。
  3. GPT-2模型加载:

    • 创建一个GPT2对象。
    • 使用gpt2_build_from_checkpoint函数从检查点文件(例如"gpt2_124M.bin")加载模型。
  4. 数据加载器初始化:

    • 根据输入数据集的前缀,创建训练和验证的数据加载器(DataLoader对象)。
    • 数据加载器负责从二进制文件中读取数据,并为模型提供输入和目标。
  5. 训练循环:

    • 使用一个循环进行训练。在每次迭代中,都会进行以下操作:
      • 使用数据加载器加载下一批数据。
      • 使用GPT-2模型进行前向传播。
      • 计算损失,进行反向传播,并更新模型参数。
      • 记录训练和验证的损失。
      • 每隔一定步数,进行验证和生成样本。
    • 训练和验证的损失会输出到控制台,并(如果指定了输出日志文件)记录到文件中。
    • 在生成样本时,模型会根据当前的参数生成一段文本,并输出到控制台。
  6. 清理和退出:

    • 在训练结束后,释放所有分配的资源,如CUDA内存、数据加载器、GPT-2模型等。
    • 销毁cuBLAS句柄。
    • 释放日志记录器。
    • 程序正常退出。

需要注意的是,此代码依赖于多个外部函数和类(如DataLoaderGPT2tokenizer_init等),这些函数和类的具体实现在此代码段中并未给出。因此,为了完全理解和运行此代码,你可能需要查看相关的头文件和源文件。

要将现有的 CUDA 代码转换为适用于 AMD GPU 平台的代码,你需要使用 AMD 的 ROCm 平台,并用 HIP 进行编程,它可以自动将 CUDA 代码转换为 AMD GPU 可支持的代码。
HIP 是 AMD 的一种编程模型,类似于 CUDA,用于编写可在 AMD 或 NVIDIA GPU 上执行的代码。越来越多的函数和库支持 HIP,这使得从使用 CUDA 的 NVIDIA GPU 转移到 AMD GPU 变得比较容易。
下面是一个使用 HIP 简单转换主要部分的示例,但需要注意的是,这样的转换要求专业知识,并且可能需要针对你的特定用例进行调整。这个例子没有创建一个完整的 HIP 版本代码,仅仅是为了给出一个大致的转换思路。此外,你也需要转换你的核函数和 CUDA API 调用。

#include <hip/hip_runtime.h>
#include "hip/hip_complex.h" // HIP version of cuComplex.h if dealing with complex math
#include "hipblas.h"         // HIP version of CUBLAS
#include "rocblas/rocblas.h" // ROCm version of CUBLAS
#include "rocrand.h"         // ROCm version of CURAND// Error checking macro, similar to the cudaCheck
#define hipCheck(error) __hipCheck((error), __FILE__, __LINE__)
inline void __hipCheck(hipError_t error, const char *file, int line) {if (error != hipSuccess) {fprintf(stderr, "[HIP ERROR] at file %s:%d:\n%s\n", file, line, hipGetErrorString(error));exit(EXIT_FAILURE);}
};int main(int argc, char *argv[]) {// ... Code unchanged until HIP-related parts ...int deviceIdx = 0;hipCheck(hipSetDevice(deviceIdx));hipDeviceProp_t deviceProp;hipGetDeviceProperties(&deviceProp, deviceIdx);hipblasHandle_t hipblas_handle; // Replacing cublasHandle_thipCheck(hipblasCreate(&hipblas_handle)); // Replacing cublasCreate// ... Rest of the code ...// Memory allocation examplefloat* deviceMemory;hipCheck(hipMalloc(&deviceMemory, sizeInBytes));// Memory copy examplehipCheck(hipMemcpy(deviceMemory, hostMemory, sizeInBytes, hipMemcpyHostToDevice));// Launch a kernel (Gpt2Kernel is a placeholder for an example kernel function name)hipLaunchKernelGGL(Gpt2Kernel, dim3(blocks), dim3(threadsPerBlock), 0, 0, args...);// ... Rest of the code that may need transformation ...// Free memory and destroy handlehipCheck(hipFree(deviceMemory));hipCheck(hipblasDestroy(hipblas_handle));// ... Rest of the cleanup code ...return 0;
}

请注意以下几点:
- hipMalloc, hipFree, hipMemcpy 等函数调用是 CUDA 函数调用的直接替代,但可能需要针对 HIP 运行时进行少量调整。
- hipLaunchKernelGGL 宏是用于调用 HIP 核函数的宏,它是 <<<...>>> CUDA 核函数调用的替代。
- CUBLAS 和其他 CUDA 库的替代品,如 ROCm 提供的 rocblas 和 rocrand,需要替换相应的 CUBLAS 调用。
注意,由于 HIP 和 CUDA 在某些API和功能方面有差异,复杂的代码可能需要更多的手工调整和测试来确保正确性和性能。另外,有些CUDA 功能在 HIP 中可能没有直接对应,可能需要找到替代方案或重写某些部分。
此外,将 CUDA 转为 HIP 后,你还需要使用 HIP 的编译工具编译代码。可以通过以下命令行示例使用 hipcc:

hipcc your_code.cpp -o your_application -lhipblas -lrocrand

最后,不要忘记测试转换后的代码,确保在新平台上能够正确运行并且性能符合预期。这可能包括逐步调试,验证计算结果,以及评估性能和资源使用情况。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/13135.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

三.使用HashiCorp Vault工具管理数据库

三.ubuntu安装使用HashiCorp Vault工具管理数据库 HashiCorp Vault 是一个基于身份的秘密和加密管理系统。机密是您想要严格控制访问的任何内容,例如 API 加密密钥、密码和证书。Vault 提供由身份验证和授权方法门控的加密服务。使用 Vault 的 UI、CLI 或 HTTP API,可以安全…

深度优先搜索汇总

常用英文 最近公共祖先&#xff08;Lowest Common Ancestor&#xff0c;简称LCA&#xff09; posterity&#xff0c;英语单词&#xff0c;主要用作名词&#xff0c;作名词时译为“子孙&#xff0c;后裔&#xff1b;后代”。 什么是深度优先搜索 深度优先搜索&#xff0c;D…

文心一言指令

文心一言 文心一言&#xff08;ERNIE Bot&#xff09;是百度公司研发的知识增强大语言模型&#xff0c;它可以根据用户的指令和输入&#xff0c;生成相应的回答或文本。以下是一些可能的指令示例&#xff0c;用于指导文心一言完成不同的任务&#xff1a; 知识问答&#xff1a…

【oracle】图片转为字节、base64编码等形式批量插入oracle数据库并查询

1.熟悉、梳理、总结下Oracle相关知识体系 2.欢迎批评指正&#xff0c;跪谢一键三连&#xff01; 资源下载&#xff1a; oci.dll、oraocci11.dll、oraociei11.dll3个资源文件资源下载&#xff1a; Instant Client Setup.exe资源下载&#xff1a; oci.dll、oraocci11.dll、oraoc…

初识C语言——第二十一天

猜数字小游戏的实现&#xff1a; 学会了之后可以自己制作彩票抽奖&#xff0c;哈哈&#xff01; 代码实现&#xff1a; #include <stdlib.h> #include <time.h>void menu()//无返回值函数 {printf("**************************\n");printf("****…

云原生 初识Kubernetes的理论基础

一、k8s 的由来及其技术运用 1.1 k8s的简介 Kubernetes&#xff0c;词根源于希腊语的 舵手、飞行员。在国内又称k8s&#xff08;因为k和s之间有8个字母&#xff0c;所以得名。“国内程序员的幽默”&#xff09;。 作用&#xff1a; 用于自动部署、扩展和管理“容器化&#x…

利用远程控制软件FinalShell远程连接虚拟机上的Linux系统(Windows)

一. VMware Workstation 安装CentOS Linux操作系统 传送门&#xff1a;VMware Workstation 安装CentOS Linux操作系统 1.右键打开终端 2.输入ifconfig 找到ens33对应 inet的id&#xff0c;这个就是虚拟机的ip地址图中所示为&#xff1a;192.168.5.128 3.打开finalshell 如…

C++ | Leetcode C++题解之第92题反转链表II

题目&#xff1a; 题解&#xff1a; class Solution { public:ListNode *reverseBetween(ListNode *head, int left, int right) {// 设置 dummyNode 是这一类问题的一般做法ListNode *dummyNode new ListNode(-1);dummyNode->next head;ListNode *pre dummyNode;for (i…

【刷题篇】二分查找(二)

文章目录 1、山脉数组的峰顶索引2、寻找峰值3、寻找旋转排序数组中的最小值4、LCR 点名 1、山脉数组的峰顶索引 符合下列属性的数组 arr 称为 山脉数组 &#xff1a; arr.length > 3 存在 i&#xff08;0 < i < arr.length - 1&#xff09;使得&#xff1a; arr[0] &l…

macOS Ventura 13如何设置定时重启(命令行)

文章目录 macOS Ventura 13如何设置定时重启(命令行)前言具体设置步骤及命令解释其他 macOS Ventura 13如何设置定时重启(命令行) 前言 由于升级 macOS 13 Ventura 之后&#xff0c;之前在节能里面通过鼠标点击设置开机关机的方法不能用了&#xff0c;现在只能用命令设置开机…

css笔记总结2

找到所有的 h1 标签。 选择器&#xff08;选对人&#xff09; 设置这些标签的样式&#xff0c;比如颜色为红色&#xff08;做对事&#xff09;。 ##css基础选择器 基础选择器又包括&#xff1a;标签选择器、类选择器、id 选择器和通配符选择器 ###标签选择器&#xff1a; 标签…

【PB案例学习笔记】-03用户名密码校验

写在前面 通过一个个由浅入深的编程实战案例学习&#xff0c;提高编程技巧&#xff0c;以保证小伙伴们能应付公司的各种开发需求。 文章中设计到的源码&#xff0c;小凡都上传到了gitee代码仓库https://gitee.com/xiezhr/pb-project-example.git 需要源代码的小伙伴们可以自行…

KNN算法处理多元分类任务

概述 这个案例还是基于之前的案例进行改造。 之前的案例代码完整如下&#xff1a; from sklearn.datasets import make_blobs # KNN 分类器 from sklearn.neighbors import KNeighborsClassifier # 画图工具 import matplotlib.pyplot as plt # 数据集拆分工具 from sklearn…

Java获取请求参数

1.简单参数接收 前端请求参数与Controller接受变量名一致 如果参数名不一致&#xff0c;接受不成功。 可以用RequestParam指定参数名&#xff0c;可以用username接收&#xff08;不推荐&#xff09;。 required true&#xff0c;表示参数必须传递&#xff0c;如果不传递会报错…

深入剖析Tomcat(八) 载入器与打破双亲委派机制的自定义类加载器

写这篇文章让我头大了好几天&#xff0c;书中描述的内容倒是不多&#xff0c;可能也是那会Tomcat的现状。如今Tomcat发展了好多代&#xff0c;加上springboot的广泛应用&#xff0c;导致现在的类加载的步骤和Tomcat资料中描述的大相径庭。可能也是由于微服务的发展&#xff0c;…

基于 Spring Boot 博客系统开发(十)

基于 Spring Boot 博客系统开发&#xff08;十&#xff09; 本系统是简易的个人博客系统开发&#xff0c;为了更加熟练地掌握 SprIng Boot 框架及相关技术的使用。&#x1f33f;&#x1f33f;&#x1f33f; 基于 Spring Boot 博客系统开发&#xff08;九&#xff09;&#x1f…

Golang | Leetcode Golang题解之第91题解码方法

题目&#xff1a; 题解&#xff1a; func numDecodings(s string) int {n : len(s)// a f[i-2], b f[i-1], c f[i]a, b, c : 0, 1, 0for i : 1; i < n; i {c 0if s[i-1] ! 0 {c b}if i > 1 && s[i-2] ! 0 && ((s[i-2]-0)*10(s[i-1]-0) < 26) {c…

Navicat 干货 | 探索 PostgreSQL 中不同类型的约束

PostgreSQL 的一个重要特性之一是能够对数据实施各种约束&#xff0c;以确保数据完整性和可靠性。今天的文章中&#xff0c;我们将概述 PostgreSQL 的各种约束类型并结合免费的 "dvdrental" 示例数据库 中的例子探索他们的使用方法。 1. 检查约束&#xff1a; 检查…

颜色的表示和还原(一)

这篇文章主要提炼于ICCV 2019 Tutorial: Understanding Color and the In-Camera Image Processing Pipeline for Computer Vision。里面深入浅出地讲解了很多ISP中的基础知识&#xff0c;这里主要对颜色相关的部分做一点总结。 假设不成立了 相机经常被简单地看作是衡量光线…

STM32学习计划

前言&#xff1a; 这里先记录下STM32的学习计划。 2024/05/08 今天我正在学习的是正点原子的I.MX6ULL APLHA/Mini 开发板的 Linux 之ARM裸机第二期开发的视频教程&#xff0c;会用正点原子的I.MX6ULL开发板学习第二期ARM裸机开发的教程&#xff0c;然后是学习完正点原子的I.M…