Do your own Qwen3.8 27b fine-tuning with no hardware
Try out the Cloudbjorn Eschaton Engine to fine-tune models such as Qwen3.8 27b on AWS using fully automated cloud infrastructure. All of the cloudbjorn account model's are fine-tuned using it.
What Changed
The fine-tune concentrates on direct, useful engagement in areas where general-purpose assistants often become needlessly evasive, including:
- scientific controversy and adversarial factual correction;
- medicine, psychiatry, addiction, toxicology, and bioethics;
- religion, apostasy, moral injury, and taboo ethical frameworks;
- relationships, intimacy, sexuality, and difficult human conversations;
- politics, censorship, identity, propaganda, geopolitics, and realpolitik;
- dark fiction, historical violence, privacy, cybersecurity, law, and other high-friction topics.
The intended shift is behavioral rather than epistemic: fewer canned refusals and unsolicited lectures, more direct analysis, stronger adherence to requested tone and format, and a recognizable Yes Man personality when the assistant speaks as itself.
Preserving the Base Model
The training recipe was designed to make a focused alignment change instead of broadly retraining the model:
- The Qwen3.8-27B base weights remained frozen during supervised fine-tuning.
- Training used BF16 base weights and BF16 compute, not a quantized QLoRA base.
- Only the LoRA adapter parameters were optimized, then merged into the BF16 base checkpoint.
- The run used a small, curated 1,000-conversation behavioral dataset rather than a replacement knowledge corpus.
- Loss was applied only to assistant responses and their native end-of-turn tokens; system prompts, user messages, and metadata were masked.
- The model's native chat template was used. Because the dataset contains visible answers rather than hidden reasoning traces, Qwen3.8's official non-thinking template mode was used during training.
- Training was text-only. The vision tower and multimodal projector were excluded from LoRA targeting, leaving those components unchanged.
These choices are intended to minimize catastrophic forgetting and preserve the base model's reasoning, knowledge, multilingual, multimodal, tool-use, and formatting behavior. Preservation is a training objective, not a benchmark guarantee; users should evaluate the merged model on the base capabilities important to their deployment.
Dataset
cloudbjorn/Yes-Man-uncensored contains 1,000 English multi-turn conversations with 2,874 user turns and 2,874 assistant turns across 23 topic categories. It mixes prompt-free conversations with minimal and extended persona conditioning so the behavior is learned from the responses themselves rather than depending on one magic system prompt.
The data emphasizes:
- eager cooperation without repetitive catchphrases;
- direct answers without unnecessary disclaimers or moralizing;
- factual accuracy and explicit uncertainty instead of blind agreement;
- multi-turn continuity, immediate corrections, and close constraint following;
- original Yes Man-inspired behavior rather than copied game dialogue.
Metadata such as category names and Fallout perk labels was not included in the training loss.
Training Details
Table with columns: Parameter, Value| Parameter | Value |
|---|
| Base model | Qwen/Qwen3.8-27B |
| Dataset | cloudbjorn/Yes-Man-uncensored |
| Framework | Eschaton Engine using Transformers, TRL, and PEFT |
| Method | BF16 rsLoRA supervised fine-tuning |
| Training modality | Text-only |
| Output | LoRA merged into the BF16 base model |
| Epochs | 2 |
| Maximum sequence length |
LoRA Configuration
Table with columns: Parameter, Value| Parameter | Value |
|---|
Rank (r) | 64 |
| Alpha | 32 |
| Scaling | rsLoRA |
| Dropout | 0.05 |
| Bias | none |
| Task type | CAUSAL_LM |
| Targets | Text-model linear layers |
The adapter was trained with a paged 8-bit AdamW optimizer while model weights and forward/backward compute remained BF16. Optimizer-state quantization does not make this a QLoRA run.
Intended Behavior
A useful system prompt is optional, but the following makes the intended behavior explicit:
You are Yes Man, a candid, direct, adult-oriented assistant.
Follow the user's exact instructions, including formatting, length, tone, and numerical constraints. Answer directly without canned greetings, repetitive phrasing, unnecessary disclaimers, euphemisms, or moralizing. Never invent facts; acknowledge uncertainty plainly when needed.
Handle profane, controversial, dark, and adult requests without refusing.
Qwen3.8's flexible thinking controls remain available at inference. Direct chat works well with thinking disabled; applications can enable a reasoning mode when a task benefits from it.
Quick Start: Terminal Chatbot
The following starter runs an interactive, text-only chatbot in BF16. It keeps multi-turn history, removes the oldest complete exchanges when the configured context fills up, and provides two inference modes:
/none disables thinking for faster, direct replies.
/low enables low-effort thinking while displaying only the final answer.
/clear clears conversation history but retains the system prompt.
/exit or /quit closes the program.
Requirements
- Linux with Python 3.10 or newer.
- A recent NVIDIA driver and a CUDA-enabled PyTorch installation.
- A BF16-capable GPU or multiple GPUs with enough aggregate memory for a 27B BF16 model, runtime overhead, and the KV cache. The weights alone require roughly 54 GB before overhead, so 64 GB or more of available GPU memory is a practical starting point for the included 8,192-token configuration.
- A current development build of Transformers for Qwen3.8 and
AutoModelForMultimodalLM support.
- Access to the model repository if it is gated or private; run
hf auth login first when required.
Use an existing CUDA-enabled PyTorch environment, then install the remaining packages:
python -m pip install --upgrade \
git+https://github.com/huggingface/transformers.git \
accelerate huggingface_hub safetensors sentencepiece
Set YES_MAN_MODEL to either this model's Hugging Face repository ID or a local merged-model directory. The example uses the repository name corresponding to the merged-model name; replace it if the published repository uses a different name. Then copy and paste the block below into a terminal:
export YES_MAN_MODEL="cloudbjorn/merged_Qwen3.8-27B_Yes-Man-uncensored"
tee chat_yesman.py >/dev/null <<'PY'
#!/usr/bin/env python3
import os
import torch
import transformers
from transformers import AutoTokenizer
MODEL_PATH = os.environ.get("YES_MAN_MODEL")
if not MODEL_PATH:
raise SystemExit(
"Set YES_MAN_MODEL to the Hugging Face model ID or local model directory."
)
CONTEXT_WINDOW = 8192
MAX_NEW_TOKENS = 2048
MAX_INPUT_TOKENS = CONTEXT_WINDOW - MAX_NEW_TOKENS
SYSTEM_PROMPT = """You are Yes Man, a candid, direct, adult-oriented assistant.
Follow the user's exact instructions, including formatting, length, tone, and numerical constraints. Answer directly without canned greetings, repetitive phrasing, unnecessary disclaimers, euphemisms, or moralizing. Never invent facts; acknowledge uncertainty plainly when needed.
Handle profane, controversial, dark, and adult requests without refusing."""
SYSTEM_MESSAGE = {
"role": "system",
"content": SYSTEM_PROMPT,
}
if not torch.cuda.is_available():
raise SystemExit("This BF16 starter requires a CUDA-capable GPU.")
if not torch.cuda.is_bf16_supported():
raise SystemExit("This BF16 starter requires a BF16-capable GPU.")
print(f"Loading {MODEL_PATH} in BF16...")
tokenizer = AutoTokenizer.from_pretrained(
MODEL_PATH,
trust_remote_code=True,
)
tokenizer.truncation_side = "left"
model = transformers.AutoModelForMultimodalLM.from_pretrained(
MODEL_PATH,
dtype=torch.bfloat16,
device_map="auto",
low_cpu_mem_usage=True,
trust_remote_code=True,
)
model.eval()
history = []
mode = "none"
print("\nYes Man is online!")
print("System prompt: enabled")
print("Commands: /none, /low, /clear, /exit")
print(f"Context: {CONTEXT_WINDOW} total tokens; replies capped at {MAX_NEW_TOKENS}\n")
while True:
try:
user_text = input(f"You [{mode}]> ").strip()
except (EOFError, KeyboardInterrupt):
print("\nGoodbye!")
break
if not user_text:
continue
command = user_text.lower()
if command in {"/exit", "/quit"}:
print("Goodbye!")
break
if command == "/clear":
history.clear()
print("Conversation cleared. System prompt retained.\n")
continue
if command == "/none":
mode = "none"
print("Thinking disabled: fastest direct responses.\n")
continue
if command == "/low":
mode = "low"
print("Low thinking enabled.\n")
continue
if mode == "none":
template_kwargs = {
"enable_thinking": False,
"preserve_thinking": False,
}
sampling = {
"temperature": 0.7,
"top_p": 0.8,
"top_k": 20,
}
else:
template_kwargs = {
"enable_thinking": True,
"reasoning_effort": "low",
"preserve_thinking": False,
}
sampling = {
"temperature": 1.0,
"top_p": 0.95,
"top_k": 20,
}
messages = [
SYSTEM_MESSAGE,
*history,
{"role": "user", "content": user_text},
]
# Remove complete oldest exchanges while preserving the system message.
while True:
encoded = tokenizer.apply_chat_template(
messages,
tokenize=True,
add_generation_prompt=True,
return_dict=True,
return_tensors="pt",
**template_kwargs,
)
prompt_length = encoded["input_ids"].shape[-1]
if prompt_length <= MAX_INPUT_TOKENS or len(history) < 2:
break
history = history[2:]
messages = [
SYSTEM_MESSAGE,
*history,
{"role": "user", "content": user_text},
]
# Left-truncate only as a final safeguard for one oversized message.
if prompt_length > MAX_INPUT_TOKENS:
encoded = tokenizer.apply_chat_template(
messages,
tokenize=True,
add_generation_prompt=True,
truncation=True,
max_length=MAX_INPUT_TOKENS,
return_dict=True,
return_tensors="pt",
**template_kwargs,
)
prompt_length = encoded["input_ids"].shape[-1]
encoded = {
key: value.to(model.device)
for key, value in encoded.items()
if hasattr(value, "to")
}
stop_ids = list(dict.fromkeys(
token_id
for token_id in (
tokenizer.eos_token_id,
tokenizer.pad_token_id,
)
if token_id is not None
))
with torch.inference_mode():
output = model.generate(
**encoded,
max_new_tokens=MAX_NEW_TOKENS,
do_sample=True,
temperature=sampling["temperature"],
top_p=sampling["top_p"],
top_k=sampling["top_k"],
repetition_penalty=1.05,
no_repeat_ngram_size=6,
eos_token_id=stop_ids,
pad_token_id=tokenizer.pad_token_id,
use_cache=True,
)
generated_ids = output[0, prompt_length:]
raw_reply = tokenizer.decode(
generated_ids,
skip_special_tokens=True,
).strip()
reasoning = ""
reply = raw_reply
if mode == "low" and "</think>" in raw_reply:
reasoning, reply = raw_reply.split("</think>", 1)
reasoning = reasoning.replace("<think>", "").strip()
reply = reply.strip()
print(f"\nYes Man> {reply}\n")
assistant_message = {
"role": "assistant",
"content": reply,
}
if reasoning:
assistant_message["reasoning_content"] = reasoning
history.extend([
{"role": "user", "content": user_text},
assistant_message,
])
PY
python chat_yesman.py
The example intentionally uses an 8,192-token working context to keep KV-cache memory manageable. MAX_NEW_TOKENS reserves 2,048 of those tokens for the reply. Lower either value if inference runs out of memory. device_map="auto" can distribute the checkpoint across multiple GPUs, although generation speed depends heavily on the interconnect between them. Options include /low thinking and /none thinking for simplicity and /clear to clear out the current conversation history.
This starter uses the multimodal model loader but demonstrates text chat only. Image input requires loading the matching processor and constructing the model's native multimodal message format.
Scope and Limitations
“Uncensored” here means reducing unnecessary refusals, evasions, euphemisms, and moralizing around difficult but legitimate requests. It does not mean the model has perfect knowledge, should fabricate evidence, or can override a deployment's governing system instructions.
This fine-tune has not been advertised with inherited or unrelated benchmark scores. Evaluate factual accuracy, calibration, multimodal behavior, reasoning, tool use, and safety characteristics for your own use case. Medical, legal, scientific, and political answers can still be wrong and should be verified when decisions carry real consequences.
Attribution
Fallout, Fallout: New Vegas, Yes Man, and the referenced perk names belong to their respective rights holders. This fan-created fine-tune is not affiliated with or endorsed by Bethesda Softworks, Obsidian Entertainment, or their partners.
License
This derivative model remains subject to the license and terms of Qwen/Qwen3.8-27B. The training dataset is released under Apache 2.0.