作者归档:admin

大模型概念之: 权重

🧠 大模型中的“权重”概念

在大模型(LLM)的语境下,权重是指模型中的参数(Parameters),它们是模型在训练过程中学习到的数值

简单来说,如果把大模型想象成一个巨型的人脑网络,那么:

  1. 神经元(Neurons):是信息处理的基本单位。
  2. 连接(Connections):是神经元之间传递信息的路径。
  3. 权重(Weights):就是这些连接上的“强度”或“重要性”数值。

1. 权重的本质和作用

  • 数值集合(The Numbers):权重是模型中数十亿甚至数万亿个**浮点数(Floating-point numbers)**的集合。
  • 知识和规则(Knowledge & Rules):这些数值共同编码了模型从海量训练数据中学到的语言结构、语法规则、世界知识、事实信息以及推理能力
  • 计算的核心(The Core Calculation):在模型进行推理(如生成一个回复)时,输入数据(文本、图像等)会在每一层神经网络中与这些权重进行矩阵乘法等运算。权重决定了输入信息应该如何被组合、转换和传递到下一层。

例如: 当模型看到“猫”这个词时,与“猫”相关的权重可能被激活,并指导模型在生成下一个词时偏向于“抓”、“毛茸茸”、“宠物”等词汇。

2. 权重和模型大小的关系

  • 参数量(Parameter Count):通常用来衡量一个模型的大小。一个 $8\text{B}$ 模型就有 80 亿个参数(即 80 亿个权重值)。参数量越大,理论上模型能编码的知识和处理复杂任务的能力就越强。

3. 权重分布和量化的关系(承接 INT4 话题)

当讨论到**量化(Quantization)**时,权重分布变得非常重要:

  • 分布特点(Distribution):大型模型的权重值通常呈窄而高的正态分布(Normal Distribution),这意味着绝大多数权重的值都集中在 0 附近。
  • 量化优化(Optimization):INT4 量化技术(如 NF4)正是利用了这一特点。
    • NF4 (Normalized Float 4) 是一种针对正态分布权重优化的数据类型,它能更有效地将这些集中在 0 附近的浮点值映射到 4 位的整数空间,从而在大幅压缩存储空间的同时,最大限度地减少信息损失。

因此,“权重”是模型的大脑记忆,而“权重分布”是它的数值特征,决定了我们能用多高效的方式(如 INT4 量化)来存储和运行它。

1. 正态分布的特点与量化挑战

大型语言模型的权重(Weight)在训练后,通常表现为**以零为中心的、服从正态分布(Normal Distribution)**的形状,也被称为“钟形曲线”:

  • 特点一:高度集中于中心 (0)
    • 含义: 绝大多数的权重值都非常接近 $0$(例如,在 $-0.1$ 到 $+0.1$ 之间)。这些“小值”贡献了模型的绝大部分信息和功能。
    • 量化挑战: 如果采用均匀量化(即,将数值范围平均分配给 $2^4 = 16$ 个量化点),那么大部分量化点会被浪费在极值(如 $-1$ 或 $+1$)上,而权重集中的 $0$ 附近只有很少的量化点。这会导致 $0$ 附近的细微差别被粗略地映射到相同的量化点,造成严重的精度损失
  • 特点二:越靠近边缘,数值越稀疏
    • 含义: 只有极少数的权重值是较大的正数或负数(这些是模型中少数关键连接)。
    • 量化挑战: 稀疏的极值(Outliers)虽然对模型影响大,但由于数量少,即使分配的量化点少一些,精度损失也可以接受。

2. NF4 如何匹配正态分布(非均匀量化)

NF4 的核心思想是实现非均匀量化,即在权重集中的区域分配更多的量化点,在稀疏的区域分配更少的量化点。

量化点NF4 的分配原则均匀量化的分配原则
靠近 0 的区域分配更多的量化点,使得 $0$ 附近的细微数值变化能被精确地编码。数量少,数值间的间隔大。
远离 0 的区域分配更少的量化点,允许数值间的间隔更大。数量多,但大部分时候用不上。

NF4 实现这种匹配的关键在于它是一种归一化浮点格式 (Normalized Float 4)

① 步骤:归一化 (Normalization)

首先,NF4 会找到权重矩阵中的最大绝对值 $M$(即归一化常数),然后将所有权重值 $W$ 归一化到 $[-1, 1]$ 的范围内。

$$\text{W}_{\text{normalized}} = \frac{W}{M}$$

② 核心:信息理论最优 (Information Theoretically Optimal)

NF4 的设计是信息论最优的。这意味着在只有 4 位的约束下,它能够以最小的信息损失来编码正态分布的数据。

NF4 实际上定义了一个具有 $2^4=16$ 个离散值的码本 (Codebook),这些离散值的间隔是不等距的。这些量化点被巧妙地放置在归一化后的 $[-1, 1]$ 区间内:

  • 量化点密集区: 大部分的量化点(如 10 个以上)被紧密地安排在靠近 $0$ 的区域。
  • 量化点稀疏区: 只有少数几个量化点被用来表示远离 $0$ 的较大值。

这种非线性、非均匀的量化方式,确保了那些对模型性能贡献最大的小权重值(靠近 $0$ 的区域)能得到最高的编码精度,而对模型精度影响较小的极值则采用较粗略的编码,从而用最小的位宽(4 位)实现了最大的精度保留。

总结

NF4 能够与 LLM 的权重分布完美匹配,是因为它利用了正态分布**“中心密集,两端稀疏”的特性,通过非均匀分配**其 16 个量化点,将编码的精度资源集中在了最重要的“小权重”区域。这是实现高压缩率(4-bit)且低精度损失的关键所在。

如何使用google edns测试区域调度是否合理

v4:

dig @8.8.8.8 www.qq.com +subnet=108.165.64.0/24

v6:

dig @2001:4860:4860::8888 www.qq.com +subnet=2400:8d60:13::/56

google常用的DNS有: 8.8.8.8 8.8.4.4 2001:4860:4860::8844 2001:4860:4860::8888

腾讯的DNS也好用: 119.29.29.29

需要注意的是: v4里边最小的掩码是24, V6里边最小的掩码是56, 否则可能会出现如下提示EDE: 49152: (Provided ECS includes 64 bits, but no more than 56 are allowed. https://developers.google.com/speed/public-dns/docs/ecs)

nginx 1.28.0 with openssl3.5测试

首先, 1.28.0是支持openssl3.5 build with HTTP3了

--with-openssl=openssl-3.5.0 --with-http_v3_module

从nginx 官方HTTP3的文档看, OPENSSL是不支持early_data,也就是0-RTT的, 可以参考链接:https://nginx.org/en/docs/quic.html

An SSL library that provides QUIC support is recommended to build nginx, such as BoringSSL, LibreSSL, or QuicTLS. Otherwise, the OpenSSL compatibility layer will be used that does not support early data.

这里使用boringSSL和openSSL, 开启HTTP3 和 ssl_early_data on , 分别使用curl和wireshark听包做了测试

以上是使用chrome访问, 并使用wireshark 听包的结果, 可以看到openssl3.5支持H3但是不支持0-RTT

这是使用curl 8.14.1 增加了DEBUG代码后对比发现的, 可以看到openssl 并没有max early_data的值, 应该是这个原因导致H3 0-RTT失败

主要修改了curl代码里边lib/vtls/openssl.c ossl_init_session_and_alpns函数

/* 将二进制数据转换为十六进制字符串 */
static void bin_to_hex(const unsigned char *bin, size_t len, char *out, size_t out_size) {
size_t i;
for (i = 0; i < len && i * 2 < out_size – 2; i++) {
snprintf(out + i * 2, 3, “%02X”, bin[i]);
}
out[i * 2] = ‘\0’;
}

/* 将协议版本转换为字符串 */
static const char *protocol_version_str(int version) {
switch (version) {
case SSL3_VERSION: return “SSLv3”;
case TLS1_VERSION: return “TLSv1.0”;
case TLS1_1_VERSION: return “TLSv1.1”;
case TLS1_2_VERSION: return “TLSv1.2”;
case TLS1_3_VERSION: return “TLSv1.3”;
default: return “Unknown”;
}
}

/* 将早期数据状态转换为字符串 */
static const char *early_data_status_str(int status) {
switch (status) {
case SSL_EARLY_DATA_ACCEPTED: return “Accepted”;
case SSL_EARLY_DATA_REJECTED: return “Rejected”;
case SSL_EARLY_DATA_NOT_SENT: return “None”;
default: return “Unknown”;
}
}

/* 获取公钥信息 */
static void get_pubkey_info(EVP_PKEY *pkey, char *out, size_t out_size) {
if (!pkey) {
snprintf(out, out_size, “None”);
return;
}

int key_type = EVP_PKEY_base_id(pkey);
switch (key_type) {
    case EVP_PKEY_RSA: {
        int bits = EVP_PKEY_bits(pkey);
        snprintf(out, out_size, "RSA, %d bits", bits);
        break;
    }
    case EVP_PKEY_EC: {
        const EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(pkey);
        if (ec_key) {
            int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key));
            const char *curve_name = OBJ_nid2sn(nid);
            snprintf(out, out_size, "EC, curve %s", curve_name ? curve_name : "Unknown");
        } else {
            snprintf(out, out_size, "EC, unknown curve");
        }
        break;
    }
    default: {
        const char *name = OBJ_nid2sn(key_type);
        snprintf(out, out_size, "%s", name ? name : "Unknown");
        break;
    }
}

}

static CURLcode
ossl_init_session_and_alpns(struct ossl_ctx *octx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ssl_peer *peer,
const struct alpn_spec *alpns_requested,
Curl_ossl_init_session_reuse_cb *sess_reuse_cb)
{
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
struct alpn_spec alpns;
char error_buffer[256];
CURLcode result;

Curl_alpn_copy(&alpns, alpns_requested);

octx->reused_session = FALSE;
if(ssl_config->primary.cache_session) {
struct Curl_ssl_session *scs = NULL;

result = Curl_ssl_scache_take(cf, data, peer->scache_key, &scs);


if(!result && scs && scs->sdata && scs->sdata_len) {
  const unsigned char *der_sessionid = scs->sdata;
  size_t der_sessionid_size = scs->sdata_len;
  SSL_SESSION *ssl_session = NULL;

  /* If OpenSSL does not accept the session from the cache, this
   * is not an error. We just continue without it. */
  ssl_session = d2i_SSL_SESSION(NULL, &der_sessionid,
                                (long)der_sessionid_size);
  if(ssl_session) {

    /* XX-DEBUG */
    int proto_version = SSL_SESSION_get_protocol_version(ssl_session);
    infof(data, "XXX-DEBUG: Protocol version: %s", protocol_version_str(proto_version));


    unsigned int sid_len;
    const unsigned char *sid = SSL_SESSION_get_id(ssl_session, &sid_len);
    char sid_hex[256] = "";
    bin_to_hex(sid, sid_len, sid_hex, sizeof(sid_hex));
    infof(data, "XXX-DEBUG: Session ID: %s (length: %u)", sid_hex, sid_len);


    unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH];
    size_t master_key_len = SSL_SESSION_get_master_key(ssl_session, master_key, sizeof(master_key));
    infof(data, "XXX-DEBUG: Master key length: %zu bytes", master_key_len);

    /*const SSL_CIPHER *cipher = SSL_SESSION_get0_cipher(scs->sdata);
    const char *cipher_name = cipher ? SSL_CIPHER_get_name(cipher) : "Unknown";
    infof(data, "XXX-DEBUG: Cipher suite: %s\n", cipher_name);*/

    uint32_t max_early_data = SSL_SESSION_get_max_early_data(ssl_session);
    infof(data, "XXX-DEBUG: Max early data: %u bytes", max_early_data);

    /* 早期数据状态 没找到这个函数*/
    /*int early_data_status = SSL_SESSION_get_early_data_status(ssl_session);
    infof(data, "XXX-DEBUG: Early data status: %s\n", early_data_status_str(early_data_status));*/

    /* 证书链:主题、颁发者、公钥 */
    X509 *peer_cert = SSL_SESSION_get0_peer(ssl_session);
    if (peer_cert) {

        char subject_str[256];
        X509_NAME *subject = X509_get_subject_name(peer_cert);
        X509_NAME_oneline(subject, subject_str, sizeof(subject_str));
        infof(data, "XXX-DEBUG: Peer certificate subject: %s", subject_str);


        char issuer_str[256];
        X509_NAME *issuer = X509_get_issuer_name(peer_cert);
        X509_NAME_oneline(issuer, issuer_str, sizeof(issuer_str));
        infof(data, "XXX-DEBUG: Peer certificate issuer: %s", issuer_str);


        char pubkey_info[256];
        EVP_PKEY *pubkey = X509_get0_pubkey(peer_cert);
        get_pubkey_info(pubkey, pubkey_info, sizeof(pubkey_info));
        infof(data, "XXX-DEBUG: Peer certificate public key: %s", pubkey_info);
        EVP_PKEY_free(pubkey); 
    } else {
        infof(data, "XXX-DEBUG: Peer certificate: None");
    }


    long session_time = SSL_SESSION_get_time(ssl_session);
    char time_str[64];
    struct tm *tm = gmtime(&session_time);
    strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S GMT", tm);
    infof(data, "XXX-DEBUG: Session creation time: %s", time_str);


    long timeout = SSL_SESSION_get_timeout(ssl_session);
    infof(data, "XXX-DEBUG: Session timeout: %ld seconds", timeout);




    const char *hostname = SSL_SESSION_get0_hostname(ssl_session);
    infof(data, "XXX-DEBUG: Hostname (SNI): %s", hostname ? hostname : "None");


    const unsigned char *ticket;
    size_t ticket_len;
    SSL_SESSION_get0_ticket(ssl_session, &ticket, &ticket_len);
    char ticket_hex[512] = "";
    bin_to_hex(ticket, ticket_len, ticket_hex, sizeof(ticket_hex));
    infof(data, "XXX-DEBUG: Session ticket: %s (length: %zu)", ticket_hex, ticket_len);

    /* 对端信息(简化为证书存在性) */
    infof(data, "XXX-DEBUG: Peer info: %s", peer_cert ? "Certificate present" : "No peer info");
    /* XX-DEBUG END */

nginx 1.27.3新增动态resolver

nginx 1.27.3新增了一个非常强大的功能:动态resolver, 这本是商业版的特殊属性, 现在下放到社区

主要有2个:

  1. upstream配置里边支持增加单独的resolver
  2. upstream 里边的server 可以增加resolve 后缀表示使用resolver解析

第一点可以跟全局的resolver分开, 比如部分的域名我就只希望走内网解析, 交给内网的LDNS, 而另一部分的域名则希望走公网,会交给另一组的LDNS

第二点则是商业版下发的福利了, 按照以前版本的功能, 如果server 里边接的是域名, 那么解析只在nginx启动的时候生效, 如果域名解析修改了(比如服务异常摘掉部分IP/修改了解析),nginx 是无感知的, 需要重启服务才能获取新的A记录. 现在则会动态更新并维护一个动态的zone

https://nginx.org/en/docs/http/ngx_http_upstream_module.html#resolver

Adblock plus 还是 uBlock origin?

打开google搜索Adblock plus 还是 uBlock origin, 一直是有争议的问题, 我也是用了很久的adblock plus

自从youtube 广告越来越多, 动辄3个广告几分钟, 而热衷于商业价值的adblock plus 貌似越来越”无能为力”,  uBlock origin实际上已经成为唯一的选择

而使用下来可以发现uBlock 更是有节省内存,性能更佳的优点, 屏蔽youtube广告, 干净, 清爽

其实从2016年, Mozilla Firefox 就把默认推荐的广告插件从adblock plus替换成了uBlock origin

pip install 安装不上怎么办

安装一些模块的时候偶尔会遇到”ERROR: Could not find a version that satisfies the requirement”的提示

其实就是当前的python对应的pip安装包没有这个新版本了, 如果不想往上升, 其实是可以往下降的

以最新安装bloompy遇到问题为例, 很古老的包了, 需要两个前置组件

install_requires=[
“bitarray >= 0.8.3”,
‘mmh3 >= 2.5.1’,
],

但是pip3帮我安装的时候, 选用的mmh3 却是4.0.1版本的, 这个导致它需要setuptools 需要>= 61.0.0

因为, 可以指定版本来安装

pip3 install mmh3==2.5.1

pip3 install bitarray==0.8.3

只要跟其他组件不冲突就OK, 当然如果实在环境依赖太复杂, 那就建议直接使用conda了

OpenWRT 提示opkg Cannot install package

家里一台安装了一段时间的openwrt 突然发现opkg install 和 opkg update 都失败了

其中opkg update 发现其中的包都404了

Downloading https://downloads.openwrt.org/snapshots/targets/mediatek/filogic/packages/Packages.gz
*** Failed to download the package list from https://downloads.openwrt.org/snapshots/targets/mediatek/filogic/packages/Packages.gz

查了一下, 发现在2024.1的时候, openwrt的SNAPSHOT branch已经迁移到新的包管理APK了,可以参考:

https://forum.openwrt.org/t/the-future-is-now-opkg-vs-apk/201164

因此, 需要修改/etc/opkg/ 配置里边的snapshot ==> release/YOUR_OPENWRT_VERSION

比如distfeeds.conf里边的:

https://downloads.openwrt.org/releases/23.05.5/targets/mediatek/filogic/packages/Packages.gz

然后opkg update一下就好了

盘符丢失如何处理

如果是Dell的机器, 可以通过MegaRaiD工具来操作, 不需要重启机器

/opt/MegaRAID/MegaCli/MegaCli64 -cfgforeign -clear a0 先清掉

比如是 slot8 掉盘了, 通过这个方式加回去
/opt/MegaRAID/MegaCli/MegaCli64 -CfgLdAdd -r0[32:8] -a0 根据slot 加回去

rhel6 centos6 如何安装python3 和升级pip

旧版本的操作系统有时候需要跑python3的代码, 这里介绍下最简单的模式

从epel源安装python3

Download the EPEL repository:

wget https://archives.fedoraproject.org/pub/archive/epel/6/x86_64/epel-release-6-8.noarch.rpm

Install the EPEL repository:

rpm -Uvh epel-release-6*.rpm

    yum install python34 python34-devel -y

    使用GET-PIP官方脚本安装升级pip

    wget https://bootstrap.pypa.io/pip/3.4/get-pip.py -O get-pip_3.4.py
    python3 get-pip_3.4.py

    由于RHEL6 实际上是非常古老的操作系统了, 所以这里使用了最简单的方式安装python3和升级pip让新的python代码可以在这个平台上可以运行

    nginx upstream [warn] load balancing method redefined 处理办法

    <pre class="wp-block-code"><code>业务同事反馈新增consistent hash url的时候有报错, "load balancing method redefined"
    
    看了下配置, 大致是这样子
    <p>upstream 2165 {
    keepalive 4096;
    check interval=10000 rise=2 fall=3 timeout=3000 type=http default_down=false;
    check_http_send 'GET /check_alive HTTP/1.0\r\nHost: check.sohuitc.cn\r\n\r\n';
    check_http_expect_alive http_2xx;
    server 1.1.1.1 max_fails=0;
    server 1.1.1.2 max_fails=0;
    hash $request_uri consistent;
    }</p>
    简单搜索了下, 有这么个答案:
    https:&#47;&#47;ma.ttias.be/nginx-nginx-warn-load-balancing-method-redefined/
    答案是: "You can mix keepalive and least_conn, but you should define least_conn before keepalive.", 就是把LB的method 放到Keepalive 指令的后边, 考虑到least_conn 和 hash其实都是LB的method
    
    那么, 这是为什么呢?
    参考nginx官方的文档, https://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive
    <p><code>When using load balancing methods other than the default round-robin method, it is necessary to activate them before the keepalive directive.</code></p>
    官方文档要求把keepalive指令放到其他非RR的LB method的后边
    
    我还想知道为什么呢?
    翻开nginx的代码, 可以看到我这个hash 函数有个判断
    http/modules/ngx_http_upstream_hash_module.c
    <p>
        if (uscf-&gt;peer.init_upstream) {
            ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
                               "load balancing method redefined");
        }</code>而Keepalive指令, 会尝试去初始化这个 <span style="background-color: initial; font-family: inherit; font-size: 0.857143rem;">uscf-&gt;peer.init_upstream</p>
    http/modules/ngx_http_upstream_keepalive_module.c
    <p>
      kcf-&gt;original_init_upstream = uscf-&gt;peer.init_upstream
                                      ? uscf-&gt;peer.init_upstream
                                      : ngx_http_upstream_init_round_robin;
    
        uscf-&gt;peer.init_upstream = ngx_http_upstream_init_keepalive;</p>
    所以如果Keepalive指令在前边, 准备加载LB method的时候, 会发现这个变量已经被初始化了, 会认为是有其他LB method被加载? 就会有个<span style="background-color: initial; font-family: inherit; font-size: 0.857143rem;">load balancing method redefined</span> 告警了
    
    另外, 这个问题其实是由于另一个小的配置问题引出来的, 这里一并记录下
    我们的配置有个报错, "enable hash balancing method support parameter backup", upstream中有backup配置也需要新增hash method, 触发了这个问题
    参考文档https://forum.nginx.org/read.php?29,281365,281369#msg-281369
    <p>Generally, hash methods don't support the "backup" parameter,
    but for those who need backup when falling back to round robin,
    there's a work around: put the "hash" directive after the
    "server" directives in the "upstream" block.</p>
    因此需要把hash 挪到后边, 这就刚好跟keepalive指令有了前后的冲突</code></pre>
    从1.12版本测试结果看, hash 和backup一起用, 会导致backup无法起作用, 需要特别留意, 而1.25系列则正常, 估计是做了修复