
RTX 3090 + 128GB DDR5 환경에서 DeepSeek-V4-Flash-0731 UD-IQ3_S 12.5 tok/s 구동
요약
RTX 3090 24GB VRAM과 128GB DDR5 RAM 환경에서 DeepSeek-V4-Flash 모델을 구동하는 최적화 방법을 소개합니다. llama.cpp의 --n-cpu-moe 옵션을 활용해 MoE 전문가 일부를 시스템 RAM에 배치함으로써 제한된 VRAM 내에서 대규모 모델을 실행하는 데 성공했습니다.
핵심 포인트
- --n-cpu-moe 옵션으로 MoE 전문가를 시스템 RAM에 분산 배치 가능
- RTX 3090(24GB)과 대용량 DDR5 RAM 조합으로 대형 모델 구동
- llama.cpp 최신 바이너리 교체를 통한 실행 환경 최적화
- 모델 성능이 CPU 및 RAM 대역폭에 크게 의존함
저는 다음과 같은 사양으로 text-generation-webui에서 DeepSeek-V4-Flash-0731 UD-IQ3_S를 실행하는 데 성공했습니다: RTX 3090 24 GB, AMD EXPO를 사용하여 5600 MHz로 오버클럭된 128 GB DDR5, llama.cpp 로더(loader) 사용. 우선, 다소 극단적인 우회 방법을 사용해야 했습니다. text-generation-webui에 포함된 llama.cpp 바이너리(binaries)를 다음에서 다운로드한 최신 공식 릴리스로 교체했습니다: https://github.com/ggml-org/llama.cpp/releases. 새로운 바이너리를 다음 경로에 복사했습니다: textgen\venv\lib\site-packages\llama_cpp_binaries\bin. 먼저 기존 폴더를 백업해 두는 것을 권장합니다. 저의 현재 설정은 다음과 같습니다:
gpu-layers: 44
ctx-size: 384000
cache-type: fp16
split-mode: layer
parallel: 1
threads: 0
threads-batch: 0
batch-size: 1024
ubatch-size: 512
fit-target: 512
no-mmap: enabled
no-kv-offload: disabled
cpu-moe: disabled
추가 플래그(Extra flags): --n-cpu-moe 39
가장 중요한 옵션은 --n-cpu-moe 39입니다. 이 옵션은 MoE(Mixture of Experts) 전문가의 일부를 VRAM 대신 시스템 RAM에 유지합니다. 이 덕분에 24 GB의 VRAM만으로도 모델을 실행할 수 있지만, 성능은 CPU와 RAM 대역폭(bandwidth)에 크게 좌우됩니다. 로더(loader)는 모델을 로드하는 데 약 136 GB가 필요할 것으로 추정하므로, 5600 MHz로 작동하는 128 GB의 DDR5가 대부분의 중책을 수행하고 있습니다.
현재 저의 설정값은 다음과 같습니다: gpu-layers: 44, ctx-size: 384000, cache-type: fp16, split-mode: layer, parallel: 1, threads: 0, threads-batch: 0, batch-size: 1024, ubatch-size: 512, fit-target: 512, no-mmap: enabled, no-kv-offload: disabled, cpu-moe: disabled
추가 옵션: --n-cpu-moe 39
가장 중요한 옵션은 --n-cpu-moe 39입니다. 이 옵션은 MoE (Mixture of Experts) 전문가의 일부를 VRAM (Video RAM) 대신 시스템 RAM에 유지할 수 있게 해줍니다. 덕분에 성능이 프로세서와 RAM 대역폭에 크게 의존하기는 하지만, 단 24GB의 VRAM만으로도 모델을 실행할 수 있습니다. 로드 프로그램은 모델을 로드하는 데 약 136GB가 필요할 것으로 추정하므로, 5600 MHz로 작동하는 128GB의 DDR5가 대부분의 중책을 수행하고 있습니다. 결과값 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Voxel Japanese Pagoda Garden</title> <style> body { margin: 0; overflow: hidden; font-family: sans-serif; } canvas { display: block; } #info { position: fixed; bottom: 16px; left: 16px; color: #fff; background: rgba(0, 0, 0, 0.35); padding: 8px 14px; border-radius: 12px; font-size: 14px; pointer-events: none; z-index: 10; text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5); user-select: none; } </style> </head> <body> <div id="info">🌸 Japanese Pagoda Garden — drag to orbit · scroll to zoom</div> <script type="importmap"> { "imports": { "three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js", "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/" } } </script> <script type="module"> import * as THREE from 'three'; import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); renderer.setSize(window.innerWidth, window.innerHeight); renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; renderer.outputColorSpace = THREE.SRGBColorSpace; document.body.appendChild(renderer.domElement); const scene = new THREE.Scene(); scene.background = new THREE.Color(0x87CEEB); scene.fog = new THREE.Fog(0x87CEEB, 30, 80); const camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 100); camera.position.set(14, 10, 16); const controls = new OrbitControls(camera, renderer.domElement); controls.target.set(0, 3, 0); controls.enableDamping = true; controls.dampingFactor = 0.05; controls.minDistance = 5; controls.maxDistance = 35; controls.maxPolarAngle = Math.PI / 2.1; const ambient = new THREE.AmbientLight(0xffffff, 0.4); scene.add(ambient); const hemi = new THREE.HemisphereLight(0x87CEEB, 0x6daa3d, 0.6); scene.add(hemi); const dirLight = new THREE.DirectionalLight(0xfff5e6, 1.2); dirLight.position.set(10, 20, 5); dirLight.castShadow = true; dirLight.shadow.mapSize.width = 2048; dirLight.shadow.mapSize.height = 2048; dirLight.shadow.camera.near = 0.5; dirLight.shadow.camera.far = 50; dirLight.shadow.camera.left = -15; dirLight.shadow.camera.right = 15; dirLight.shadow.camera.top = 15; dirLight.shadow.camera.bottom = -15; scene.add(dirLight); const grassMat = new THREE.MeshStandardMaterial({ color: 0x7cb74a }); const stoneMat = new THREE.MeshStandardMaterial({ color: 0x9a9a9a }); const woodMat = new THREE.MeshStandardMaterial({ color: 0x8b3a3a }); const roofMat = new THREE.MeshStandardMaterial({ color: 0x2d2d2d }); const waterMat = new THREE.MeshStandardMaterial({ color: 0x2e8bcc, transparent: true, opacity: 0.8 }); const trunkMat = new THREE.MeshStandardMaterial({ color: 0x6b4226 }); const lanternLightMat = new THREE.MeshStandardMaterial({ color: 0xffdd99, emissive: 0xffaa55, emissiveIntensity: 0.6 }); const ground = new THREE.Mesh(new THREE.PlaneGeometry(40, 40), grassMat); ground.rotation.x = -Math.PI / 2; ground.receiveShadow = true; scene.add(ground); function createPagoda() { const
group = new THREE.Group(); const base = new THREE.Mesh(new THREE.BoxGeometry(8, 1.5, 8), stoneMat); base.position.y = 0.75; base.castShadow = true; base.receiveShadow = true; group.add(base); for (let i = 0; i < 3; i++) { const step = new THREE.Mesh(new THREE.BoxGeometry(2.5 - i * 0.4, 0.25, 1.0), stoneMat); step.position.set(0, 0.125 + i * 0.25, 4.5 + i * 0.5); step.castShadow = true; step.receiveShadow = true; group.add(step); } let y = 1.5; for (let i = 0; i < 5; i++) { const bodyW = 5.0 - i * 0.6; const bodyH = 1.8; const body = new THREE.Mesh(new THREE.BoxGeometry(bodyW, bodyH, bodyW), woodMat); body.position.y = y + bodyH / 2; body.castShadow = true; body.receiveShadow = true; group.add(body); const roofW = bodyW + 1.6; const roofH = 0.5; const roof = new THREE.Mesh(new THREE.BoxGeometry(roofW, roofH, roofW), roofMat); roof.position.y = y + bodyH + roofH / 2; roof.castShadow = true; roof.receiveShadow = true; group.add(roof); const cornerSize = 0.5; const corners = [[-1, -1], [-1, 1], [1, -1], [1, 1]]; for (const [sx, sz] of corners) { const corner = new THREE.Mesh(new THREE.BoxGeometry(cornerSize, 0.4, cornerSize), roofMat); corner.position.set(sx * roofW / 2, roof.position.y + roofH / 2 + 0.2, sz * roofW / 2); corner.castShadow = true; group.add(corner); } y = roof.position.y + roofH / 2; } const spireMat = new THREE.MeshStandardMaterial({ color: 0xffd700, emissive: 0xffaa00, emissiveIntensity: 0.3 }); const spireBase = new THREE.Mesh(new THREE.BoxGeometry(0.6, 0.6, 0.6), spireMat); spireBase.position.y = y + 0.3; group.add(spireBase); const spire = new THREE.Mesh(new THREE.BoxGeometry(0.3, 1.8, 0.3), spireMat); spire.position.y = y + 1.2; group.add(spire); const spireTop = new THREE.Mesh(new THREE.BoxGeometry(0.8, 0.2, 0.8), spireMat); spireTop.position.y = y + 2.1; group.add(spireTop); return group; } scene.add(createPagoda()); function createCherryTree(x, z, scale) { const group = new THREE.Group(); const trunk = new THREE.Mesh(new THREE.BoxGeometry(0.5
- scale, 1.6 * scale, 0.5 * scale), trunkMat); trunk.position.y = 0.8 * scale; trunk.castShadow = true; group.add(trunk); const foliage = new THREE.Group(); foliage.position.y = 1.6 * scale; const pinkMats = [ new THREE.MeshStandardMaterial({ color: 0xffb7c5 }), new THREE.MeshStandardMaterial({ color: 0xff9bb5 }), new THREE.MeshStandardMaterial({ color: 0xffc0cb }), new THREE.MeshStandardMaterial({ color: 0xffa6c9 }) ]; for (let i = 0; i < 14; i++) { const angle = (i / 14) * Math.PI * 2; const r = 1.0 + Math.random() * 0.8; const dx = Math.cos(angle) * r; const dz = Math.sin(angle) * r; const dy = Math.random() * 1.6; const cube = new THREE.Mesh( new THREE.BoxGeometry(0.8 * scale, 0.8 * scale, 0.8 * scale), pinkMats[Math.floor(Math.random() * pinkMats.length)] ); cube.position.set(dx, dy, dz); cube.castShadow = true; foliage.add(cube); } group.add(foliage); group.position.set(x, 0, z); return group; } scene.add(createCherryTree(4, 4, 1.1)); scene.add(createCherryTree(-5, 3, 0.9)); scene.add(createCherryTree(3, -5, 1.0)); scene.add(createCherryTree(-4, -4, 1.2)); scene.add(createCherryTree(6, -2, 0.8)); scene.add(createCherryTree(-6, -1, 1.0)); function createLantern(x, z) { const group = new THREE.Group(); const base = new THREE.Mesh(new THREE.BoxGeometry(0.9, 0.3, 0.9), stoneMat); base.position.y = 0.15; base.castShadow = true; group.add(base); const pillar = new THREE.Mesh(new THREE.BoxGeometry(0.3, 1.2, 0.3), stoneMat); pillar.position.y = 0.9; pillar.castShadow = true; group.add(pillar); const light = new THREE.Mesh(new THREE.BoxGeometry(0.7, 0.7, 0.7), lanternLightMat); light.position.y = 1.85; light.castShadow = true; group.add(light); const roof = new THREE.Mesh(new THREE.BoxGeometry(1.2, 0.3, 1.2), roofMat); roof.position.y = 2.35; roof.castShadow = true; group.add(roof); const top = new THREE.Mesh(new THREE.BoxGeometry(0.4, 0.2, 0.4), stoneMat); top.position.y = 2.6; top.castShadow = true; group.add(top); const glow = new THREE.PointLight(0xffaa55, 0.4,
6); glow.position.y = 2; group.add(glow); group.position.set(x, 0, z); return group; } scene.add(createLantern(2.0, 2.0)); scene.add(createLantern(2.0, 7.8)); scene.add(createLantern(7.8, 2.0)); scene.add(createLantern(9.8, 7.8)); function createPond() { const group = new THREE.Group(); const water = new THREE.Mesh(new THREE.BoxGeometry(7, 0.15, 5), waterMat); water.position.set(6, 0.075, 5); water.receiveShadow = true; group.add(water); const stone = new THREE.Mesh(new THREE.BoxGeometry(0.5, 0.3, 0.5), stoneMat); const positions = []; for (let x = 2.5; x <= 9.5; x += 0.7) { positions.push([x, 0.25, 2.5], [x, 0.25, 7.5]); } for (let z = 3; z <= 7; z += 0.7) { positions.push([2.5, 0.25, z], [9.5, 0.25, z]); } for (const [px, py, pz] of positions) { const s = stone.clone(); s.position.set(px, py, pz); s.castShadow = true; s.receiveShadow = true; group.add(s); } return group; } scene.add(createPond()); function createPathStone(x, z) { const s = new THREE.Mesh(new THREE.BoxGeometry(0.8, 0.08, 0.8), stoneMat); s.position.set(x, 0.04, z); s.castShadow = true; s.receiveShadow = true; scene.add(s); } createPathStone(1.0, 4.5); createPathStone(1.8, 4.8); createPathStone(2.5, 5.2); const petals = []; function createPetals() { const petalGeo = new THREE.BoxGeometry(0.15, 0.15, 0.15); const petalMat = new THREE.MeshStandardMaterial({ color: 0xffb7c5 }); for (let i = 0; i < 180; i++) { const mesh = new THREE.Mesh(petalGeo, petalMat); mesh.position.set( (Math.random() - 0.5) * 20, Math.random() * 8 + 2, (Math.random() - 0.5) * 20 ); mesh.rotation.set(Math.random() * Math.PI, Math.random() * Math.PI, Math.random() * Math.PI); petals.push({ mesh, speed: 0.5 + Math.random() * 0.8, phase: Math.random() * Math.PI * 2, rotSpeed: new THREE.Vector3( 1 + Math.random() * 2, 1 + Math.random() * 2, 1 + Math.random() * 2 ) }); scene.add(mesh); } } createPetals(); function onResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight); } window.addEventListener('resize', onResize); const clock = new THREE.Clock(); function animate() { requestAnimationFrame(animate); const delta = Math.min(clock.getDelta(), 0.05); const elapsed = clock.getElapsedTime(); for (const petal of petals) { petal.mesh.position.y -= petal.speed * delta; petal.mesh.position.x += Math.sin(petal.phase + elapsed) * 0.02 * delta; petal.mesh.position.z += Math.cos(petal.phase + elapsed * 0.7) * 0.02 * delta; petal.mesh.rotation.x += petal.rotSpeed.x * delta; petal.mesh.rotation.y += petal.rotSpeed.y * delta; petal.mesh.rotation.z += petal.rotSpeed.z * delta; if (petal.mesh.position.y < 0) { petal.mesh.position.y = 6 + Math.random() * 4; petal.mesh.position.x = (Math.random
AI 자동 생성 콘텐츠
본 콘텐츠는 r/LocalLLaMA의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기