Jump to content

Pyramid vector quantization

From Wikipedia, the free encyclopedia

This is an old revision of this page, as edited by X-Fi6 (talk | contribs) at 05:52, 5 April 2021 (Created page with ''''Pyramid vector quantization''' ('''PVQ''') is method used in audio and video codecs to quantize and transmit unit v...'). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

(diff) ← Previous revision | Latest revision (diff) | Newer revision → (diff)

Pyramid vector quantization (PVQ) is method used in audio and video codecs to quantize and transmit unit vectors, i.e. vectors whose magnitudes are known to the decoder but whose directions are unknown. PVQ may also be used as part of a gain/shape quantization scheme, whereby the magnitude and direction of a vector are quantized separately from each other. PVQ was initially described in 1986 in the paper "A Pyramid Vector Quantizer" by Thomas R. Fischer.[1]

One caveat of PVQ is that it operates under the taxicab distance (L1-norm). Conversion to/from the more familiar Euclidean distance (L2-norm) is possible via vector projection, though results in a less uniform distribution of quantization points (the poles of the Euclidean n-sphere become denser than non-poles).[2] No efficient algorithm for the ideal (i.e., uniform) vector quantization of the Euclidean n-sphere is known as of 2010.[3]

PVQ is used in the Opus audio codec and the Daala video codec.

Overview

As a form of vector quantization, PVQ defines a codebook of M quantization points, each of which is assigned an integer codeword from 0 to M−1. The goal of the encoder is to find the codeword of the closest vector, which the decoder must decode back into a vector.

The PVQ codebook consists of all L-dimensional points p with integer-only coordinates whose absolute values sum to a constant K (i.e. whose L1-norm equals K). In set-builder notation:

where denotes the L1-norm of .

As it stands, the set S tesselates the surface of an L-dimensional pyramid. If desired, we may reshape it into a sphere by "projecting" the points onto the sphere, i.e. by normalizing them:

where denotes the L2-norm of .

Increasing the parameter K results in more quantization points, and hence typically yields a more "accurate" approximation of the original unit vector at the cost of larger integer codewords that require more bits to transmit.

Example

Suppose we wish to quantize 3-dimensional unit vectors using the parameter K=2. Our codebook becomes:

Codeword Point Normalized point
0 <−2, 0, 0> <−1.000, 0.000, 0.000>
1 <−1, −1, 0> <−0.707, −0.707, 0.000>
2 <−1, 0, −1> <−0.707, 0.000, −0.707>
3 <−1, 0, 1> <−0.707, 0.000, 0.707>
4 <−1, 1, 0> <−0.707, 0.707, 0.000>
5 <0, −2, 0> <0.000, −1.000, 0.000>
6 <0, −1, −1> <0.000, −0.707, −0.707>
7 <0, −1, 1> <0.000, −0.707, 0.707>
8 <0, 0, −2> <0.000, 0.000, −1.000>
9 <0, 0, 2> <0.000, 0.000, 1.000>
Codeword Point Normalized point
10 <0, 1, −1> <0.000, 0.707, −0.707>
11 <0, 1, 1> <0.000, 0.707, 0.707>
12 <0, 2, 0> <0.000, 1.000, 0.000>
13 <1, −1, 0> <0.707, −0.707, 0.000>
14 <1, 0, −1> <0.707, 0.000, −0.707>
15 <1, 0, 1> <0.707, 0.000, 0.707>
16 <1, 1, 0> <0.707, 0.707, 0.000>
17 <2, 0, 0> <1.000, 0.000, 0.000>

(0.707 = rounded to 3 decimal places.)

Now, suppose we wish to transmit the unit vector <0.517, −0.675, 0.330> (rounded here to 3 decimal places, for clarity). According to our codebook, the closest point we can pick is codeword 6 (<−0.707, −0.707, 0.000>), located approximately 0.381 units away from our original point.

Increasing the parameter K results in a larger codebook, which typically increases the reconstruction accuracy. For example, based on the Python code below, K=5 (codebook size: 102) yields an error of only 0.097 units, and K=20 (codebook size: 1602) yields an error of only 0.042 units.

Python code

import itertools
import math
from typing import List, NamedTuple, Tuple

class PVQEntry(NamedTuple):
	codeword: int
	point: Tuple[int, ...]
	normalizedPoint: Tuple[float, ...]

def createPVQCodebook(n: int, k: int) -> List[PVQEntry]:
	"""
	Naive algorithm to generate an n-dimensional PVQ codebook
	with k pulses.
	Runtime complexity: O(k**n)
	"""
	ret = []
	for p in itertools.product(range(-k,k+1), repeat=n):
		if sum(abs(x) for x in p) == k:
			norm = math.sqrt(sum(abs(x)**2 for x in p))
			q = tuple(x/norm for x in p)
			ret.append(PVQEntry(len(ret), p, q))
	
	return list(ret)

def searchPVQCodebook(codebook: List[PVQEntry], p: Tuple[float, ...]) -> Tuple[PVQEntry,float]:
	"""
	Naive algorithm to search the PVQ codebook. Returns the point in the
	codebook that's "closest" to p, according to the Euclidean distance.)
	"""
	ret = None
	min_dist = None
	for i in range(len(codebook)):
		q = codebook[i].normalizedPoint
		dist = math.sqrt(sum(abs(q[i]-p[i])**2 for i in range(len(p))))
		if min_dist == None or dist < min_dist:
			ret = codebook[i]
			min_dist = dist
	
	return ret, min_dist

def example(p: Tuple[float, ...], k: int) -> None:
	n = len(p)
	codebook = createPVQCodebook(n, k)
	print('Number of codebook entries: ' + str(len(codebook)))
	entry, dist = searchPVQCodebook(codebook, p)
	print('Best entry: ' + str(entry))
	print('Distance: ' + str(dist))

phi = 1.2
theta = 5.4
x = math.sin(phi)*math.cos(theta)
y = math.sin(phi)*math.sin(theta)
z = math.cos(phi)
p = (x, y, z)
example(p, 2)
example(p, 5)
example(p, 10)

Complexity

The PVQ codebook can be searched in .[2]

The codebook size obeys the recurrence[2]

with for all and for all .

A closed-form solution is given by[4]

where is the hypergeometric function.

References

  1. ^ Fischer, Thomas R. (July 1986). "A Pyramid Vector Quantizer". IEEE Transactions on Information Theory. 32 (4): 568–583. doi:10.1109/TIT.1986.1057198.
  2. ^ a b c Valin, Jean-Marc (September 2013). "Pyramid Vector Quantization for Video Coding" (PDF). Xiph.Org Foundation.
  3. ^ Valin, Jean-Marc; Terriberry, Timothy B.; Montgomery, Christopher; Maxwell, Gregory (January 2010). "A High-Quality Speech and Audio Codec With Less Than 10 ms Delay". IEEE Transactions on Audio, Speech, and Language Processing. 18 (1): 58–67. doi:10.1109/TASL.2009.2023186.
  4. ^ Terriberry, Timothy B. (December 2007). "Pulse Vector Coding". Xiph.Org Foundation. Archived from the original on September 30, 2019.

See also