news 2026/10/1 3:18:18

RPM包管理从入门到实践:命令、依赖与rpmbuild打包

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
RPM包管理从入门到实践:命令、依赖与rpmbuild打包

拿到一台新的 Linux 服务器,尤其是 CentOS、Rocky 或者 RedHat 这类基于 RPM 体系的系统,你总要跟rpm这个命令打交道。不管是装个 MySQL、部署个 Java 环境,还是排查某个文件到底属于哪个软件包,都绕不开它。但说实话,很多人对 rpm 的认知停留在"装包工具"这个层面,出了问题就靠--force和--nodeps硬上,最后把系统搞到依赖一团乱麻,不得不重装。这篇文章我就把 RPM 这套体系从头到尾拆开来讲——它到底是怎么工作的、日常命令怎么用、依赖问题为什么会产生、以及更进阶的:怎么自己打包一个 rpm 文件。内容会尽量贴近实际运维场景,不是那种随手查得到的 man 手册翻译版。

1. RPM 包内部是什么:一个自带说明书和安装脚本的"加密压缩包"

RPM 全称是 RPM Package Manager,虽然叫 Package Manager,但本质上它是一套文件打包 + 安装记录 + 脚本执行的完整规范。一个.rpm文件并不是简单的 tar.gz 压缩一下再改个后缀,它内部有严格的二进制结构,包含文件载荷、元数据、安装卸载脚本、签名信息等多个分区。

1.1 一张图看懂 rpm 包的文件结构

想象一下你收到一个快递盒子。盒子外面贴着快递单(元数据),里面有你要买的商品(程序文件),还附带一张安装说明书(安装脚本)和一张售后卡(签名信息)。RPM 包就是这个盒子的标准化版本:

  • Lead 区:包含 magic number 和版本信息,用来识别"这是一个 rpm 文件";
  • Signature 区:存放 SHA-256 等签名值,用于校验包完整性和来源可信度;
  • Header 区:这是整个包的大脑,记录了软件名称、版本号、Release 号、依赖关系(Requires)、提供的能力(Provides)、安装卸载前后的脚本等;
  • Payload 区:实际要安装的文件本身,通常用 zstd 或 gzip 压缩后存放。

这些数据综合保证了:一个 rpm 包安装到系统里,不只是把文件复制过去,还要更新系统的软件记账数据库(即 RPM 数据库),记录哪些文件被装到了哪个位置、属于哪个包、版本是多少。

1.2 为什么 RPM 能解决"源码安装五步走"的痛点

早年间 Linux 装软件的主流方式是源码安装:./configure、make、make install,听起来很"极客",但实际用起来非常痛苦。比如你装了一个依赖库 A 的软件 B,几十个文件散落到/usr/local各个目录里,想卸载只能一个个找;升级的时候文件被新版本覆盖,但老版本的配置残留可能引发玄学 bug。

RPM 把这个流程彻底规范化了。它保证:

  • 安装前检查依赖是否满足,不满足直接拒绝安装并明确告诉你缺什么;
  • 安装时把文件清单登记到数据库,每个文件都能追溯来源;
  • 卸载时可以"干净地"反悔,把装进去的文件全部撤掉;
  • 升级时知道哪些配置文件是用户改过的,不会盲目覆盖。

这就是为什么企业级 Linux 发行版(RHEL、CentOS、Rocky、openEuler、银河麒麟等)都采用 RPM 体系——它让软件安装从"手工爆破"变成了"可审计的标准化操作"。

1.3 RPM 数据库:系统里那本看不见的账本

你用rpm命令做的每一个查询,本质上都是在访问系统里的 RPM 数据库。这个数据库位于/var/lib/rpm目录,在较新的发行版上(rpm 4.16 之后)默认使用 sqlite 后端,文件通常叫rpmdb.sqlite,老一点的则是一组 BDB(BerkeleyDB)文件。

数据库里记录了三类关键信息:

  • 已安装包列表:每个 rpm 包的名称、版本、Release、安装时间;
  • 文件清单:每个包安装的所有文件路径、权限、类型;
  • 依赖关系:每个包 requires 什么能力、provides 什么能力。

你在执行rpm -qa时,其实就是在"翻阅账本"。这也带来一个常见的坑:如果系统异常断电导致 RPM 数据库文件损坏,那么所有 rpm 查询和安装操作都会报错,不过这个坑我在第 4 节会专门讲恢复方案。

2. 日常用得最多的 rpm 操作:查询、安装、升级、卸载的完整命令拆解

rpm 的命令语法不复杂,但参数多且容易混。核心要点是记住动作字母:-q查询、-i安装、-U升级、-e卸载、-V校验,然后加上辅助参数组合使用。

2.1 查询类命令:决定你"是不是个老手"的分水岭

很多人对 rpm 的查询参数不熟悉,遇到问题只会rpm -qa | grep。实际上,组合查询是日常排查效率最高的动作。

命令组合作用实用场景
rpm -qa列出系统所有已安装的 rpm 包想确认某软件装没装
rpm -q 包名查询指定包是否安装及版本只确认单个包
rpm -ql 包名列出该包安装的所有文件路径想知道软件装哪了
rpm -qf /路径/文件查询某个文件归属于哪个包排查文件被谁动了
rpm -qi 包名查看包的详细信息(含安装时间)需要包的全量元数据
rpm -qc 包名列出该包的配置文件快速找配置位置
rpm -qd 包名列出该包的文档文件找帮助文档

举个例子,你发现/etc/my.cnf不知道被谁改坏了,想找到它属于哪个包:

rpm -qf /etc/my.cnf

输出会是mariadb-connector-c-config-3.2.5-1.el9.noarch之类的包名。这就是把"从文件反查包"的能力用起来了,非常实用。

再举一个典型场景:你想知道 Nginx 装完后把文件都放哪了。

rpm -ql nginx

输出会列出/etc/nginx、/usr/sbin/nginx、/usr/share/nginx等一长串路径。通过这个方式,你能快速掌握一个陌生服务的安装布局。

2.2 安装和升级:-ivh、-Uvh、-Fvh 这三兄弟的区别

新手最容易混淆的三个参数。先说结论,再讲原理:

  • rpm -ivh 包名.rpm:安装一个新包,如果这个包已经存在,会报"package already installed";
  • rpm -Uvh 包名.rpm:升级包,如果包没装过,它会直接安装(相当于 install);
  • rpm -Fvh 包名.rpm:只升级已存在的包,如果包没装过,直接跳过,不装。

-i、-U、-F后面通常搭配-v(显示详细过程)和-h(显示安装进度条),就组成了-ivh、-Uvh、-Fvh这三兄弟。

实操中最常见的,是在已有老版本的情况下想换成指定版本:

rpm -Uvh mysql-community-server-8.0.36-1.el7.x86_64.rpm

如果老版本是 8.0 系列,它会自动覆盖升级;注意这里我要提醒一句:跨大版本升级(比如 5.7 升 8.0)一定先备份数据,RPM 层面的文件覆盖不会帮你做数据库兼容处理。

还有个小技巧:某些场景下你想强制降级(downgrade),但rpm -Uvh默认不允许装比当前更旧的版本,会报 "older version installed"。这时需要加--oldpackage参数:

rpm -Uvh --oldpackage mysql-community-server-5.7.44-1.el7.x86_64.rpm

2.3 卸载:-e 的正确姿势与两个"后悔药"参数

卸载用rpm -e,但这个命令最有讲究的是它默认不允许卸载被其他包依赖的包。

比如你执行:

rpm -e httpd

如果系统里有别的包依赖 httpd 的某些文件,你会看到:

error: Failed dependencies: httpd is needed by (installed) php-xxx

这时候千万不要头脑一热加--nodeps强删。正确的做法是:先卸载依赖它的上层应用,或者用rpm -e --test做一次试删,观察会不会报依赖错误:

rpm -e --test httpd

--test 是个很少人用但非常安全的参数,它会模拟整个卸载流程,告诉你"如果真卸载会发生什么",但不会真的删文件。我在处理环境清理类需求时,总是先--test再动手,等于给操作上了一份保险。

2.4 校验功能:-V 参数检查哪些文件被篡改过

rpm -V是检查已安装包文件完整性的命令。它会把系统里现有文件的属性、内容、权限等与 RPM 数据库里记录的初始值比对,输出差异。

rpm -V openssh-server

输出结果中如果每一行都以点号(.)开头,说明文件完好无损;如果出现字母,就表示对应属性变了:

  • S:文件大小变了
  • M:权限/文件类型变了
  • 5:文件内容(MD5/SHA256哈希)变了
  • D:设备号变了
  • L:符号链接目标变了
  • U/G:属主/属组变了
  • T:修改时间变了

遇到5标记要特别警惕,这往往是文件被手动改动过或者中招的征兆。这个命令在系统加固和安全排查时很有价值。

3. 依赖地狱:为什么 rpm 单独装包总会失败,以及 yum/dnf 如何帮你收拾残局

几乎每个从新手期走来的人都经历过这种报错:

error: Failed dependencies: libcrypto.so.10()(64bit) is needed by mysql-community-xxx

这就是 RPM 最经典的"依赖地狱"问题——一个包依赖的共享库或工具必须预先存在,否则安装会被拒绝。RPM 的设计哲学是"安全优先,缺依赖就不装",这是保护机制,不是 bug。

3.1 依赖是硬编码在包里的"能力声明"

每个 rpm 包在构建时,会扫描出自己依赖哪些共享库、哪些命令,把它们以Requires字段写进包元数据里。同时,每个包也会声明自己"提供"哪些能力,以Provides字段记录。

举个例子说明流程。你下载了一个mysql-community-server的 rpm,执行安装时,rpm 会:

  1. 读取它的 Requires 列表,找到libaio.so.1、libnuma.so.1等依赖;
  2. 扫描系统 RPM 数据库里所有已安装包的 Provides 列表;
  3. 如果发现某个依赖没有任何包提供,直接报错终止。

所以--nodeps这个参数的本质是"跳过依赖检查,强行装",它绕过的是安全门禁,不是在帮你解除依赖——装完照样缺依赖,运行起来照样崩。

3.2 yum/dnf 的高明之处:自动从仓库里补齐依赖

正因 rpm 单独装包会卡在依赖上,现代 Linux 发行版都标配了 yum(CentOS 7 及以前)或 dnf(CentOS 8 及以后、Fedora)。

yum/dnf 的定位是"rpm 的前端工具",它们做的事情可以概括为:

  • 从配置好的软件仓库(repo)下载 rpm 包;
  • 自动解析依赖关系,按顺序把所有需要的包全部装齐;
  • 建立本地缓存,下次装相同包不用重复下载。

这就是为什么我强烈建议:能用 yum/dnf 装的就不要手动 rpm -ivh。尤其在生产环境里,手动装一个 rpm 往往会牵扯出一连串手工装依赖的操作,得不偿失。

一条命令装完 MySQL 的典型姿势:

yum install -y mysql-community-server

如果本地没有合适仓库,你也能用yum localinstall让它同时处理本地 rpm 和线上依赖:

yum localinstall mysql-community-server-8.0.36-1.el7.x86_64.rpm

3.3 最小化安装系统后,先配 dnf 源再谈其他

很多初学者装完 CentOS/Rocky 后第一件事就是yum install xxx,结果提示找不到软件包。排查思路是三步:

  1. 确认网络通不通:curl -I https://mirrors.xxx.com(或你配置的源地址);
  2. 查看仓库列表是否正常:dnf repolist;
  3. 清除旧缓存重新生成:dnf clean all && dnf makecache。

在配置软件源的时候,国内生产环境通常建议配置可用的内网镜像源或企业自建源,加速效果明显。改源时注意备份原文件,结构大致是/etc/yum.repos.d/下的.repo配置文件。

配好之后,日常运维绝大多数软件安装都能通过dnf install解决,rpm 手动命令要保留给"安装本地离线包"和"查询系统信息"这两类场景。

4. 那些年踩过的 rpm 坑:命令找不到、数据库损坏、强删依赖

这部分我讲几个真实发生过的坑,每个都是反复出现的问题,希望你能避雷。

4.1 "没找到 rpm 命令"是真没装还是环境变量破了

有些轻量容器镜像、嵌入式 Linux 环境,真的没有 rpm 命令。但也有些场景下 rpm 命令存在却提示bash: rpm: command not found,这多半是 PATH 环境变量被改坏了。

判断方式很简单:

which rpm /usr/bin/rpm

如果 which 能找到但 bash 执行不了,就是你的 PATH 里没有/usr/bin。这种情况不用急着重装,直接:

export PATH=/usr/bin:/bin:/usr/sbin:/sbin:$PATH

就能临时恢复。不过在高危发行版上(比如某些用 dnf 替代 rpm 的衍生系统),也可能真的没有 rpm 前端,那就通过dnf install rpm装回来。

另外一个高频场景是 Debian/Ubuntu 系系统里有人习惯性敲rpm命令,会得到 command not found。正确的是用 dpkg 和 apt,严格来说 RPM 体系只适用于 Red Hat 系和 OpenSUSE 等,这属于"选错工具"而不是系统坏了。

4.2 RPM 数据库损坏了怎么救

我在实际运维中遇到过不止一次:某台机器断电重启后,任何 rpm 查询都报这样的错:

rpm: fatal error: ... rpmdb: damaged

或者:

error: db5 error(11) from dbenv->open: Resource temporarily unavailable

这种问题大概率是/var/lib/rpm目录下的数据库文件异常导致的。恢复思路依赖你使用的后端,现代 rpm 默认是 sqlite 后端,先尝试重建索引:

rm -f /var/lib/rpm/__db.* rpm --rebuilddb

如果是老版本 Berkleley DB 后端,上面的清理方式同样适用。重建后执行rpm -qa | head验证一下是否能正常输出。

这里必须强调一个原则:处理数据库问题之前先备份,别上来就删。文件是系统的账本,删错了会更麻烦。推荐顺序是:

cp -a /var/lib/rpm /var/lib/rpm.bak.$(date +%F) rm -f /var/lib/rpm/__db.* rpm --rebuilddb

4.3 --force 和 --nodeps 是"核武器",不是常规工具

有些教程动不动就让人rpm -ivh --force --nodeps xxx.rpm,我非常反对这种习惯。

--force的本质是"忽略文件冲突、强制覆盖",--nodeps是"跳过依赖检查"。两者叠加等于告诉系统"别管合理性,直接塞进去"。短时间可能装上并跑起来了,但系统里的 RPM 数据库已经"说谎"——它记录了一个缺依赖的包,后续任何更新合并都可能失败。

什么情况下可以合理使用?

  • --nodeps只在确认"系统里其实有等价能力(比如自己编译的库),只是 rpm 数据库不认账"时用;
  • --force只在覆盖重装某个"文件被误删的包"时用,比如:
rpm -ivh --force openssh-server-xxx.rpm

但记住:用完这两个参数后,应该立刻用yum/dnf做一次check或重装校验,确认系统依赖关系是正常的,善后工作比操作本身更重要。

5. 从使用者到打包者:手写 spec 文件,给自己工具打一个 rpm 包

作为运维/后端工程师,除了"会用",还要"会打"。比如内网要分发一个自己编译的二进制工具,官方没有 rpm 包,手工复制到每台机器显得很"原始",打成一个 rpm 包走 yum 仓库分发才是规范做法。这一节用一个小例子完整演示打包流程。

5.1 rpmbuild 环境准备与目录结构

首先安装打包工具:

yum install -y rpm-build rpmdevtools

然后使用rpmdev-setuptree帮你生成标准工作目录:

rpmdev-setuptree

这个命令会在你的 HOME 下生成rpmbuild目录,内部结构是:

  • BUILD:构建源码时用的临时目录;
  • BUILDROOT:打包时模拟安装的根目录(装出来的东西先进这里);
  • RPMS:最终的二进制 rpm 包输出目录(按架构分 x86_64、noarch 等);
  • SOURCES:存放源码包、补丁等原材料;
  • SPECS:spec 文件所在地,这是打包的核心控制文件;
  • SRPMS:源码 rpm 包输出目录。

5.2 一个最小可用的 spec 文件逐行拆解

以打包一个非常简单的 hello 命令为例,源码就一个 C 文件hello.c,编译后输出可执行文件/usr/bin/hello。

把hello.c打成 tar.gz 放进 SOURCES:tar czvf hello-1.0.tar.gz hello.c。

然后写 SPECS 下的hello.spec:

Name: hello Version: 1.0 Release: 1%{?dist} Summary: A simple hello world rpm package License: MIT URL: https://example.com/hello Source0: %{name}-%{version}.tar.gz BuildRequires: gcc Requires: glibc %description A minimal example rpm package built for demonstration purposes. %prep %setup -q %build gcc -o hello hello.c %install install -D -m 0755 hello %{buildroot}/usr/bin/hello %files /usr/bin/hello %changelog * Wed Jul 10 2024 Your Name <you@example.com> - 1.0-1 - Initial package build

几个关键字段解释:

  • Name/Version/Release:这是包唯一名的三要素,组合起来就是hello-1.0-1.el9.x86_64.rpm;
  • Source0:告诉 rpmbuild 原材料 tar 包在哪,变量%{name}-%{version}自动展开成hello-1.0;
  • BuildRequires:构建期依赖,比如编译需要 gcc;
  • Requires:运行期依赖,这个二进制程序依赖 glibc;
  • %prep:准备阶段,通常写%setup -q,作用是解开 tar 包并进入目录;
  • %build:执行编译命令;
  • %install:把编出来的文件安装到%{buildroot}对应的目录里。这里-D是自动创建父目录,-m 0755设权限;
  • %files:声明最终 rpm 包里要包含哪些文件路径,注意这里写的是系统安装后的路径,不是 buildroot 里的路径;
  • %changelog:版本变更记录,写规范了后面追溯很有用。

5.3 完整打包与常见报错处理

执行打包命令:

rpmbuild -ba rpmbuild/SPECS/hello.spec

如果一切正常,你会在rpmbuild/RPMS/x86_64/下看到hello-1.0-1.el9.x86_64.rpm。这时可以拿它去别的机器上安装验证:

rpm -ivh hello-1.0-1.el9.x86_64.rpm

然后执行:

hello

输出Hello, World!就说明打包成功了。

几个新手高发报错和原因:

  • error: File not found: /root/rpmbuild/BUILDROOT/hello-1.0-1.el9.x86_64/usr/bin/hello:说明%install阶段没有把文件准确放到%{buildroot}下对应的路径里。检查install命令的路径与 spec 里是否一致;
  • Exec failed: No such file or directory:往往是%build阶段缺少编译依赖,给 BuildRequires 补上对应工具即可;
  • Package already exists: ...:rpmbuild 的输出目录里已经有同名 rpm,清掉旧文件或者提高 Release 版本号。

进阶一点:如果需要打包的东西是 Python 脚本或纯配置文件,可以把%build留空、%install直接拷贝文件;如果软件有多个不同架构版本,还可以用 spec 里的条件判断来控制编译逻辑。

6. 进阶实践:用 rpmbuild 处理 OpenSSH 这类"自己定制版本"的打包需求

很多人搜索"centos8 openssh 打包rpm",本质是想把一个编译版 OpenSSH 维护进系统的 RPM 体系里,避免和 yum/dnf 管理的官方包冲突。

实际操作步骤可以总结为:

  1. 准备源码:下载目标版本 OpenSSH 源码包,放到 SOURCES;
  2. 编写 spec:参考系统自带 openssh 的 spec 改版本号。查看系统自带 spec 可以用:
yumdownloader --source openssh rpm -ivh openssh-*.src.rpm # 然后查看 ~/rpmbuild/SPECS/openssh.spec
  1. 改版本号:把Version改为目标版本,Release改成自定义值,比如1.custom;
  2. 执行打包:rpmbuild -ba SPECS/openssh.spec;
  3. 本地安装验证:yum localinstall RPMS/x86_64/openssh-*.rpm,安装到测试机验证连接、权限、PAM 兼容性等。

这种做法的好处是:最终的服务仍然由 RPM 数据库管理,卸载可以干净回滚,后续rpm -V也能校验完整性。另一个重点:自定义打包时严禁把 Release 设成和官方包相同的值,否则后续 yum 更新时会分不清谁新谁旧,导致覆盖混乱。

OpenSSH 因为涉及 PAM、systemd、selinux 等联动组件,打包复杂度远高于 hello 程序,但思路是通用的——先解压官方 src.rpm 获得 spec 基础,再改版本号和 patch,最后重新打包。我处理过几次这类需求,最深的感受是"永远在构建环境里测试,不要在生产机器上直接 rpmbuild",因为打包过程会缺 build 依赖,而且 rpmbuild 的%buildroot如果配置不当会有越界安装的风险。

7. 一些我压箱底的经验:rpm 使用的习惯与意识

最后分享几个我这些年实际工作中总结出的习惯,谈不上系统理论,但真的能少走不少弯路。

第一个经验是"能查就查,别瞎试"。所有关于 rpm 的"灵异问题",第一动作永远是rpm -qa | grep确认装的版本,然后rpm -ql确认文件位置,再rpm -V确认文件有没有被动过。三步走完,80% 的疑问都能自己解开。

第二个经验是"参数从短到长,责任从小到大"。安装时先rpm -ivh --test,没问题再正式装;卸载时先rpm -e --test;校验先rpm -V。把"看似多余"的试运行变成肌肉记忆,就不会动不动把系统搞坏。

第三个经验是"RPM 数据库是系统安全审计的重要线索"。生产服务器如果发现某个系统二进制文件被替换(rpm -V报5),要立刻排查入侵痕迹。这个我在一次应急响应中被验证过——通过rpm -V定位到sshd和ls两个命令的文件哈希异常,才顺藤摸瓜确认了设备被黑。

第四个经验是"特殊情况下,RPM 也能装进非标准目录"。比如内网环境没法用 root 权限安装某些依赖库,你可以用rpm -i --prefix=$HOME/opt把包装到指定前缀目录。注意这要求包本身支持 relocatable(spec 里定义了Prefix:字段),很多包不支持,所以这个方法有局限性,但了解一下没坏处。需要提一句的是:这种方式装的文件不会完整记录到系统 RPM 数据库(严格说会记录但路径计算逻辑不同),生产环境慎用。

这些年看下来,RPM 相关的问题,90% 不是命令不会,而是"没理解包管理的基本逻辑"。当你明白了"包是清单+文件+脚本的组合体""数据库是账本""依赖是硬性契约"这三件事,绝大多数坑都能自己绕过去。剩下的 10%,靠rpm -V、rpm --rebuilddb、--test这几个工具也就够用了。

如果这篇文章对你有点帮助,欢迎留言分享你踩过的 rpm 相关的坑,或者你有更刁钻的 rpm 用法,也欢迎交流。

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

C#上位机通过OPCAutomation连接KEPServerEX 6实现曲线监控

简介&#xff1a;一份完整的C# OPC通信示例工程&#xff0c;演示通过OPC自动化接口连接KEPServerEX 6服务器&#xff0c;并借助Windows窗体与图表控件将实时数据绘制成动态曲线。内容涵盖OPC服务器连接、数据项订阅、定时刷新、异常重连与图表优化等关键环节&#xff0c;适合工…

作者头像 李华
网站建设 2026/10/1 3:17:17

企业AI转型四步法:从场景选择到规模化落地的避坑指南

我们部门去年搞了一场AI转型动员会&#xff0c;各部门负责人都到了。讲台上厂商顾问放了一段特别炫酷的演示&#xff0c;大模型在屏幕上秒答问题、自动生成报表&#xff0c;台下几位老总眼里都在放光。三个月后我再去回访&#xff0c;发现那套系统除了在汇报PPT里出现过&#x…

作者头像 李华
网站建设 2026/10/1 3:17:06

帝国CMS处理Word图文混排的完整指南

做网站内容运营的朋友&#xff0c;十有八九都遇到过这种场景&#xff1a;编辑在Word里把图文排版打理得整整齐齐&#xff0c;复制粘贴到帝国CMS&#xff08;EmpireCMS&#xff09;后台编辑器里&#xff0c;结果图片全变成了带本地路径的破图&#xff0c;表格样式挤成一团&#…

作者头像 李华
网站建设 2026/10/1 3:16:41

体育赛事实时数据分析:Kafka架构设计、集群部署与消费端优化实战

1. 体育赛事数据的特殊性&#xff1a;为什么流式架构是绕不开的做体育数据这行之前&#xff0c;我一直觉得Kafka就是个普通的消息管道——往里丢消息&#xff0c;消费者取出来&#xff0c;完事。直到真正接手实时比赛数据分析系统&#xff0c;被体育赛事的流量节奏和数据形态连…

作者头像 李华
网站建设 2026/10/1 3:16:12

肺炎胸片4分类实战:从数据处理到迁移学习与模型评估

简介&#xff1a;面向医学图像分类任务的肺炎胸片四分类数据集&#xff0c;适合深度学习初学者与医疗影像研究人员直接用于模型训练与验证。数据涵盖COVID&#xff08;新型冠状肺炎&#xff09;、Lung_Opacity&#xff08;肺部浑浊&#xff09;、Normal&#xff08;正常&#x…

作者头像 李华
网站建设 2026/10/1 3:15:54

CH32L103 RISC-V工业MCU选型与低功耗设计实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华