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
696 changes: 687 additions & 9 deletions README.md

Large diffs are not rendered by default.

Binary file added TinyInfiniTrain_作业报告.docx
Binary file not shown.
209 changes: 125 additions & 84 deletions example/common/tiny_shakespeare_dataset.cc
Original file line number Diff line number Diff line change
@@ -1,84 +1,125 @@
#include "example/common/tiny_shakespeare_dataset.h"

#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <functional>
#include <iostream>
#include <memory>
#include <numeric>
#include <string>
#include <unordered_map>
#include <utility>
#include <variant>
#include <vector>

#include "glog/logging.h"

#include "infini_train/include/tensor.h"

namespace {
using DataType = infini_train::DataType;
using TinyShakespeareType = TinyShakespeareDataset::TinyShakespeareType;
using TinyShakespeareFile = TinyShakespeareDataset::TinyShakespeareFile;

const std::unordered_map<int, TinyShakespeareType> kTypeMap = {
{20240520, TinyShakespeareType::kUINT16}, // GPT-2
{20240801, TinyShakespeareType::kUINT32}, // LLaMA 3
};

const std::unordered_map<TinyShakespeareType, size_t> kTypeToSize = {
{TinyShakespeareType::kUINT16, 2},
{TinyShakespeareType::kUINT32, 4},
};

const std::unordered_map<TinyShakespeareType, DataType> kTypeToDataType = {
{TinyShakespeareType::kUINT16, DataType::kUINT16},
{TinyShakespeareType::kUINT32, DataType::kINT32},
};

std::vector<uint8_t> ReadSeveralBytesFromIfstream(size_t num_bytes, std::ifstream *ifs) {
std::vector<uint8_t> result(num_bytes);
ifs->read(reinterpret_cast<char *>(result.data()), num_bytes);
return result;
}

template <typename T> T BytesToType(const std::vector<uint8_t> &bytes, size_t offset) {
static_assert(std::is_trivially_copyable<T>::value, "T must be trivially copyable.");
T value;
std::memcpy(&value, &bytes[offset], sizeof(T));
return value;
}

TinyShakespeareFile ReadTinyShakespeareFile(const std::string &path, size_t sequence_length) {
/* =================================== 作业 ===================================
TODO:实现二进制数据集文件解析
文件格式说明:
----------------------------------------------------------------------------------
| HEADER (1024 bytes) | DATA (tokens) |
| magic(4B) | version(4B) | num_toks(4B) | reserved(1012B) | token数据 |
----------------------------------------------------------------------------------
=================================== 作业 =================================== */
}
} // namespace

TinyShakespeareDataset::TinyShakespeareDataset(const std::string &filepath, size_t sequence_length) {
// =================================== 作业 ===================================
// TODO:初始化数据集实例
// HINT: 调用ReadTinyShakespeareFile加载数据文件
// =================================== 作业 ===================================
}

std::pair<std::shared_ptr<infini_train::Tensor>, std::shared_ptr<infini_train::Tensor>>
TinyShakespeareDataset::operator[](size_t idx) const {
CHECK_LT(idx, text_file_.dims[0] - 1);
std::vector<int64_t> dims = std::vector<int64_t>(text_file_.dims.begin() + 1, text_file_.dims.end());
// x: (seq_len), y: (seq_len) -> stack -> (bs, seq_len) (bs, seq_len)
return {std::make_shared<infini_train::Tensor>(text_file_.tensor, idx * sequence_size_in_bytes_, dims),
std::make_shared<infini_train::Tensor>(text_file_.tensor, idx * sequence_size_in_bytes_ + sizeof(int64_t),
dims)};
}

size_t TinyShakespeareDataset::Size() const { return num_samples_; }
#include "example/common/tiny_shakespeare_dataset.h"

#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <functional>
#include <iostream>
#include <memory>
#include <numeric>
#include <string>
#include <unordered_map>
#include <utility>
#include <variant>
#include <vector>

#include "glog/logging.h"

#include "infini_train/include/tensor.h"

namespace {
using DataType = infini_train::DataType;
using TinyShakespeareType = TinyShakespeareDataset::TinyShakespeareType;
using TinyShakespeareFile = TinyShakespeareDataset::TinyShakespeareFile;

const std::unordered_map<int, TinyShakespeareType> kTypeMap = {
{1, TinyShakespeareType::kUINT16}, // GPT-2 (legacy)
{20240520, TinyShakespeareType::kUINT16}, // GPT-2
{20240801, TinyShakespeareType::kUINT32}, // LLaMA 3
};

const std::unordered_map<TinyShakespeareType, size_t> kTypeToSize = {
{TinyShakespeareType::kUINT16, 2},
{TinyShakespeareType::kUINT32, 4},
};

const std::unordered_map<TinyShakespeareType, DataType> kTypeToDataType = {
{TinyShakespeareType::kUINT16, DataType::kUINT16},
{TinyShakespeareType::kUINT32, DataType::kINT32},
};

std::vector<uint8_t> ReadSeveralBytesFromIfstream(size_t num_bytes, std::ifstream *ifs) {
std::vector<uint8_t> result(num_bytes);
ifs->read(reinterpret_cast<char *>(result.data()), num_bytes);
return result;
}

template <typename T> T BytesToType(const std::vector<uint8_t> &bytes, size_t offset) {
static_assert(std::is_trivially_copyable<T>::value, "T must be trivially copyable.");
T value;
std::memcpy(&value, &bytes[offset], sizeof(T));
return value;
}

TinyShakespeareFile ReadTinyShakespeareFile(const std::string &path, size_t sequence_length) {
/* =================================== 作业 ===================================
TODO:实现二进制数据集文件解析
文件格式说明:
----------------------------------------------------------------------------------
| HEADER (1024 bytes) | DATA (tokens) |
| 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;

// Read header (1024 bytes)
auto header = ReadSeveralBytesFromIfstream(1024, &ifs);

int32_t magic = BytesToType<int32_t>(header, 0);
int32_t version = BytesToType<int32_t>(header, 4);
int32_t num_toks = BytesToType<int32_t>(header, 8);

CHECK(kTypeMap.contains(version)) << "Unknown version: " << version;
TinyShakespeareType type = kTypeMap.at(version);
size_t element_size = kTypeToSize.at(type);

// Read token data
size_t data_size = num_toks * element_size;
auto data = ReadSeveralBytesFromIfstream(data_size, &ifs);

// Convert tokens to int64_t and reshape into (num_toks / sequence_length, sequence_length)
int64_t num_sequences = num_toks / sequence_length;
std::vector<int64_t> dims = {num_sequences, static_cast<int64_t>(sequence_length)};

auto tensor = infini_train::Tensor(dims, DataType::kINT64);
int64_t *tensor_ptr = static_cast<int64_t *>(tensor.DataPtr());

int64_t num_elements = num_sequences * sequence_length;
for (int64_t i = 0; i < num_elements; ++i) {
if (type == TinyShakespeareType::kUINT16) {
tensor_ptr[i] = static_cast<int64_t>(BytesToType<uint16_t>(data, i * element_size));
} else {
tensor_ptr[i] = static_cast<int64_t>(BytesToType<uint32_t>(data, i * element_size));
}
}

return {type, dims, tensor};
}
} // namespace

TinyShakespeareDataset::TinyShakespeareDataset(const std::string &filepath, size_t sequence_length)
: 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) {
// =================================== 作业 ===================================
// TODO:初始化数据集实例
// HINT: 调用ReadTinyShakespeareFile加载数据文件
// =================================== 作业 ===================================
}

std::pair<std::shared_ptr<infini_train::Tensor>, std::shared_ptr<infini_train::Tensor>>
TinyShakespeareDataset::operator[](size_t idx) const {
CHECK_LT(idx, text_file_.dims[0] - 1);
std::vector<int64_t> dims = std::vector<int64_t>(text_file_.dims.begin() + 1, text_file_.dims.end());
// x: (seq_len), y: (seq_len) -> stack -> (bs, seq_len) (bs, seq_len)
return {std::make_shared<infini_train::Tensor>(text_file_.tensor, idx * sequence_size_in_bytes_, dims),
std::make_shared<infini_train::Tensor>(text_file_.tensor, idx * sequence_size_in_bytes_ + sizeof(int64_t),
dims)};
}

size_t TinyShakespeareDataset::Size() const { return num_samples_; }
86 changes: 43 additions & 43 deletions example/common/tiny_shakespeare_dataset.h
Original file line number Diff line number Diff line change
@@ -1,43 +1,43 @@
#pragma once

#include <cstddef>
#include <cstdlib>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "infini_train/include/dataset.h"
#include "infini_train/include/tensor.h"

class TinyShakespeareDataset : public infini_train::Dataset {
/*
Dataset bin file is downloaded and processed using the script at
https://github.com/karpathy/llm.c/blob/master/dev/data/tinyshakespeare.py
*/
public:
enum class TinyShakespeareType : int {
kUINT16, // For GPT-2
kUINT32, // For LLaMA 3
kINVALID,
};

struct TinyShakespeareFile {
TinyShakespeareType type = TinyShakespeareType::kINVALID;
std::vector<int64_t> dims;
infini_train::Tensor tensor;
};

TinyShakespeareDataset(const std::string &filepath, size_t sequence_length);

std::pair<std::shared_ptr<infini_train::Tensor>, std::shared_ptr<infini_train::Tensor>>
operator[](size_t idx) const override;

size_t Size() const override;

private:
TinyShakespeareFile text_file_;
const size_t sequence_length_ = 0;
const size_t sequence_size_in_bytes_ = 0;
const size_t num_samples_ = 0;
};
#pragma once
#include <cstddef>
#include <cstdlib>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "infini_train/include/dataset.h"
#include "infini_train/include/tensor.h"
class TinyShakespeareDataset : public infini_train::Dataset {
/*
Dataset bin file is downloaded and processed using the script at
https://github.com/karpathy/llm.c/blob/master/dev/data/tinyshakespeare.py
*/
public:
enum class TinyShakespeareType : int {
kUINT16, // For GPT-2
kUINT32, // For LLaMA 3
kINVALID,
};
struct TinyShakespeareFile {
TinyShakespeareType type = TinyShakespeareType::kINVALID;
std::vector<int64_t> dims;
infini_train::Tensor tensor;
};
TinyShakespeareDataset(const std::string &filepath, size_t sequence_length);
std::pair<std::shared_ptr<infini_train::Tensor>, std::shared_ptr<infini_train::Tensor>>
operator[](size_t idx) const override;
size_t Size() const override;
private:
TinyShakespeareFile text_file_;
const size_t sequence_length_ = 0;
const size_t sequence_size_in_bytes_ = 0;
const size_t num_samples_ = 0;
};
Loading