Separate vision projector device from LLM GPU split

This commit is contained in:
Mikei386 committed 2026-10-01 12:58:45 +02:00
1 parent 69927ca5e6
commit 9add6d0547
5 files changed
+31 -8

No files matched your search

+11 -4
View File
@@ -158,6 +158,7 @@ class LlamaWorker:
if params['split_mode']=='none':selected=selected[:1]
if not selected or any(g['processes'] or g['free_mib']<2048 for g in selected):raise InferenceError('Benötigte GPU ist durch einen anderen Dienst belegt. Deck stoppt keine fremden Prozesse.')
mem={line.split(':')[0]:int(line.split()[1])*1024 for line in Path('/proc/meminfo').read_text().splitlines() if line.startswith('MemAvailable:')}
model_devices=list(selected)
projector=None;vision_args=[];vision_bytes=0;vision_device=params.get('vision_device','cpu')
if params.get('vision_projector'):
projector=self.catalog.entry(params['vision_projector'])
@@ -166,7 +167,11 @@ class LlamaWorker:
vision_args=['--mmproj',str((self.catalog.root/projector['id']/'model.gguf').resolve())]
if vision_device=='cpu':vision_args+=['--no-mmproj-offload']
else:
if vision_device not in [g['uuid'] for g in selected]:raise InferenceError('Projektor-GPU ist nicht ausgewählt.')
if vision_device not in [g['uuid'] for g in selected]:
target=next((g for g in devices if g['uuid']==vision_device),None)
if target is None:raise InferenceError('Projektor-GPU ist nicht verfügbar.')
if target['processes'] or target['free_mib']<2048:raise InferenceError('Projektor-GPU ist durch einen anderen Dienst belegt.')
selected.append(target)
vision_args+=['--mmproj-device','CUDA'+str([g['uuid'] for g in selected].index(vision_device)),'--mmproj-offload']
staging=entry['size']+4*GIB+vision_bytes
if mem.get('MemAvailable',0)<staging+4*GIB:raise InferenceError('Zu wenig freier RAM für Modellladen und Host-Reserve.')
@@ -177,7 +182,8 @@ class LlamaWorker:
env.update(CUDA_VISIBLE_DEVICES=','.join(g['uuid'] for g in selected),HF_HUB_OFFLINE='1',OMP_NUM_THREADS=str(params['threads']))
reserve_mode=params.get('gpu_reserve_mode','auto')
margins=[0 if reserve_mode=='none' else params.get('gpu_reserve_mib',{}).get(g['uuid'],512) if reserve_mode=='manual' else max(512,round(g['total_mib']*.025)) for g in selected]
common=['--model',str(model),'--ctx-size',str(params['context']),'--parallel',str(params['slots']),'--batch-size',str(params['batch']),'--ubatch-size',str(params['ubatch']),'--cache-type-k',params.get('cache_type_k','q4_0'),'--cache-type-v',params.get('cache_type_v','q4_0'),'--flash-attn','on','--split-mode',params['split_mode'],'--fit-target',','.join(map(str,margins))]
common=['--model',str(model),'--ctx-size',str(params['context']),'--parallel',str(params['slots']),'--batch-size',str(params['batch']),'--ubatch-size',str(params['ubatch']),'--cache-type-k',params.get('cache_type_k','q4_0'),'--cache-type-v',params.get('cache_type_v','q4_0'),'--flash-attn','on','--split-mode',params['split_mode'],'--fit-target',','.join(map(str,margins[:len(model_devices)]))]
common+=['--device',','.join('CUDA'+str(i) for i in range(len(model_devices)))]
if params['tensor_split']:common+=['--tensor-split',','.join(map(str,params['tensor_split']))]
tool=str(directory/'build/bin/llama-fit-params')
mtp_fit=['--deck-mtp'] if mtp else []
@@ -188,7 +194,8 @@ class LlamaWorker:
for line in output.splitlines():
parts=line.split()
if len(parts)==4 and all(x.isdigit() for x in parts[1:]):rows[parts[0]]=sum(map(int,parts[1:]))
if 'Host' not in rows or any('CUDA'+str(i) not in rows for i in range(len(selected))):raise InferenceError('Speicherprognose unvollständig; Start abgebrochen.')
if 'Host' not in rows or any('CUDA'+str(i) not in rows for i in range(len(model_devices))):raise InferenceError('Speicherprognose unvollständig; Start abgebrochen.')
for i in range(len(model_devices),len(selected)):rows.setdefault('CUDA'+str(i),0)
if projector:
target='Host' if vision_device=='cpu' else 'CUDA'+str([g['uuid'] for g in selected].index(vision_device))
rows[target]+=round(vision_bytes/1024**2)
@@ -226,7 +233,7 @@ class LlamaWorker:
layers=int(fit['-ngl'])
if '-ts' in fit:
parts=fit['-ts'].split(',')
if len(parts)!=len(selected) or any(not x.replace('.','',1).isdigit() for x in parts):raise InferenceError('Ungültige automatische GPU-Verteilung.')
if len(parts)!=len(model_devices) or any(not x.replace('.','',1).isdigit() for x in parts):raise InferenceError('Ungültige automatische GPU-Verteilung.')
extra=['--tensor-split',fit['-ts']]
fits,memory=estimate(layers,extra)
if not fits:raise InferenceError('Speicherprognose überschreitet die GPU-/RAM-Reserve.')