네거티브 프롬프트

Negative prompt

생성 결과에서 빼고 싶은 개념을 지정하는, 프롬프트와 반대 방향으로 작동하는 텍스트.

다른 이름: Negative conditioning
···
html
<div class="wrap">
  <canvas id="cv"></canvas>
  <div class="panel">
    <div class="row"><i class="ic" id="ic" data-state="bad"></i><span id="lbl">네거티브 프롬프트 미사용</span></div>
    <div class="neg" id="neg"></div>
  </div>
</div>
css
.wrap{position:relative;width:100%;height:100%}
#cv{position:absolute;inset:0;width:100%;height:100%}
.panel{position:absolute;left:10px;right:10px;bottom:10px;z-index:2;padding:8px 10px;border-radius:10px;
  background:rgba(13,13,18,0.6);backdrop-filter:blur(6px);border:1px solid rgba(255,255,255,0.15)}
.row{display:flex;align-items:center;gap:7px;font-size:11.5px;font-weight:600;color:#f1f0ec}
.ic{width:16px;height:16px;border-radius:50%;position:relative;flex-shrink:0}
.ic[data-state=bad]{background:var(--accent-2)}
.ic[data-state=bad]::before,.ic[data-state=bad]::after{content:"";position:absolute;width:8px;height:1.6px;background:#fff;top:50%;left:50%}
.ic[data-state=bad]::before{transform:translate(-50%,-50%) rotate(45deg)}
.ic[data-state=bad]::after{transform:translate(-50%,-50%) rotate(-45deg)}
.ic[data-state=good]{background:var(--accent-3)}
.ic[data-state=good]::before{display:none}
.ic[data-state=good]::after{content:"";width:4px;height:7px;border:solid #fff;border-width:0 1.6px 1.6px 0;transform:rotate(45deg) translate(-1px,-1px);top:45%;left:42%}
.neg{margin-top:4px;font-family:ui-monospace,monospace;font-size:10.5px;color:#b7b7c2}
js
const cv = document.getElementById('cv'), ctx = cv.getContext('2d');
const ic = document.getElementById('ic'), lbl = document.getElementById('lbl'), neg = document.getElementById('neg');
function fit() { const dpr = Math.min(devicePixelRatio || 1, 2); cv.width = innerWidth * dpr; cv.height = innerHeight * dpr; ctx.setTransform(dpr, 0, 0, dpr, 0, 0); }
addEventListener('resize', fit); fit();

function mulberry32(a) { return function () { a |= 0; a = a + 0x6D2B79F5 | 0; let t = Math.imul(a ^ a >>> 15, 1 | a); t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t; return ((t ^ t >>> 14) >>> 0) / 4294967296; }; }

function paintBase(w, h) {
  const r = mulberry32(42);
  const g = ctx.createLinearGradient(0, 0, 0, h);
  g.addColorStop(0, 'hsl(210 55% 78%)'); g.addColorStop(1, 'hsl(210 40% 42%)');
  ctx.fillStyle = g; ctx.fillRect(0, 0, w, h);
  ctx.beginPath(); ctx.arc(w * 0.72, h * 0.24, Math.min(w, h) * 0.08, 0, Math.PI * 2); ctx.fillStyle = 'hsl(45 90% 82%)'; ctx.fill();
  for (let l = 0; l < 2; l++) {
    ctx.beginPath(); ctx.moveTo(0, h);
    for (let i = 0; i <= 6; i++) { const x = w * i / 6; const y = h * (0.55 + l * 0.15) - r() * h * 0.1; ctx.lineTo(x, y); }
    ctx.lineTo(w, h); ctx.closePath();
    ctx.fillStyle = 'hsl(150 ' + (30 - l * 8) + '% ' + (24 + l * 12) + '%)'; ctx.fill();
  }
}
function paintArtifacts(w, h) {
  const r = mulberry32(99);
  ctx.strokeStyle = 'rgba(255,20,147,0.7)'; ctx.lineWidth = 3; ctx.lineCap = 'round';
  ctx.beginPath(); ctx.moveTo(w * 0.15, h * 0.35);
  for (let i = 0; i < 5; i++) ctx.lineTo(w * (0.15 + i * 0.12) + r() * 20, h * (0.35 + (r() - 0.5) * 0.3));
  ctx.stroke();
  ctx.fillStyle = 'rgba(255,255,255,0.85)';
  ctx.fillRect(w * 0.6, h * 0.68, w * 0.24, h * 0.1);
  for (let i = 0; i < 10; i++) { ctx.fillStyle = 'hsl(' + Math.floor(r() * 360) + ' 90% 60%)'; ctx.beginPath(); ctx.arc(w * 0.5 + r() * w * 0.35, h * 0.15 + r() * h * 0.15, 2 + r() * 3, 0, Math.PI * 2); ctx.fill(); }
}
function render(bad) {
  const w = innerWidth, h = innerHeight;
  paintBase(w, h);
  if (bad) paintArtifacts(w, h);
}
const list = 'blurry, extra limbs, watermark, noisy';
function cycle(bad) {
  render(bad);
  ic.dataset.state = bad ? 'bad' : 'good';
  lbl.textContent = bad ? '네거티브 프롬프트 미사용' : '네거티브 프롬프트 사용';
  neg.textContent = bad ? '(제외 지정 없음)' : list;
  setTimeout(() => cycle(!bad), 2400);
}
cycle(true);

프롬프트가 "이쪽으로 가라"는 조건이라면 네거티브 프롬프트는 "이쪽에서는 멀어져라"는 조건입니다. 분류자 없는 안내(classifier-free guidance) 기법에서는 매 스텝마다 프롬프트를 조건으로 준 예측과, 네거티브 프롬프트(또는 빈 텍스트)를 조건으로 준 예측을 함께 계산해서 그 차이만큼 결과를 밀어냅니다 — 즉 네거티브 프롬프트에 적은 단어들은 결과에서 통계적으로 억제됩니다.

"blurry", "extra limbs", "watermark"처럼 흔히 겪는 결함을 나열해두면 그런 결함이 나올 확률이 줄어듭니다. 다만 이건 확률적인 억제이지 절대 금지가 아니라서, 나열해도 가끔은 그대로 나타날 수 있습니다.

네거티브 프롬프트를 지나치게 길고 관용적인 목록으로 채우면 오히려 스타일이 과도하게 제약되어 결과가 밋밋해질 수 있습니다. 특정 결함이 반복될 때만 그에 맞춰 추가하는 편이 안전합니다.

아래 데모는 실제 확산 모델의 안내 계산 대신, 네거티브 프롬프트를 껐을 때만 미리 그려둔 "결함"(얼룩·과다 노출 점·워터마크 상자)을 덧그리는 단순화한 시뮬레이션입니다.

언제 쓰나

반복적으로 나타나는 특정 결함을 줄이고 싶을 때 그 결함을 짧게 적습니다. 모든 생성에 만능 목록을 습관적으로 붙이기보다, 실제로 반복되는 문제에 맞춰 조정하는 편이 낫습니다.