news 2026/10/3 13:58:13

基于Paillier同态加密的CNN图像分类实战拆解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于Paillier同态加密的CNN图像分类实战拆解

简介:一套面向Python深度学习学习者的加密图像分类系统项目,聚焦云计算场景下加密图像的隐私保护分类需求,适合作为毕业设计、课程设计或工程实训。项目基于卷积神经网络实现端到端流程,兼顾安全与识别任务,可作为安全方向与CV方向结合的实操范例。压缩包共2004个文件,约148.84MB,以JavaScript、Markdown和JSON类型为主,分别承担前端展示、步骤说明与配置管理,另有少量Python脚本、HTML页面和文本说明,整体目录结构清晰,便于按模块查阅。当前已有116人学习下载。通过学习可掌握CNN图像分类模型的构建方法、加密图像预处理思路以及云端隐私保护场景下的系统集成方式,配套文档与配置细节有助于快速复现和二次开发。

1. 加密图像分类:为什么「先解密再分类」这条路走不通

把图像传到云端做人脸识别、病灶分类,业务上很顺手,但隐私上的坎过不去:一旦云端看到明文图像,或者数据库被拖走,用户的隐私就彻底暴露了。加密图像分类系统要解决的核心问题,就是在图像全程以密文形态存在云端的前提下,让卷积神经网络(CNN)仍然能把类别分出来。这篇笔记拆解的这个Python项目,用的是一套「本地CNN提特征、Paillier密文域算分类层」的混合架构,适合正在做毕设、课程设计或想动手验证同态加密落地效果的人。你不用先啃完同态加密的论文,照着代码把环境配好就能跑通端到端流程。

2. 技术选型:同态加密家族的三个候选,为什么最后选了Paillier

2.1 先定威胁模型:我们防的是哪种「偷看」

在做隐私保护方案之前,必须先说清楚防御对象。加密云端图像分类这个场景,默认的威胁模型是「诚实但好奇」的云端——它不会篡改你的数据、不会伪造结果,但它有权限访问服务器上的所有文件,也可能会被拖库、被备份泄露、被内部人员翻看。换句话说,云端本身不是恶意攻击者,但它是一个潜在的偷看者。

明确了这一点,架构上的第一原则就出来了:私钥绝对不能离开客户端。图像一旦用公钥加密,云端手里就只有密文,即使它把磁盘镜像拷走,也无法还原明文。与之相对的,如果方案设计成「先传到云端解密再分类」,那这个系统的隐私保护就名存实亡了——解密发生在云端,等于把钥匙放在锁旁边。我在评审课程设计时见过不少这样的翻车作品,图方便把解密逻辑写在服务器接口里,答辩老师一问密钥在哪,直接就答不上来。

所以这个项目虽然叫「加密图像分类系统」,本质上它是一套「明文特征提取 + 密文分类」的外包计算系统。客户端保留图像信息的最小充分统计量(深度特征),云端只参与把特征映射到类别得分的那部分线性计算,全程接触不到原始图像,也还原不出图像内容。

2.2 同态加密三选一:Paillier、CKKS、BFV怎么定

同态加密允许在密文上直接做计算,解密后结果等于明文计算结果。但不同方案能做的运算是不一样的,这是选型的核心。常见候选有Paillier、CKKS、BFV,我列个表对比:

方案支持的密文运算精度模型Python库适合干什么
Paillier加法、明文数乘整数精确phe线性层、加权求和、统计聚合
CKKS加法、乘法(含密文乘法)浮点近似TenSEAL卷积、多项式近似激活
BFV加法、乘法整数精确TenSEAL整数卷积、量化网络

CKKS和BFV都能做密文乘法,看起来更适合CNN,但代价是噪声管理。每做一次密文乘法,噪声预算就消耗一截,预算耗尽后解密结果就是垃圾数据,需要在网络层设计、批量编码、重线性化(relinearization)上花大量功夫。毕设和课程设计周期内,把CKKS跑在CIFAR-10上且精度不掉,我见过的人里十个有九个最后翻车在噪声预算上。

Paillier虽然只能做加法和数乘,但恰好够用:CNN最后几层里最常见的全连接层、批归一化的线性变换部分,本质就是权重乘特征再求和(线性组合)。把加密放在特征和分类层之间,密文域只需要两类运算:数乘和加法。这两个Paillier原生支持,语义安全有保障,phe库安装简单,代码量小。所以这个项目的结构是:用Torch在本地提特征,然后只在分类层走Paillier加密计算。

2.3 整个系统的数据流:五步走,每步在谁手里

把选型确定后,系统流程就非常清晰了,五步走:

  1. 客户端加载图片,跑CNN骨干网络提取深度特征向量(这个向量是压缩后的图像语义信息,但不直接暴露像素)。
  2. 客户端把浮点特征整数化,用公钥逐元素加密,把密文特征发送给云端。
  3. 云端拿着明文权重(分类层参数),在密文特征上做数乘和加法,得到每个类别的密文得分。
  4. 云端把所有类别的密文得分返回给客户端,不返回任何中间层特征。
  5. 客户端用私钥解密,做softmax和argmax,得到最终分类标签。

这个流程的关键点在第三步:云端做计算时,它手里的权重是明文的,特征向量是密文的。权重属于模型提供方,本来就不需要保密;要保护的是用户输入的图像。两边信息不对称,但分类任务照常完成。与传统方案比,它把「不得不信任云端」这个假设从系统里拿掉了——云端即使把所有日志都留下,也只能看到一堆随机数。

3. 把系统跑起来:环境、预处理与CNN特征提取

3.1 环境准备:装什么、怎么装、装完怎么验证

这个项目的运行环境不需要GPU,CPU也能跑,因为加密阶段本来就慢,瓶颈不在模型推理上。安装依赖用pip一条命令就能完成:

pip install torch torchvision phe numpy scikit-learn

这里有几个安装细节值得注意。phe是python-paillier库的导入名,你如果去PyPI搜「paillier」也能找到它,包名叫python-paillier,别装成另一个同名但已经停维护的老包。torch和torchvision建议用官方默认源,如果网速不理想可以加-i https://pypi.tuna.tsinghua.edu.cn/simple,但phe不要从镜像装——我遇到过一次镜像源里的phe版本比较旧,generate_paillier_keypair的参数签名都对不上,后来还是从官方源重装就好了。

装完之后跑一条冒烟测试,确认密码学库可用:

python -c "from phe import paillier; pub, pri = paillier.generate_paillier_keypair(n_length=1024); print(pub.encrypt(42) + pub.encrypt(7))"

能打印出密文对象就说明环境没问题。注意这里故意用1024位密钥做测试,目的是快速验证,正式跑实验时必须用2048位。

项目目录结构我建议这样组织:

encrypted-image-classifier/ ├── config.py # 密钥长度、缩放因子、特征维度等全局参数 ├── feature_extractor.py # CNN模型定义与训练 ├── encrypt_client.py # 客户端:特征提取、加密、发送 ├── server_classify.py # 云端:密文域分类 ├── decrypt_client.py # 客户端:解密与结果展示 ├── evaluate.py # 测试集全流程评估 └── weights/ ├── feature_extractor.pt └── server_head.npy

我一般把「客户端加密」和「云端分类」拆成两个独立脚本,模拟真实网络环境中的两端。实际部署时甚至应该跑在两台机器上,开发阶段可以先都在本机,通过文件或socket传密文。

3.2 图像预处理:归一化参数别乱改,特征范围决定了缩放因子

CNN特征提取前的预处理直接影响加密环节的缩放因子选择,这一点很多人会忽略。图像先统一尺寸,再归一化:

from torchvision import transforms transform = transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ])

这里用的是ImageNet的均值和标准差。为什么要用这一组数值?因为项目采用预训练ResNet18做骨干网络,它的权重就是在ImageNet分布上训练的,输入数据保持同分布,提取出来的特征才稳定。如果你换了自己训练的CNN,这组均值方差就要跟着训练数据重新统计,否则特征分布偏移,后面加密了也分类不准。

预处理之后,特征向量的数值范围会是一个很关键的信息,建议在进入加密前先打印一下:

import torch def inspect_feature(feat): print(f"shape={tuple(feat.shape)}, " f"range=[{feat.min().item():.4f}, {feat.max().item():.4f}], " f"mean={feat.mean().item():.4f}") return feat

这一步输出的数值直接决定了第3.4节里缩放因子的选取。如果特征值集中在0.01量级,scale取1e2会把大部分信息抹成0;如果特征值在100量级,scale取1e4又会让中间乘积膨胀到Python大整数,拖慢计算速度。先观察再定参,别凭感觉抄代码。

3.3 CNN特征提取:ResNet18改最后一层,输出64维特征

模型上我建议在预训练ResNet18的骨干后面接一个自己定义的全连接头,把输出维度压到64。维度不能太高,也不能太低,理由后面加密环节会体现。模型定义:

import torch.nn as nn from torchvision import models class FeatureExtractor(nn.Module): def __init__(self, out_dim=64): super().__init__() base = models.resnet18(weights=models.ResNet18_Weights.DEFAULT) self.backbone = nn.Sequential(*list(base.children())[:-1]) self.fc = nn.Linear(512, out_dim) def forward(self, x): feat = self.backbone(x).flatten(1) return self.fc(feat)

list(base.children())[:-1]这一步把ResNet18自带的全局平均池化和全连接层去掉,只保留卷积骨干。骨干输出的512维特征图做flatten后,再经过一个64维全连接层。这个新全连接层的权重需要训练出来,因为预训练模型原本是接1000类ImageNet分类头的,直接拿原始输出做特征,语义颗粒度对CIFAR-10这类小数据集不合适。

训练时任选一个标准分类器附加在特征后面,用交叉熵端到端微调:

class EncryptedClassifier(nn.Module): def __init__(self, feat_dim=64, num_classes=10): super().__init__() self.feature_extractor = FeatureExtractor(feat_dim) self.head = nn.Linear(feat_dim, num_classes) def forward(self, x): return self.head(self.feature_extractor(x)) model = EncryptedClassifier(feat_dim=64) optimizer = torch.optim.Adam(model.parameters(), lr=1e-4) criterion = nn.CrossEntropyLoss() for epoch in range(5): for imgs, labels in train_loader: optimizer.zero_grad() logits = model(imgs) loss = criterion(logits, labels) loss.backward() optimizer.step()

训练结束后,把feature_extractor的权重单独保存给客户端,把head的权重导出给云端:

torch.save(model.feature_extractor.state_dict(), "weights/feature_extractor.pt") W = model.head.weight.detach().cpu().numpy() b = model.head.bias.detach().cpu().numpy() np.save("weights/server_head.npy", {"W": W, "b": b})

head的全连接权重是分类层参数,必须和特征提取部分解耦保存。训练时合在一起,部署时拆开,这是这套加密架构和普通CNN推理最大的区别。云端只拥有后半个分类层,客户端只拥有前半个特征提取器。

3.4 特征编码:浮点转整数,Paillier只认整数

Paillier加密算法的明文空间是整数,而CNN特征几乎必然是浮点数,所以必须做一次量化编码。这一步的精度损失是加密分类相比明文分类的额外误差来源,要控制在可忽略范围内:

def encode_feature(feat, scale=1e4): feat_list = feat.cpu().numpy().tolist() return [int(round(v * scale)) for v in feat_list]

这里有三个参数选择需要解释。第一,scale取1e4是我的默认值,理由是特征归一化后典型范围在-3到3之间,乘1e4后变成-30000到30000的整数,既能保留4位小数精度,又不至于让密文乘积膨胀到夸张的位数。第二,round必须配合int转换,因为Python的round在浮点边界上可能返回float类型,而phe库的encrypt方法对非int入参会抛异常。第三,注意这里乘的是普通float运算,特征值本身没有做额外的偏移——负数是允许的,Paillier对负整数加密完全没问题,但解密时你要记住这是带符号整数。

编码后做一次校验,确认每一维的编码值与原始浮点值的差异不会影响分类:

decoded = [v / scale for v in encoded] mse = sum((a - b) ** 2 for a, b in zip(feat_list, decoded)) / len(feat_list) assert mse < 1e-6, f"encoding loss too high: {mse}"

这个断言写进去,能避免后续踩到「加密分类全错但找不到原因」的坑。如果MSE超过1e-6,说明scale太小或者特征数值范围异常,先回到3.2节检查归一化参数。

4. 密文域分类实现:Paillier加密推理的实战细节

4.1 密钥生成:公钥给云端,私钥锁死在客户端

密钥管理是这套系统里安全性的根。先用phe生成一对Paillier密钥:

from phe import paillier def generate_keys(n_length=2048): pub_key, priv_key = paillier.generate_paillier_keypair(n_length=n_length) return pub_key, priv_key def serialize_pubkey(pub_key): return pub_key.to_json() # 公钥可以发给云端

n_length=2048是密钥位数,对应RSA 2048级别的安全强度。位数翻倍到4096安全性更高,但客户端加密和解密耗时大约会涨三到四倍,演示项目没必要。生成密钥对耗时大约几秒,一次性生成、后面反复使用即可。

公钥会被发送给云端,云端可以用它加密和做同态运算,但永远无法解密。私钥只存在于客户端进程内,最好连磁盘都不要落盘。有些课程设计为了省事把私钥序列化后和代码放一起,这等于把系统的安全假设全打破了——一旦项目代码外泄,私钥就泄露,所有历史密文都能被解开。

4.2 客户端加密:逐元素加密特征向量

客户端拿到64维整数特征后,用公钥逐元素加密,得到64个密文对象:

def encrypt_feature(encoded_feat, pub_key): enc_feat = [pub_key.encrypt(v) for v in encoded_feat] return enc_feat

encrypt内部做的是模幂运算,这是整个流程里最耗时的部分。以2048位密钥为例,单元素加密在我的旧笔记本上大约耗时100到300毫秒,64维特征串行加密就是6到20秒。这个耗时对demo可以接受,但如果你把特征维度设成512维,单张图加密就要花一两分钟,交互体验会很差。这也是前面把特征压到64维的直接原因。

密文对象可以直接用pickle序列化后走网络传输:

import pickle def send_to_server(enc_feat): payload = pickle.dumps(enc_feat, protocol=4) with open("enc_feat.bin", "wb") as f: f.write(payload) return payload

注意pickle的protocol参数,protocol=4对大对象支持更好,处理几十个密文对象时快且稳。实际项目中可以用socket或HTTP传输,开发阶段写文件模拟两端交互就够验证流程了。

4.3 云端密文分类:数乘和加法,刚好是Paillier的主场

云端收到密文特征后,拿着明文权重做全连接层的前向计算。全连接层的数学表达是logit_j = sum_i(W[j,i] * x_i) + b_j,这正好拆成两类操作:权重乘以密文(数乘)、把所有乘积与偏置加在一起(加法)。代码如下:

import numpy as np from phe import EncryptedNumber def encrypted_linear(enc_feat, W, b, pub_key, scale=1e4): num_classes, feat_dim = W.shape enc_logits = [] for j in range(num_classes): acc = pub_key.encrypt(int(round(b[j] * scale))) for i in range(feat_dim): wi = float(W[j, i]) acc += wi * enc_feat[i] enc_logits.append(acc) return enc_logits

这段代码有几个值得讲的细节。第一,偏置先乘了scale再加密,目的是让偏置和特征处于同一数值尺度,解密后直接除以scale就能得到正确的logit,不用在密文域做额外缩放。第二,wi * enc_feat[i]这个表达式里,wi是明文的numpy.float64,phe的EncryptedNumber支持与float数乘,等价于计算E(wi * fi')。第三,循环里反复用acc +=做密文加法,Paillier的密文加法会累积噪声但不会累积到无法解密,因为加法是精确的,只有噪声预算增长的问题;几百次加法完全在安全范围内。

云端计算结束后,把所有类别的密文logit打包返回。这里特别注意:云端不应该尝试自己挑出最大得分——密文域做大小比较不是Paillier能直接干的,硬要实现就得上更复杂的比较协议,成本翻好几倍。正确做法是把整包密文logit还给客户端。

4.4 解密与判定:只在客户端做一次softmax

客户端收到密文logit,私钥解密,再完成最后的分类决策:

import numpy as np from scipy.special import softmax def decrypt_logits(enc_logits, priv_key, scale=1e4): logits_int = [priv_key.decrypt(e) for e in enc_logits] logits = np.array([v / scale for v in logits_int], dtype=np.float64) return logits def predict(logits): probs = softmax(logits) return int(np.argmax(probs)), float(np.max(probs))

解密返回的是整数,除以scale后才回到真实量纲。softmax放在解密后做,因为明文侧做softmax开销几乎为零,而在密文域做指数运算完全不现实。整个流程中,云端接触到的只是「64个密文特征」和「10个密文logit」,从这些数据里恢复出原始图像属于计算不可行,这正是隐私保护的核心承诺。

5. 加密图像分类避坑指南:五个我实测踩过的翻车现场

5.1 现象:解密后logits和明文计算结果差出一个数量级,分类全错

原因:缩放因子scale取得不对。特征归一化后数值只有0.001量级时,scale=1e2会让整数化后的特征大量变成0,信息被直接抹掉;相反,scale取到1e6时,特征整数可以到几十万,与权重相乘后膨胀到上千位的大整数,Python虽然能处理任意精度整数,但密文对象的运算开销会高到离谱,甚至在一轮加法里就把中间值撑爆。

解决:先跑3.2节的inspect_feature看特征的真实数值范围,再定scale。经验值是让特征乘以scale后的最大值落在1万到10万之间。改完scale之后,记得把4.3节偏置的scale参数一起改,两边必须保持一致,否则解密结果永远对不上。

5.2 现象:128维特征加密单张图要等两分钟,以为程序死循环了

原因:Paillier逐元素加密是模幂运算,每维一次,耗时随维度线性增长。我把特征维度从64改到128想提精度,结果加密耗时直接翻倍,整批实验完全跑不动。

解决:特征维度设64就够,分类精度和128维在CIFAR-10上差距通常在1个点以内。如果确实要提精度,优先微调骨干网络的训练轮数,而不是加密特征维度。另外可以对加密循环做并行:multiprocessing.Pool.map把64个加密任务分发到4个核,单张图加密耗时能压到原来的30%左右,代码改动不到五步。

5.3 现象:想在云端直接输出类别编号,密文域算argmax算不出来

原因:Paillier只支持加法和数乘,不支持密文比较。要在密文上比较大小,需要额外引入混淆电路、不经意传输等协议,复杂度远超课程设计范畴。

解决:不要在云端做argmax。云端把全部10个类别的密文logit返回给客户端,客户端解密后做一个轻量argmax。云端最多知道「分类所需类别数」,这是隐私可接受的泄露。这个限制是Paillier方案的原生特征,不是代码bug,答辩时主动讲出这一点反而加分。

5.4 现象:项目传到GitHub后被人提醒「私钥泄露了」

原因:demo代码里把生成好的私钥序列化存成了key.pem,.gitignore没写这条规则,提交时一起进了仓库。任何拿到仓库的人都能用它解密之前的密文日志,整个系统等于没有加密。

解决:密钥每次运行临时生成,不落盘;或者用环境变量传入私钥,配置文件只保留公钥。提交前跑一遍git status检查有无密钥文件混入,顺手在.gitignore里加一行*.pem和*.pk。

5.5 现象:pub_key.encrypt(v)报TypeError,说不能处理numpy.int64

原因:phe的encrypt要求入参是Python原生int,而从numpy数组取出的标量类型是numpy.int64,两者在类型检查上不兼容。

解决:编码函数里显式做int(round(v * scale)),不要省掉int()。这个坑在第一次跑时几乎必踩,踩过之后把编码函数写稳,后面所有流程都顺畅。

6. 验证与进阶:用混淆矩阵压测加密分类,再谈一个效率技巧

6.1 端到端验证:明文精度与加密精度必须一致

先建立基线,跑一遍纯明文分类精度,再跑加密流程,两者的Top-1相差应该在1%以内。用混淆矩阵看具体哪些类被混淆:

from sklearn.metrics import confusion_matrix, classification_report import numpy as np def evaluate(test_loader, encrypt_pipeline, decrypt_pipeline): y_true, y_pred = [], [] for imgs, labels in test_loader: for img, label in zip(imgs, labels): logits = decrypt_pipeline(encrypt_pipeline(img)) pred = int(np.argmax(logits)) y_true.append(label.item()) y_pred.append(pred) cm = confusion_matrix(y_true, y_pred) print(classification_report(y_true, y_pred, digits=4)) return cm

encrypt_pipeline接收单张图像,内部做:特征提取、整数化、加密、模拟云端线性层、解密;decrypt_pipeline接收解密后的logits并转成预测标签。这里我把两端封装成参数可切换的函数,方便在纯明文和加密模式之间来回切换,定位误差来源。

经验上,加密模式掉点如果超过1%,先怀疑特征整数化那一环,回到3.4节的MSE断言检查。差在1%以内是正常的,因为浮点转整数本身就有量化噪声,这个噪声在softmax之前被logits的求和运算部分平均掉了。

6.2 性能基线:心里有数才能设计

给你一份我在CPU机器(i5-9400F,16G内存)上跑出的参考数据,特征维度64,密钥2048位,单张图全流程耗时分布:

环节耗时说明
特征提取<0.1s纯CPU推理,batch=1
特征编码趋近于064维乘除运算
加密约7~9s64次模幂,串行
密文分类<0.5s10类线性层,纯加法
解密+argmax<0.05s10次解密

加密是绝对瓶颈,占比超过90%。如果想做实时性更强的演示,把特征维度压到32,加密时间能降到4秒左右,精度损失又会增加一点。毕设答辩演示时建议先预加密几十张图,现场只跑密文分类和解密环节,避免让评委干等。

6.3 一个效率小技巧:把偏置编码成「常数特征」,省一次加密

我后来发现4.3节里每个类别都要对偏置单独做一次pub_key.encrypt,这个加密其实可以省掉。技巧是把偏置看作「特征恒等于1的那一维」:在特征向量末尾追加一个固定编码值1×scale,在权重矩阵里对应追加一列偏置值,这样整个线性层就统一成纯粹的密文加权求和:

def build_augmented(enc_feat, b, pub_key, scale=1e4): # 在密文特征末尾拼接一个“恒等偏置项” enc_bias = pub_key.encrypt(int(round(1 * scale))) return enc_feat + [enc_bias] def encrypted_linear_fast(enc_feat_aug, W_aug): enc_logits = [] for j in range(W_aug.shape[0]): acc = W_aug[j, -1] * enc_feat_aug[-1] for i in range(W_aug.shape[1] - 1): acc += W_aug[j, i] * enc_feat_aug[i] enc_logits.append(acc) return enc_logits

这个改法把每类偏置的预加密动作全部去掉,只多了一个常数特征,云端代码少一整个循环,核心计算里加法和数乘的数量没变,但初始化时间省掉了。更重要的是,它把「线性层 + 偏置」从两个步骤统一成一个纯线性的密文操作,逻辑上更干净,讲给答辩老师听也更容易解释。

要把这个技巧讲透,本质是意识到Paillier密文上的线性变换是封闭的:任何sum(w_i * x_i) + b都能通过「虚拟输入为1」的方式,改写成sum(w'_i * x'_i)的形式。这个思路在安全多方计算里叫虚拟节点技术,做联邦学习特征工程时同样适用。

我第一次跑完整套系统,是在一个周五晚上,当时把scale调成1e6,解密出来的logits数字漂亮,但Top-1全是错的,查了半小时才发现是特征整数化时溢出到了超长整数,密文计算慢得离谱。从那以后,我每次调整scale、特征维度或密钥位数,都强制先拿三张图走一遍「提取—加密—分类—解密」的冒烟测试,确认无误再跑全量测试集。加密系统不像普通模型训练,出了错不是loss不降这样直观,而是「看起来一切正常但结果全错」,所以冒烟测试这一步无论如何不能省。希望这份拆解和踩坑记录能帮到你,让你在这条路上走得比我第一次顺。

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

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

2026企业AI办公平台选型指南:从管控、集成到场景落地

一、企业选AI办公工具&#xff0c;为什么不能只看功能列表 企业数字化团队在采购AI办公平台时&#xff0c;容易陷入功能清单对比的惯性思维。在产品介绍页罗列大量能力项、演示案例丰富的平台&#xff0c;往往会获得更高关注度&#xff0c;但大量试点项目反馈&#xff0c;单纯功…

作者头像 李华
网站建设 2026/10/3 13:55:22

人机协同预训练:三条路线,一条拉开差距

【具身AGI导读】同一套数据、同一套训练与评测设置&#xff0c;三种把第一视角数据接进预训练的做法被放在一起比。结果里有一条并不好看&#xff1a;被寄予厚望的那条&#xff0c;反而低于它自己的机器人基线。近日&#xff0c;arXiv 上出现一篇题为 AtomEgo 的预印本&#xf…

作者头像 李华
网站建设 2026/10/3 13:55:09

LM25143RHAR的外围电路设计

创作背景&#xff1a;我在为项目设计电源板。系统整体由 12V 供电&#xff0c;需要同时为多个子系统提供稳定的能量&#xff1a;一路 5V 需要持续输出 5A&#xff0c;用于驱动 DRV8874 电机驱动芯片&#xff1b;另一路需要约 7.4V&#xff08;7V~9V区间&#xff09;&#xff0c…

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

音视频面试题之rtmp-02推流源码梳理

1. 模块初始化顺序(PushWork::Init) 入口 main_publish.cpp:78 调用 pushwork.Init(properties),整个初始化顺序严格按"先网络、再编码、后采集"排列,确保第一帧数据到来时所有下游都就绪: pushwork.Init() ├─ 1. 读取 Properties 配置(采样率、码率、分辨…

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

第055篇 Optional 与空值处理——比判空更优雅的表达

摘要:本篇是《Android软件开发面试从入门到精通》第 55 篇,主题为「Optional 与空值处理——比判空更优雅的表达」。「Optional 与空值处理——比判空更优雅的表达」是面试里出场率极高的一环。本篇按概念、原理、代码、误区四步走,看完就能组织出自己的回答。 关键词:Andr…

作者头像 李华
网站建设 2026/10/3 13:52:51

# 软件设计师考试模拟试题 计算机与软件工程知识(选择题)

软件设计师考试模拟试题依据《软件设计师考试大纲》编写&#xff0c;覆盖大纲 12 项知识与能力要求。 考试科目&#xff1a;计算机与软件工程知识&#xff08;上午&#xff0c;选择题&#xff09;、软件设计&#xff08;下午&#xff0c;问答题&#xff09;。第一部分 计算机与…

作者头像 李华