File size: 6,671 Bytes
e55c8a4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#!/usr/bin/env python
"""
Environment check for cpt_gemma4_sinhala.py (Unsloth + Gemma 4 E4B on an A40).

    python check_env.py            # quick checks (no model download)
    python check_env.py --model    # also loads Gemma 4 E4B, adds LoRA, runs 1 train step (~16 GB download)

Exit code 0 = everything passed.
"""
import argparse
import importlib
import importlib.metadata as md
import subprocess
import sys

OK, BAD, WARN = "[ OK ]", "[FAIL]", "[WARN]"
failures = []


def report(tag, msg):
    print(f"{tag} {msg}")
    if tag == BAD:
        failures.append(msg)


def ver(pkg):
    try:
        return md.version(pkg)
    except md.PackageNotFoundError:
        return None


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--model", action="store_true", help="load model + 1 training step")
    ap.add_argument("--model_name", default="unsloth/gemma-4-E4B")
    args = ap.parse_args()

    print(f"Python {sys.version.split()[0]}")

    # 1. GPU / torch  (import unsloth FIRST, as in the training script)
    try:
        import unsloth  # noqa: F401
        report(OK, f"unsloth imported (v{ver('unsloth')})")
    except Exception as e:  # noqa: BLE001
        report(BAD, f"unsloth import failed: {type(e).__name__}: {e}")

    try:
        import torch
        report(OK, f"torch {torch.__version__}, CUDA build {torch.version.cuda}")
        if torch.cuda.is_available():
            p = torch.cuda.get_device_properties(0)
            report(OK, f"GPU: {p.name}, {p.total_memory / 1024**3:.1f} GB, bf16={torch.cuda.is_bf16_supported()}")
        else:
            report(BAD, "torch.cuda.is_available() is False (Unsloth needs a GPU)")
    except Exception as e:  # noqa: BLE001
        report(BAD, f"torch import failed: {e}")

    # 2. Pinned versions
    transformers_v = ver("transformers")
    if transformers_v == "5.5.0":
        report(OK, "transformers 5.5.0")
    else:
        report(BAD, f"transformers is {transformers_v}, expected 5.5.0 "
                    "(re-run: pip install --no-deps transformers==5.5.0)")

    tok_v = ver("tokenizers")
    try:
        from packaging.version import Version
        good = tok_v and Version("0.22.0") <= Version(tok_v) <= Version("0.23.0")
    except Exception:  # noqa: BLE001
        good = False
    report(OK if good else BAD, f"tokenizers {tok_v} (need >=0.22.0,<=0.23.0)")

    hub_v = ver("huggingface_hub")
    try:
        from packaging.version import Version
        good = hub_v and Version("1.5.0") <= Version(hub_v) < Version("2.0")
    except Exception:  # noqa: BLE001
        good = False
    report(OK if good else BAD, f"huggingface_hub {hub_v} (need >=1.5.0,<2.0)")

    # 3. Other packages the script imports
    for pkg in ["trl", "peft", "datasets", "pandas", "accelerate", "bitsandbytes", "timm", "hf_transfer"]:
        v = ver(pkg)
        report(OK if v else BAD, f"{pkg} {v or 'NOT INSTALLED'}")

    # 4. Imports the training script actually does
    for stmt in ["from unsloth import FastModel",
                 "from trl import SFTConfig, SFTTrainer",
                 "from datasets import Dataset",
                 "from huggingface_hub import hf_hub_download"]:
        try:
            exec(stmt, {})  # noqa: S102
            report(OK, stmt)
        except Exception as e:  # noqa: BLE001
            report(BAD, f"{stmt} -> {type(e).__name__}: {e}")

    # 5. Do the SFTConfig args used by the script exist in this TRL version?
    try:
        from trl import SFTConfig
        import inspect
        fields = set(inspect.signature(SFTConfig.__init__).parameters)
        for a in ["max_length", "packing", "dataset_text_field", "bf16", "optim",
                  "eval_strategy", "warmup_ratio"]:
            report(OK if a in fields else BAD, f"SFTConfig accepts '{a}'")
    except Exception as e:  # noqa: BLE001
        report(WARN, f"could not inspect SFTConfig: {e}")

    # 6. pip's own dependency check (informational: --no-deps installs can show conflicts)
    out = subprocess.run([sys.executable, "-m", "pip", "check"], capture_output=True, text=True).stdout.strip()
    if out and "No broken requirements" not in out:
        print(f"{WARN} pip check reported:\n{out}\n       (conflicts about transformers/tokenizers are often "
              "harmless with --no-deps; only worry if the model test below fails)")
    else:
        report(OK, "pip check: no broken requirements")

    # 7. Optional end-to-end test
    if args.model:
        try:
            import torch
            from unsloth import FastModel
            from datasets import Dataset
            from trl import SFTConfig, SFTTrainer

            print(f"\nLoading {args.model_name} ...")
            model, tok = FastModel.from_pretrained(
                model_name=args.model_name, dtype=None, max_seq_length=512,
                load_in_4bit=False, full_finetuning=False)
            report(OK, "model + tokenizer loaded")

            model = FastModel.get_peft_model(
                model, finetune_vision_layers=False, finetune_language_layers=True,
                finetune_attention_modules=True, finetune_mlp_modules=True,
                r=8, lora_alpha=8, lora_dropout=0, bias="none", use_rslora=True, random_state=3407)
            report(OK, "LoRA attached (use_rslora accepted)")

            sin = "ශ්‍රී ලංකාව ඉන්දියන් සාගරයේ පිහිටි ද්වීපයකි."
            ids = tok(sin, add_special_tokens=False)["input_ids"]
            print(f"       Sinhala sample -> {len(ids)} tokens for {len(sin)} chars")

            ds = Dataset.from_dict({"text": [(sin + "\n") * 20] * 16})
            cfg = SFTConfig(output_dir="/tmp/envcheck", dataset_text_field="text", max_length=512,
                            packing=True, per_device_train_batch_size=2, gradient_accumulation_steps=1,
                            max_steps=2, learning_rate=5e-5, bf16=True, optim="adamw_8bit",
                            logging_steps=1, save_strategy="no", report_to="none")
            tr = SFTTrainer(model=model, tokenizer=tok, train_dataset=ds, args=cfg)
            tr.train()
            report(OK, f"2 training steps ran; peak VRAM {torch.cuda.max_memory_reserved() / 1024**3:.1f} GB")
        except Exception as e:  # noqa: BLE001
            import traceback
            traceback.print_exc()
            report(BAD, f"model test failed: {type(e).__name__}: {e}")

    print("\n" + ("ALL CHECKS PASSED" if not failures else f"{len(failures)} PROBLEM(S):"))
    for f in failures:
        print("  -", f)
    sys.exit(1 if failures else 0)


if __name__ == "__main__":
    main()