Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 40 additions & 2 deletions example/common/tiny_shakespeare_dataset.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <filesystem>
#include <fstream>
#include <functional>
Expand Down Expand Up @@ -61,15 +62,52 @@ TinyShakespeareFile ReadTinyShakespeareFile(const std::string &path, size_t sequ
| magic(4B) | version(4B) | num_toks(4B) | reserved(1012B) | token数据 |
----------------------------------------------------------------------------------
=================================== 作业 =================================== */
std::ifstream ifs(path, std::ios::binary);
CHECK(ifs.is_open()) << "Failed to open file: " << path;

auto header_bytes = ReadSeveralBytesFromIfstream(1024, &ifs);
const uint32_t magic = BytesToType<uint32_t>(header_bytes, 0);
const uint32_t version = BytesToType<uint32_t>(header_bytes, 4);
const uint32_t num_toks = BytesToType<uint32_t>(header_bytes, 8);
(void)version;

CHECK(kTypeMap.contains(magic)) << "Unsupported magic number: " << magic;
const TinyShakespeareType type = kTypeMap.at(magic);
const size_t token_size = kTypeToSize.at(type);

CHECK_GT(num_toks, sequence_length) << "Not enough tokens for one sequence";
infini_train::Tensor tensor(std::vector<int64_t>{static_cast<int64_t>(num_toks)}, DataType::kINT64);
auto *dst = static_cast<int64_t *>(tensor.DataPtr());

if (token_size == 2) {
std::vector<uint16_t> tokens(num_toks);
ifs.read(reinterpret_cast<char *>(tokens.data()), static_cast<std::streamsize>(num_toks * token_size));
for (uint32_t i = 0; i < num_toks; ++i) {
dst[i] = static_cast<int64_t>(tokens[i]);
}
} else {
std::vector<uint32_t> tokens(num_toks);
ifs.read(reinterpret_cast<char *>(tokens.data()), static_cast<std::streamsize>(num_toks * token_size));
for (uint32_t i = 0; i < num_toks; ++i) {
dst[i] = static_cast<int64_t>(tokens[i]);
}
}

// dims[0] is used by operator[] as CHECK_LT(idx, dims[0] - 1)
// Non-overlapping windows (llm.c semantics): sample idx covers tokens[idx*seq_len : (idx+1)*seq_len]
const int64_t num_samples = static_cast<int64_t>(num_toks) / static_cast<int64_t>(sequence_length);
std::vector<int64_t> dims{num_samples + 1, static_cast<int64_t>(sequence_length)};
return TinyShakespeareFile{type, dims, std::move(tensor)};
}
} // namespace

TinyShakespeareDataset::TinyShakespeareDataset(const std::string &filepath, size_t sequence_length) {
TinyShakespeareDataset::TinyShakespeareDataset(const std::string &filepath, size_t sequence_length)
// =================================== 作业 ===================================
// TODO:初始化数据集实例
// HINT: 调用ReadTinyShakespeareFile加载数据文件
// =================================== 作业 ===================================
}
: text_file_(ReadTinyShakespeareFile(filepath, sequence_length)), sequence_length_(sequence_length),
sequence_size_in_bytes_(sequence_length * sizeof(int64_t)), num_samples_(text_file_.dims[0] - 1) {}

std::pair<std::shared_ptr<infini_train::Tensor>, std::shared_ptr<infini_train::Tensor>>
TinyShakespeareDataset::operator[](size_t idx) const {
Expand Down
52 changes: 50 additions & 2 deletions example/common/tokenizer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

#include <cctype>
#include <cstdint>
#include <cstring>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <unordered_map>
#include <vector>

#include "glog/logging.h"
Expand Down Expand Up @@ -78,13 +80,36 @@ Tokenizer::Tokenizer(const std::string &filepath) {
| magic(4B) | version(4B) | vocab_size(4B) | reserved(1012B) | token词表数据 |
----------------------------------------------------------------------------------
===================================== 作业 ===================================== */
std::ifstream ifs(filepath, std::ios::binary);
CHECK(ifs.is_open()) << "Failed to open tokenizer file: " << filepath;

auto header_bytes = ReadSeveralBytesFromIfstream(1024, &ifs);
magic_number_ = BytesToType<uint32_t>(header_bytes, 0);
const uint32_t version = BytesToType<uint32_t>(header_bytes, 4);
vocab_size_ = BytesToType<uint32_t>(header_bytes, 8);
(void)version;

CHECK(kEotMap.contains(magic_number_)) << "Unsupported tokenizer magic: " << magic_number_;
eot_token_ = kEotMap.at(magic_number_);

token_table_.resize(vocab_size_);
for (uint32_t i = 0; i < vocab_size_; ++i) {
uint8_t len = 0;
ifs.read(reinterpret_cast<char *>(&len), 1);
std::string token(len, '\0');
ifs.read(token.data(), len);
token_table_[i] = std::move(token);
}
}

std::string Tokenizer::Decode(uint32_t token_id) const {
/* ===================================== 作业 =====================================
TODO:实现token_id到文本的转换
功能描述:根据token_id返回对应的文本片段
===================================== 作业 ===================================== */
if (token_id < token_table_.size()) {
return token_table_[token_id];
}
return "";
}

Expand All @@ -104,13 +129,36 @@ void Tokenizer::GenerateText(infini_train::nn::Module &model, uint32_t batch_siz
std::cout << "The meaning of life is";

auto x = std::make_shared<infini_train::Tensor>(x_tensor.To(device));
uint64_t kRngState = kRngState;
uint64_t rng_state = kRngState;
LOG(INFO) << "start generate text:";
for (int t = prompt_len; t < text_length; t++) {
for (int t = prompt_len; t < static_cast<int>(text_length); t++) {
/* ===================================== 作业 =====================================
TODO:实现单步文本生成逻辑
HINT:调用model.Forward推理获取logits,根据推理结果进行随机采样,调用Decode获取文本结果
===================================== 作业 ===================================== */
auto outputs = model.Forward({x});
auto logits = outputs[0];
const int last_pos = (t < static_cast<int>(sequence_length)) ? (t - 1) : (static_cast<int>(sequence_length) - 1);
auto last_logits = logits->Slice(1, last_pos, last_pos + 1, 1)->Squeeze(1);
auto probs = nn::function::Softmax(last_logits, -1)->To(Device(DeviceType::kCPU, 0));
float *probs_ptr = static_cast<float *>(probs.DataPtr());

for (uint32_t b = 0; b < batch_size; ++b) {
const float coin = RandomF32(rng_state);
const int next_token = SampleMult(probs_ptr + b * vocab_size_, static_cast<int>(vocab_size_), coin);
if (b == 0) {
std::cout << Decode(static_cast<uint32_t>(next_token)) << std::flush;
}
if (t < static_cast<int>(sequence_length)) {
x_buff[b * sequence_length + t] = next_token;
} else {
for (uint32_t i = 0; i + 1 < sequence_length; ++i) {
x_buff[b * sequence_length + i] = x_buff[b * sequence_length + i + 1];
}
x_buff[b * sequence_length + sequence_length - 1] = next_token;
}
}
x = std::make_shared<infini_train::Tensor>(x_tensor.To(device));
}
std::cout << std::endl;
}
Expand Down
53 changes: 37 additions & 16 deletions example/gpt2/net.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,27 @@
#include "infini_train/include/nn/modules/sparse.h"
#include "infini_train/include/tensor.h"

#include <string>
#include <type_traits>

namespace {
template <typename T>
std::string ToStr(const T &v) {
if constexpr (std::is_arithmetic_v<T>) {
return std::to_string(v);
} else {
return std::string(v);
}
}
template <typename... Args>
std::string JoinDot(Args &&...args) {
std::string out;
size_t i = 0;
((out += (i++ ? "." : "") + ToStr(args)), ...);
return out;
}
} // namespace

namespace nn = infini_train::nn;

namespace {
Expand Down Expand Up @@ -272,104 +293,104 @@ std::unique_ptr<GPT2> GPT2::FromLLMC(const std::string &filepath) {
auto state_dict = gpt2->StateDict();
// transformer.wte.weight
// (padded_vocab_size, n_embd) -> un_pad -> (vocab_size, n_embd)
auto &transformer_wte_weight = state_dict[std::format("{}.{}.{}", GPT2::kTransformerLayerName, GPT2::kWTELayerName,
auto &transformer_wte_weight = state_dict[JoinDot(GPT2::kTransformerLayerName, GPT2::kWTELayerName,
nn::Embedding::kParamWeightName)];
ifs.read(reinterpret_cast<char *>(transformer_wte_weight->DataPtr()), transformer_wte_weight->SizeInBytes());
ifs.ignore((padded_vocab_size - vocab_size) * n_embd * sizeof(float));
// transformer.wpe.weight
auto &transformer_wpe_weight = state_dict[std::format("{}.{}.{}", GPT2::kTransformerLayerName, GPT2::kWPELayerName,
auto &transformer_wpe_weight = state_dict[JoinDot(GPT2::kTransformerLayerName, GPT2::kWPELayerName,
nn::Embedding::kParamWeightName)];
ifs.read(reinterpret_cast<char *>(transformer_wpe_weight->DataPtr()), transformer_wpe_weight->SizeInBytes());
// transformer.h.{i}.ln_1.weight
for (int idx = 0; idx < n_layer; idx++) {
auto &tensor
= state_dict[std::format("{}.{}.{}.{}.{}", GPT2::kTransformerLayerName, GPT2::kHLayerName,
= state_dict[JoinDot(GPT2::kTransformerLayerName, GPT2::kHLayerName,
std::to_string(idx), Block::kLn1LayerName, nn::LayerNorm::kParamWeightName)];
ifs.read(reinterpret_cast<char *>(tensor->DataPtr()), tensor->SizeInBytes());
}
// transformer.h.{i}.ln_1.bias
for (int idx = 0; idx < n_layer; idx++) {
auto &tensor
= state_dict[std::format("{}.{}.{}.{}.{}", GPT2::kTransformerLayerName, GPT2::kHLayerName,
= state_dict[JoinDot(GPT2::kTransformerLayerName, GPT2::kHLayerName,
std::to_string(idx), Block::kLn1LayerName, nn::LayerNorm::kParamBiasName)];
ifs.read(reinterpret_cast<char *>(tensor->DataPtr()), tensor->SizeInBytes());
}
// transformer.h.{i}.attn.c_attn.weight
for (int idx = 0; idx < n_layer; idx++) {
auto &tensor = state_dict[std::format("{}.{}.{}.{}.{}.{}", GPT2::kTransformerLayerName, GPT2::kHLayerName,
auto &tensor = state_dict[JoinDot(GPT2::kTransformerLayerName, GPT2::kHLayerName,
std::to_string(idx), Block::kAttnLayerName,
CausalSelfAttention::kCAttnLayerName, GPT2Linear::kParamWeightName)];
ifs.read(reinterpret_cast<char *>(tensor->DataPtr()), tensor->SizeInBytes());
}
// transformer.h.{i}.attn.c_attn.bias
for (int idx = 0; idx < n_layer; idx++) {
auto &tensor = state_dict[std::format("{}.{}.{}.{}.{}.{}", GPT2::kTransformerLayerName, GPT2::kHLayerName,
auto &tensor = state_dict[JoinDot(GPT2::kTransformerLayerName, GPT2::kHLayerName,
std::to_string(idx), Block::kAttnLayerName,
CausalSelfAttention::kCAttnLayerName, GPT2Linear::kParamBiasName)];
ifs.read(reinterpret_cast<char *>(tensor->DataPtr()), tensor->SizeInBytes());
}
// transformer.h.{i}.attn.c_proj.weight
for (int idx = 0; idx < n_layer; idx++) {
auto &tensor = state_dict[std::format("{}.{}.{}.{}.{}.{}", GPT2::kTransformerLayerName, GPT2::kHLayerName,
auto &tensor = state_dict[JoinDot(GPT2::kTransformerLayerName, GPT2::kHLayerName,
std::to_string(idx), Block::kAttnLayerName,
CausalSelfAttention::kCProjLayerName, GPT2Linear::kParamWeightName)];
ifs.read(reinterpret_cast<char *>(tensor->DataPtr()), tensor->SizeInBytes());
}
// transformer.h.{i}.attn.c_proj.bias
for (int idx = 0; idx < n_layer; idx++) {
auto &tensor = state_dict[std::format("{}.{}.{}.{}.{}.{}", GPT2::kTransformerLayerName, GPT2::kHLayerName,
auto &tensor = state_dict[JoinDot(GPT2::kTransformerLayerName, GPT2::kHLayerName,
std::to_string(idx), Block::kAttnLayerName,
CausalSelfAttention::kCProjLayerName, GPT2Linear::kParamBiasName)];
ifs.read(reinterpret_cast<char *>(tensor->DataPtr()), tensor->SizeInBytes());
}
// transformer.h.{i}.ln_2.weight
for (int idx = 0; idx < n_layer; idx++) {
auto &tensor
= state_dict[std::format("{}.{}.{}.{}.{}", GPT2::kTransformerLayerName, GPT2::kHLayerName,
= state_dict[JoinDot(GPT2::kTransformerLayerName, GPT2::kHLayerName,
std::to_string(idx), Block::kLn2LayerName, nn::LayerNorm::kParamWeightName)];
ifs.read(reinterpret_cast<char *>(tensor->DataPtr()), tensor->SizeInBytes());
}
// transformer.h.{i}.ln_2.bias
for (int idx = 0; idx < n_layer; idx++) {
auto &tensor
= state_dict[std::format("{}.{}.{}.{}.{}", GPT2::kTransformerLayerName, GPT2::kHLayerName,
= state_dict[JoinDot(GPT2::kTransformerLayerName, GPT2::kHLayerName,
std::to_string(idx), Block::kLn2LayerName, nn::LayerNorm::kParamBiasName)];
ifs.read(reinterpret_cast<char *>(tensor->DataPtr()), tensor->SizeInBytes());
}
// transformer.h.{i}.mlp.c_fc.weight
for (int idx = 0; idx < n_layer; idx++) {
auto &tensor = state_dict[std::format("{}.{}.{}.{}.{}.{}", GPT2::kTransformerLayerName, GPT2::kHLayerName,
auto &tensor = state_dict[JoinDot(GPT2::kTransformerLayerName, GPT2::kHLayerName,
std::to_string(idx), Block::kMlpLayerName, MLP::kCFclayerName,
GPT2Linear::kParamWeightName)];
ifs.read(reinterpret_cast<char *>(tensor->DataPtr()), tensor->SizeInBytes());
}
// transformer.h.{i}.mlp.c_fc.bias
for (int idx = 0; idx < n_layer; idx++) {
auto &tensor = state_dict[std::format("{}.{}.{}.{}.{}.{}", GPT2::kTransformerLayerName, GPT2::kHLayerName,
auto &tensor = state_dict[JoinDot(GPT2::kTransformerLayerName, GPT2::kHLayerName,
std::to_string(idx), Block::kMlpLayerName, MLP::kCFclayerName,
GPT2Linear::kParamBiasName)];
ifs.read(reinterpret_cast<char *>(tensor->DataPtr()), tensor->SizeInBytes());
}
// transformer.h.{i}.mlp.c_proj.weight
for (int idx = 0; idx < n_layer; idx++) {
auto &tensor = state_dict[std::format("{}.{}.{}.{}.{}.{}", GPT2::kTransformerLayerName, GPT2::kHLayerName,
auto &tensor = state_dict[JoinDot(GPT2::kTransformerLayerName, GPT2::kHLayerName,
std::to_string(idx), Block::kMlpLayerName, MLP::kCProjLayerName,
GPT2Linear::kParamWeightName)];
ifs.read(reinterpret_cast<char *>(tensor->DataPtr()), tensor->SizeInBytes());
}
// transformer.h.{i}.mlp.c_proj.bias
for (int idx = 0; idx < n_layer; idx++) {
auto &tensor = state_dict[std::format("{}.{}.{}.{}.{}.{}", GPT2::kTransformerLayerName, GPT2::kHLayerName,
auto &tensor = state_dict[JoinDot(GPT2::kTransformerLayerName, GPT2::kHLayerName,
std::to_string(idx), Block::kMlpLayerName, MLP::kCProjLayerName,
GPT2Linear::kParamBiasName)];
ifs.read(reinterpret_cast<char *>(tensor->DataPtr()), tensor->SizeInBytes());
}
// transformer.ln_f.weight
auto &transformer_ln_f_weight = state_dict[std::format("{}.{}.{}", GPT2::kTransformerLayerName, GPT2::kLnFLayerName,
auto &transformer_ln_f_weight = state_dict[JoinDot(GPT2::kTransformerLayerName, GPT2::kLnFLayerName,
nn::LayerNorm::kParamWeightName)];
ifs.read(reinterpret_cast<char *>(transformer_ln_f_weight->DataPtr()), transformer_ln_f_weight->SizeInBytes());
// transformer.ln_f.bias
auto &transformer_ln_f_bias = state_dict[std::format("{}.{}.{}", GPT2::kTransformerLayerName, GPT2::kLnFLayerName,
auto &transformer_ln_f_bias = state_dict[JoinDot(GPT2::kTransformerLayerName, GPT2::kLnFLayerName,
nn::LayerNorm::kParamBiasName)];
ifs.read(reinterpret_cast<char *>(transformer_ln_f_bias->DataPtr()), transformer_ln_f_bias->SizeInBytes());

Expand Down
17 changes: 12 additions & 5 deletions infini_train/include/dispatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ class KernelFunction {
// =================================== 作业 ===================================

using FuncT = RetT (*)(ArgsT...);
// TODO: 实现函数调用逻辑
auto func = reinterpret_cast<FuncT>(func_ptr_);
return func(std::forward<ArgsT>(args)...);
}

private:
Expand All @@ -48,15 +49,21 @@ class Dispatcher {
// TODO:实现kernel注册机制
// 功能描述:将kernel函数与设备类型、名称绑定
// =================================== 作业 ===================================
CHECK(!key_to_kernel_map_.contains(key))
<< "Kernel already registered: " << key.second << " on device: " << static_cast<int>(key.first);
key_to_kernel_map_.emplace(key, KernelFunction(std::forward<FuncT>(kernel)));
}

private:
std::map<KeyT, KernelFunction> key_to_kernel_map_;
};
} // namespace infini_train

#define REGISTER_KERNEL_INTERNAL(device, kernel_name, kernel_func, line) \
static const bool register_##kernel_name##_##line [[maybe_unused]] = []() { \
::infini_train::Dispatcher::Instance().Register({device, #kernel_name}, kernel_func); \
return true; \
}();

#define REGISTER_KERNEL(device, kernel_name, kernel_func) \
// =================================== 作业 ===================================
// TODO:实现自动注册宏
// 功能描述:在全局静态区注册kernel,避免显式初始化代码
// =================================== 作业 ===================================
REGISTER_KERNEL_INTERNAL(device, kernel_name, kernel_func, __LINE__)
12 changes: 10 additions & 2 deletions infini_train/src/autograd/elementwise.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,25 @@ std::vector<std::shared_ptr<Tensor>> Neg::Forward(const std::vector<std::shared_
// TODO:通过Dispatcher获取设备专属kernel,对输入张量进行取反操作
// NOTES: 依赖test_dispatcher,Neg kernel实现已给出
// =================================== 作业 ===================================
CHECK_EQ(input_tensors.size(), 1);
const auto &input = input_tensors[0];

return std::vector<std::shared_ptr<Tensor>>();
auto device = input->GetDevice().Type();
auto kernel = Dispatcher::Instance().GetKernel({device, "NegForward"});
return {kernel.Call<std::shared_ptr<Tensor>>(input)};
}

std::vector<std::shared_ptr<Tensor>> Neg::Backward(const std::vector<std::shared_ptr<Tensor>> &grad_outputs) {
// =================================== 作业 ===================================
// TODO:通过Dispatcher获取设备专属的反向传播kernel,计算梯度
// NOTES: 依赖test_dispatcher,Neg的kernel实现已给出
// =================================== 作业 ===================================
CHECK_EQ(grad_outputs.size(), 1);
const auto &grad_output = grad_outputs[0];

return std::vector<std::shared_ptr<Tensor>>();
auto device = grad_output->GetDevice().Type();
auto kernel = Dispatcher::Instance().GetKernel({device, "NegBackward"});
return {kernel.Call<std::shared_ptr<Tensor>>(grad_output)};
}

std::vector<std::shared_ptr<Tensor>> Reciprocal::Forward(const std::vector<std::shared_ptr<Tensor>> &input_tensors) {
Expand Down
Loading