泰勒公式与量化#

定理

假设 \(f(x)\)\(x_0 \in [a, b]\) 内有直到 \(n+1\) 阶导,则当 \(x \in [a, b]\) 时,泰勒多项式

(1)#\[ p_n (x) = \sum_{k=0}^n \cfrac{f^{(k)}(x_0)}{k!} (x - x_0)^k \]

满足

(2)#\[ f(x) - p_n(x) = \cfrac{f^{(n+1)}(\xi)}{(n+1)!} (x - x_0)^{n+1} \]

其中 \(\xi \in [x_0, x]\),因而,\(\xi \in [a, b]\)

这样,可以使用 \(p\) 进制数近似浮点数:

(3)#\[ x = \sum_{k=0}^{\infty} x_k p^k \]

其中 \(x_k \in Q\)

这里 \(Q\) 表示 \(p\) 进制数的值域。

比特(bit)是表示信息量的最小单位,可以用 \(0\) (不存在)和 \(1\) (存在)来度量。这样二进制数域 \(\{0, 1\}\) 便可等价于信息量。

备注

计算机中数据存储是以“字节”(Byte,简写为 B)为单位,数据传输大多是以“位”(bit,又名“比特”)为单位,且有 \(1 \text{B} = 8 \text{bit}\)\(1 \text{bit}\) 表示 \(0\)\(1\) 两种状态。

计算机存储整数可能有 int8,uint8,int32,int64 等。

如若限定 \(k=8, p=2, x_k \in \{0, 1\}\),则 \(x \in [0,2^8-1] \cap \mathbb{N} \)。这种约束下的集合便是值域为 \([0, 255]\) 的 uint8 数据。

import numpy as np

a = np.array(2, dtype="uint8")
a
array(2, dtype=uint8)

查看数据占用字节数:

a.itemsize # 1字节=8比特
1

可以存储两个 uint8 数据为一个块:

a = np.array([2, 7], dtype="uint8")
a
array([2, 7], dtype=uint8)

单个元素占用字节数:

a.itemsize
1

全部数据集合占用字节数:

a.nbytes
2

单个 uint8 数据,图示:

flowchart LR subgraph uint8 x0[0或1] x1[0或1] x2[0或1] x3[0或1] x4[0或1] x5[0或1] x6[0或1] x7[0或1] end

其他数据类型可以类推。也可以对数据类型进行转换:

v = np.array([300, 5, 100, -20], dtype="int32")
v
array([300,   5, 100, -20], dtype=int32)

转换为 uint8 数据:

q = v.astype("uint8")
q
array([ 44,   5, 100, 236], dtype=uint8)

可见数据被截断了。

v % 256
array([ 44,   5, 100, 236], dtype=int32)

量化数据#

def normalize(v):
    """将数据缩放到 [0, 1]"""
    b = v.min() # \alpha
    a = v.max() - b # \beta
    v = v - b
    return v/a
class Quant:
    def __init__(self, x, dtype="uint8"):
        self.x = x
        self.dtype = dtype
        self.q = x.astype(self.dtype)
    
    @property 
    def scale(self):
        a = self.x.max() - self.x.min()
        b =  self.q.max() - self.q.min()
        return a/b
    
    @property
    def zero_point(self):
        return np.round(self.q.max() - self.x.max()/self.scale)
v = np.array([300, 5, 100, -20], dtype="int32")
v
array([300,   5, 100, -20], dtype=int32)
self = Quant(v)
self.scale, self.zero_point
(1.3852813852813852, 19.0)
x = (self.q - self.zero_point) * self.scale
x = x.astype("int32")
x
array([ 34, -19, 112, 300], dtype=int32)
v
array([300,   5, 100, -20], dtype=int32)