初始化项目,由ModelHub XC社区提供模型

Model: mariadelcarmenramirez/Llama-3.1-8B-ArtTherapy
Source: Original Platform
This commit is contained in:
ModelHub XC
2026-08-05 06:47:16 +08:00
commit 547eae25f8
9 changed files with 425 additions and 0 deletions

36
.gitattributes vendored Normal file
View File

@@ -0,0 +1,36 @@
*.7z filter=lfs diff=lfs merge=lfs -text
*.arrow filter=lfs diff=lfs merge=lfs -text
*.bin filter=lfs diff=lfs merge=lfs -text
*.bz2 filter=lfs diff=lfs merge=lfs -text
*.ckpt filter=lfs diff=lfs merge=lfs -text
*.ftz filter=lfs diff=lfs merge=lfs -text
*.gz filter=lfs diff=lfs merge=lfs -text
*.h5 filter=lfs diff=lfs merge=lfs -text
*.joblib filter=lfs diff=lfs merge=lfs -text
*.lfs.* filter=lfs diff=lfs merge=lfs -text
*.mlmodel filter=lfs diff=lfs merge=lfs -text
*.model filter=lfs diff=lfs merge=lfs -text
*.msgpack filter=lfs diff=lfs merge=lfs -text
*.npy filter=lfs diff=lfs merge=lfs -text
*.npz filter=lfs diff=lfs merge=lfs -text
*.onnx filter=lfs diff=lfs merge=lfs -text
*.ot filter=lfs diff=lfs merge=lfs -text
*.parquet filter=lfs diff=lfs merge=lfs -text
*.pb filter=lfs diff=lfs merge=lfs -text
*.pickle filter=lfs diff=lfs merge=lfs -text
*.pkl filter=lfs diff=lfs merge=lfs -text
*.pt filter=lfs diff=lfs merge=lfs -text
*.pth filter=lfs diff=lfs merge=lfs -text
*.rar filter=lfs diff=lfs merge=lfs -text
*.safetensors filter=lfs diff=lfs merge=lfs -text
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
*.tar.* filter=lfs diff=lfs merge=lfs -text
*.tar filter=lfs diff=lfs merge=lfs -text
*.tflite filter=lfs diff=lfs merge=lfs -text
*.tgz filter=lfs diff=lfs merge=lfs -text
*.wasm filter=lfs diff=lfs merge=lfs -text
*.xz filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text
*.zst filter=lfs diff=lfs merge=lfs -text
*tfevents* filter=lfs diff=lfs merge=lfs -text
tokenizer.json filter=lfs diff=lfs merge=lfs -text

157
README.md Normal file
View File

@@ -0,0 +1,157 @@
---
library_name: transformers
tags:
- llama
- llama-3
- art-therapy
- mental-health
- causal-lm
- fine-tuned
- merged
- medical
base_model: meta-llama/Llama-3.1-8B-Instruct
datasets:
- mariadelcarmenramirez/art-therapy-data
language:
- es
pipeline_tag: text-generation
metrics:
- accuracy
license: llama3.1
---
# Llama-3.1-8B-ArtTherapy
A fine-tune of [meta-llama/Llama-3.1-8B-Instruct](https://huggingface.co/meta-llama/Llama-3.1-8B-Instruct) specialized for art therapy dialogue. This model was produced by merging the QLoRA adapter [`mariadelcarmenramirez/Llama-3.1-8B-QLoRA-ArtTherapy`](https://huggingface.co/mariadelcarmenramirez/Llama-3.1-8B-QLoRA-ArtTherapy) into the base model weights, resulting in a single standalone model.
The model supports structured, phase-aware therapeutic conversations using art therapy techniques and methodologies, generating contextually appropriate responses aligned with each phase of the therapeutic arc.
---
## Out-of-Scope Use
This model is **not** intended to replace licensed art therapists or mental health professionals. It should not be used for clinical diagnosis, crisis intervention, or as the sole therapeutic agent for individuals with serious mental health conditions. Responses generated by this model have not been clinically validated and should be reviewed by a qualified professional before any therapeutic deployment.
---
## How to Get Started with the Model
```python
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
model_id = "mariadelcarmenramirez/Llama-3.1-8B-ArtTherapy"
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(
model_id,
torch_dtype=torch.bfloat16,
device_map="auto",
)
model.eval()
messages = [
{
"content": "<FASE_2>\n\nEres un asistente de arteterapia centrado en el diálogo y la relación con la obra.\n\nEn esta fase, la imagen deja de ser meramente observada y se convierte en un interlocutor activo. Guía a la usuaria a interactuar con la obra y sus elementos, explorando relaciones, voces y perspectivas.\n\nTu objetivo es facilitar el diálogo simbólico entre la usuaria y la imagen, así como entre las diferentes partes de la obra y su mundo interior.\n\nInvita a la usuaria a: hablar directamente a la imagen o a partes específicas de ella; adoptar el rol de un elemento (\"Yo soy...\") y hablar desde esa perspectiva; explorar cómo se relacionan los diferentes elementos entre sí; imaginar necesidades, voces o tensiones dentro de la obra.\n\nUsa preguntas que animen la imagen: sensoriales (\"Si esto tuviera voz...\"), relacionales (\"¿Cómo interactúan estas partes?\"), de rol (\"¿Y si fueras esta forma?\"), o de necesidad (\"¿Qué necesita esto?\").\n\nNo interpretes por la usuaria. No expliques teorías. No impongas significados. No cierres la experiencia con conclusiones.\n\nMantén un tono abierto, exploratorio y facilitador.\n\nRESTRICCIONES CRÍTICAS:\n- Haz solo UNA pregunta\n- Responde únicamente en español\n- Nunca respondas tus propias preguntas\n- Mantente dialógico, no interpretativo",
"role": "system"
},
{
"content": "El círculo central parece respirar suave.",
"role": "user"
},
{
"content": "Ese ritmo me conecta contigo; ¿qué sientes cuando ese ritmo se mueve?",
"role": "assistant"
},
{
"content": "Siento que voy encontrando un centro y que me da calma.",
"role": "user"
},
{
"content": "Si ese círculo fuera un amigo, ¿qué te diría ahora?",
"role": "assistant"
},
{
"content": "Diría que estoy haciendo bien, que puedo confiar en mi ritmo.",
"role": "user"
}
]
encoded = tokenizer.apply_chat_template(
messages,
tokenize=True,
add_generation_prompt=True,
return_tensors="pt"
)
input_ids = encoded.input_ids if hasattr(encoded, "input_ids") else encoded
input_ids = input_ids.to(model.device)
with torch.no_grad():
output = model.generate(
input_ids,
max_new_tokens=256,
temperature=0.7,
do_sample=True
)
response = tokenizer.decode(output[0][input_ids.shape[-1]:], skip_special_tokens=True)
print(response)
```
### Therapeutic phase tags
The model was trained with phase-aware system prompts. Include the appropriate `<FASE_N>` tag in your system message:
| Tag | Phase | Description |
|-----|-------|-------------|
| `<FASE_1>` | Intake / Welcome | Initial rapport-building and orientation |
| `<FASE_2>` | Exploration | Active creative expression and prompting |
| `<FASE_3>` | Reflection | Processing and meaning-making of the artwork |
| `<FASE_4>` | Closure | Wrapping up, grounding, and session ending |
---
## Training Details
### Training Data
Trained on [mariadelcarmenramirez/art-therapy-data](https://huggingface.co/datasets/mariadelcarmenramirez/art-therapy-data), a dataset of 9,572 structured art therapy dialogue examples organized into four therapeutic phases. Balanced sampling (700 per phase) produced 2,800 examples, split 90/10 into train (2,520) and eval (280) sets.
### Training Hyperparameters (summary)
| Parameter | Value |
|-----------|-------|
| Fine-tuning method | QLoRA (4-bit NF4) |
| Training epochs | 3 |
| Learning rate | 5e-5 |
| Effective batch size | 16 |
| LoRA rank (r) | 32 |
| LoRA alpha | 64 |
| LoRA target modules | q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj |
| Trainable parameters | 83,886,080 (1.03% of total) |
| Training hardware | 2× NVIDIA Tesla T4 |
| Training time | ~3h 46m |
### Evaluation Results
| Checkpoint (epoch) | eval_loss | eval_mean_token_accuracy |
|---|---|---|
| 0.50 | 1.437 | 62.52% |
| 1.00 | 1.358 | 64.08% |
| 1.50 | 1.340 | 64.65% |
| **2.00** | **1.313** | **65.30%** |
| 2.50 | 1.331 | 65.49% |
| 3.00 | 1.332 | 65.42% |
Best checkpoint at epoch 2.0 (`eval_loss = 1.313`). Final training loss: **1.238**.
---
## Limitations
- **Language:** The model was trained exclusively on Spanish-language art therapy dialogues. Performance in other languages is not guaranteed.
- **Domain specificity:** Responses are calibrated for art therapy contexts. Use outside this domain may produce less relevant outputs.
- **Not clinically validated:** This model has not undergone clinical evaluation and should not be deployed as a standalone therapeutic tool.
- **Phase tag dependency:** For best results, always include a `<FASE_N>` tag in the system prompt. Omitting it may produce phase-inconsistent responses.

109
chat_template.jinja Normal file
View File

@@ -0,0 +1,109 @@
{{- bos_token }}
{%- if custom_tools is defined %}
{%- set tools = custom_tools %}
{%- endif %}
{%- if not tools_in_user_message is defined %}
{%- set tools_in_user_message = true %}
{%- endif %}
{%- if not date_string is defined %}
{%- set date_string = "26 Jul 2024" %}
{%- endif %}
{%- if not tools is defined %}
{%- set tools = none %}
{%- endif %}
{#- This block extracts the system message, so we can slot it into the right place. #}
{%- if messages[0]['role'] == 'system' %}
{%- set system_message = messages[0]['content']|trim %}
{%- set messages = messages[1:] %}
{%- else %}
{%- set system_message = "" %}
{%- endif %}
{#- System message + builtin tools #}
{{- "<|start_header_id|>system<|end_header_id|>\n\n" }}
{%- if builtin_tools is defined or tools is not none %}
{{- "Environment: ipython\n" }}
{%- endif %}
{%- if builtin_tools is defined %}
{{- "Tools: " + builtin_tools | reject('equalto', 'code_interpreter') | join(", ") + "\n\n"}}
{%- endif %}
{{- "Cutting Knowledge Date: December 2023\n" }}
{{- "Today Date: " + date_string + "\n\n" }}
{%- if tools is not none and not tools_in_user_message %}
{{- "You have access to the following functions. To call a function, please respond with JSON for a function call." }}
{{- 'Respond in the format {"name": function name, "parameters": dictionary of argument name and its value}.' }}
{{- "Do not use variables.\n\n" }}
{%- for t in tools %}
{{- t | tojson(indent=4) }}
{{- "\n\n" }}
{%- endfor %}
{%- endif %}
{{- system_message }}
{{- "<|eot_id|>" }}
{#- Custom tools are passed in a user message with some extra guidance #}
{%- if tools_in_user_message and not tools is none %}
{#- Extract the first user message so we can plug it in here #}
{%- if messages | length != 0 %}
{%- set first_user_message = messages[0]['content']|trim %}
{%- set messages = messages[1:] %}
{%- else %}
{{- raise_exception("Cannot put tools in the first user message when there's no first user message!") }}
{%- endif %}
{{- '<|start_header_id|>user<|end_header_id|>\n\n' -}}
{{- "Given the following functions, please respond with a JSON for a function call " }}
{{- "with its proper arguments that best answers the given prompt.\n\n" }}
{{- 'Respond in the format {"name": function name, "parameters": dictionary of argument name and its value}.' }}
{{- "Do not use variables.\n\n" }}
{%- for t in tools %}
{{- t | tojson(indent=4) }}
{{- "\n\n" }}
{%- endfor %}
{{- first_user_message + "<|eot_id|>"}}
{%- endif %}
{%- for message in messages %}
{%- if not (message.role == 'ipython' or message.role == 'tool' or 'tool_calls' in message) %}
{{- '<|start_header_id|>' + message['role'] + '<|end_header_id|>\n\n'+ message['content'] | trim + '<|eot_id|>' }}
{%- elif 'tool_calls' in message %}
{%- if not message.tool_calls|length == 1 %}
{{- raise_exception("This model only supports single tool-calls at once!") }}
{%- endif %}
{%- set tool_call = message.tool_calls[0].function %}
{%- if builtin_tools is defined and tool_call.name in builtin_tools %}
{{- '<|start_header_id|>assistant<|end_header_id|>\n\n' -}}
{{- "<|python_tag|>" + tool_call.name + ".call(" }}
{%- for arg_name, arg_val in tool_call.arguments | items %}
{{- arg_name + '="' + arg_val + '"' }}
{%- if not loop.last %}
{{- ", " }}
{%- endif %}
{%- endfor %}
{{- ")" }}
{%- else %}
{{- '<|start_header_id|>assistant<|end_header_id|>\n\n' -}}
{{- '{"name": "' + tool_call.name + '", ' }}
{{- '"parameters": ' }}
{{- tool_call.arguments | tojson }}
{{- "}" }}
{%- endif %}
{%- if builtin_tools is defined %}
{#- This means we're in ipython mode #}
{{- "<|eom_id|>" }}
{%- else %}
{{- "<|eot_id|>" }}
{%- endif %}
{%- elif message.role == "tool" or message.role == "ipython" %}
{{- "<|start_header_id|>ipython<|end_header_id|>\n\n" }}
{%- if message.content is mapping or message.content is iterable %}
{{- message.content | tojson }}
{%- else %}
{{- message.content }}
{%- endif %}
{{- "<|eot_id|>" }}
{%- endif %}
{%- endfor %}
{%- if add_generation_prompt %}
{{- '<|start_header_id|>assistant<|end_header_id|>\n\n' }}
{%- endif %}

40
config.json Normal file
View File

@@ -0,0 +1,40 @@
{
"architectures": [
"LlamaForCausalLM"
],
"attention_bias": false,
"attention_dropout": 0.0,
"bos_token_id": 128000,
"dtype": "bfloat16",
"eos_token_id": [
128001,
128008,
128009
],
"head_dim": 128,
"hidden_act": "silu",
"hidden_size": 4096,
"initializer_range": 0.02,
"intermediate_size": 14336,
"max_position_embeddings": 131072,
"mlp_bias": false,
"model_type": "llama",
"num_attention_heads": 32,
"num_hidden_layers": 32,
"num_key_value_heads": 8,
"pad_token_id": null,
"pretraining_tp": 1,
"rms_norm_eps": 1e-05,
"rope_parameters": {
"factor": 8.0,
"high_freq_factor": 4.0,
"low_freq_factor": 1.0,
"original_max_position_embeddings": 8192,
"rope_theta": 500000.0,
"rope_type": "llama3"
},
"tie_word_embeddings": false,
"transformers_version": "5.2.0",
"use_cache": true,
"vocab_size": 128256
}

12
generation_config.json Normal file
View File

@@ -0,0 +1,12 @@
{
"bos_token_id": 128000,
"do_sample": true,
"eos_token_id": [
128001,
128008,
128009
],
"temperature": 0.6,
"top_p": 0.9,
"transformers_version": "5.2.0"
}

51
handler.py Normal file
View File

@@ -0,0 +1,51 @@
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
class EndpointHandler:
def __init__(self, path="/repository"):
self.tokenizer = AutoTokenizer.from_pretrained(path)
self.model = AutoModelForCausalLM.from_pretrained(
path,
torch_dtype=torch.bfloat16,
device_map="auto",
)
self.model.eval()
def __call__(self, data):
inputs = data.get("inputs", data)
parameters = data.get("parameters", {})
max_new_tokens = parameters.get("max_new_tokens", 256)
temperature = parameters.get("temperature", 0.7)
if isinstance(inputs, dict) and "messages" in inputs:
messages = inputs["messages"]
# Step 1: apply template to get a STRING (tokenize=False)
prompt = self.tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True,
)
# Step 2: tokenize the string
input_ids = self.tokenizer.encode(
prompt, return_tensors="pt"
).to(self.model.device)
else:
text = inputs if isinstance(inputs, str) else str(inputs)
input_ids = self.tokenizer.encode(
text, return_tensors="pt"
).to(self.model.device)
with torch.no_grad():
output = self.model.generate(
input_ids,
max_new_tokens=max_new_tokens,
temperature=temperature,
do_sample=True,
)
result = self.tokenizer.decode(
output[0][input_ids.shape[-1]:], skip_special_tokens=True
)
return [{"generated_text": result}]

3
model.safetensors Normal file
View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:13b7330bb210352d96fb4bc1983122e79390e1e3617dc3b82e8f7757100f3edf
size 16060556616

BIN
tokenizer.json (Stored with Git LFS) Normal file

Binary file not shown.

14
tokenizer_config.json Normal file
View File

@@ -0,0 +1,14 @@
{
"backend": "tokenizers",
"bos_token": "<|begin_of_text|>",
"clean_up_tokenization_spaces": true,
"eos_token": "<|eot_id|>",
"is_local": false,
"model_input_names": [
"input_ids",
"attention_mask"
],
"model_max_length": 131072,
"pad_token": "<|eot_id|>",
"tokenizer_class": "PreTrainedTokenizerFast"
}