news 2026/9/24 0:13:34

Cesium地形开挖实战:裁剪平面原理、代码实现与避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Cesium地形开挖实战:裁剪平面原理、代码实现与避坑指南

简介:面向Cesium初学者与前端开发者的地形开挖示例包,通过单个HTML文件完整演示了基于Cesium的三维地形开挖核心实现。压缩包内仅含1个HTML文件,大小仅1KB,代码集中,可直接在浏览器中运行,适合作为入门模板二次开发。示例覆盖Cesium.Viewer初始化、开挖区域几何构建、Material材质配置以及GroundPrimitive地面图元添加等关键环节,并涉及通过Rectangle与GeometryPipeline定义挖洞边界、利用Material自定义开挖区域外观等实用做法;前端开发者可对照学习HTML、CSS与JavaScript在三维GIS场景中的应用,也可基于此扩展鼠标事件以动态调整开挖位置与深度。示例将Cesium库的引入、页面容器定义与JavaScript逻辑组织得相当清晰,几乎无需额外配置即可运行。目前已有1218人学习下载,适合需要快速掌握Cesium地形开挖实现思路的开发者参考。

1. 为什么「cesium地形开挖」让前端开发又爱又恨

在三维 GIS 项目里,把地形挖开一个坑,是提气又熬人的需求。我最早在智慧矿山项目里碰到它:要给采坑做进度动画,让数字地球直接凹下去一块。第一版我用 entity 的 polygon 铺了一个黑色假坑,镜头一低就直接穿帮。真正能用的 cesium地形开挖,靠的是渲染管线里的裁剪平面,把地形像素按平面方程一块一块丢弃,只做视觉切削,不改动底层高程数据。这篇笔记围绕「html 页面里做三维开发最常用的一个实例」展开,目标读者是已经能加载 Cesium 地球、准备做开挖交互的前端开发工程师。下面从原理拆起,把最小可运行代码、参数坑和工程化收尾一次讲清楚。

2. 地形开挖的原理先立住:裁剪平面、entity 与 primitive 的边界、两种开挖形态

2.1 一个无限平面怎么把地形削出洞:半空间与法向量

Cesium 里做地形开挖的核心对象是ClippingPlane,一个裁剪平面在数学上就是方程normal · p + d = 0。它把三维空间切成两个半空间:法向量normal指向的一侧叫正侧,另一侧叫负侧。渲染时,如果一个片元落在多个裁剪平面的负侧,GPU 就把这个片元丢弃(discard),于是地形上出现空洞。

很多人第一次用会困惑:一个平面是无限的,怎么围出一个有限的坑?答案是围合。用一圈平面,每个平面的法向量都指向坑外。坑内部的点,对每个平面来说都在负侧,被丢弃;坑外部的点,至少对一个平面来说在正侧,保留下来。这就是为什么凸多边形能挖出干净利落的坑,而凹多边形会出问题——这一点后面专门讲。

关键参数只有两个:normaldnormal是三维单位向量,决定平面朝向;d是平面到原点的偏移量,单位是米。最容易翻车的点是:d不是“深度”,而是平面方程里的常数项。比如要让平面过某个点mid,必须先用d = -dot(normal, mid)反推出来。直接把d写成 0,平面就会过地球原点,在经纬度很大的区域里挖出个莫名其妙的斜洞,看到效果时基本是一脸懵。

2.2 entity 与 primitive 的区别:为什么 polygon 铺不出真坑

许多三维开发前端刚上手时会走同一条弯路:在地形上画一个带低的 polygon,以为这就是开挖。这背后其实是 Cesium 里 entity 与 primitive 的本质区别。entity 是面向业务封装的高层对象,适合描述“场景里有什么”;primitive 是底层渲染体,直接驱动 GPU 绘制。地形本身是 globe 这一层 primitive 在渲染,entity 的 polygon 只是贴在其上的一张“几何皮”,它没有能力改变地形高程块的数据,更不会让地球表面真的缺一块。

所以真正的地形开挖,必须把裁剪挂在 globe 上:

要裁的对象裁剪挂载点对地形是否生效
全球地形(globe)viewer.scene.globe.clippingPlanes
3D Tiles 倾斜摄影tileset.clippingPlanestileset.clippingPolygons
glTF/GLB 模型modelPrimitive.clippingPlanes
entity 多边形viewer.scene.clippingPlanes只裁实体,不裁地形

如果你在代码里把平面挂到了tileset.clippingPlanes上,倾斜摄影会切得整整齐齐,地形却纹丝不动。这是三个独立系统,各挂各的,别指望一个数组统一生效。

顺带说一句,globe.clippingPlanes用的是无限平面集合,而 Cesium 1.89 之后的 3D Tiles 还支持ClippingPolygonCollection,可以直接用任意凹多边形裁剪倾斜摄影。但注意它只对 3D Tiles 生效,对 globe 地形无效。所以「cesium地形开挖」如果目标是原始地形,方案仍然是平面围合这一套。

2.3 垂直开挖与放坡开挖:两个形态对应一套法向量

开挖形态主要分两种,但代码差异只是法向量的一个分量。

垂直开挖是默认形态。每个侧面的法向量保持水平,方向指向多边形外部。这样挖出来的是竖直侧壁,坑顶和坑底形状完全一致。适合基坑、隧道出入口这类要求侧壁垂直的场景。

放坡开挖在工程里更常见,为了防止土体塌方,侧壁要有一个坡度。实现方法非常简单:把每个侧面的法向量从水平方向“抬”起来,加上一个垂直分量。法向量变成(flat.x, flat.y, slopeFactor),再归一化。其中slopeFactor的换算关系是slopeFactor = 垂直变化 / 水平外扩。比如你要做一个高度 1 米、水平外扩 0.5 米的边坡,也就是 1:0.5 的放坡系数,那么slopeFactor = 1 / 0.5 = 2

还有一个容易忽略的地方:垂直开挖到底需要几个平面?经验是只需要侧壁一圈,不需要底面。侧壁平面围合出来的柱体向地下无限延伸,视觉上是个无底洞;坑底的“深度”由我们额外铺的一块底板实体来表现。这样视觉效果正确,而且代码简单。如果非要加一个水平底面裁剪平面,整个坑底以下的地球都会被削掉,从侧面看场景直接裂开,属于典型翻车。

3. 用 HTML 在本地跑通第一个 Cesium 地形开挖实例:选点、画范围、调深度

这一章给出一个完整的 HTML 页面。我一般把 Cesium 在本地自托管,或者直接用 CDN 引固定版本。版本建议锁定在 1.104 或更新的 LTS 附近,太老的版本 API 差异比较大,照着抄容易卡在莫名其妙的地方。代码里的 CDN 地址换成你自己项目里的相对路径也可以。

3.1 最小页面骨架:初始化 Viewer 与交互工具栏

先做一个全屏三维页面,加上四个按钮:画范围、执行开挖、重置、以及一个深度输入框。

<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="utf-8"> <title>Cesium 地形开挖实例</title> <link href="https://cdn.jsdelivr.net/npm/cesium@1.104/Build/Cesium/Widgets/widgets.css" rel="stylesheet"> <style> html, body { margin: 0; height: 100%; } #cesiumContainer { width: 100%; height: 100%; } #toolbar { position: absolute; top: 16px; left: 16px; z-index: 10; background: rgba(255, 255, 255, 0.92); padding: 10px 14px; border-radius: 8px; font-size: 14px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); } #toolbar button { margin-right: 6px; } </style> </head> <body> <div id="cesiumContainer"></div> <div id="toolbar"> <button id="btnDraw">画开挖范围</button> <button id="btnExcavate">执行开挖</button> <button id="btnReset">重置</button> <label>深度(m) <input id="depthInput" type="number" value="60" style="width:70px"></label> </div> <script src="https://cdn.jsdelivr.net/npm/cesium@1.104/Build/Cesium/Cesium.js"></script> <script> // 默认 token 换成你自己在 cesium ion 申请的,不换会在地球上方弹水印 Cesium.Ion.defaultAccessToken = '换成你的 ion token'; const viewer = new Cesium.Viewer('cesiumContainer', { terrainProvider: Cesium.createWorldTerrainAsync(), // 如果是旧版本,改回 createWorldTerrain() animation: false, timeline: false, infoBox: false, selectionIndicator: false, baseLayerPicker: false }); // 关掉地形深度测试,否则坑底贴板会被地形挡住看不到 viewer.scene.globe.depthTestAgainstTerrain = false; viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(116.39, 39.90, 1200), orientation: { heading: 0, pitch: -Cesium.Math.PI_OVER_TWO, roll: 0 } }); </script> </body> </html>

这段代码有两个参数值得说明。depthTestAgainstTerrain默认是 false,但如果你之前在别的项目里把它设成了 true,坑底部分会被地形遮挡,看起来像挖了个黑洞。createWorldTerrainAsync是 1.104 之后的异步版本,旧版本用同步的createWorldTerrain(),如果发现地形加载不出来,先检查这里。

3.2 在地形上点选多边形:生成开挖范围的坐标集合

绘制矩形或任意多边形的逻辑是一样的:监听鼠标左键,用pickEllipsoid把屏幕坐标转换到椭球面上的三维坐标,存进数组。双击结束绘制,顺便生成一个半透明预览面。

let drawing = false; let picked = []; const drawHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas); drawHandler.setInputAction(function (movement) { if (!drawing) return; const cartesian = viewer.camera.pickEllipsoid(movement.position, viewer.scene.globe.ellipsoid); if (!Cesium.defined(cartesian)) return; picked.push(cartesian); viewer.entities.add({ position: cartesian, point: { pixelSize: 8, color: Cesium.Color.YELLOW, outlineColor: Cesium.Color.BLACK, outlineWidth: 2 } }); }, Cesium.ScreenSpaceEventType.LEFT_CLICK); drawHandler.setInputAction(function () { if (!drawing || picked.length < 3) return; drawing = false; picked.pop(); // 双击会额外触发一次单击,导致末尾多一个重复点,先弹掉 viewer.entities.add({ polygon: { hierarchy: picked.slice(), material: Cesium.Color.RED.withAlpha(0.3), outline: true, outlineColor: Cesium.Color.YELLOW } }); }, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK); document.getElementById('btnDraw').addEventListener('click', function () { drawing = true; picked = []; viewer.entities.removeAll(); // 清掉上一轮的点位和预览面 });

pickEllipsoid返回的是 WGS84 椭球面上的Cartesian3坐标,已经带高程,不需要再手动转换。注意双击结束的时机:双击本身会先触发一两次单击事件,所以数组末尾会混进去一个重复点,picked.pop()是必须的,否则最后一条边会缩成一个零长度边,生成的裁剪平面会出现异常。

3.3 执行开挖的核心函数:构建侧面裁剪平面并挂到 globe

选完点、填好深度之后,核心函数就是把多边形每一条边生成一个向外指的裁剪平面,再整体挂到viewer.scene.globe.clippingPlanes上。

function buildSidePlanes(positions, slopeFactor) { // 用包围球算几何中心,作为“向内/向外”的参考点 const center = Cesium.BoundingSphere.fromPoints(positions).center; const n = positions.length; const planes = []; for (let i = 0; i < n; i++) { const p1 = positions[i]; const p2 = positions[(i + 1) % n]; const mid = Cesium.Cartesian3.midpoint(p1, p2, new Cesium.Cartesian3()); // 从中心指向边中点的向量,去掉 Z 分量后归一化,得到水平外法向 const outward = Cesium.Cartesian3.subtract(mid, center, new Cesium.Cartesian3()); const flat = new Cesium.Cartesian3(outward.x, outward.y, 0); Cesium.Cartesian3.normalize(flat, flat); // slopeFactor 为 0 是垂直开挖;大于 0 是放坡,法向量向上抬 const normal = new Cesium.Cartesian3(flat.x, flat.y, slopeFactor || 0); Cesium.Cartesian3.normalize(normal, normal); // 平面过 mid 点,d 要反推,不能直接写 0 const d = -Cesium.Cartesian3.dot(normal, mid); planes.push(new Cesium.ClippingPlane(normal, d)); } return planes; } document.getElementById('btnExcavate').addEventListener('click', function () { if (picked.length < 3) return; const depth = parseFloat(document.getElementById('depthInput').value) || 60; const sidePlanes = buildSidePlanes(picked, 0); viewer.scene.globe.clippingPlanes = new Cesium.ClippingPlanesCollection({ planes: sidePlanes, edgeColor: Cesium.Color.WHITE, edgeWidth: 2 }); // 计算多边形平均高程,作为坑底高度的基准 const cartos = picked.map(p => Cesium.Cartographic.fromCartesian(p)); const avgHeight = cartos.reduce((sum, c) => sum + c.height, 0) / cartos.length; const bottomHeight = avgHeight - depth; const flatDegrees = []; cartos.forEach(c => { flatDegrees.push(Cesium.Math.toDegrees(c.longitude), Cesium.Math.toDegrees(c.latitude)); }); viewer.entities.add({ polygon: { hierarchy: Cesium.Cartesian3.fromDegreesArray(flatDegrees), height: bottomHeight, material: Cesium.Color.SANDY_BROWN.withAlpha(0.95), outline: true, outlineColor: Cesium.Color.WHITE } }); });

这里有几个参数不能改错。ClippingPlanesCollectionplanes是完整数组,每次执行开挖我都重新建一个新的 collection 赋给globe.clippingPlanes,而不是去改旧 collection 里的元素,省得增删平面时触发一堆状态同步问题。edgeColoredgeWidth是 1.104 版本支持的裁剪边缘描边效果,旧版本不报错但不渲染,不影响开挖本身。

bottomHeight用的是“平均高程减去深度”。严格来说,如果地形起伏大,坑底应该是一个随地形起伏的曲面,这里用平均值会造成底板在某些位置露出地表或悬空。对于多数演示场景这个简化够用;如果要精确,需要用开挖区域内的 DEM 数据做空间插值,计算每个顶点的真实坑底高程。

3.4 坑底铺板与放坡开挖:两处小改动让效果像施工图

执行开挖后,坑实际上是一个向地心延伸的无底洞,我们在视觉上用一个底板把它封住。底板的高度就是刚才算的bottomHeight,颜色用土黄色更像施工图。这一步在上一节代码里已经完成,但有两个细节值得展开。

第一,底板实体本身不在 globe 的裁剪范围内。globe.clippingPlanes只管地形,不管 entity,所以底板不会被侧壁平面二次裁掉,这是巧合同时也是设计,不需要额外处理。

第二,如果要把垂直开挖变成放坡开挖,只需要把buildSidePlanes的第三个参数从 0 改成一个正数。例如要做 1:1 的放坡,也就是下降 1 米外扩 1 米,slopeFactor就等于 1:

// 1:1 放坡开挖,侧壁与水平面夹角约 45 度 const sidePlanes = buildSidePlanes(picked, 1.0);

注意slopeFactor越大,坡面越陡还是越缓?法向量从水平向上抬,坡面与水平面的夹角是atan(slopeFactor)slopeFactor = 0时坡角 0 度,是垂直侧壁;slopeFactor = 1时坡角 45 度;slopeFactor = 2时约 63 度。工程上写放坡系数是 1:m,即高度 1 米对应水平 m 米,换算过来slopeFactor = 1 / m。这个换算关系建议直接写在代码注释里,项目验收时经常要调。

4. 地形开挖最常见的 5 个翻车现场:现象、原因和解决

4.1 地形没反应,倾斜摄影却被挖了 —— 裁剪对象挂错了

现象:写了tileset.clippingPlanes = new Cesium.ClippingPlanesCollection(...),然后发现加载出来的倾斜摄影模型被切开了,但底下的地形完全没变化。

原因:地形、3D Tiles、模型这三者的裁剪系统是独立的。tileset.clippingPlanes只管当前这个瓦片集,剪不到 globe。反过来,如果你目标只是地形,挂到tileset上就是白写。

解决:目标对象是数字地球地形,就用viewer.scene.globe.clippingPlanes;目标是倾斜摄影,用tileset.clippingPlanes。如果两个都要挖,两处都要各挂一份平面数组。另外注意,早期版本的 Cesium 要求手动设置clippingPlanes.modelsLength才能让模型裁剪生效,新版已经自动管理,如果你还在用很老的版本,裁剪不生效时去中文文档里查一下这个参数,会少走弯路。

4.2 挖出来的不是坑而是柱子 —— 法向量方向反了

现象:执行开挖后,多边形内部的区域保留成一个凸起的高台,周围地形全部消失了,像一根柱子立在地球上。

原因:平面法向量方向反了。法向量指向“保留侧”,我们想让坑内被裁掉、坑外保留,所以每个侧面的法向量必须指向坑外。计算几何中心后用mid - center得到的向量朝外,但如果代码里写成了center - mid,方向就反了,结果是对称翻车:坑外被裁,坑内保留。

解决:把buildSidePlanesCesium.Cartesian3.subtract(mid, center, ...)改成subtract(center, mid, ...)。调试时有个土办法:临时把depth调到 10000,如果看到被切掉的是周围大片区域,说明方向肯定反了。

4.3 凹多边形开挖后形状不对 —— 平面裁剪本质是凸半空间求交

现象:选择 L 形、U 形等凹多边形作为开挖范围,执行后挖出来的形状跟预期的凹轮廓完全对不上,有的地方该挖的没挖,有的地方外面的地形缺了一块。

原因:裁剪平面围合的本质是求一组半空间的交集,而有限个半空间的交集一定是凸区域。凹多边形的凹角会让“坑内”和“坑外”的判定失控,外部某些点反而同时落在所有平面的负侧,于是被误删。

解决:要么把凹多边形近似成凸包,接受多挖一部分;要么改用tileset.clippingPolygons,这个 API 直接支持凹多边形裁剪,但它只对 3D Tiles 生效,对 globe 地形无效。实际项目里,如果地形开挖范围确实是凹的,我一般建议先用turf.convex求凸包,再生成平面;如果产品经理不接受多挖,就把原始凹多边形切分成多个凸多边形,每个凸区域单独做一次开挖渲染,但这在同一个 globe 上实现成本很高。

4.4 坑底和侧壁发黑发紫 —— 深度测试与底板的配合

现象:开挖后,坑的侧面出现大片黑色区域,底板颜色发紫或者闪动,转动视角时尤其明显。

原因:两个因素叠加。第一,如果viewer.scene.globe.depthTestAgainstTerrain = true,地形之外的片段在深度测试中会被丢弃,坑底实体在地形高程以下,于是整个底板被遮挡,露出背后的天黑色。第二,底板高度取了平均高程,在地形高处可能露出地表、在低处又陷入山体,产生紫黑穿插。

解决:初始化时显式设置viewer.scene.globe.depthTestAgainstTerrain = false。同时把底板height的设置改成“区域最高点高程减去深度”,保证底板绝不会露出地表;如果底部跟山体重叠的瑕疵仍然明显,给底板再叠加一层半透明材质,或者把底板向下多压几米,用厚度掩盖缝隙。

4.5 选点过程反复翻车 —— 双击多加点、镜头漂移和状态清理

现象:双击结束选点时,多边形末尾多了一个折点;选点过程中拖动鼠标,地球跟着旋转,坐标点落到意想不到的位置;第二次画范围时,旧的点位和预览面还留在场景里。

原因:双击会先触发单击事件;绘制状态下没有禁用相机控制;重复点击“画开挖范围”没有清理上轮实体。

解决:三行代码的事。双击回调里picked.pop()去掉重复点;进入绘制模式时执行viewer.screenSpaceCameraController.enableInputs = false,双击结束后恢复true;点击“画开挖范围”按钮时先viewer.entities.removeAll()。这三个坑我几乎每次演示都会踩一遍,现在固定写成模板,不再靠临场反应。

提示:如果发现选点时的坐标和实际地表位置有偏差,检查一下pickEllipsoid的时机。相机还在飞行动画中时点选,椭球交点会漂移。稳妥做法是先等viewer.camera.flyTo的 promise 结束,再开启绘制。

5. 把开挖做成可复用的渲染函数:参数化配置、多坑取舍与验收口径

做到这一步,一个可以交互的 cesium地形开挖实例已经能跑了。但项目里不能每次都用全局变量和按钮事件堆逻辑,我习惯把整套流程收敛成一个参数化函数,方便真正的前端开发同学集成进业务框架。

const pitConfig = { depth: 60, slopeFactor: 0, region: [ [116.39, 39.90], [116.40, 39.90], [116.40, 39.91], [116.39, 39.91] ] }; function renderExcavation(cfg) { const positions = cfg.region.map(function (item) { return Cesium.Cartesian3.fromDegrees(item[0], item[1]); }); const planes = buildSidePlanes(positions, cfg.slopeFactor || 0); viewer.scene.globe.clippingPlanes = new Cesium.ClippingPlanesCollection({ planes: planes }); // 坑底逻辑复用前面的平均高程减深度方案 }

region直接放经纬度数组,比在页面上手动画范围更适合对接后端接口。后端从施工图纸读出设计坐标,前端拿到配置一调用,开挖效果立刻出现。接入了前端 agent 或本地 MCP 工具的项目,还能把renderExcavation暴露成可调用函数,通过自然语言改深度和坡度再调起,省掉一版又一版的沟通成本。

多区域开挖要提前想清楚取舍。一个globe只有一个clippingPlanes属性,多个坑要在一个场景里同时存在,不能简单地把两组平面塞进同一个 collection,因为平面裁剪是交集语义,两组平面会互相干扰,挖出错误形状。实际项目我见到的做法是优先保障单个关键坑位精确,其余区域用倾斜摄影的clippingPolygons覆盖,或者等后端把多个坑合并成一个 GeoJSON 区域再统一处理。

验收时有一个容易忽略的口径:globe.clippingPlanes只是渲染层裁剪,不会修改地形数据。viewer.scene.globe.getHeight(cartographic)在开挖后拿到的仍然是原始地表高程,拿它验证坑深会得到错误结论。正确做法是直接读底板实体 polygon 的height和原始平均高程的差值。这句话我每次交底都会跟测试强调一遍,免得验收单上多一条假 bug。

这套方案到现在我还在持续改。前阵子接手一个新项目,对方要求把采坑周围做 1:0.75 的放坡,我按slopeFactor = 1 / 0.75换算完,五分钟后效果就对了。倒是那些藏在法向量和depthTestAgainstTerrain里的小坑,几乎每个月都会在某个同事的电脑上重新发生一次。希望这次梳理能帮你把 Cesium 地形开挖这条路上的雷提前拆干净,也希望后面接手你代码的兄弟少掉几根头发。

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

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

SSM垃圾分类系统课程设计:从环境搭建到二次开发全攻略

简介&#xff1a;这是一套面向Java初学者与课程设计需求的SSM框架垃圾分类管理系统完整源码包&#xff0c;适合作为框架入门练手项目或课程作业参考。系统采用SpringSpringMVCMyBatis架构&#xff0c;前端以JSP页面实现展示与交互&#xff0c;数据库选用MySQL&#xff0c;整体结…

作者头像 李华
网站建设 2026/9/24 0:12:12

SVM手写数字识别实战:预处理、LibSVM调参与避坑指南

简介&#xff1a;这份资源围绕基于支持向量机&#xff08;SVM&#xff09;的手写字体识别展开&#xff0c;面向计算机视觉与机器学习入门者、课程设计或实验项目开发者&#xff0c;帮助理解从图像预处理、特征提取到分类器训练与评估的完整流程。压缩包共85个文件&#xff0c;约…

作者头像 李华
网站建设 2026/9/24 0:09:47

LSTM时序预测实战:数据预处理、状态管理与滚动预测

简介&#xff1a;本资源是一份面向深度学习初学者与时间序列建模实践者的LSTM预测算法入门级代码实现&#xff0c;聚焦金融价格等一维时序数据的未来值预测任务。资源核心为单文件Python脚本&#xff08;LSTM.py&#xff09;&#xff0c;完整涵盖LSTM网络结构定义、滑动窗口数据…

作者头像 李华
网站建设 2026/9/24 0:02:56

DEiT图像分类实战:数据高效Transformer的训练与推理

简介&#xff1a;面向深度学习与计算机视觉学习者&#xff0c;这份DEiT实战资源围绕Facebook提出的DeiT模型&#xff0c;展示如何在不依赖外部数据集的情况下&#xff0c;利用知识蒸馏策略完成ImageNet级别的高效训练&#xff0c;并落地到图像分类任务中。DeiT通过引入蒸馏令牌…

作者头像 李华