From 6d6e0a3ccb739ff9a08a35ce06a7d342cf2510a4 Mon Sep 17 00:00:00 2001 From: Rene Leonhardt <65483435+reneleonhardt@users.noreply.github.com> Date: Sat, 27 Apr 2024 22:50:03 +0200 Subject: [PATCH] feat: Support Phi-3 Mini model (#516) --- src/main/cpp/llama.cpp | 2 +- .../codegpt/completions/HuggingFaceModel.java | 9 ++- .../codegpt/completions/llama/LlamaModel.java | 16 ++++- .../completions/llama/PromptTemplate.java | 19 ++++++ .../codegpt/completions/PromptTemplateTest.kt | 63 +++++++++++++++++++ 5 files changed, 106 insertions(+), 3 deletions(-) diff --git a/src/main/cpp/llama.cpp b/src/main/cpp/llama.cpp index 7dbdba56..46e12c46 160000 --- a/src/main/cpp/llama.cpp +++ b/src/main/cpp/llama.cpp @@ -1 +1 @@ -Subproject commit 7dbdba5690ca61b3ee8c92cfac8e7e251042e787 +Subproject commit 46e12c4692a37bdd31a0432fc5153d7d22bc7f72 diff --git a/src/main/java/ee/carlrobert/codegpt/completions/HuggingFaceModel.java b/src/main/java/ee/carlrobert/codegpt/completions/HuggingFaceModel.java index 857a50a4..51c51dba 100644 --- a/src/main/java/ee/carlrobert/codegpt/completions/HuggingFaceModel.java +++ b/src/main/java/ee/carlrobert/codegpt/completions/HuggingFaceModel.java @@ -52,7 +52,14 @@ public enum HuggingFaceModel { LLAMA_3_8B_Q8_0(8, 8, "Meta-Llama-3-8B-Instruct-Q8_0.gguf", "lmstudio-community", 8.54), LLAMA_3_70B_IQ1(70, 1, "Meta-Llama-3-70B-Instruct-IQ1_M.gguf", "lmstudio-community", 16.8), LLAMA_3_70B_IQ2_XS(70, 2, "Meta-Llama-3-70B-Instruct-IQ2_XS.gguf", "lmstudio-community", 21.1), - LLAMA_3_70B_Q4_K_M(70, 4, "Meta-Llama-3-70B-Instruct-Q4_K_M.gguf", "lmstudio-community", 42.5); + LLAMA_3_70B_Q4_K_M(70, 4, "Meta-Llama-3-70B-Instruct-Q4_K_M.gguf", "lmstudio-community", 42.5), + + PHI_3_3_8B_4K_IQ4_NL(4, 4, "Phi-3-mini-4k-instruct-IQ4_NL.gguf", "lmstudio-community", 2.18), + PHI_3_3_8B_4K_Q5_K_M(4, 5, "Phi-3-mini-4k-instruct-Q5_K_M.gguf", "lmstudio-community", 2.64), + PHI_3_3_8B_4K_Q5_K_S(4, 5, "Phi-3-mini-4k-instruct-Q5_K_S.gguf", "lmstudio-community", 2.82), + PHI_3_3_8B_4K_Q6_K(4, 6, "Phi-3-mini-4k-instruct-Q6_K.gguf", "lmstudio-community", 3.14), + PHI_3_3_8B_4K_Q8_0(4, 8, "Phi-3-mini-4k-instruct-Q8_0.gguf", "lmstudio-community", 4.06), + PHI_3_3_8B_4K_FP16(4, 16, "Phi-3-mini-4k-instruct-fp16.gguf", "lmstudio-community", 7.64); private final int parameterSize; private final int quantization; diff --git a/src/main/java/ee/carlrobert/codegpt/completions/llama/LlamaModel.java b/src/main/java/ee/carlrobert/codegpt/completions/llama/LlamaModel.java index dc1288ba..770bd3b9 100644 --- a/src/main/java/ee/carlrobert/codegpt/completions/llama/LlamaModel.java +++ b/src/main/java/ee/carlrobert/codegpt/completions/llama/LlamaModel.java @@ -99,7 +99,21 @@ public enum LlamaModel { HuggingFaceModel.LLAMA_3_8B_Q8_0, HuggingFaceModel.LLAMA_3_70B_IQ1, HuggingFaceModel.LLAMA_3_70B_IQ2_XS, - HuggingFaceModel.LLAMA_3_70B_Q4_K_M)); + HuggingFaceModel.LLAMA_3_70B_Q4_K_M)), + PHI_3( + "Phi-3 Mini", + "Phi-3 Mini is a 3.8B parameters, lightweight, state-of-the-art open model. " + + "When assessed against benchmarks testing common sense, language understanding, math, " + + "code, long context and logical reasoning, Phi-3 Mini-4K-Instruct showcased a robust " + + "and state-of-the-art performance among models with less than 13 billion parameters.", + PromptTemplate.PHI_3, + List.of( + HuggingFaceModel.PHI_3_3_8B_4K_IQ4_NL, + HuggingFaceModel.PHI_3_3_8B_4K_Q5_K_M, + HuggingFaceModel.PHI_3_3_8B_4K_Q5_K_S, + HuggingFaceModel.PHI_3_3_8B_4K_Q6_K, + HuggingFaceModel.PHI_3_3_8B_4K_Q8_0, + HuggingFaceModel.PHI_3_3_8B_4K_FP16)); private final String label; private final String description; diff --git a/src/main/java/ee/carlrobert/codegpt/completions/llama/PromptTemplate.java b/src/main/java/ee/carlrobert/codegpt/completions/llama/PromptTemplate.java index 7101587a..27164bd4 100644 --- a/src/main/java/ee/carlrobert/codegpt/completions/llama/PromptTemplate.java +++ b/src/main/java/ee/carlrobert/codegpt/completions/llama/PromptTemplate.java @@ -125,6 +125,25 @@ public enum PromptTemplate { .toString(); } }, + PHI_3("Phi-3 Mini", List.of("<|end|>")) { + @Override + public String buildPrompt(String systemPrompt, String userPrompt, List history) { + StringBuilder prompt = new StringBuilder(); + + for (Message message : history) { + prompt.append("<|user|>\n") + .append(message.getPrompt()) + .append("<|end|>\n<|assistant|>\n") + .append(message.getResponse()) + .append("<|end|>\n"); + } + + return prompt.append("<|user|>\n") + .append(userPrompt) + .append("<|end|>\n<|assistant|>") + .toString(); + } + }, ALPACA("Alpaca/Vicuna") { @Override public String buildPrompt(String systemPrompt, String userPrompt, List history) { diff --git a/src/test/kotlin/ee/carlrobert/codegpt/completions/PromptTemplateTest.kt b/src/test/kotlin/ee/carlrobert/codegpt/completions/PromptTemplateTest.kt index 84dad146..7847ec54 100644 --- a/src/test/kotlin/ee/carlrobert/codegpt/completions/PromptTemplateTest.kt +++ b/src/test/kotlin/ee/carlrobert/codegpt/completions/PromptTemplateTest.kt @@ -4,6 +4,7 @@ import ee.carlrobert.codegpt.completions.llama.PromptTemplate.ALPACA import ee.carlrobert.codegpt.completions.llama.PromptTemplate.CHAT_ML import ee.carlrobert.codegpt.completions.llama.PromptTemplate.LLAMA import ee.carlrobert.codegpt.completions.llama.PromptTemplate.LLAMA_3 +import ee.carlrobert.codegpt.completions.llama.PromptTemplate.PHI_3 import ee.carlrobert.codegpt.completions.llama.PromptTemplate.TORA import ee.carlrobert.codegpt.conversations.message.Message import org.assertj.core.api.Assertions.assertThat @@ -104,6 +105,68 @@ class PromptTemplateTest { TEST_USER_PROMPT<|eot_id|><|start_header_id|>assistant<|end_header_id|>""".trimIndent()) } + @Test + fun shouldBuildPhi3PromptWithoutHistory() { + val prompt = PHI_3.buildPrompt(SYSTEM_PROMPT, USER_PROMPT, listOf()) + + assertThat(prompt).isEqualTo(""" + <|user|> + TEST_USER_PROMPT<|end|> + <|assistant|>""".trimIndent() + ) + } + + @ParameterizedTest + @NullAndEmptySource + @ValueSource(strings = [" ", "\t", "\n"]) + fun shouldBuildPhi3PromptWithoutHistorySkippingBlankSystemPrompt(systemPrompt: String?) { + val prompt = PHI_3.buildPrompt(systemPrompt, USER_PROMPT, listOf()) + + assertThat(prompt).isEqualTo(""" + <|user|> + TEST_USER_PROMPT<|end|> + <|assistant|>""".trimIndent() + ) + } + + @Test + fun shouldBuildPhi3PromptWithHistory() { + val prompt = PHI_3.buildPrompt(SYSTEM_PROMPT, USER_PROMPT, HISTORY) + + assertThat(prompt).isEqualTo(""" + <|user|> + TEST_PREV_PROMPT_1<|end|> + <|assistant|> + TEST_PREV_RESPONSE_1<|end|> + <|user|> + TEST_PREV_PROMPT_2<|end|> + <|assistant|> + TEST_PREV_RESPONSE_2<|end|> + <|user|> + TEST_USER_PROMPT<|end|> + <|assistant|>""".trimIndent()) + } + + @ParameterizedTest + @NullAndEmptySource + @ValueSource(strings = [" ", "\t", "\n"]) + fun shouldBuildPhi3PromptWithHistorySkippingBlankSystemPrompt(systemPrompt: String?) { + val prompt = PHI_3.buildPrompt(systemPrompt, USER_PROMPT, HISTORY) + + assertThat(prompt).isEqualTo(""" + <|user|> + TEST_PREV_PROMPT_1<|end|> + <|assistant|> + TEST_PREV_RESPONSE_1<|end|> + <|user|> + TEST_PREV_PROMPT_2<|end|> + <|assistant|> + TEST_PREV_RESPONSE_2<|end|> + <|user|> + TEST_USER_PROMPT<|end|> + <|assistant|>""".trimIndent()) + } + @Test fun shouldBuildAlpacaPromptWithHistory() { val prompt = ALPACA.buildPrompt(SYSTEM_PROMPT, USER_PROMPT, HISTORY)