Views
No views yet
| Property | Detail |
|---|---|
| Base Model | mistralai/Mistral-7B-Instruct-v0.3 |
| Fine-tuning Type | QLoRA (Quantized Low-Rank Adaptation) |
| Quantization | 4-bit NF4 |
| Domain Focus | Psychological analysis, classic suspense/horror cinema, character monologues |
| Persona | Psychoanalytic narrative tone (1960s-inspired) |
| License | MIT |
trl SFTTrainer.psycho_datasetv2.jsonl1{"instruction": "Analyze the main character’s psychological state.", "response": "The subject displays..."}
2
3
4
5💻 Inference Example (Google Colab + Gradio)
6
7You can test the model interactively using the python code below. Change Runtime Type to T4 GPU.
8
9
10
11
12# -------------------------
13# 1️⃣ Install Dependencies
14# -------------------------
15!pip install -q --upgrade gradio transformers accelerate peft safetensors bitsandbytes huggingface_hub sentence-transformers datasets faiss-cpu
16
17# -------------------------
18# 2️⃣ Imports
19# -------------------------
20import gradio as gr
21import torch, os, shutil, re
22from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
23from huggingface_hub import snapshot_download
24from datasets import load_dataset
25from sentence_transformers import SentenceTransformer
26import faiss
27import numpy as np
28
29# -------------------------
30# 3️⃣ Load Mistral Psycho Model
31# -------------------------
32model_name = "antfr99/mistral-7B-psycho-1960-movie"
33expected_file = "model-001.safetensors"
34target_file = "model.safetensors"
35
36cache_path = snapshot_download(repo_id=model_name, allow_patterns=["*.json", "*.py", "*.model", "*.safetensors"])
37src = os.path.join(cache_path, expected_file)
38dst = os.path.join(cache_path, target_file)
39if os.path.exists(src) and not os.path.exists(dst):
40 try: os.symlink(src, dst)
41 except OSError: shutil.copy2(src, dst)
42
43tokenizer = AutoTokenizer.from_pretrained(cache_path)
44quant_config = BitsAndBytesConfig(
45 load_in_4bit=True,
46 bnb_4bit_quant_type="nf4",
47 bnb_4bit_use_double_quant=True,
48 bnb_4bit_compute_dtype=torch.float16
49)
50model = AutoModelForCausalLM.from_pretrained(
51 cache_path,
52 device_map="auto",
53 torch_dtype=torch.float16,
54 quantization_config=quant_config,
55 trust_remote_code=True
56)
57
58
59# -------------------------
60# 3️⃣ Load Psycho Dataset (Prompt-Completion)
61# -------------------------
62dataset = load_dataset("antfr99/psycho-1960-film-dataset", split="train")
63psycho_passages = [f"{row['prompt']} {row['completion']}" for row in dataset]
64
65# -------------------------
66# 4️⃣ Build FAISS Index
67# -------------------------
68embed_model = SentenceTransformer('all-MiniLM-L6-v2')
69passage_embeddings = embed_model.encode(psycho_passages, convert_to_numpy=True)
70dim = passage_embeddings.shape[1]
71index = faiss.IndexFlatL2(dim)
72index.add(passage_embeddings)
73
74# -------------------------
75# 5️⃣ Stopwords / Psycho Keywords
76# -------------------------
77STOPWORDS = set([
78 "the","in","her","his","their","a","an","and","or","of","on","for","to","with",
79 "at","by","is","was","as","from","that","which","it","he","she","they","this",
80 "these","those","but","not","had","have","has","also","after","before","so",
81 "would","could","should","who","what","when","where","why","how","does","did",
82 "do","i","you","we","me","my","your"
83])
84
85keyword_file_path = snapshot_download(repo_id=model_name, allow_patterns=["psycho_keywords.txt"])
86with open(os.path.join(keyword_file_path, "psycho_keywords.txt"), "r", encoding="utf-8") as f:
87 PSYCHO_REFERENCES = [line.strip() for line in f if line.strip() != ""]
88
89# -------------------------
90# 6️⃣ Prompt Validation
91# -------------------------
92def check_prompt_relevance(prompt):
93 clean_prompt = re.sub(r"[’']", "", prompt) # remove apostrophes
94 words = re.findall(r"\b[A-Za-z0-9]+\b", clean_prompt.lower()) # lowercase all words
95
96 # Preprocess Psycho keywords (lowercased and stripped)
97 valid_terms = set([k.lower().rstrip('s') for k in PSYCHO_REFERENCES])
98
99 # Ignore stopwords and simple plural/possessive forms
100 non_psycho = []
101 for w in words:
102 w_clean = w.rstrip('s') # handle "Crane’s" or "Crane" or "Cranes"
103 if w_clean not in valid_terms and w not in STOPWORDS:
104 non_psycho.append(w)
105
106 if non_psycho:
107 return "⚠️ Warning: Your question may contain terms NOT related to Psycho (1960): " + ", ".join(non_psycho)
108 return "✅ Prompt appears Psycho-related."
109
110# -------------------------
111# 7️⃣ Response Generation with Retrieval
112# -------------------------
113def generate_response(prompt, max_new_tokens=256, temperature=0.2, top_p=0.98, top_k=30, strict_mode=True):
114 # Validate prompt
115 prompt_warning = check_prompt_relevance(prompt)
116 if strict_mode and "⚠️" in prompt_warning:
117 return f"{prompt_warning}\n\n❌ Model refusal: This question is not about Psycho (1960)."
118
119 # Retrieve top 3 passages
120 query_vec = embed_model.encode([prompt], convert_to_numpy=True)
121 D, I = index.search(query_vec, k=3)
122 top_passages = "\n".join([psycho_passages[i] for i in I[0]])
123
124 # Format prompt for model
125 system_prompt = (
126 "You are a film scholar. Answer questions strictly about the 1960 film 'Psycho' by Alfred Hitchcock. "
127 "Do not hallucinate. Base your answers only on the retrieved passages below:\n\n"
128 f"{top_passages}"
129 ) if strict_mode else ""
130
131 formatted = f"<s>[INST] {system_prompt}\n\nUser: {prompt} [/INST]" if strict_mode else f"<s>[INST] {prompt} [/INST]"
132
133 # Generate
134 inputs = tokenizer(formatted, return_tensors="pt").to(model.device)
135 with torch.no_grad():
136 output = model.generate(
137 **inputs,
138 max_new_tokens=max_new_tokens,
139 temperature=temperature,
140 top_p=top_p,
141 top_k=top_k,
142 do_sample=True,
143 pad_token_id=tokenizer.eos_token_id
144 )
145 response = tokenizer.decode(output[0][inputs.input_ids.shape[-1]:], skip_special_tokens=True)
146 return f"{prompt_warning}\n\n{response}"
147
148# -------------------------
149# 8️⃣ Gradio Interface
150# -------------------------
151
152with gr.Blocks() as demo:
153 gr.Markdown("### 🎥 Psycho (1960) Film Q&A Interface")
154
155 # Input prompt (left) & output box (right)
156 with gr.Row():
157 prompt_input = gr.Textbox(lines=5, label="Input Prompt", placeholder="Ask about a scene in Psycho...")
158 output_box = gr.Textbox(lines=5, label="Model Response", placeholder="Model output will appear here...")
159
160 # Submit button below output
161 with gr.Row():
162 submit_btn = gr.Button("Submit")
163
164 # When calling generate_response, provide default values for sliders/checkbox
165 submit_btn.click(
166 fn=generate_response,
167 inputs=[prompt_input,
168 gr.State(256), # max_tokens
169 gr.State(0.2), # temperature
170 gr.State(0.98), # top_p
171 gr.State(30), # top_k
172 gr.State(True)], # strict_mode
173 outputs=output_box
174 )
175
176demo.launch()