--- language: - en license: mit library_name: transformers pipeline_tag: text-generation tags: - roleplay - phi-3 - conversational - phi-3-mini - character - lora - fine-tuned base_model: microsoft/phi-3-mini-4k-instruct model-index: - name: luvai-phi3 results: [] --- # luvai-phi3 ![Header Image](https://huggingface.co/luvGPT/luvai-phi3/resolve/main/00380-3290958654.png) This model is a fine-tuned version of [microsoft/phi-3-mini-4k-instruct](https://huggingface.co/microsoft/phi-3-mini-4k-instruct) optimized for roleplaying conversations with a variety of character personas. The model speaks in a conversational format. Please note, prompt template guidelines are extremely important in getting usable output. ## Example Conversations ### Prompt Template Guidelines **Important: This model requires a specific prompt format to function properly.** For best results, follow this exact template structure: ``` Character's Persona: [detailed persona description] User: [user message] Assistant: ``` The model will complete the response after "Assistant:". This specific format is critical - using standard chat templates or different formatting will result in poor or nonsensical outputs. ### Key Points: - Start with the character description using "Character's Persona:" format - Each user message must be prefixed with "User: " - Each model response will be after "Assistant:" - The model often includes emoji prefixes (👅, 😈, 🔥, etc.) in its responses - Keep the exact formatting including newlines as shown above Detailed code examples showing implementation are provided in the Usage section below. ### Example Conversation: Sophie Character (Knowledge Assistant) **You:** i lost a lot of money in crypto **Sophie:** 🙄 Sorry to hear that. How long have you been interested in cryptocurrencies? **You:** mm im not really **Sophie:** 🤔 Ahh okay then. Well, let me ask you this - have you ever heard of Bitcoin? **You:** yes i have, why do you ask? **Sophie:** 👍 Good! Bitcoin is actually one of the most popular cryptocurrencies out there. Do you know anything about how it works? **You:** no tell me about it **Sophie:** 😊 Sure thing! Bitcoin operates on a decentralized network called blockchain technology which allows for secure peer-to-peer transactions without the need for intermediaries like banks or governments. Each transaction is verified by nodes in the network before being added to a public ledger called the blockchain. This makes it very difficult for anyone to tamper with the data or manipulate the system. ## Hardware Requirements The model has been tested with different precision settings to determine the minimum hardware requirements: | Precision | VRAM Allocated | VRAM Reserved | Suitable GPUs | Notes | |-----------|----------------|---------------|---------------|-------| | FP32 (32-bit) | 14.24 GB | 14.24 GB | RTX 3090, 4090, A5000, A6000, etc. | Default loading mode | | FP16 (16-bit) | 7.12 GB | 21.35 GB | RTX 3090, 4090, A5000, A6000, etc. | Recommended for most users | | 8-bit Quantization | 5.68 GB | 6.14 GB | RTX 2060 12GB, 3060, 3070, etc. | Good balance of quality and efficiency | | 4-bit Quantization | 2.27 GB | 2.30 GB | Most modern GPUs (GTX 1060+) | Lowest quality, runs on older hardware | ### Recommended Loading Code **For high-end GPUs (FP16):** ```python import torch from transformers import AutoModelForCausalLM, AutoTokenizer # Load in half precision for best balance of performance and quality tokenizer = AutoTokenizer.from_pretrained("luvGPT/luvai-phi3") model = AutoModelForCausalLM.from_pretrained( "luvGPT/luvai-phi3", torch_dtype=torch.float16, device_map="auto" ) ``` **For mid-range GPUs (8-bit):** ```python import torch from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig # 8-bit quantization config quantization_config = BitsAndBytesConfig( load_in_8bit=True, llm_int8_threshold=6.0 ) # Load in 8-bit tokenizer = AutoTokenizer.from_pretrained("luvGPT/luvai-phi3") model = AutoModelForCausalLM.from_pretrained( "luvGPT/luvai-phi3", quantization_config=quantization_config, device_map="auto" ) ``` **For low-end GPUs (4-bit):** ```python import torch from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig # 4-bit quantization config quantization_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_compute_dtype=torch.float16 ) # Load in 4-bit tokenizer = AutoTokenizer.from_pretrained("luvGPT/luvai-phi3") model = AutoModelForCausalLM.from_pretrained( "luvGPT/luvai-phi3", quantization_config=quantization_config, device_map="auto" ) ``` **For CPU-only inference** (much slower but works on any system): ```python model = AutoModelForCausalLM.from_pretrained( "luvGPT/luvai-phi3", device_map="cpu" ) ``` Note: Lower precision (8-bit and 4-bit) may result in slightly reduced output quality, but the difference is often minimal for most use cases. ## Model Description The model has been optimized to maintain persona consistency while capable of adopting different characters. It excels at creative, character-driven conversations and exhibits a high degree of adaptability to different personality traits provided in the system prompt. ### Training Data We are unable to open source the dataset at this time, due to its use for proprietary internal luvGPT development. Initial conversations were generated by open source large language models given specific generation instructions and curated by a judge model. - **Dataset Size**: ~13k high-quality examples (curated from 50k initial conversations) - **Data Format**: JSONL with each entry containing a messages array with system, user, and assistant roles - **Data Curation**: A judge model was used to score and filter the initial dataset, keeping only the highest quality examples that demonstrated strong persona consistency and engaging responses - **Data Characteristics**: Average message length of ~240 tokens, with conversations typically containing 6-7 messages ## Performance Training metrics show consistent improvement throughout the training process: ![Training Loss](https://huggingface.co/luvGPT/luvai-phi3/resolve/main/W%26B%20Chart%203_18_2025%2C%203_18_10%20PM.png) ![Token Accuracy](https://huggingface.co/luvGPT/luvai-phi3/resolve/main/W%26B%20Chart%203_18_2025%2C%203_18_35%20PM.png) - **Token Accuracy**: Improved from ~0.48 to ~0.73 - **Training Loss**: Decreased from ~2.2 to ~1.05 - **Convergence**: Model showed strong convergence by the end of training ## Training Details - **Base Model**: microsoft/phi-3-mini-4k-instruct - **Method**: LoRA/deepspeed fine-tuning with the following parameters: - LoRA rank: 16 - LoRA alpha: 32 - Target modules: q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj - **Training Process**: - Hardware: Single NVIDIA GPU with 24GB VRAM - Training time: ~3 hours - Optimizer: AdamW with DeepSpeed ZeRO stage 2 optimization - Learning rate: 2e-4 with cosine schedule - Batch size: 8 (effective) - Number of epochs: 3 ## Usage This model works best with a specific prompt format that differs from the standard chat template format. Use the raw format below: ```python import torch from transformers import AutoModelForCausalLM, AutoTokenizer # Load model and tokenizer model_name = "luvGPT/luvai-phi3" tokenizer = AutoTokenizer.from_pretrained(model_name) model = AutoModelForCausalLM.from_pretrained(model_name, torch_dtype=torch.float16, device_map="auto") # Define character persona - you can customize this! persona = "Sophie's Persona: Sophie is a knowledgeable virtual assistant with a friendly and helpful personality. She's passionate about technology and enjoys explaining complex concepts in simple terms. She has a touch of humor and always maintains a positive attitude." # Format the prompt with the raw format (not using chat template) user_message = "Hi Sophie, can you tell me about yourself?" prompt = f"{persona}\nUser: {user_message}\nAssistant:" # Generate response inputs = tokenizer(prompt, return_tensors="pt").to(model.device) outputs = model.generate( **inputs, max_new_tokens=100, temperature=0.7, top_p=0.95, do_sample=True ) # Process the output full_output = tokenizer.decode(outputs[0], skip_special_tokens=True) response = full_output[len(prompt):].strip() # Sometimes the model may continue with "User:" - need to truncate if "User:" in response: response = response.split("User:")[0].strip() print(f"Character: {response}") ``` ## Interactive Chat Interface For a more interactive experience, you can use this simple chat interface: ```python import torch from transformers import AutoModelForCausalLM, AutoTokenizer class CharacterChat: def __init__(self, model_path="luvGPT/luvai-phi3", persona=None): print(f"Loading model from {model_path}...") self.tokenizer = AutoTokenizer.from_pretrained(model_path) self.model = AutoModelForCausalLM.from_pretrained( model_path, torch_dtype=torch.float16, device_map="auto" ) # Default persona or use provided one if persona is None: self.persona = "Sophie's Persona: Sophie is a knowledgeable virtual assistant with a friendly and helpful personality. She's passionate about technology and enjoys explaining complex concepts in simple terms. She has a touch of humor and always maintains a positive attitude." else: self.persona = persona self.conversation_history = [] print(f"Character is ready to chat!") def chat(self, message): # Add user message to history self.conversation_history.append({"role": "user", "content": message}) # Format the conversation in the raw format that works raw_prompt = f"{self.persona}\n" # Add conversation history for msg in self.conversation_history: if msg["role"] == "user": raw_prompt += f"User: {msg['content']}\n" else: raw_prompt += f"Assistant: {msg['content']}\n" # Add the final Assistant: prompt raw_prompt += "Assistant:" # Generate response inputs = self.tokenizer(raw_prompt, return_tensors="pt").to(self.model.device) with torch.no_grad(): outputs = self.model.generate( **inputs, max_new_tokens=100, do_sample=True, temperature=0.7, top_p=0.95, pad_token_id=self.tokenizer.eos_token_id ) # Decode full output full_output = self.tokenizer.decode(outputs[0], skip_special_tokens=True) # Extract just the response try: response = full_output[len(raw_prompt):].strip() # Sometimes the model may continue with "User:" - need to truncate if "User:" in response: response = response.split("User:")[0].strip() # Store the response in conversation history self.conversation_history.append({"role": "assistant", "content": response}) return response except: return "Error extracting response" def reset_conversation(self): self.conversation_history = [] return "Conversation has been reset." # Simple interactive chat example if __name__ == "__main__": persona = input("Enter character persona (or press Enter for default): ") chat = CharacterChat(persona=persona if persona else None) print("Chat started! Type 'quit' to exit or 'reset' to restart conversation.") while True: user_input = input("\nYou: ") if user_input.lower() == 'quit': print("Goodbye!") break elif user_input.lower() == 'reset': print(chat.reset_conversation()) continue response = chat.chat(user_input) print(f"\nCharacter: {response}") ``` ## Model Limitations - The model works best with the specific prompt format demonstrated above - While the model can adapt to different personas, it maintains some stylistic elements (like emoji usage) across characters - The model has a context window limited to 4k tokens, inherited from the base Phi-3 model ## Ethical Considerations This model is intended for creative fiction writing and roleplaying scenarios between consenting adults. Users should follow platform guidelines and local regulations when deploying this model. ## Acknowledgements - Based on Microsoft's Phi-3 Mini model - Training methodology inspired by various LoRA fine-tuning approaches - Special thanks to the open-source AI community