Skip to content

Commit bbcf761

Browse files
committed
refactor(embedding): share embedding normalization for future multimodal embeddings
- Extract normalization into a shared utility and reuse it in Llama.embed(). - Preserve existing normalization modes, bool compatibility, zero-vector handling, and raw ranking scores. Signed-off-by: JamePeng <jame_peng@sina.com>
1 parent c58bd96 commit bbcf761

2 files changed

Lines changed: 34 additions & 38 deletions

File tree

‎llama_cpp/_utils.py‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,38 @@
33

44
from typing import Any, Dict
55

6+
7+
def normalize_embedding(vector, mode=2):
8+
"""Normalize an embedding using llama.cpp modes; return a list.
9+
10+
vector (sequence[float]): Input embedding; zero vectors stay unchanged.
11+
mode (bool/int): True selects L2 (2), False selects no normalization (-1).
12+
<0: None; preserve the original values.
13+
0: MaxInt16; scale max(abs(x)) to 32760, retaining floating-point values.
14+
1: L1; divide by sum(abs(x)) so absolute values sum to one.
15+
2: L2; divide by sqrt(sum(x**2)) to produce a unit-length vector.
16+
>2: Lp; divide by sum(abs(x)**p)**(1/p), with p = mode.
17+
"""
18+
import numpy as np
19+
20+
if isinstance(mode, bool):
21+
mode = 2 if mode else -1
22+
if not isinstance(mode, int):
23+
raise TypeError("normalize must be a bool or int")
24+
values = list(vector)
25+
if mode < 0:
26+
return values
27+
array = np.asarray(values, dtype=np.float32)
28+
if mode == 0:
29+
norm = float(np.max(np.abs(array))) if array.size else 0.0
30+
elif mode == 1:
31+
norm = float(np.sum(np.abs(array)))
32+
elif mode == 2:
33+
norm = float(np.linalg.norm(array))
34+
else:
35+
norm = float(np.sum(np.abs(array) ** mode) ** (1.0 / mode))
36+
return values if norm == 0 else ((array / norm) * (32760.0 if mode == 0 else 1.0)).tolist()
37+
638
# Avoid "LookupError: unknown encoding: ascii" when open() called in a destructor
739
outnull_file = open(os.devnull, "w")
840
errnull_file = open(os.devnull, "w")

‎llama_cpp/llama.py‎

Lines changed: 2 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@
8282
clear_log_filters,
8383
reset_log_filters,
8484
)
85-
from ._utils import suppress_stdout_stderr
85+
from ._utils import suppress_stdout_stderr, normalize_embedding
8686

8787

8888
def _format_speculative_duration(seconds: float) -> str:
@@ -3166,43 +3166,7 @@ def embed(
31663166
raise TypeError("normalize must be a bool or int")
31673167

31683168
def normalize_vector(vector: Sequence[float]) -> List[float]:
3169-
values = list(vector)
3170-
# -1 (NONE): preserve the original vector. RANK always preserves
3171-
# raw classification scores regardless of the requested mode.
3172-
if normalize_mode == -1 or is_rank:
3173-
return values
3174-
3175-
array = np.asarray(values, dtype=np.float32)
3176-
# Compute y = scale * x / norm(x).
3177-
if normalize_mode == 0:
3178-
# 0 (MAX_INT16): y = 32760 * x / max(abs(x)). The result
3179-
# remains floating point; this is scaling, not int16 quantization.
3180-
norm = float(np.max(np.abs(array))) if array.size else 0.0
3181-
scale = 32760.0
3182-
elif normalize_mode == 1:
3183-
# 1 (TAXICAB / L1): y = x / sum(abs(x)).
3184-
norm = float(np.sum(np.abs(array)))
3185-
scale = 1.0
3186-
elif normalize_mode == 2:
3187-
# 2 (EUCLIDEAN / L2): y = x / sqrt(sum(x_i ** 2)).
3188-
norm = float(np.linalg.norm(array))
3189-
scale = 1.0
3190-
elif normalize_mode > 2:
3191-
# p > 2 (PNORM): y = x / (sum(abs(x_i) ** p)) ** (1/p).
3192-
# The mode itself is p; NORM_MODE_PNORM = 6 selects the L6 norm.
3193-
norm = float(
3194-
np.sum(np.abs(array) ** normalize_mode)
3195-
** (1.0 / normalize_mode)
3196-
)
3197-
scale = 1.0
3198-
else:
3199-
# Other negative modes retain the existing passthrough behavior.
3200-
return values
3201-
3202-
# Zero vectors remain zero rather than producing NaNs on division.
3203-
if norm == 0.0:
3204-
return values
3205-
return ((array / norm) * scale).tolist()
3169+
return list(vector) if is_rank else normalize_embedding(vector, normalize_mode)
32063170

32073171
if isinstance(input, str):
32083172
inputs: List[Union[str, List[int]]] = (

0 commit comments

Comments
 (0)