news 2026/10/27 17:51:55

PostgreSQL uuid-ossp 安装与 UUID 主键排错实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PostgreSQL uuid-ossp 安装与 UUID 主键排错实战

简介:面向 PostgreSQL 数据库管理员与后端开发者的 uuid-ossp 扩展安装包,用于在数据库中启用符合标准的 UUID 生成能力,解决分布式系统、多个数据库实例之间数据同步时唯一标识符的生成与存储问题,也适合需要厘清版本 1 时间序 UUID 与版本 4 随机 UUID 适用场景的开发者查阅。压缩包共 5 个文件,约 11KB,以 3 个 sql 安装与升级脚本为主体,配合 1 个 so 动态库和 1 个 control 控制文件,分别承担扩展定义、函数实现与元信息声明,体积小巧,便于随项目归档或离线部署。目前已有 471 人学习。读者可据此理清扩展的注册流程与脚本版本演进关系,对照 control 文件与动态库完成部署验证,并顺带留意 libuuid 等系统依赖的检查思路,为在微服务与分布式架构中稳定使用 UUID 打下基础。

1. 一条建表语句跑不通:uuid-ossp 安装插件到底缺了哪一环

上周帮一位同事看他的初始化脚本,DEFAULT uuid_generate_v4()在本地跑得好好的,一上测试库就报function uuid_generate_v4() does not exist。这几乎是我见过的 uuid-ossp 安装插件问题里最高频的一种:扩展没装、装了没启用、启用了但不在 search_path 上,三种情况报错长得一模一样,但修改方法完全不同。uuid-ossp 是 PostgreSQL 官方 contrib 里的一组 UUID 生成函数集合,提供 v1、v3、v4、v5 四代算法,外加几个命名空间常量和变体函数。

它适合两种人:一是要把 UUID 当主键、又不想额外部署一个 ID 生成服务的后端开发;二是需要确定性 UUID(同一个输入永远得到同一个输出)来做幂等导入、跨库对账的数据工程。接下来按“先选路、再装、再调参、最后排错”的顺序,把这条路走完整。

2. 先分清三条生成路径:uuid-ossp、pgcrypto 与内核内置函数

动手装之前,最省时间的做法是先把现有实例的能力查一遍。同一个“生成 UUID”的需求,在 PostgreSQL 里至少有三种实现路径,能力边界不一样,装错了不仅白折腾,还会在后期迁移时踩坑。

2.1 三种来源的能力差异

生成方式代表函数随机源是否带时间有序需要扩展
uuid-osspuuid_generate_v4()/v1()/v1mc()/v3()/v5()后端强随机 / MAC / 命名空间哈希v1 系带时间戳是,需装 contrib
pgcryptogen_random_uuid()后端强随机否是,需装 contrib
内核内置gen_random_uuid(),较新主版本另有时间有序版本后端强随机视函数而定否

关键差别在 v3 和 v5。pgcrypto 和内核函数只能给你“随机”的 UUID,而 uuid-ossp 的uuid_generate_v3(namespace, name)和uuid_generate_v5(namespace, name)是确定性生成:把一段业务字符串加上命名空间,用 MD5(v3)或 SHA-1(v5)压成 128 位。做幂等导入时,同一笔订单数据反复灌库,拿到的id天然不变,去重逻辑直接省掉一层。

另一个差别是 v1 系。uuid_generate_v1()把 60 位时间戳、时钟序列和节点标识拼在一起,天生带着时间前缀,插入 B-tree 时局部性好于纯随机的 v4。代价是节点位默认取网卡 MAC,跨机器导出数据时等于把硬件标识带出去了,这一点在对外交付的数据集里要留意,uuid_generate_v1mc()就是为这个场景准备的,节点位换成随机多播地址。

2.2 版本差异导致的选型分叉

较新的主版本里,gen_random_uuid()已经进了内核,不装任何扩展就能用;再往后的版本还内置了带时间戳前缀的 UUID 版本,专门解决 v4 随机主键的索引局部性问题。所以第一步永远是探测,而不是上来就装。

-- 一次性看清三件事:内核函数在不在、两个扩展装没装、装在了哪个 schema SELECT proname, pg_get_function_identity_arguments(oid) AS args FROM pg_proc WHERE proname IN ('gen_random_uuid', 'uuid_generate_v4'); SELECT e.extname, n.nspname, e.extversion FROM pg_extension e JOIN pg_namespace n ON n.oid = e.extnamespace;

第一段查pg_proc,返回空说明内核里没有gen_random_uuid,得走扩展;第二段查pg_extension,能看出uuid-ossp到底装没装、装在了public还是别的 schema。这一步的价值在于:如果内核已经有了时间有序的生成函数,你大概率不需要 uuid-ossp,直接省掉一次编译和一串运维沟通。

2.3 上线前做一次能力探测

选型结论落到代码之前,建议在目标库上跑一遍探测脚本,把结果贴进变更单。这不是形式主义,我自己就吃过亏:开发环境的内核版本新,gen_random_uuid()随便用;生产环境落后两个主版本,函数不存在,SQL 一到线上就炸。

-- 探测脚本:结果非空即代表该路径可用 SELECT 'core' AS path, count(*) FROM pg_proc WHERE proname = 'gen_random_uuid' UNION ALL SELECT 'uuid-ossp', count(*) FROM pg_extension WHERE extname = 'uuid-ossp' UNION ALL SELECT 'pgcrypto', count(*) FROM pg_extension WHERE extname = 'pgcrypto';

参数说明:pg_proc里同名函数可能有多个重载,数条数只用于判断“存不存在”,不要用它判断具体签名。真要确认签名,还是用 2.2 里那段带pg_get_function_identity_arguments的写法。

探测结果是 0 的那一行,就是你要补的路径。三条都是 0 也别慌,按下一章的顺序装就行。

3. 三条安装路径:包管理器、源码编译、容器镜像

装 uuid-ossp 本质上不是装一个“插件文件”,而是两步:先让扩展的控制文件(.control)和 SQL 脚本落到数据库实例的sharedir下,再在目标库里执行一次CREATE EXTENSION把它注册进元数据。第一步失败报 “is not available”,第二步失败报 “does not exist”,两种错经常被混为一谈。

3.1 包管理器:先对齐版本,再谈安装

deb 系和 rpm 系的 contrib 包名不同,但踩的坑一样:机器上有多套 PostgreSQL 时,包会装到默认的那一套里,而不是你正在跑的那一套。

# 先确认「正在跑的实例」和「命令行工具」是不是同一套 psql -c "SELECT version();" pg_config --version which psql

三条输出对不上,说明 PATH 里的psql连的不是本地实例,或者本地装了两套。这时候装包必须显式带主版本号,否则装进去也白搭。

# deb 系:包名带主版本号,跟着服务端走 sudo apt-get install -y postgresql-contrib-<主版本号> # rpm 系:同样是带版本号的包 sudo yum install -y postgresql<主版本号>-contrib # 装完确认控制文件落到了正确位置 ls "$(pg_config --sharedir)/extension/" | grep -i uuid

逻辑说明:pg_config --sharedir输出的是编译时写死的扩展安装目录,只有这个目录下的.control文件才会被CREATE EXTENSION识别。如果ls看不到uuid-ossp.control,说明包装到了别处,用dpkg -L postgresql-contrib-<版本>或rpm -ql查到实际路径,再判断是不是版本错配。

还有一类更隐蔽的错配:客户端和服务端分属不同机器。你在应用机上装 contrib 没有任何意义,扩展必须在数据库服务端那台机器上装。

3.2 源码编译:--with-uuid后面的选项决定你能用哪些函数

源码编译这条路,麻烦不在make,在于 uuid-ossp 本身不自带 UUID 算法实现,它依赖外部的 UUID 库。configure阶段的--with-uuid参数有两个取值,选错了会导致函数“装上了但用不了”。

# 先确认依赖库在哪:OSSP 的库和 e2fsprogs 的库路径完全不同 ls /usr/include/ossp/uuid.h # OSSP uuid ls /usr/include/uuid/uuid.h # e2fsprogs 的 libuuid # 走 OSSP:功能最全,v1/v3/v4/v5 全支持 ./configure --with-uuid=ossp --prefix=/usr/local/pgsql make -j"$(nproc)" sudo make install # 单独编译 contrib 里的目标扩展 sudo make -C contrib/uuid-ossp install

参数说明:--with-uuid=ossp链接的是 OSSP 库,uuid_generate_v3和uuid_generate_v5都能正常工作。换成--with-uuid=e2fs也能编过,但 e2fsprogs 那套 libuuid 不提供基于命名空间的哈希生成,编出来之后调uuid_generate_v3()会直接报uuid_generate_v3 is not implemented。这个报错在搜索引擎里经常被误判成“权限问题”,实际是编译期就定死了的。

逻辑说明:make -C contrib/uuid-ossp install只装扩展本身,依赖主库已经 install 过。如果先装扩展再装主库,控制文件会被覆盖,顺序不能反。装完用ls复核一次控制文件,和 3.1 的校验方式一致。

提示:容器镜像里做这一步,pg_config指向的可能是编译期的临时路径,make install后要确认sharedir与运行时的pg_config --sharedir一致,否则宿主机挂载的扩展目录里看不到文件。

3.3CREATE EXTENSION的两个参数:schema 与权限

文件到位之后,注册动作本身只有一行,但有两个参数值得说清楚。

-- 扩展名含连字符,必须用双引号包起来 -- 不加引号会被解析成 uuid 减 ossp,报语法错误 CREATE EXTENSION IF NOT EXISTS "uuid-ossp" WITH SCHEMA public; -- Registry:确认扩展落在哪个 schema、版本是多少 SELECT e.extname, e.extversion, n.nspname FROM pg_extension e JOIN pg_namespace n ON n.oid = e.extnamespace WHERE e.extname = 'uuid-ossp'; -- 冒烟测试:随机 + 确定性各一 SELECT uuid_generate_v4(); SELECT uuid_generate_v5(uuid_ns_url(), 'order:20240513:8842');

参数说明:WITH SCHEMA public决定函数最终落在哪个命名空间,不写则落到当前search_path的第一个可写 schema,行为依赖会话状态,不建议省略。IF NOT EXISTS只保证不报错,它不会帮你把装错位置的扩展挪回来,装歪了还是得DROP EXTENSION重来。

权限方面,CREATE EXTENSION传统上要求超级用户。较新的版本把 uuid-ossp 标记成了 trusted extension,只要对目标库有CREATE权限,普通账号也能在自己拥有的 schema 里装。但WITH SCHEMA public这种写法通常仍需要更高权限,给应用账号授权时建议单独开一个 schema,别往public里塞。

部署脚本里最常见的写法是这样:

-- 幂等部署片段:先建 schema,再装扩展,最后授执行权限 CREATE SCHEMA IF NOT EXISTS ext; CREATE EXTENSION IF NOT EXISTS "uuid-ossp" WITH SCHEMA ext; GRANT USAGE ON SCHEMA ext TO app_role;

注意最后一行:只给USAGE就够调用函数了,不需要给EXECUTE(函数默认对PUBLIC开放)。但应用连接的search_path里必须包含ext,否则还是会报 “does not exist”,这就是第 5 章要展开的第一个坑。

4. 函数族与参数:v4 还是 v1mc,v5 的命名空间怎么传

扩展装好之后,真正影响线上表现的是“选哪个函数”和“参数怎么传”。这一章把四个主函数拆开讲,每个都配上能直接抄的 SQL。

4.1 v4 与 v1mc:随机性和索引局部性的取舍

uuid_generate_v4()是纯随机,122 位熵,碰撞概率低到可以忽略——按生日问题估算,要生成到 10^18 量级才有一半概率撞上。它是绝大多数业务表主键的默认选择,代码简单,跨库迁移不会带出任何机器信息。

uuid_generate_v1()把时间戳放在高位,插入时新值集中在 B-tree 右侧,页分裂少,缓存命中率高。但它有两个副作用:节点位默认是 MAC 地址;时间戳精度有限,高并发下同一毫秒内密集生成时,时钟序列的推进逻辑就成了黑匣子,跨机器合并数据时更要注意重复。

-- 对比两者:v1 的第三段(节点)在同一后端进程内基本固定,v1mc 每次不同 SELECT uuid_generate_v1() AS v1_once, uuid_generate_v1() AS v1_again, uuid_generate_v1mc() AS v1mc_once, uuid_generate_v1mc() AS v1mc_again;

参数说明:这四个函数都不接受入参,行为差异全在内部。跑两次能直观看到 v1 的节点段稳定、v1mc 的节点段变化。如果业务对“ID 里不能出现硬件标识”有要求,v1 直接排除,只能用 v1mc 或 v4。

我的习惯是:普通业务主键用 v4,日志、流水这类只增不改、写入量大的表考虑 v1mc,需要对外暴露且不希望泄露生成时间的场景一律 v4。

4.2 v3 与 v5:把业务字符串压成确定性 UUID

这两个函数签名一致:uuid_generate_v5(namespace uuid, name text)。namespace 是一个 128 位的 UUID,用来划定“命名空间边界”,name 是任意文本。相同 namespace + 相同 name,永远得到同一个 UUID。

扩展自带四个预定义命名空间常量:uuid_ns_dns()、uuid_ns_url()、uuid_ns_oid()、uuid_ns_x500()。

-- 同一条业务数据反复生成,结果完全一致 SELECT uuid_generate_v5(uuid_ns_url(), 'order:20240513:8842') AS a, uuid_generate_v5(uuid_ns_url(), 'order:20240513:8842') AS b; -- 命名空间不同,结果不同:这是隔离不同业务域的标准做法 SELECT uuid_generate_v5(uuid_ns_url(), 'order:20240513:8842') AS url_ns, uuid_generate_v5(uuid_ns_dns(), 'order:20240513:8842') AS dns_ns;

参数说明:namespace必须是合法的 UUID 字面量,传 NULL 返回 NULL,不报错——这一点容易在批量导入时静默产生空主键,务必在入库前加非空校验。name建议拼上业务域前缀(示例里的order:),否则不同表的同名业务键会撞在同一个 UUID 上。

v3 和 v5 的唯一区别是哈希算法:v3 用 MD5,v5 用 SHA-1。新项目直接用 v5,别用 v3。另外,如果编译时选的是 e2fs 那套库,这两个函数会直接抛 “not implemented”,回到 3.2 重新编译。

自建命名空间的做法是先固定一个根 UUID,再用 v5 往下派生子命名空间:

-- 用固定根 + 租户标识派生出该租户专属的命名空间 WITH root AS (SELECT '6ba7b810-9dad-11d1-80b4-00c04fd430c8'::uuid AS ns) SELECT uuid_generate_v5(ns, 'tenant:acme') AS tenant_ns FROM root;

把tenant_ns存进租户表,后续该租户下所有业务对象的 ID 都用它作 namespace 生成。这样即使两个租户的业务键文本完全相同,UUID 也不会撞。

4.3 主键默认值与批量插入的实际开销

把函数挂到列默认值上是最常见的用法:

CREATE TABLE t_order ( id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), tenant text NOT NULL, payload text NOT NULL, created_at timestamptz NOT NULL DEFAULT now() );

参数说明:DEFAULT表达式在每次 INSERT 时逐行求值,函数是 VOLATILE 的,不存在“整批只算一次”的优化。所以 100 万行的批量插入,就是 100 万次随机数生成,这部分 CPU 开销随行数线性增长。

-- 压一把:100 万行随机主键,观察耗时与索引体积 INSERT INTO t_order (tenant, payload) SELECT 'acme', md5(g::text) FROM generate_series(1, 1000000) AS g; SELECT pg_size_pretty(pg_relation_size('t_order_pkey')) AS pkey_size, pg_size_pretty(pg_total_relation_size('t_order')) AS total_size;

跑完这组 SQL,你会看到t_order_pkey的体积明显超过按顺序插入时的水平。原因是随机 UUID 让插入点分散在整个 B-tree 上,页分裂和空洞都变多。这个数字不是“不能用”的证据,而是容量规划的依据——评估磁盘和 shared_buffers 时把它算进去,别等监控告警了才发现。

5. 避坑与排查:五条高频翻车记录

这一章按“现象 → 原因 → 解决”记录五条真实踩过的坑,顺序基本对应我遇到的频率。

5.1 报 function does not exist,但扩展明明装了

现象:pg_extension里能查到uuid-ossp,调用uuid_generate_v4()还是报不存在。

原因:扩展装在了非默认 schema,而应用连接的search_path里没有它。函数名不带 schema 前缀时,PostgreSQL 只查search_path里的 schema。

解决:先定位,再决定是改search_path还是改调用方式。

-- 查清楚函数在哪 SELECT n.nspname, p.proname FROM pg_proc p JOIN pg_namespace n ON n.oid = p.pronamespace WHERE p.proname = 'uuid_generate_v4'; -- 方案一:会话内补路径(适合连接池统一配置) SET search_path = ext, public; -- 方案二:调用时带全限定名(适合零散脚本) SELECT ext.uuid_generate_v4();

实测下来,方案一更省事,但要确保连接池的初始化 SQL 里也加了这行,否则换个客户端又失效。

5.2 备份恢复失败,报 extension is not available

现象:pg_dump出来的脚本拿到新实例恢复,中途报extension "uuid-ossp" is not available。

原因:扩展的函数定义不会出现在备份脚本里,只有一句CREATE EXTENSION。目标实例如果没装 contrib 包,sharedir下没有控制文件,这句就执行不了。备份是“逻辑层”,扩展是“文件层”,两者不同步。

解决:把“装 contrib”写进目标实例的初始化流程,恢复前先执行一次。

# 恢复前先确保目标实例有扩展文件 ls "$(pg_config --sharedir)/extension/uuid-ossp.control" || \ sudo apt-get install -y postgresql-contrib-<主版本号> # 只导出结构,确认扩展语句在脚本里而不是函数体在 pg_dump --schema-only mydb | grep -i "CREATE EXTENSION"

后一条命令能验证备份里确实只有CREATE EXTENSION而没有函数定义,这决定了恢复时到底依赖什么。

5.3 编译期的一个选项,让 v5 永远不可用

现象:uuid_generate_v4()正常,调uuid_generate_v5()报uuid_generate_v5 is not implemented。

原因:编译时用了--with-uuid=e2fs,那套库不支持命名空间哈希生成,函数符号编进去了但内部是空实现。报错看起来像运行时问题,实际在编译阶段就注定了。

解决:重新用--with-uuid=ossp编译并覆盖安装,然后重装扩展。

./configure --with-uuid=ossp --prefix=/usr/local/pgsql make -j"$(nproc)" && sudo make install sudo make -C contrib/uuid-ossp install
-- 覆盖安装后要重建扩展,否则 registry 里还是旧记录 DROP EXTENSION "uuid-ossp"; CREATE EXTENSION "uuid-ossp" WITH SCHEMA ext;

注意DROP EXTENSION会连带删掉依赖这些函数的列默认值,生产环境务必先评估依赖。

5.4 主键膨胀和写入抖动一起出现

现象:表数据量涨到千万级后,写入延迟的 P99 明显抬头,主键索引体积是预期的一倍多。

原因:随机 UUID 主键的插入点均匀散布在整个 B-tree 上,每次插入大概率触发随机页读写,页分裂频繁,缓存命中率下降。这不是 bug,是随机主键的固有代价。

解决:三个方向,按改动成本排序。第一,评估能否换成带时间前缀的 UUID 版本(较新主版本内置,或 v1mc 折中),让插入集中到右侧;第二,把主键索引的填充因子调低,预留学生空间,减少分裂。

-- 降填充因子,给后续插入留空间;重建后生效 ALTER TABLE t_order SET (fillfactor = 80); REINDEX INDEX CONCURRENTLY t_order_pkey;

第三,如果只是“ID 不能自增暴露”,其实可以用自增主键 + 对外独立的 UUID 列,两者分开,别让索引结构背这个锅。

5.5 普通账号执行 CREATE EXTENSION 被拒

现象:应用部署脚本里带CREATE EXTENSION,用业务账号跑报权限不足。

原因:CREATE EXTENSION需要超级用户,或者该扩展被标记为 trusted 且账号对目标库有CREATE权限。多数历史镜像里的扩展没有这个标记。

解决:把安装动作和业务动作拆开,安装走 DBA 账号,业务账号只拿USAGE。

-- 由具备权限的账号执行一次 CREATE SCHEMA IF NOT EXISTS ext; CREATE EXTENSION IF NOT EXISTS "uuid-ossp" WITH SCHEMA ext; -- 业务账号只需要这个 GRANT USAGE ON SCHEMA ext TO app_role;

部署脚本里加一句SELECT count(*) FROM pg_extension WHERE extname='uuid-ossp',装过了就跳过,避免每次发布都撞权限墙。

6. 进阶验证:用执行计划和索引体积判断 UUID 落库质量

装完、配好、跑通,还不算完。UUID 主键最容易出问题的地方在半年后,而不是上线当天。我一般会在压测阶段就做三组对照,把结论写进容量评估表里。

第一组,看写入路径的执行计划。同一批数据,分别用随机 UUID 和顺序主键插入,比对BUFFERS里的共享页读写次数。

EXPLAIN (ANALYZE, BUFFERS) INSERT INTO t_order (tenant, payload) SELECT 'acme', md5(g::text) FROM generate_series(1, 10000) AS g;

随机主键那一次,shared hit和shared read的差值会明显更大,说明访问的页面更分散。这个差值不需要精确到个位,两者对比着看就够判断趋势了。

第二组,看索引体积的增长曲线。分别在 100 万、500 万、1000 万行时采样:

SELECT reltuples::bigint AS est_rows, pg_size_pretty(pg_relation_size('t_order_pkey')) AS pkey_size FROM pg_class WHERE relname = 't_order';

如果 pkey 体积的增长斜率明显超过行数斜率,说明页分裂在持续发生,这时候再考虑fillfactor或者换生成策略,比等到磁盘告警了再动手从容得多。

第三组,验证备份恢复的闭环。这条最容易被跳过,但恰恰是我踩过最疼的一次:备份脚本里只有CREATE EXTENSION,恢复环境没装 contrib,整个恢复流程卡在第五分钟。从那以后,我每次做结构性变更,都强制走一遍「pg_dump --schema-only→ 干净实例恢复 → 跑冒烟 SQL」这条链,冒烟 SQL 就两行:

SELECT uuid_generate_v4(); SELECT uuid_generate_v5(uuid_ns_url(), 'smoke:test');

两行都能出结果,才算这个 uuid-ossp 安装插件真正落地。一条最简单但经常被忘的经验:别在开发机上验证“装没装”,那台机器上什么都有;去目标环境的从库上跑一次探测脚本,五分钟的事,能省掉半夜被叫起来的麻烦。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/27 17:51:06

AI大模型在生命科学领域的应用挑战与优化策略

1. 项目背景&#xff1a;当AI大模型遇上生命科学最近看到LifeOmni发布的一份评测报告&#xff0c;标题直戳痛点——《会背书 ≠ 懂生命&#xff01;LifeOmni榜单揭示大模型生命科学实战短板》。作为一名在生物信息学和AI交叉领域摸爬滚打多年的从业者&#xff0c;这个标题瞬间抓…

作者头像 李华
网站建设 2026/10/27 17:50:56

AI工程化落地:智能体容错、模型部署与AI编程关键实践

如果只看热搜&#xff0c;你会觉得AI圈一天能冒出几百个新东西&#xff1b;但真去工程现场走一圈&#xff0c;你会发现大多数团队头疼的还是那几件事&#xff1a;Agent怎么稳定跑完一条链路、模型怎么部署才能不亏算力、AI编程怎么才能真的帮自己省时间。这篇AI前沿推介我按3.2…

作者头像 李华
网站建设 2026/10/27 17:50:42

YOLO13-C3k2-HFERB模型在珠宝智能检测中的应用

1. 珠宝检测行业的技术变革与YOLO13-C3k2-HFERB模型解析 珠宝行业正经历着从人工鉴定到智能检测的历史性转变。传统珠宝检测依赖专业鉴定师的经验判断&#xff0c;不仅人力成本高昂&#xff0c;而且存在主观性差异。我们团队开发的YOLO13-C3k2-HFERB模型&#xff0c;在珠宝物品…

作者头像 李华
网站建设 2026/10/27 17:50:29

PC端麦克风采集与录音上传:从getUserMedia到Blob分片闭环

简介&#xff1a;围绕H5音频采集与上传场景整理的示例包&#xff0c;面向需要实现浏览器调用麦克风、获取实时音频流、录音并提交后台的前端开发者。内容聚焦Web Audio API与MediaRecorder的配合&#xff0c;涉及音频流接入、录音分块、Blob合并和服务端接收等环节&#xff0c;…

作者头像 李华
网站建设 2026/10/27 17:49:29

深度学习实战:卷积神经网络中的填充、步幅与下采样技术解析

1. 从零开始的深度学习日记&#xff1a;填充、步幅与下采样实战解析 三周前当我第一次打开卷积神经网络的代码时&#xff0c;那些神秘的padding参数和stride设置就像天书一样。直到在CIFAR-10数据集上连续跑了5次模型都得到低于50%的准确率后&#xff0c;我才真正意识到这些基础…

作者头像 李华
网站建设 2026/10/27 17:47:15

太阳能光伏板缺陷检测数据集与应用解析

1. 项目概述&#xff1a;太阳能光伏板缺陷检测数据集解析这个856张7类别的光伏板缺陷数据集采用了工业检测领域最常用的VOCYOLO双格式&#xff0c;正好填补了新能源行业在缺陷检测数据上的空白。去年我在参与一个光伏电站巡检项目时&#xff0c;就苦于找不到合适的训练数据&…

作者头像 李华