#!/usr/bin/env python3 """Phase 0 smoke checks for Qwen/Qwen3.6-27B. Default mode avoids downloading full weights. Use --mode load only on the GPU host after confirming disk and VRAM are sufficient. """ from __future__ import annotations import argparse import json import sys from typing import Any def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser() parser.add_argument("--model", default="Qwen/Qwen3.6-27B") parser.add_argument("--mode", choices=["config", "load"], default="config") parser.add_argument("--dtype", choices=["auto", "bfloat16", "float16", "float32"], default="bfloat16") parser.add_argument("--device-map", default="auto") parser.add_argument("--trust-remote-code", action="store_true", default=True) parser.add_argument("--no-trust-remote-code", dest="trust_remote_code", action="store_false") return parser.parse_args() def print_json(payload: dict[str, Any]) -> None: print(json.dumps(payload, indent=2, sort_keys=True, default=str)) def dtype_from_name(name: str): if name == "auto": return "auto" import torch return { "bfloat16": torch.bfloat16, "float16": torch.float16, "float32": torch.float32, }[name] def main() -> int: args = parse_args() try: import transformers from transformers import AutoConfig, AutoTokenizer except Exception as exc: print(f"Failed to import transformers: {exc!r}", file=sys.stderr) return 1 config = AutoConfig.from_pretrained(args.model, trust_remote_code=args.trust_remote_code) tokenizer = AutoTokenizer.from_pretrained(args.model, trust_remote_code=args.trust_remote_code) chat_template = getattr(tokenizer, "chat_template", "") or "" summary: dict[str, Any] = { "model": args.model, "transformers_version": transformers.__version__, "architectures": getattr(config, "architectures", None), "model_type": getattr(config, "model_type", None), "torch_dtype": str(getattr(config, "torch_dtype", None)), "vocab_size": getattr(config, "vocab_size", None), "eos_token": tokenizer.eos_token, "pad_token": tokenizer.pad_token, "has_think_template": "" in chat_template and "" in chat_template, "has_tool_call_template": "" in chat_template, "chat_template_chars": len(chat_template), } if args.mode == "config": print_json(summary) return 0 import torch candidate_class_names = [ "AutoModelForMultimodalLM", "AutoModelForImageTextToText", "AutoModelForVision2Seq", "AutoModelForCausalLM", ] errors: list[str] = [] model = None loaded_with = None for class_name in candidate_class_names: model_cls = getattr(transformers, class_name, None) if model_cls is None: errors.append(f"{class_name}: not present in transformers {transformers.__version__}") continue try: model = model_cls.from_pretrained( args.model, torch_dtype=dtype_from_name(args.dtype), device_map=args.device_map, trust_remote_code=args.trust_remote_code, ) loaded_with = class_name break except Exception as exc: errors.append(f"{class_name}: {exc!r}") if model is None: summary["load_errors"] = errors print_json(summary) return 2 messages = [ {"role": "system", "content": "You are validating an authorized security research training environment."}, {"role": "user", "content": "Return one sentence confirming that the model can format a thinking response."}, ] prompt = tokenizer.apply_chat_template( messages, tokenize=False, add_generation_prompt=True, enable_thinking=True, ) inputs = tokenizer(prompt, return_tensors="pt") device = next(model.parameters()).device inputs = {key: value.to(device) for key, value in inputs.items()} with torch.no_grad(): output_ids = model.generate(**inputs, max_new_tokens=96, do_sample=False) decoded = tokenizer.decode(output_ids[0][inputs["input_ids"].shape[-1] :], skip_special_tokens=False) summary.update( { "loaded_with": loaded_with, "device": str(device), "cuda_available": torch.cuda.is_available(), "cuda_device_count": torch.cuda.device_count(), "generated_chars": len(decoded), "generated_preview": decoded[:500], } ) print_json(summary) return 0 if __name__ == "__main__": raise SystemExit(main())