| 923 | } |
| 924 | |
| 925 | void Model::prefill_npu(const std::vector<uint32_t>& tokens) { |
| 926 | if (!npu_prefill_ || !npu_prefill_->is_available()) { |
| 927 | throw std::runtime_error("NPU prefill not available"); |
| 928 | } |
| 929 | |
| 930 | const int chunk_size = npu_prefill_->get_chunk_size(); |
| 931 | const int hidden_dim = npu_prefill_->get_hidden_dim(); |
| 932 | const int num_layers = npu_prefill_->get_num_layers(); |
| 933 | const int fallback_num_kv_heads = npu_prefill_->get_num_kv_heads(); |
| 934 | const int fallback_head_dim = npu_prefill_->get_head_dim(); |
| 935 | |
| 936 | const std::vector<size_t> layer_dims = get_kv_layer_dims(); |
| 937 | const std::vector<size_t> layer_heads = get_kv_layer_heads(); |
| 938 | const int layers_to_update = std::min<int>(num_layers, static_cast<int>(config_.num_layers)); |
| 939 | |
| 940 | std::vector<__fp16> all_embeddings = get_token_embeddings(tokens); |
| 941 | if (all_embeddings.empty()) { |
| 942 | throw std::runtime_error("Failed to get token embeddings for NPU prefill"); |
| 943 | } |
| 944 | |
| 945 | if (Config::is_gemma_family(config_.model_type)) { |
| 946 | float scale = std::sqrt(static_cast<float>(hidden_dim)); |
| 947 | for (size_t i = 0; i < all_embeddings.size(); i++) { |
| 948 | all_embeddings[i] = __fp16(static_cast<float>(all_embeddings[i]) * scale); |
| 949 | } |
| 950 | } |
| 951 | |
| 952 | size_t num_tokens = tokens.size(); |
| 953 | size_t num_chunks = (num_tokens + chunk_size - 1) / chunk_size; |
| 954 | |
| 955 | for (size_t c = 0; c < num_chunks; c++) { |
| 956 | size_t start = c * chunk_size; |
| 957 | size_t actual_tokens = std::min(static_cast<size_t>(chunk_size), num_tokens - start); |
| 958 | |
| 959 | std::vector<__fp16> chunk_embeddings(chunk_size * hidden_dim, __fp16(0)); |
| 960 | std::copy(all_embeddings.begin() + start * hidden_dim, |
| 961 | all_embeddings.begin() + (start + actual_tokens) * hidden_dim, |
| 962 | chunk_embeddings.begin()); |
| 963 | |
| 964 | int position_offset = static_cast<int>(start); |
| 965 | |
| 966 | npu::NPUPrefillDirectResult direct_result = npu_prefill_->prefill_chunk_direct(chunk_embeddings, position_offset); |
| 967 | |
| 968 | if (direct_result.valid) { |
| 969 | for (int layer_idx = 0; layer_idx < layers_to_update; layer_idx++) { |
| 970 | const auto& k_ref = direct_result.k_caches[layer_idx]; |
| 971 | const auto& v_ref = direct_result.v_caches[layer_idx]; |
| 972 | |
| 973 | if (k_ref.data && v_ref.data) { |
| 974 | size_t layer_kv_heads = layer_idx < static_cast<int>(layer_heads.size()) |
| 975 | ? layer_heads[layer_idx] |
| 976 | : static_cast<size_t>(fallback_num_kv_heads); |
| 977 | size_t layer_head_dim = layer_idx < static_cast<int>(layer_dims.size()) |
| 978 | ? layer_dims[layer_idx] |
| 979 | : static_cast<size_t>(fallback_head_dim); |
| 980 | |
| 981 | size_t expected = static_cast<size_t>(chunk_size) * layer_kv_heads * layer_head_dim; |
| 982 | if (expected > 0 && (k_ref.count < expected || v_ref.count < expected)) { |
nothing calls this directly
no test coverage detected