Generate a fixed 512 px image with FLUX.2 Klein4B on a CPU desktop
Use the complete official FLUX.2 Klein4B distilled Diffusers bundle: transformer, Qwen3 text encoder, tokenizer, scheduler and VAE. Native CPU float32 generates one 512 × 512 PNG from a fixed original geometric prompt in four denoising steps. The configured prompt bound is 512 positions including its chat template; image latent positions are separate. This private educational experiment has unknown CPU fit, speed and image quality.
- Hardware
- Intel Core i5-12400 desktop, 8 inference threads, 64 GiB RAM
- Runtime
- Native Diffusers FLUX.2 Klein4B complete CPU float32 image pipeline diffusers0.37.1 source ad3a3afc3a4d3068bbb12f58129c855087ffc6d6; Transformers4.57.6; HFhub0.36.2; torch2.6.0+cpu; Python3.12 · CPU
- Model format
- Diffusers safetensors bundle · Whole native pipeline CPU float32; no CUDA/offload/quantization/custom kernel · Unquantized official bundle; selected complete CPU float32
- Workload
- 512 token context · 1 concurrent
Based on source documentation; this setup has not been executed by OpenTools. Memory: unknown. No compatible measurement available.
Read the complete setup guide
Before you start
- Use an owned Intel Core i5-12400 Ubuntu 24.04 x86_64 desktop with 64 GiB RAM, 80 GiB free disk and eight threads as planning allocations, not proven fit or minima.
- Review the actual Apache 2.0 grant for this exact 4B bundle and dependency licenses. This guide uses the distilled 4B checkpoint, not 9B/base/dev or a transformer-only single-file workflow.
- Use Python 3.12, torch 2.6 CPU, Diffusers 0.37.1, Transformers 4.57.6, Hugging Face Hub 0.36.2, Accelerate 1.12.0 and safetensors 0.7.0. Source metadata supports their version-range intersection; none has been installed or model-tested here. Save resolution and stop on pip check/import/shape errors.
- The private endpoint accepts only its fixed benign geometric prompt selector, no arbitrary prompts/images/URLs/files. Generated imagery still needs human inspection for prompt adherence, artifacts and appropriateness; no downstream suitability is promised.
Exact model and requirements
- Artifact:
- Black Forest Labs / FLUX.2 Klein4B distilled complete Diffusers bundle · checkpoint black-forest-labs/FLUX.2-klein-4B
- Publisher revision:
- e7b7dc27f91deacad38e78976d1f2b499d76a294
- Artifact digest:
- A multi-file pipeline has no single publisher aggregate byte digest. Each of19 required files is independently bound in the reader manifest by publisher LFS SHA256 or exact Git blob SHA1.
- Download size:
- 14.87 GiB
- Memory requirement (unknown):
- Unknown — No measured full-process peak for full FP32 transformer/text encoder/VAE plus512image activations.
- System RAM / disk:
- Unknown / Unknown
- Placement:
- single device. One CPU host, one prompt, one image, one serial request. All complete native modules remain on CPU float32; no GPU or disk offload.
- KV cache:
- No autoregressive text generation or retained text K/V cache. Native Qwen3 encoder runs use_cache=False; diffusion latents are distinct.
- Workload:
- 512 token context; 512 input tokens; Not applicable; concurrency 1; batch 1; cache cold; repetitions Unknown.
- Tokenizer:
- Bundle Qwen2TokenizerFast and native user chat template, thinking disabled;512 padded prompt positions · e7b7dc27f91deacad38e78976d1f2b499d76a294
- Sampling / reasoning:
- Fixed original prompt: a red cube beside a blue sphere on white. Complete formatted prompt is counted before native truncation and rejected above 512. Native pipeline pads to 512 positions, uses Qwen3 hidden layers 9/18/27 with no text generation/cache. One512 × 512 image, four distilled steps, guidance_scale 1.0, CPU generator seed 0. Seed is a reproducibility parameter, not a cross-hardware image equality guarantee. 512 is the chosen native prompt-encoder maximum including template; the unpadded count is reported at reader execution. It is not the Qwen3 theoretical 40960 capacity or total joint image/text attention. VAE downsampling8 and2 × 2 latent packing give 1024 image latent positions at 512square, separate from text. Four steps are the publisher distilled recipe, not a text sampler.
- Runtime prerequisites:
- Ubuntu 24.04 x86_64; See prerequisites above.
The actual bundle LICENSE.md and publisher model card grant FLUX.2 Klein4B under Apache License2.0, including this selected complete bundle. Preserve applicable license/copyright/NOTICE and change/patent conditions. Do not transfer noncommercial 9B or FLUX.2 dev terms from names in VAE metadata to this 4B bundle. Publisher encourages safety filtering; its card says recommendations do not modify the grant. No safety classifier is claimed here; fixed benign geometry prompt, manual inspection and applicable laws still matter. This is no legal clearance or trademark endorsement.
- text_encoder/model-00001-of-00002.safetensors · 4.63 GiB · revision e7b7dc27f91deacad38e78976d1f2b499d76a294
- text_encoder/model-00002-of-00002.safetensors · 2.87 GiB · revision e7b7dc27f91deacad38e78976d1f2b499d76a294
- transformer/diffusion_pytorch_model.safetensors · 7.22 GiB · revision e7b7dc27f91deacad38e78976d1f2b499d76a294
- vae/diffusion_pytorch_model.safetensors · 0.16 GiB · revision e7b7dc27f91deacad38e78976d1f2b499d76a294
- 15,964,212,614 bytes is the sum of four official safetensors file sizes, not full installed footprint or runtime RAM. The standalone7.75 GB transformer file alone is not the complete pipeline.
- 64 GiB RAM, 80 GiB disk and eight threads are planning choices. CPU float32 increases weight storage relative to source tensor dtype; image attention, decoder, temporary load buffers, packages and OS add unknown peak memory.
One-time setup and hardware
- hardware
- Unknown — Existing desktop purchase price and incremental hardware cost depend on the reader; unknown.
- Existing desktop purchase price and incremental hardware cost depend on the reader; unknown. Tax: unknown.
- setup
- Unknown — Initial provisioning/build time and labor cost are unknown.
- Initial provisioning/build time and labor cost are unknown. Tax: unknown.
Recurring costs
- electricity
- Unknown — Actual wall power, electricity rate and powered hours are unknown; no TDP-to-wall-power conversion.
- Actual wall power, electricity rate and powered hours are unknown; no TDP-to-wall-power conversion. Tax: unknown.
- storage
- Unknown — Incremental cost of local disk capacity is unknown. The 80 GiB free-disk walkthrough allocation is an author choice, not a measured requirement.
- Incremental cost of local disk capacity is unknown. The 80 GiB free-disk walkthrough allocation is an author choice, not a measured requirement. Tax: unknown.
- egress
- Unknown — Data transfer price, allowances and traffic volume are unknown.
- Data transfer price, allowances and traffic volume are unknown. Tax: unknown.
- administration
- Unknown — Maintenance labor rate and hours are unknown.
- Maintenance labor rate and hours are unknown. Tax: unknown.
Install the runtime
1. Install the compatible native CPU stack
Use a dedicated virtualenv and official matched CPU wheel hashes. Diffusers 0.37.1 is chosen because its HFhub range intersects Transformers 4.57.6; latest Diffusers 0.41.0 requires a different hub generation and is not substituted. No all-extra, CUDA, offload, optional flash kernel or remote code is enabled.
Commandset -e sudo apt-get update sudo apt-get install -y python3.12 python3.12-venv curl ca-certificates openssl mkdir -p "$HOME/flux2-klein4b-image/model" cd "$HOME/flux2-klein4b-image" python3.12 -m venv .venv .venv/bin/python -m pip install 'https://download.pytorch.org/whl/cpu/torch-2.6.0%2Bcpu-cp312-cp312-linux_x86_64.whl#sha256=59e78aa0c690f70734e42670036d6b541930b8eabbaa18d94e090abf14cc4d91' 'https://download-r2.pytorch.org/whl/cpu/torchvision-0.21.0%2Bcpu-cp312-cp312-linux_x86_64.whl#sha256=d6874431e678ba107b60a83f255c33f3755f06bad587b1b919aa514ec325dcd8' .venv/bin/python -m pip install 'diffusers==0.37.1' 'transformers==4.57.6' 'tokenizers==0.22.2' 'huggingface-hub==0.36.2' 'accelerate==1.12.0' 'safetensors==0.7.0' 'numpy==2.2.3' 'Pillow==11.1.0' .venv/bin/python -m pip check .venv/bin/python -m pip freeze > resolved-environment.txtExpected result: Pinned direct versions resolve and pip check passes; exact transitive/system resolution is saved. No native execution/compatibility or fit claim.
Download the model
1. Write the complete immutable component manifest
This reader-authored manifest selects 19 exact bundle files, including all four weight files. LFS blobs use publisher SHA256; regular source files use their exact Git blob SHA1. SHA1 is Git identity, not a modern adversarial integrity guarantee; immutable official HTTPS revision remains the provenance boundary.
Commandset -e cd "$HOME/flux2-klein4b-image" cat > component-manifest.json <<'MANIFEST' { "repository": "black-forest-labs/FLUX.2-klein-4B", "revision": "e7b7dc27f91deacad38e78976d1f2b499d76a294", "files": [ { "file": "LICENSE.md", "bytes": 9584, "algorithm": "git-blob-sha1", "digest": "0afa7632c1a195ea6627a3c53e6ebf18d1be3aa5" }, { "file": "model_index.json", "bytes": 446, "algorithm": "git-blob-sha1", "digest": "554a39bf1019138dd0b28809b745df8ef33657c8" }, { "file": "scheduler/scheduler_config.json", "bytes": 486, "algorithm": "git-blob-sha1", "digest": "7e53605e2643440b310fa554f087641893883c5f" }, { "file": "text_encoder/config.json", "bytes": 1536, "algorithm": "git-blob-sha1", "digest": "86f951d170cfd1fdc1c8a57a041e05c27b7b789b" }, { "file": "text_encoder/generation_config.json", "bytes": 214, "algorithm": "git-blob-sha1", "digest": "f5af93d0c7764fa38e3b1cd3aaba1b6307246d3b" }, { "file": "text_encoder/model-00001-of-00002.safetensors", "bytes": 4967215360, "algorithm": "sha256", "digest": "8c0506e7f4936fa7e26183a4fd8da4e2bdbc5990ba64ae441f965d51228f36ea" }, { "file": "text_encoder/model-00002-of-00002.safetensors", "bytes": 3077766632, "algorithm": "sha256", "digest": "82f2bd839378541b0557bfabaf37c7d3d637071fdcb73302dedd7cf61162ce07" }, { "file": "text_encoder/model.safetensors.index.json", "bytes": 32855, "algorithm": "git-blob-sha1", "digest": "b65d8063815c8679d85bb919337b36fae8de75cf" }, { "file": "tokenizer/added_tokens.json", "bytes": 707, "algorithm": "git-blob-sha1", "digest": "b54f9135e44c1e81047e8d05cb027af8bc039eed" }, { "file": "tokenizer/chat_template.jinja", "bytes": 4168, "algorithm": "git-blob-sha1", "digest": "01be9b307daa2d425f7c168c9fb145a286e0afb4" }, { "file": "tokenizer/merges.txt", "bytes": 1671853, "algorithm": "git-blob-sha1", "digest": "31349551d90c7606f325fe0f11bbb8bd5fa0d7c7" }, { "file": "tokenizer/special_tokens_map.json", "bytes": 613, "algorithm": "git-blob-sha1", "digest": "ac23c0aaa2434523c494330aeb79c58395378103" }, { "file": "tokenizer/tokenizer.json", "bytes": 11422654, "algorithm": "sha256", "digest": "aeb13307a71acd8fe81861d94ad54ab689df773318809eed3cbe794b4492dae4" }, { "file": "tokenizer/tokenizer_config.json", "bytes": 5404, "algorithm": "git-blob-sha1", "digest": "ddaf69808214a44fdd26d3785b66c1367c78277a" }, { "file": "tokenizer/vocab.json", "bytes": 2776833, "algorithm": "git-blob-sha1", "digest": "4783fe10ac3adce15ac8f358ef5462739852c569" }, { "file": "transformer/config.json", "bytes": 541, "algorithm": "git-blob-sha1", "digest": "f21592ae2bc9f43052e78785bde7414f219ae369" }, { "file": "transformer/diffusion_pytorch_model.safetensors", "bytes": 7751109744, "algorithm": "sha256", "digest": "9f29f9edcfdae452a653ffb51a534ca4decd389952c225724ff3b94042612a6e" }, { "file": "vae/config.json", "bytes": 821, "algorithm": "git-blob-sha1", "digest": "c3f38eb4c188a96a462519159356bd0fcc28cd14" }, { "file": "vae/diffusion_pytorch_model.safetensors", "bytes": 168120878, "algorithm": "sha256", "digest": "ca70d2202afe6415bdbcb8793ba8cd99fd159cfe6192381504d6c4d3036e0f04" } ] } MANIFEST sha256sum --check <<'SHA256' f03107bcd53ab215deeee44072681f15658a94a755ae242bb42741dfca6405e3 component-manifest.json SHA256Expected result: Exact complete manifest verifies before any reader weight retrieval.
2. Retrieve and verify all native components
Reader-only downloads from one exact ungated publisher revision. Do not fetch the standalone transformer-only file or float revisions. Stop on any size/hash mismatch; no model loading occurs in this retrieval script.
Commandset -e cd "$HOME/flux2-klein4b-image" .venv/bin/python - <<'PYDOWNLOAD' import hashlib,json,pathlib,shutil from huggingface_hub import hf_hub_download m=json.load(open('component-manifest.json')) for row in m['files']: src=hf_hub_download(m['repository'],row['file'],revision=m['revision']) dst=pathlib.Path('model')/row['file'];dst.parent.mkdir(parents=True,exist_ok=True);shutil.copyfile(src,dst) assert dst.stat().st_size==row['bytes'] h=hashlib.sha256() if row['algorithm']=='sha256' else hashlib.sha1() if row['algorithm']=='git-blob-sha1':h.update(('blob '+str(row['bytes'])+'\0').encode()) with dst.open('rb') as f: for chunk in iter(lambda:f.read(1024*1024),b''):h.update(chunk) assert h.hexdigest()==row['digest'],row['file'] print('All19 components verified; model loading has not run.') PYDOWNLOADExpected result: All 19 exact files verify. Download cache duplicates disk usage;80 GiB is an allocation, not a measured peak. Offline loading follows only after complete verification.
Configure
1. Create a stable private service key
Generate only when absent; preserve existing access. Do not print or share the local key.
Commandset -e cd "$HOME/flux2-klein4b-image" umask 077 if [ ! -e .api-key ]; then openssl rand -hex 32 > .api-key; fi chmod 600 .api-key test -s .api-key || { echo "Restore empty key before continuing"; exit 1; }Expected result: Private64-character lowercase hexadecimal key preserved or created.
2. Create the native image harness
Reader-authored wrapper, not publisher server. It rechecks every component before explicit native local_files_only safetensors component loading. Reject any missing, unexpected, mismatched or error diagnostic before assembling the native pipeline. All modules use CPU float32; fixed prompt is chat-formatted with thinking disabled and checked before native 512 truncation. No full model binary was fetched or executed by the author.
Commandset -e cd "$HOME/flux2-klein4b-image" cat > flux2_image.py <<'PYSERVER' """Reader-authored educational fixed-input FLUX.2 Klein4B harness; not publisher server.""" import hashlib import hmac import json import math import pathlib from http.server import BaseHTTPRequestHandler, HTTPServer ROOT = pathlib.Path(__file__).resolve().parent PORT = 8995 PROMPT = 'A simple red cube beside a blue sphere on a plain white background, clean studio illustration.' def validate_image(result): import base64 import struct png, count = result if type(count) is not int or not 0 < count <= 512: raise ValueError('prompt_budget') if not isinstance(png, bytes) or not 57 <= len(png) <= 8*1024*1024: raise ValueError('png_bound') if png[:8] != b'\x89PNG\r\n\x1a\n' or png[12:16] != b'IHDR': raise ValueError('png_header') if struct.unpack('>II', png[16:24]) != (512, 512) or png[-8:-4] != b'IEND': raise ValueError('png_shape_or_end') return {'fixture': 'author-t2i-v1', 'prompt': PROMPT, 'prompt_tokens_before_padding': count, 'padded_prompt_positions': 512, 'image_shape': [512, 512, 3], 'configured_image_latent_positions': 1024, 'denoising_steps': 4, 'seed': 0, 'guidance_scale': 1.0, 'mime_type': 'image/png', 'png_base64': base64.b64encode(png).decode('ascii'), 'generated_text_tokens': None} def make_encoder(): # Reader-run only. Fake tests do not import Torch, Diffusers or Pillow. import os os.environ['HF_HUB_OFFLINE'] = '1' os.environ['TRANSFORMERS_OFFLINE'] = '1' import torch from diffusers import (Flux2KleinPipeline, Flux2Transformer2DModel, AutoencoderKLFlux2, FlowMatchEulerDiscreteScheduler) from transformers import Qwen3ForCausalLM, Qwen2TokenizerFast manifest = json.loads((ROOT / 'component-manifest.json').read_text()) model_root = ROOT / 'model' for row in manifest['files']: file = model_root / row['file'] if file.stat().st_size != row['bytes']: raise RuntimeError('component_size') hasher = hashlib.sha256() if row['algorithm'] == 'sha256' else hashlib.sha1() if row['algorithm'] == 'git-blob-sha1': hasher.update(('blob '+str(row['bytes'])+'\0').encode()) with file.open('rb') as stream: for chunk in iter(lambda: stream.read(1024*1024), b''): hasher.update(chunk) if hasher.hexdigest() != row['digest']: raise RuntimeError('component_hash') torch.set_num_threads(8) def load_checked(cls, subfolder): component, info = cls.from_pretrained( str(model_root / subfolder), torch_dtype=torch.float32, local_files_only=True, use_safetensors=True, output_loading_info=True) for key in ['missing_keys', 'unexpected_keys', 'mismatched_keys', 'error_msgs']: if info.get(key): raise RuntimeError('component_loading_diagnostics_'+subfolder+'_'+key) return component.float().cpu().eval() transformer = load_checked(Flux2Transformer2DModel, 'transformer') text_encoder = load_checked(Qwen3ForCausalLM, 'text_encoder') vae = load_checked(AutoencoderKLFlux2, 'vae') tokenizer = Qwen2TokenizerFast.from_pretrained(str(model_root / 'tokenizer'), local_files_only=True) scheduler = FlowMatchEulerDiscreteScheduler.from_pretrained( str(model_root / 'scheduler'), local_files_only=True) pipe = Flux2KleinPipeline(transformer=transformer, text_encoder=text_encoder, vae=vae, tokenizer=tokenizer, scheduler=scheduler, is_distilled=True) pipe = pipe.to('cpu') pipe.set_progress_bar_config(disable=True) if not json.loads((model_root / 'model_index.json').read_text())['is_distilled'] or not pipe.config.is_distilled: raise RuntimeError('wrong_variant') formatted = pipe.tokenizer.apply_chat_template( [{'role': 'user', 'content': PROMPT}], tokenize=False, add_generation_prompt=True, enable_thinking=False) token_count = len(pipe.tokenizer(formatted, truncation=False)['input_ids']) if not 0 < token_count <= 512: raise RuntimeError('prompt_would_truncate') def encode(): import io import numpy as np from PIL import Image def check_latents(pipeline, step, timestep, values): if not torch.isfinite(values['latents']).all(): raise RuntimeError('nonfinite_latents') return values with torch.inference_mode(): image = pipe(prompt=PROMPT, height=512, width=512, num_inference_steps=4, guidance_scale=1.0, max_sequence_length=512, num_images_per_prompt=1, output_type='np', callback_on_step_end=check_latents, callback_on_step_end_tensor_inputs=['latents'], generator=torch.Generator(device='cpu').manual_seed(0)).images[0] if image.shape != (512, 512, 3) or not np.isfinite(image).all(): raise RuntimeError('image_shape_or_finiteness') if image.min() < 0 or image.max() > 1: raise RuntimeError('image_range') image = Image.fromarray((image*255).round().astype('uint8'), mode='RGB') buf = io.BytesIO() image.save(buf, format='PNG') return buf.getvalue(), token_count return encode PYSERVERExpected result: First complete native loader and PNG-validation fragment written.
3. Complete and verify private transport
Append fixed-input private serial HTTP transport. No model code runs in syntax/hash checks.
Commandset -e cd "$HOME/flux2-klein4b-image" cat >> flux2_image.py <<'PYSERVER' def create_server(encoder, key, port=PORT): if not isinstance(key, str) or len(key) != 64 or any(c not in '0123456789abcdef' for c in key): raise ValueError('key_format') class Handler(BaseHTTPRequestHandler): def setup(self): super().setup() self.connection.settimeout(5) def log_message(self, *_): pass # Do not log Bearer keys or request bodies. def reply(self, status, obj): data = json.dumps(obj, allow_nan=False, separators=(',', ':')).encode() self.send_response(status) self.send_header('Content-Type', 'application/json') self.send_header('Content-Length', str(len(data))) self.send_header('Connection', 'close') self.end_headers() self.wfile.write(data) self.close_connection = True def authorized(self): values = self.headers.get_all('Authorization', []) return len(values) == 1 and hmac.compare_digest(values[0].encode(), ('Bearer ' + key).encode()) def do_GET(self): if not self.authorized(): return self.reply(401, {'error': 'unauthorized'}) if self.path != '/health': return self.reply(404, {'error': 'not_found'}) return self.reply(200, {'ready': True, 'padded_prompt_positions': 512, 'configured_image_latent_positions': 1024, 'generated_text_tokens': None}) def do_POST(self): if not self.authorized(): return self.reply(401, {'error': 'unauthorized'}) if self.path != '/v1/fixed-image': return self.reply(404, {'error': 'not_found'}) if self.headers.get('Transfer-Encoding') is not None: return self.reply(400, {'error': 'transfer_encoding_unsupported'}) lengths = self.headers.get_all('Content-Length', []) if len(lengths) != 1: return self.reply(411, {'error': 'content_length_required'}) raw = lengths[0] if not raw or len(raw) > 4 or any(c not in '0123456789' for c in raw): return self.reply(413, {'error': 'invalid_or_excessive_length'}) n = int(raw) if n < 1 or n > 256: return self.reply(413, {'error': 'body_limit'}) if self.headers.get_content_type() != 'application/json': return self.reply(415, {'error': 'json_required'}) try: body = self.rfile.read(n) except (TimeoutError, OSError): return self.reply(408, {'error': 'body_timeout'}) if len(body) != n: return self.reply(400, {'error': 'incomplete_body'}) try: def unique(pairs): obj = {} for k, v in pairs: if k in obj: raise ValueError('duplicate_key') obj[k] = v return obj request = json.loads(body.decode('utf-8'), object_pairs_hook=unique, parse_constant=lambda _: (_ for _ in ()).throw(ValueError('constant'))) except (ValueError, UnicodeError, RecursionError): return self.reply(400, {'error': 'invalid_json'}) if type(request) is not dict or request != {'fixture': 'author-t2i-v1'}: return self.reply(400, {'error': 'fixed_fixture_required'}) try: result = validate_image(encoder()) except Exception: return self.reply(500, {'error': 'pipeline_or_png_failure'}) return self.reply(200, result) return HTTPServer(('127.0.0.1', port), Handler) if __name__ == '__main__': secret = (ROOT / '.api-key').read_text().strip() encoder = make_encoder() with create_server(encoder, secret) as server: server.serve_forever() PYSERVER .venv/bin/python -m py_compile flux2_image.py sha256sum --check <<'SHA256' d4e624292a3cec1f07856e464c0020b3d2db6591555e04ffe673ac3f2dffaefb flux2_image.py SHA256Expected result: Exact wrapper bytes and Python syntax verify without model loading.
Start the model
1. Start the complete CPU image experiment
Foreground serial endpoint. Full pipeline load and first image may be slow or exceed RAM; no fit/speed is promised. Explicit native loaders select all model_index components, reject loading diagnostics and assemble the native pipeline with offline safetensors and CPU float32; no VAE/text-encoder substitution. Each denoising-step latent tensor and final NumPy image must be finite before PNG conversion.
Commandset -e cd "$HOME/flux2-klein4b-image" HF_HUB_OFFLINE=1 TRANSFORMERS_OFFLINE=1 .venv/bin/python flux2_image.pyExpected result: After actual reader-side component verification and native load, loopback 127.0.0.1:8995 serves. Stop on component/import/load/template errors.
Connect to your endpoint
http://127.0.0.1:8995/v1/fixed-image
Same trusted desktop loopback only.
Access: loopback. Private Bearer key required for health and image generation. Send a JSON object with fixture set to author-t2i-v1. Response includes base64 PNG, dimensions, prompt positions, steps and seed. No arbitrary prompts, uploads, URLs or files are accepted.
Verify the setup
1. Validate the PNG and inspect the generated image
Run in a second server terminal. Check private health, missing-key 401, fixed response metadata and a valid decoded 512 RGB PNG. Inspect image.png yourself for the red cube/blue sphere on white; valid dimensions do not establish semantic fidelity, safety or quality. No generated example or success claim is supplied.
Commandset -e cd "$HOME/flux2-klein4b-image" FLUX_KEY="$(cat .api-key)" curl --fail http://127.0.0.1:8995/health -H "Authorization: Bearer $FLUX_KEY" curl --fail http://127.0.0.1:8995/v1/fixed-image -H "Authorization: Bearer $FLUX_KEY" -H 'Content-Type: application/json' -d '{"fixture":"author-t2i-v1"}' -o image.json curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8995/health unset FLUX_KEY .venv/bin/python - <<'PYVERIFY' import base64,io,json from PIL import Image d=json.load(open('image.json'));assert d['generated_text_tokens'] is None assert d['image_shape']==[512,512,3] and d['padded_prompt_positions']==512 assert 0<d['prompt_tokens_before_padding']<=512 and d['configured_image_latent_positions']==1024 assert d['denoising_steps']==4 and d['seed']==0 b=base64.b64decode(d['png_base64'],validate=True);assert len(b)<=8*1024*1024 with Image.open(io.BytesIO(b)) as image: assert image.format=='PNG' and image.size==(512,512) and image.mode=='RGB';image.verify() open('image.png','wb').write(b) print('Inspect image.png; PNG validity is not semantic quality proof.') PYVERIFYExpected result: Authenticated health/generation return structured JSON; missing auth 401. Exact PNG metadata/Pillow verify passes only after reader execution. Inspect and record actual visual defects or loading failures.
Performance evidence
No compatible measurement available. Documented support and estimated memory do not establish response speed.
Limits and troubleshooting
- Complete official 4B distilled bundle is selected, not transformer-only 7.75 GB weights or9B/base/dev. Main tensor file metadata plus all required configs/processors are pinned; no model binary was downloaded.
- 512 configured prompt positions include the native user template with thinking disabled. Actual pre-padding prompt count is checked at reader execution; too-long prompts stop before native silent truncation. This is not 40960 theoretical Qwen3 context or 1024 image latent positions.
- Native four-step distilled image synthesis returns PNG pixels, not autoregressive output tokens. Guidance_scale 1.0 avoids CFG; no chat completion/reasoning output or text-generation benchmark is claimed.
- Full CPU float32 through native .to(cpu) is source-qualified, not installed/executed compatibility proof. 64 GiB RAM, 80 GiB disk/eight threads are planning allocations; fit, peak memory, latency and image quality remain unknown.
- Original fixed geometric prompt is not a third-party image fixture. Manual inspection remains necessary; fixed seed does not guarantee equal bytes across hardware/library versions. No downstream safety classifier or commercial suitability is claimed.
- Reader-authored serial HTTPServer has private key/loopback, bounded strict fixed JSON and PNG-size/shape guards, but no inference deadline, multiuser robustness or public production-service guarantee.
- All components are verified before offline local loading; no remote-code trust or unpinned auxiliary download is selected. Publisher Git blob SHA1 is identified accurately; weight SHA256s are metadata until reader actual download.
- Fake PNG protocol tests prove only request/auth/output boundary handling, not actual native tensor finiteness, denoising correctness, prompt adherence, image safety or runtime fit. Native callbacks and pre-PNG guards require finite tensors/arrays at reader execution; they have not run on model weights here.
- Image editing, multiple references, other resolutions, base variants, alternate supported GPU/quantized/offload backends and other useful modes remain open; this pair does not finalize family coverage.
- Component/hash/version or offline load error
- Stop and restore exact 19-file manifest and publisher revision. Do not float to main, omit text encoder/VAE or substitute standalone transformer-only weights. Keep safetensors/local_files_only; stop on unresolved dependency errors.
- Prompt budget or wrong variant error
- Use exact fixed prompt/tokenizer/template and distilled model_index. The pre-padding formatted prompt must fit 512 positions. Do not hide truncation, switch model variants or treat padding count as actual semantic prompt length.
- 401 or rejected body
- Use preserved matching private 64-character key and exact fixture selector. Arbitrary prompts/images/URLs/files or extra fields are rejected.
- Slow, out-of-memory, black or inaccurate image
- Record actual load/generation failure and inspect PNG. 64 GiB is not measured fit and valid dimensions do not establish semantic quality. Do not claim a smaller/partial pipeline is equivalent; stop the process if resource use is unacceptable.
Stop the model
1. Stop the private image service
Press Ctrl+C in its foreground terminal and unset client key. Confirm local loopback endpoint no longer serves.
Commandunset FLUX_KEYExpected result: Pipeline process and endpoint stop; generated files remain until explicitly removed.
Uninstall
1. Remove dedicated experiment and selected model cache
Preserve desired outputs/audit/license records first. Confirm the dedicated directory before deletion. The model-specific download cache is separate; remove only this exact cache if no other experiment needs it. Shared Ubuntu packages remain.
Commandrm -r -- "$HOME/flux2-klein4b-image" rm -r -- "$HOME/.cache/huggingface/hub/models--black-forest-labs--FLUX.2-klein-4B"Expected result: Dedicated bundle/venv/wrapper/key/outputs and this selected model cache are removed if present.
Sources and verification
Sources checked Oct 16, 2026. Verification source
- https://huggingface.co/api/models/black-forest-labs/FLUX.2-klein-4B?blobs=truepublisher · retrieved Oct 16, 2026
- https://api.github.com/repos/black-forest-labs/flux2/commits/mainpublisher · retrieved Oct 16, 2026
- https://api.github.com/repos/huggingface/diffusers/releases/latestruntime maintainer · retrieved Oct 16, 2026
- https://huggingface.co/black-forest-labs/FLUX.2-klein-4B/resolve/e7b7dc27f91deacad38e78976d1f2b499d76a294/README.mdpublisher · retrieved Oct 16, 2026 · revision e7b7dc2
- https://huggingface.co/black-forest-labs/FLUX.2-klein-4B/resolve/e7b7dc27f91deacad38e78976d1f2b499d76a294/LICENSE.mdpublisher · retrieved Oct 16, 2026 · revision e7b7dc2
- https://huggingface.co/black-forest-labs/FLUX.2-klein-4B/resolve/e7b7dc27f91deacad38e78976d1f2b499d76a294/model_index.jsonpublisher · retrieved Oct 16, 2026 · revision e7b7dc2
- https://huggingface.co/black-forest-labs/FLUX.2-klein-4B/resolve/e7b7dc27f91deacad38e78976d1f2b499d76a294/scheduler/scheduler_config.jsonpublisher · retrieved Oct 16, 2026 · revision e7b7dc2
- https://huggingface.co/black-forest-labs/FLUX.2-klein-4B/resolve/e7b7dc27f91deacad38e78976d1f2b499d76a294/text_encoder/config.jsonpublisher · retrieved Oct 16, 2026 · revision e7b7dc2
- https://huggingface.co/black-forest-labs/FLUX.2-klein-4B/resolve/e7b7dc27f91deacad38e78976d1f2b499d76a294/text_encoder/generation_config.jsonpublisher · retrieved Oct 16, 2026 · revision e7b7dc2
- https://huggingface.co/black-forest-labs/FLUX.2-klein-4B/resolve/e7b7dc27f91deacad38e78976d1f2b499d76a294/text_encoder/model.safetensors.index.jsonpublisher · retrieved Oct 16, 2026 · revision e7b7dc2
- https://huggingface.co/black-forest-labs/FLUX.2-klein-4B/resolve/e7b7dc27f91deacad38e78976d1f2b499d76a294/tokenizer/tokenizer_config.jsonpublisher · retrieved Oct 16, 2026 · revision e7b7dc2
- https://huggingface.co/black-forest-labs/FLUX.2-klein-4B/resolve/e7b7dc27f91deacad38e78976d1f2b499d76a294/tokenizer/chat_template.jinjapublisher · retrieved Oct 16, 2026 · revision e7b7dc2
- https://huggingface.co/black-forest-labs/FLUX.2-klein-4B/resolve/e7b7dc27f91deacad38e78976d1f2b499d76a294/transformer/config.jsonpublisher · retrieved Oct 16, 2026 · revision e7b7dc2
- https://huggingface.co/black-forest-labs/FLUX.2-klein-4B/resolve/e7b7dc27f91deacad38e78976d1f2b499d76a294/vae/config.jsonpublisher · retrieved Oct 16, 2026 · revision e7b7dc2
- https://raw.githubusercontent.com/black-forest-labs/flux2/50fe5162777813d869182b139e83b10743caef15/README.mdpublisher · retrieved Oct 16, 2026
- https://raw.githubusercontent.com/black-forest-labs/flux2/50fe5162777813d869182b139e83b10743caef15/pyproject.tomlpublisher · retrieved Oct 16, 2026
- https://raw.githubusercontent.com/black-forest-labs/flux2/50fe5162777813d869182b139e83b10743caef15/src/flux2/util.pypublisher · retrieved Oct 16, 2026
- https://raw.githubusercontent.com/black-forest-labs/flux2/50fe5162777813d869182b139e83b10743caef15/src/flux2/sampling.pypublisher · retrieved Oct 16, 2026
- https://raw.githubusercontent.com/huggingface/diffusers/v0.41.0/src/diffusers/pipelines/flux2/pipeline_flux2_klein.pyruntime maintainer · retrieved Oct 16, 2026
- https://raw.githubusercontent.com/huggingface/diffusers/v0.41.0/src/diffusers/models/autoencoders/autoencoder_kl_flux2.pyruntime maintainer · retrieved Oct 16, 2026
- https://raw.githubusercontent.com/huggingface/diffusers/v0.41.0/src/diffusers/models/transformers/transformer_flux2.pyruntime maintainer · retrieved Oct 16, 2026
- https://raw.githubusercontent.com/huggingface/diffusers/v0.41.0/src/diffusers/pipelines/pipeline_utils.pyruntime maintainer · retrieved Oct 16, 2026
- https://raw.githubusercontent.com/huggingface/diffusers/v0.41.0/src/diffusers/models/modeling_utils.pyruntime maintainer · retrieved Oct 16, 2026
- https://pypi.org/pypi/diffusers/0.41.0/jsonruntime maintainer · retrieved Oct 16, 2026
- https://raw.githubusercontent.com/black-forest-labs/flux2/50fe5162777813d869182b139e83b10743caef15/LICENSE.mdpublisher · retrieved Oct 16, 2026
- https://raw.githubusercontent.com/huggingface/diffusers/v0.41.0/src/diffusers/utils/torch_utils.pyruntime maintainer · retrieved Oct 16, 2026
- https://api.github.com/repos/huggingface/diffusers/releases?per_page=30runtime maintainer · retrieved Oct 16, 2026
- https://pypi.org/pypi/diffusers/0.37.1/jsonruntime maintainer · retrieved Oct 16, 2026
- https://api.github.com/repos/huggingface/diffusers/git/ref/tags/v0.37.1runtime maintainer · retrieved Oct 16, 2026 · revision v0.37.1
- https://raw.githubusercontent.com/huggingface/diffusers/v0.37.1/src/diffusers/pipelines/flux2/pipeline_flux2_klein.pyruntime maintainer · retrieved Oct 16, 2026 · revision v0.37.1
- https://pypi.org/pypi/transformers/4.57.6/jsonruntime maintainer · retrieved Oct 16, 2026
- https://api.github.com/repos/huggingface/diffusers/git/tags/717bc8feba639743b52f3b6781e0d828fa8abb23runtime maintainer · retrieved Oct 16, 2026
- https://pypi.org/pypi/huggingface-hub/0.36.2/jsonruntime maintainer · retrieved Oct 16, 2026
- https://pypi.org/pypi/accelerate/1.12.0/jsonruntime maintainer · retrieved Oct 16, 2026
- https://pypi.org/pypi/safetensors/0.7.0/jsonruntime maintainer · retrieved Oct 16, 2026
- https://raw.githubusercontent.com/huggingface/diffusers/v0.37.1/src/diffusers/pipelines/pipeline_utils.pyruntime maintainer · retrieved Oct 16, 2026 · revision v0.37.1
- https://raw.githubusercontent.com/huggingface/diffusers/v0.37.1/src/diffusers/models/transformers/transformer_flux2.pyruntime maintainer · retrieved Oct 16, 2026 · revision v0.37.1
- https://raw.githubusercontent.com/huggingface/diffusers/v0.37.1/src/diffusers/models/autoencoders/autoencoder_kl_flux2.pyruntime maintainer · retrieved Oct 16, 2026 · revision v0.37.1
- https://pypi.org/pypi/numpy/2.2.3/jsonruntime maintainer · retrieved Oct 16, 2026
- https://pypi.org/pypi/tokenizers/0.22.2/jsonruntime maintainer · retrieved Oct 16, 2026
- https://raw.githubusercontent.com/huggingface/diffusers/v0.37.1/src/diffusers/models/modeling_utils.pyruntime maintainer · retrieved Oct 16, 2026 · revision v0.37.1
- https://raw.githubusercontent.com/huggingface/transformers/v4.57.6/src/transformers/modeling_utils.pyruntime maintainer · retrieved Oct 16, 2026
- https://raw.githubusercontent.com/pytorch/vision/v0.21.0/torchvision/transforms/functional.pyruntime maintainer · retrieved Oct 16, 2026
- https://raw.githubusercontent.com/pytorch/vision/v0.21.0/torchvision/transforms/transforms.pyruntime maintainer · retrieved Oct 16, 2026
- https://pypi.org/pypi/pillow/11.1.0/jsonruntime maintainer · retrieved Oct 16, 2026
- https://download.pytorch.org/whl/cpu/torch/runtime maintainer · retrieved Oct 16, 2026
- https://docs.python.org/3.11/library/http.server.htmlruntime maintainer · retrieved Oct 16, 2026
- https://docs.python.org/3.11/library/hmac.htmlruntime maintainer · retrieved Oct 16, 2026
- https://download.pytorch.org/whl/cpu/torchvision/runtime maintainer · retrieved Oct 16, 2026
- https://raw.githubusercontent.com/pytorch/vision/v0.21.0/README.mdruntime maintainer · retrieved Oct 16, 2026
- https://pypi.org/pypi/torchvision/0.21.0/jsonruntime maintainer · retrieved Oct 16, 2026
- https://opentools.ai/llms/flux-2-klein-4bopentools · retrieved Oct 16, 2026 · revision flux2-klein4b-reader-v1
- https://www.intel.com/content/www/us/en/products/sku/134586/intel-core-i512400-processor-18m-cache-up-to-4-40-ghz/specifications.htmlmanufacturer · retrieved Oct 16, 2026
- https://raw.githubusercontent.com/ggml-org/llama.cpp/620d2225cc436ab0b001e3200e590e3b286ef9ab/docs/build.mdruntime maintainer · retrieved Oct 16, 2026 · revision 620d2225cc436ab0b001e3200e590e3b286ef9ab
- https://raw.githubusercontent.com/ggml-org/llama.cpp/620d2225cc436ab0b001e3200e590e3b286ef9ab/ggml/src/ggml-cpu/CMakeLists.txtruntime maintainer · retrieved Oct 16, 2026 · revision 620d2225cc436ab0b001e3200e590e3b286ef9ab