Skip to content

Commit 985e10a

Browse files
GodKickMyAssqinyiqun
authored andcommitted
feat: add ERNIE 4.5 VL support
1 parent a949662 commit 985e10a

23 files changed

Lines changed: 2209 additions & 53 deletions

‎csrc/engine/compiler/paged_compiler.cpp‎

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,17 @@
44

55
namespace infinilm::engine {
66

7+
namespace {
8+
bool same_shape_and_dtype(const infinicore::Tensor &lhs, const infinicore::Tensor &rhs) {
9+
return lhs->shape() == rhs->shape() && lhs->dtype() == rhs->dtype();
10+
}
11+
12+
bool is_mrope_decode_position_ids(const infinicore::Tensor &position_ids, size_t batch_size) {
13+
const auto shape = position_ids->shape();
14+
return shape.size() == 2 && shape[0] == batch_size && shape[1] == 3;
15+
}
16+
} // namespace
17+
718
PagedCompiler::PagedCompiler(const std::shared_ptr<InfinilmModel> &model, RankBarrier *barrier)
819
: GraphCompiler(model, barrier) {
920
for (size_t b = 1; b < 64; ++b) {
@@ -25,14 +36,19 @@ void PagedCompiler::compile() {
2536
size_t nblocks = dynamic_cast<const cache::PagedKVCacheConfig *>(model_->get_cache_config())->num_blocks();
2637
size_t max_batch_size = *std::max_element(decode_batch_sizes_.begin(), decode_batch_sizes_.end());
2738
compiled_map_decode_.clear();
39+
compiled_map_decode_mrope_.clear();
2840
block_tables_holder_ = infinicore::Tensor::empty(
2941
{nblocks * max_batch_size}, infinicore::DataType::I32, infinicore::context::getDevice());
3042
set_zeros(block_tables_holder_);
3143

32-
auto make_decode_input = [&](size_t b) {
44+
auto make_decode_input = [&](size_t b, bool mrope_position_ids) {
3345
InfinilmModel::Input input;
3446
input.input_ids = infinicore::Tensor::empty({1, b}, infinicore::DataType::I64, infinicore::context::getDevice());
35-
input.position_ids = infinicore::Tensor::empty({b}, infinicore::DataType::I64, infinicore::context::getDevice());
47+
if (mrope_position_ids) {
48+
input.position_ids = infinicore::Tensor::empty({b, 3}, infinicore::DataType::I64, infinicore::context::getDevice());
49+
} else {
50+
input.position_ids = infinicore::Tensor::empty({b}, infinicore::DataType::I64, infinicore::context::getDevice());
51+
}
3652
input.total_sequence_lengths = infinicore::Tensor::empty({b}, infinicore::DataType::I32, infinicore::context::getDevice());
3753
set_zeros(input.input_ids.value());
3854
set_zeros(input.position_ids.value());
@@ -66,7 +82,7 @@ void PagedCompiler::compile() {
6682

6783
{
6884
const size_t warmup_batch_size = std::min(max_batch_size, static_cast<size_t>(64));
69-
auto input = make_decode_input(warmup_batch_size);
85+
auto input = make_decode_input(warmup_batch_size, false);
7086
model_->forward(input);
7187
infinicore::context::syncStream();
7288
// Warmup runs the eager Marlin path and may leave per-layer lock
@@ -76,8 +92,10 @@ void PagedCompiler::compile() {
7692
infinicore::context::syncStream();
7793
}
7894

79-
for (size_t b : decode_batch_sizes_) {
80-
auto input = make_decode_input(b);
95+
auto capture_decode_graph = [&](size_t b,
96+
bool mrope_position_ids,
97+
std::unordered_map<size_t, CompiledResult> &compiled_map) {
98+
auto input = make_decode_input(b, mrope_position_ids);
8199

82100
barrier_->wait();
83101
(void)model_->forward(input);
@@ -96,7 +114,15 @@ void PagedCompiler::compile() {
96114
auto shared_output = std::shared_ptr<InfinilmModel::Output>(
97115
new InfinilmModel::Output{infinicore::graph::GraphTensor(output.logits)});
98116

99-
compiled_map_decode_[b] = CompiledResult{std::move(input), std::make_tuple(graph, shared_output)};
117+
compiled_map[b] = CompiledResult{std::move(input), std::make_tuple(graph, shared_output)};
118+
};
119+
120+
const bool compile_mrope_decode = model_->supports_mrope_position_ids();
121+
for (size_t b : decode_batch_sizes_) {
122+
capture_decode_graph(b, false, compiled_map_decode_);
123+
if (compile_mrope_decode) {
124+
capture_decode_graph(b, true, compiled_map_decode_mrope_);
125+
}
100126
}
101127
}
102128
}
@@ -110,12 +136,23 @@ PagedCompiler::Compiled PagedCompiler::get_compiled(const InfinilmModel::Input &
110136
if (batch_size != input.input_ids.value()->size(1)) {
111137
return {nullptr, nullptr};
112138
} else {
113-
auto result = compiled_map_decode_.find(batch_size);
114-
if (result == compiled_map_decode_.end()) {
139+
const bool mrope_position_ids = is_mrope_decode_position_ids(input.position_ids.value(), batch_size);
140+
auto &compiled_map = mrope_position_ids ? compiled_map_decode_mrope_ : compiled_map_decode_;
141+
auto result = compiled_map.find(batch_size);
142+
if (result == compiled_map.end()) {
115143
return {nullptr, nullptr};
116144
}
117145
auto &graph_input = result->second.input;
118146

147+
if (!same_shape_and_dtype(graph_input.input_ids.value(), input.input_ids.value()) ||
148+
!same_shape_and_dtype(graph_input.position_ids.value(), input.position_ids.value()) ||
149+
!same_shape_and_dtype(graph_input.total_sequence_lengths.value(), input.total_sequence_lengths.value()) ||
150+
!same_shape_and_dtype(graph_input.input_offsets.value(), input.input_offsets.value()) ||
151+
!same_shape_and_dtype(graph_input.cu_seqlens.value(), input.cu_seqlens.value()) ||
152+
!same_shape_and_dtype(graph_input.slot_mapping.value(), input.slot_mapping.value())) {
153+
return {nullptr, nullptr};
154+
}
155+
119156
graph_input.input_ids.value()->copy_from(input.input_ids.value());
120157
graph_input.position_ids.value()->copy_from(input.position_ids.value());
121158
graph_input.total_sequence_lengths.value()->copy_from(input.total_sequence_lengths.value());
@@ -132,6 +169,9 @@ PagedCompiler::Compiled PagedCompiler::get_compiled(const InfinilmModel::Input &
132169
// runtime logical region. Avoid clearing the full preallocated
133170
// holder on every decode token.
134171
auto &graph_block_tables = graph_input.block_tables.value();
172+
if (graph_block_tables->dtype() != input.block_tables.value()->dtype()) {
173+
return {nullptr, nullptr};
174+
}
135175
set_minus_one_device_async(graph_block_tables);
136176
graph_block_tables->narrow({{1, 0, block_per_req}})->copy_from(input.block_tables.value());
137177
graph_input.slot_mapping.value()->copy_from(input.slot_mapping.value());

‎csrc/engine/compiler/paged_compiler.hpp‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,10 @@ class PagedCompiler : public GraphCompiler {
2727
size_t, // num_requests
2828
CompiledResult>
2929
compiled_map_decode_;
30+
31+
std::unordered_map<
32+
size_t, // num_requests
33+
CompiledResult>
34+
compiled_map_decode_mrope_;
3035
};
3136
} // namespace infinilm::engine

‎csrc/layers/linear/fused_linear.cpp‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,10 @@ GateUpParallelLinear::GateUpParallelLinear(size_t hidden_size, size_t intermedia
151151

152152
std::tuple<infinicore::Tensor, infinicore::Tensor> GateUpParallelLinear::forward_split(infinicore::Tensor &input) {
153153
auto output = this->forward(input);
154-
auto cols = output->shape()[2];
155-
auto gate_output = output->narrow({{2, 0, cols / 2}});
156-
auto up_output = output->narrow({{2, cols / 2, cols / 2}});
154+
const size_t split_dim = output->ndim() - 1;
155+
auto cols = output->size(split_dim);
156+
auto gate_output = output->narrow({{split_dim, 0, cols / 2}});
157+
auto up_output = output->narrow({{split_dim, cols / 2, cols / 2}});
157158
return std::make_tuple(gate_output, up_output);
158159
}
159160

‎csrc/layers/moe/router/topk_router.cpp‎

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "topk_router.hpp"
22

3+
#include "../../../utils.hpp"
34
#include "infinicore/ops.hpp"
45

56
#include <stdexcept>
@@ -12,6 +13,9 @@ TopKRouterBackend parse_router_backend(const std::string &backend) {
1213
if (backend == "softmax") {
1314
return TopKRouterBackend::Softmax;
1415
}
16+
if (backend == "topksoftmax" || backend == "legacy_softmax") {
17+
return TopKRouterBackend::LegacySoftmax;
18+
}
1519
if (backend == "sigmoid") {
1620
return TopKRouterBackend::Sigmoid;
1721
}
@@ -53,9 +57,13 @@ TopKRouter::TopKRouter(std::shared_ptr<infinilm::config::ModelConfig> model_conf
5357
use_correction_bias_ = model_config->get_or<bool>({"e_score_correction_bias", "moe_router_use_correction_bias"}, false) || router_backend_ == TopKRouterBackend::FusedGate;
5458
ASSERT((num_experts_ > 0) && (num_experts_per_tok_ > 0) && (num_experts_per_tok_ <= num_experts_));
5559

60+
const auto router_dtype_name = model_config->get_or<std::string>("moe_router_dtype", "");
61+
const auto router_dtype = router_dtype_name.empty()
62+
? model_config->get_dtype()
63+
: parse_dtype(router_dtype_name);
5664
INFINICORE_NN_PARAMETER_INIT(
5765
weight,
58-
({num_experts_, model_config->get<size_t>("hidden_size")}, model_config->get_dtype(), device));
66+
({num_experts_, model_config->get<size_t>("hidden_size")}, router_dtype, device));
5967

6068
if (use_correction_bias_) {
6169
INFINICORE_NN_PARAMETER_INIT(e_score_correction_bias, ({num_experts_}, infinicore::DataType::F32, device));
@@ -79,9 +87,17 @@ TopKRouter::TopKRouter(std::shared_ptr<infinilm::config::ModelConfig> model_conf
7987

8088
std::tuple<infinicore::Tensor, infinicore::Tensor> TopKRouter::forward(const infinicore::Tensor &hidden_states) const {
8189
ASSERT(hidden_states->ndim() == 2);
82-
8390
size_t ntoken = hidden_states->shape()[0];
84-
auto router_logits = infinicore::op::linear(hidden_states, weight_, std::nullopt, 1.0f);
91+
auto router_input = hidden_states->is_contiguous() ? hidden_states : hidden_states->contiguous();
92+
auto router_weight = static_cast<infinicore::Tensor>(weight_);
93+
router_weight = router_weight->is_contiguous() ? router_weight : router_weight->contiguous();
94+
auto logits_shape = router_input->shape();
95+
logits_shape[logits_shape.size() - 1] = num_experts_;
96+
auto router_logits = infinicore::Tensor::empty(
97+
logits_shape,
98+
router_weight->dtype(),
99+
router_input->device());
100+
infinicore::op::linear_(router_logits, router_input, router_weight, std::nullopt, 1.0f);
85101

86102
auto router_scores = infinicore::Tensor::empty({ntoken, num_experts_per_tok_}, infinicore::DataType::F32, hidden_states->device());
87103
auto router_indices = infinicore::Tensor::empty({ntoken, num_experts_per_tok_}, infinicore::DataType::I32, hidden_states->device());
@@ -98,6 +114,14 @@ std::tuple<infinicore::Tensor, infinicore::Tensor> TopKRouter::forward(const inf
98114
norm_topk_prob_,
99115
moe_softcapping_);
100116
break;
117+
case TopKRouterBackend::LegacySoftmax:
118+
infinicore::op::topksoftmax(
119+
router_scores,
120+
router_indices,
121+
router_logits,
122+
num_experts_per_tok_,
123+
norm_topk_prob_);
124+
break;
101125
case TopKRouterBackend::Sigmoid:
102126
infinicore::op::moe_topk_sigmoid_(
103127
router_scores,

‎csrc/layers/moe/router/topk_router.hpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ namespace infinilm::layers::moe {
1111

1212
enum class TopKRouterBackend {
1313
Softmax,
14+
LegacySoftmax,
1415
Sigmoid,
1516
FusedGate,
1617
};
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
#include "ernie4_5_attention.hpp"
2+
3+
#include "../../global_state/global_state.hpp"
4+
#include "../../layers/attention/attention.hpp"
5+
#include "../../utils.hpp"
6+
#include "infinicore/ops.hpp"
7+
8+
#include <cmath>
9+
10+
namespace infinilm::models::ernie4_5_moe_vl {
11+
12+
Ernie4_5Attention::Ernie4_5Attention(std::shared_ptr<infinilm::config::ModelConfig> model_config,
13+
size_t layer_idx,
14+
const infinicore::Device &device) {
15+
layer_idx_ = layer_idx;
16+
hidden_size_ = model_config->get<size_t>("hidden_size");
17+
head_dim_ = model_config->get<size_t>("head_dim");
18+
19+
const auto &dtype = model_config->get_dtype();
20+
const size_t total_num_heads = model_config->get<size_t>("num_attention_heads");
21+
const size_t total_num_kv_heads = model_config->get<size_t>("num_key_value_heads");
22+
const bool use_bias = model_config->get_or<bool>("attention_bias", false);
23+
const bool use_output_bias = model_config->get_or<bool>("attention_output_bias", false);
24+
const auto &config_json = model_config->get_config_json();
25+
26+
attention_backend_ = infinilm::global_state::get_infinilm_config().attention_backend;
27+
const engine::distributed::RankInfo &rank_info = infinilm::global_state::get_tensor_model_parallel_rank_info();
28+
const int tp_rank = infinilm::global_state::get_tensor_model_parallel_rank();
29+
const int tp_size = infinilm::global_state::get_tensor_model_parallel_world_size();
30+
31+
num_attention_heads_ = total_num_heads / tp_size;
32+
num_key_value_heads_ = total_num_kv_heads < static_cast<size_t>(tp_size)
33+
? 1
34+
: total_num_kv_heads / tp_size;
35+
36+
auto quantization_method = model_config->get_quantization_method();
37+
auto register_fn = [this](const std::string &name, infinicore::nn::Parameter parameter) {
38+
this->register_parameter(name, std::move(parameter));
39+
};
40+
qkv_proj_ = std::make_shared<layers::linear::QKVParallelLinear>(
41+
hidden_size_, head_dim_, total_num_heads, total_num_kv_heads,
42+
"q_proj", "k_proj", "v_proj", register_fn,
43+
quantization_method, use_bias, dtype, device, rank_info);
44+
o_proj_ = this->register_module<layers::linear::RowParallelLinear>(
45+
"o_proj", total_num_heads * head_dim_, hidden_size_, quantization_method,
46+
use_output_bias, dtype, device, tp_rank, tp_size, rank_info.comm);
47+
48+
rotary_emb_ = infinilm::layers::rotary_embedding::get_rope(model_config, device);
49+
rope_theta_ = model_config->get_or<double>("rope_theta", 500000.0);
50+
if (config_json.contains("rope_scaling") && config_json["rope_scaling"].contains("mrope_section")) {
51+
const auto &sections = config_json["rope_scaling"]["mrope_section"];
52+
if (sections.is_array() && sections.size() == 3) {
53+
mrope_section_h_ = sections.at(0).get<size_t>();
54+
mrope_section_w_ = sections.at(1).get<size_t>();
55+
mrope_section_t_ = sections.at(2).get<size_t>();
56+
}
57+
}
58+
59+
const float scaling = 1.0f / std::sqrt(static_cast<float>(head_dim_));
60+
attn_ = std::make_shared<infinilm::layers::attention::AttentionLayer>(
61+
num_attention_heads_, head_dim_, scaling, num_key_value_heads_, layer_idx_,
62+
kv_cache_k_scale_, kv_cache_v_scale_, attention_backend_);
63+
64+
infinilm::layers::attention::init_kv_cache_quant_params(register_fn, device, kv_cache_k_scale_, kv_cache_v_scale_);
65+
}
66+
67+
infinicore::Tensor Ernie4_5Attention::forward(const infinicore::Tensor &positions,
68+
const infinicore::Tensor &hidden_states) const {
69+
if (::infinilm::backends::AttentionBackend::STATIC_ATTN == attention_backend_) {
70+
return forward_static_(positions, hidden_states);
71+
}
72+
return forward_paged_(positions, hidden_states);
73+
}
74+
75+
infinicore::Tensor Ernie4_5Attention::forward_static_(const infinicore::Tensor &position_ids,
76+
const infinicore::Tensor &hidden_states) const {
77+
auto hidden_states_mutable = hidden_states;
78+
const auto shape = hidden_states->shape();
79+
const size_t batch_size = shape[0];
80+
const size_t seq_len = shape[1];
81+
82+
auto [q, k, v] = qkv_proj_->forward_split(hidden_states_mutable);
83+
auto q_reshaped = q->view({batch_size, seq_len, num_attention_heads_, head_dim_});
84+
auto k_reshaped = k->view({batch_size, seq_len, num_key_value_heads_, head_dim_});
85+
auto v_reshaped = v->view({batch_size, seq_len, num_key_value_heads_, head_dim_});
86+
87+
auto pos_shape = position_ids->shape();
88+
if ((pos_shape.size() == 3 && pos_shape[0] == 1 && pos_shape[1] == seq_len && pos_shape[2] == 3) || (pos_shape.size() == 2 && pos_shape[0] == seq_len && pos_shape[1] == 3)) {
89+
ASSERT_EQ(batch_size, 1);
90+
auto q_mrope = q_reshaped->squeeze(0);
91+
auto k_mrope = k_reshaped->squeeze(0);
92+
infinicore::Tensor pos_ids_for_mrope = position_ids;
93+
if (pos_shape.size() == 3) {
94+
pos_ids_for_mrope = position_ids->squeeze(0);
95+
}
96+
infinicore::op::ernie45_mrope_(
97+
q_mrope, k_mrope, pos_ids_for_mrope,
98+
rope_theta_, mrope_section_h_, mrope_section_w_, mrope_section_t_);
99+
auto attn_output = attn_->forward(q_reshaped, k_reshaped, v_reshaped);
100+
return o_proj_->forward(attn_output);
101+
}
102+
103+
infinicore::Tensor pos_ids_for_rope = position_ids;
104+
if (pos_shape.size() == 2) {
105+
auto pos_narrowed = position_ids->narrow({{0, 0, 1}});
106+
pos_ids_for_rope = pos_narrowed->contiguous()->view({pos_shape[1]});
107+
} else if (pos_shape.size() == 1) {
108+
pos_ids_for_rope = position_ids->contiguous();
109+
} else {
110+
throw std::runtime_error("Ernie4_5Attention: Unexpected position_ids shape");
111+
}
112+
113+
auto q_rope = infinicore::Tensor::empty({batch_size, num_attention_heads_, seq_len, head_dim_}, q_reshaped->dtype(), q_reshaped->device())->permute({0, 2, 1, 3});
114+
rotary_emb_->forward(q_rope, q_reshaped, pos_ids_for_rope);
115+
rotary_emb_->forward(k_reshaped, pos_ids_for_rope, true);
116+
117+
auto attn_output = attn_->forward(q_rope, k_reshaped, v_reshaped);
118+
return o_proj_->forward(attn_output);
119+
}
120+
121+
infinicore::Tensor Ernie4_5Attention::forward_paged_(const infinicore::Tensor &position_ids,
122+
const infinicore::Tensor &hidden_states) const {
123+
auto hidden_states_mutable = hidden_states;
124+
const auto shape = hidden_states->shape();
125+
const size_t batch_size = shape[0];
126+
const size_t seq_len = shape[1];
127+
128+
ASSERT_EQ(batch_size, 1);
129+
130+
auto [q, k, v] = qkv_proj_->forward_split(hidden_states_mutable);
131+
auto q_reshaped = q->view({seq_len, num_attention_heads_, head_dim_});
132+
auto k_reshaped = k->view({seq_len, num_key_value_heads_, head_dim_});
133+
auto v_reshaped = v->view({seq_len, num_key_value_heads_, head_dim_});
134+
135+
auto pos_shape = position_ids->shape();
136+
if ((pos_shape.size() == 3 && pos_shape[0] == 1 && pos_shape[1] == seq_len && pos_shape[2] == 3) || (pos_shape.size() == 2 && pos_shape[0] == seq_len && pos_shape[1] == 3)) {
137+
infinicore::Tensor pos_ids_for_mrope = position_ids;
138+
if (pos_shape.size() == 3) {
139+
pos_ids_for_mrope = position_ids->squeeze(0);
140+
}
141+
infinicore::op::ernie45_mrope_(
142+
q_reshaped, k_reshaped, pos_ids_for_mrope,
143+
rope_theta_, mrope_section_h_, mrope_section_w_, mrope_section_t_);
144+
auto attn_output = attn_->forward(q_reshaped, k_reshaped, v_reshaped);
145+
return o_proj_->forward(attn_output);
146+
}
147+
148+
infinicore::Tensor pos_ids_for_rope = position_ids;
149+
if (pos_shape.size() == 2) {
150+
auto pos_narrowed = position_ids->narrow({{0, 0, 1}});
151+
pos_ids_for_rope = pos_narrowed->view({pos_shape[1]});
152+
} else if (pos_shape.size() != 1) {
153+
throw std::runtime_error("Ernie4_5Attention: Unexpected position_ids shape");
154+
}
155+
156+
rotary_emb_->forward(q_reshaped, pos_ids_for_rope, true);
157+
rotary_emb_->forward(k_reshaped, pos_ids_for_rope, true);
158+
159+
auto attn_output = attn_->forward(q_reshaped, k_reshaped, v_reshaped);
160+
return o_proj_->forward(attn_output);
161+
}
162+
163+
} // namespace infinilm::models::ernie4_5_moe_vl

0 commit comments

Comments
 (0)