Downloads · 30 days
0
kangelamw/negative-reviews-into-actionable-insights
negative-reviews-into-actionable-insights is a text generation model from kangelamw. Use it when you need the model to write or continue text. It is set up for peft. The card lists the license as mit.
Parameter-Efficient Fine-tuned Causal Language Model (PEFT/QLoRA) for Review Analysis
Downloads · 30 days
0
Access
Public
Updated Mar 17, 2025
Parameters
2.8B
5.6 GB on disk
Likes
0
Public
Click a slice to open those files.
.safetensors5.6 GB · 100%
From the Hugging Face model README
Parameter-Efficient Fine-tuned Causal Language Model (PEFT/QLoRA) for Review Analysis
A fine-tuned language model specialized in analyzing and generating insights from customer reviews. This model builds upon Microsoft's Phi-2 (2.7B parameters) base architecture and has been specifically tailored to understand sentiment, extract key points, and provide analytical feedback on review content.
Technical Approach:
Primary Capability: Extracting actionable insights from negative reviews for business improvement
This model is designed to help businesses and organizations extract valuable insights from customer reviews, particularly negative ones, to drive improvements.
This model can be directly used for:
Technical Requirements (Check the repo for more info)
This model is NOT suitable for:
This model inherits biases and limitations from several sources that users should be aware of:
no_repeat_ngram_size=3.Users should employ this model as a supplementary tool for review analysis rather than a complete replacement for human judgment.
Users (both direct and downstream) should be made aware of the risks, biases and limitations of the model.
Review the code below to get started with the model.
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch, re
# Load the model and tokenizer
model_id = "kangelamw/negative-reviews-into-actionable-insights" # Once pushed to Hub
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(
model_id,
torch_dtype=torch.float16, # Use float16 for efficiency
device_map="auto" # Automatically choose best device configuration
)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.eval()
# How to extract insights from a review
def get_emotion_label(text):
"""
Get the top 3 predicted emotions for a given text.
"""
# Tokenize text
tokens = tokenizer(text,
padding=True,
truncation=True,
max_length=128,
return_tensors="pt").to(model.device)
# Run inference
with torch.no_grad():
outputs = model(**tokens)
# Get top 3 predicted labels
probabilities = torch.nn.functional.softmax(outputs.logits, dim=1) # Convert logits to probabilities
top3_indices = torch.argsort(probabilities, descending=True)[0][:3] # Get top 3 indices
# Convert indices to emotion labels
top3_emotions = [emotion_labels[i] for i in top3_indices]
# Return as string...
emotions = ", ".join(top3_emotions)
return emotions
def create_prompt(stars, review_text, emotions):
return prompt = f"A customer left us a {stars}-star review: {review_text}. The customer feels {emotions}. Concisely, how can we best improve our services for this customer's experience? \n\nResponse: "
def clean_phi2_output(input_text, output_text):
"""
Extracts the response from the model output by removing the input prompt.
Works by detecting markers like "Answer:", "Response:", "###", or newline separation.
"""
# Normalize whitespace
input_norm = re.sub(r'\s+', ' ', input_text.strip())
output_norm = re.sub(r'\s+', ' ', output_text.strip())
# Look for common response markers
response_markers = [r"Answer:",
r"Response:",
r"###",
r"\n\n",
r"##Your task:",
r"<|Question|>",
r"<|Answer|>",
r"Instruction: ",
r"Response: ",
r"OUTPUT:"]
# Try to find the first occurrence of any marker
for marker in response_markers:
match = re.search(marker, output_norm, re.IGNORECASE)
if match:
return output_norm[match.end():].strip() # Extract everything after the marker
# If no marker is found, attempt a basic subtraction
cleaned_output = re.sub(re.escape(input_norm), '', output_norm, flags=re.IGNORECASE).strip()
return cleaned_output if cleaned_output else output_norm # Default to original if no cleaning was effective
# ===== SINGLE USE: ===== #
inputs = tokenizer(prompt, return_tensors="pt").to(device)
# Generate response
with torch.no_grad():
outputs = model.generate(
inputs.input_ids,
max_new_tokens=1000,
temperature=0.5, # Adjust for creativity vs consistency
top_p=0.9,
top_k=50
do_sample=True,
pad_token_id=tokenizer.eos_token_id # Important
)
output = tokenizer.decode(output[0], skip_special_tokens=True)
print(clean_phi2_output(prompt, output))
# ===== BATCHED USE: ===== #
batch_responses = []
for j in range(len(outputs)):
try:
full_text = tokenizer.decode(outputs[j], skip_special_tokens=True)
prompt_text = tokenizer.decode(inputs['input_ids'][j], skip_special_tokens=True)
response = full_text.replace(prompt_text, "", 1).strip()
response = clean_response(response)
except Exception as e:
response = "ERROR_GENERATING_RESPONSE"
print(f"Error: {e}")
batch_responses.append(response) # You can check the repo for the full batched code, but this is the important part for cleaning up the responses by batch, the single-use one above (clean_phi2_output) was more of a monkey patch for testing.
This is the full train data that I have: 15k Train
This is the one it was trained on: 999 Train
<!-- This should link to a Dataset Card, perhaps with a short stub of information on what the training data is all about as well as documentation related to data pre-processing or additional filtering. -->import re
# Define punctuation to keep
keep_punctuation = {".", ",", "!", "?", "'"} # 'It was great.' vs 'It was great!!!' makes a difference.
# Cleaning function
def clean_text(review):
review = review.lower() # Lowercase, I'd say optional.
# Remove unwanted characters (keep only letters, numbers, and whitelisted punctuation)
cleaned_text = "".join(char if char.isalnum() or char in keep_punctuation or char.isspace() else " " for char in review)
# Remove extra spaces (from removed characters)
cleaned_text = re.sub(r'\s+', ' ', cleaned_text).strip()
return cleaned_text
This is the full test data that I have: 3k Test
This is the one it was trained on: 333 Test
The model's performance was measured using several NLP evaluation metrics (the baseline is mistral's output):
During testing, the BERTScore is always great. This just means that the output was using similar words and the model understands what it has to talk about. The BLEURT is always low, so it's talking about something almost entirely different (tries making up stories about the review = it is missing the meaning). Low METEOR solidifies this standpoint.
Always consider ALL the metrics. They are useless by themselves.
| Initial performance | bleurt | bertscore | meteor |
|---|---|---|---|
| mean | -0.756606 | 0.838373 | 0.2222 |
| median | -0.70085 | 0.8395 | 0.2222 |
| Fine-tuned performance | bleurt | bertscore | meteor |
|---|---|---|---|
| mean | -0.376466 | 0.885482 | 0.2318 |
| median | -0.33835 | 0.8873 | 0.2318 |
Check the repo itself's README if you want to see some visuals :)
Phi-2's semantic understanding of what needs to be done has improved. The fine-tuning process has led to better semantic alignment and contextual similarity, as shown by the improvements in BLEURT, BERTScore, and METEOR.
While Phi-2 now mirrors Mistral’s responses more effectively, there is still room for improvement. BLEURT is still negative, indicating that some fine-grained semantic details might be missing. Further refinements could help Phi-2 align even more closely with Mistral’s outputs.
This is great in a way that maybe an extra round of training with 1-2k more rows per training would get it on par with Mistral's. I have about 14k/2k of train/test unused.
<!-- ## Model Examination [optional] <!-- Relevant interpretability work for the model goes here -->[More Information Needed] -->
Carbon emissions can be estimated using the Machine Learning Impact calculator presented in Lacoste et al. (2019).
This fine-tuning process used parameter-efficient methods (QLoRA) specifically to reduce computational requirements and environmental impact. The significantly reduced resource usage compared to full model fine-tuning and inference represents a more sustainable approach to applied model development.
<!-- ## Technical Specifications [optional] ### Model Architecture and Objective [More Information Needed] ### Compute Infrastructure [More Information Needed] #### Hardware [More Information Needed] #### Software [More Information Needed] ## Citation [optional] <!-- If there is a paper or blog post introducing the model, the APA and Bibtex information for that should go in this section. --> <!-- **BibTeX:** [More Information Needed] **APA:** [More Information Needed] ## Glossary [optional] <!-- If relevant, include terms and calculations in this section that can help readers understand the model or model card. --> <!-- [More Information Needed] ## More Information [optional] [More Information Needed] ## Model Card Authors [optional] [More Information Needed] -->For the hours, this is a bootcamp project, I've never really fine-tuned a model or ran inference before this one. Please don't use it by itself: fix it/fine-tune it further and as needed before using on prod.