Gemma4 遥感识别与霍城县全县切图操作复盘
Gemma4 遥感识别与霍城县全县切图操作复盘
创建时间:2026-04-22
记录人:Codex 协作整理
主题:SAM -> 单对象切图 -> Gemma4 批量识别 -> 双卡 Open WebUI/Ollama -> 霍城县全县切图
1. 这次到底做了什么
这轮主要不是单点改一个脚本,而是围绕“遥感目标识别批处理”连续做了几次方案迭代:
- 先梳理了原始单对象切图和单图识别脚本。
- 尝试过“多图一批返回多个结果”的方案。
- 尝试过“多对象拼一张图再一起识别”的方案。
- 最后又回到“单对象 chips 保持简单,但一次送 Gemma 多张图”的思路。
- 又进一步补了伊犁场景扩展类别版提示词。
- 同时搭建了双卡 Ollama / 双 Open WebUI。
- 最后为霍城县全县数据新建了专用切图脚本和并行切图脚本。
这篇记录重点总结:
- 哪些方案试过
- 遇到了什么具体问题
- 最终用了哪些脚本
- 代码和命令应该怎么组织
2. 原始参考脚本
2.1 单对象切图参考脚本
参考脚本:
/root/sam21file/cut_feature_chips_512.py
逻辑很直接:
- 读取
tif + shp - 对每个要素取外包框中心点
- 以中心点为中心裁一张
512 x 512 - 把当前要素红色边界画在图上
- 左上角写
fid - 保存
png + chips_index.csv
这个逻辑的优点是简单稳定,后面所有批量识别脚本基本都是围绕这套单对象 chips 展开的。
2.2 单图 Gemma 识别脚本
原始参考脚本:
/root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_single/classify_chips_with_gemma4_v2.py
它的问题也很明确:
- 一张图发一次请求
- 总图数接近 2000 时,HTTP 往返太多
- 整体速度明显偏慢
3. 方案演进与踩坑记录
3.1 第一阶段:尝试“多张图一批”
为了解决单图太慢的问题,新建过一个批量版思路:
- 一次请求送多张图片
- 让模型一次返回多个结果
这个思路本身是可行的,而且比逐张请求快很多。
但早期版本出现过两个问题:
chips_index.csv里的chip_path仍然指向旧目录。- 模型虽然返回了 JSON 数组,但有些批次会出现:
fid重复fid丢失- reason 混入垃圾文本,比如
reasons:、en
3.2 第二阶段:尝试“多对象一张图”
后来又试了一条更激进的思路:
- 一张复合图里放多个目标对象
- 给每个对象编号
- 让模型一次看一张图,返回多个对象结果
新建过相关脚本与目录,例如:
cut_multi_object_chips_20260421.pyclassify_multi_object_with_gemma4_20260421.py
这个思路理论上更省请求数,但最终没有作为主线继续用下去,原因是:
- 多目标图在密集区编号容易互相遮挡。
- 对模型来说,目标边界和标签混在一起时更容易串号。
- 如果遥感对象很小,多对象拼图反而会让单个目标更不清晰。
后来又试过:
- 固定网格切块
512 + overlap 64- 每块把所有要素
fid都标出来
结果也不理想:
- 稀疏区还能看
- 密集区严重拥挤
- 并不适合直接送模型
3.3 第三阶段:回到“单对象 chips + 批量送图”
最终回到一个更稳的主线:
- 切图仍然保持“一对象一图”
- 但请求改成“一次送 10 张”
- 程序端严控返回结果质量
这一阶段形成了真正可用的主脚本:
/root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_multi_object/classify_chips_with_gemma4_batch10_20260421.py
这是后面所有扩展版的底座。
4. 批量识别脚本里真正踩到的关键问题
4.1 旧 chips_index.csv 路径失效
问题:
chips_index.csv在新目录里- 但里面保存的
chip_path还是旧路径
解决:
- 在批量识别脚本里增加
resolve_chip_path - 自动尝试当前目录下的
chips_512 - 不要求手工改 CSV
4.2 模型返回 fid 重复或缺失
这是最关键的问题。
表现:
- 模型返回数组长度看起来对
- 但某些批次出现重复
fid - 后面的
fid丢失
例如:
- 期望:
181..200 - 实际:其中某个
fid出现两次 - 另一个
fid完全没了
这个问题如果不拦住,最危险的后果是:
- 程序把结果按顺序错位写进 CSV
- 表面看起来“有结果”
- 其实
fid和类别已经对不上了
解决:
- 程序端严格校验:
fid必须全部属于当前批次fid不能重复fid不能缺失
- 只要不满足,整批判错
4.3 过强的 JSON Schema 直接把 Ollama 打成 500
后面为了进一步约束模型返回,又尝试过一个“更强”的 schema:
- 不是只要求
fid是整数 - 而是要求数组中每一项的
fid必须严格等于当前批次指定值
结果:
- Ollama 直接返回
HTTP 500 - 而且即使拆到单张仍然
500
结论:
- 这个约束思路虽然理论上更严
- 但当前 Ollama / 模型组合下不稳定
- 最终退回更简单的 schema
- 通过 prompt 模板 + 程序端校验来兜底
4.4 reason 污染
问题表现:
- 返回
reasons: - 返回
en - 返回一些英文片段、符号片段
解决:
- 对
reason做清洗,只保留中文 - 其余一律截断或落成
待复核
4.5 批次失败时整批变成 -1
原始策略是:
- 一批失败
- 这一批全记成
-1
问题:
- 如果批量是
20 - 一次失败就会有
20行-1
改进:
- 批次失败后自动拆分
20 -> 10 -> 5 -> 1- 直到单张
这样不会再因为一个坏批次拖垮整批结果。
4.6 错误结果不应该被当成“已完成”
这个也是一个实战里很容易忽略的问题。
如果 -1 结果也被当作已完成,下次重跑时会被跳过。
后来改成:
- 只有
class_id != -1的结果才算完成 -1会在 rerun 时继续进入待处理列表
5. 最终形成的核心脚本
5.1 通用单对象 batch10 识别脚本
路径:
/root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_multi_object/classify_chips_with_gemma4_batch10_20260421.py
主要职责:
- 读取
chips_index.csv - 自动修复
chip_path - 每批送
10张图到 Ollama - 校验返回数组中的
fid - 失败自动拆批重试
- 写 CSV
- 回写新的 shp
5.2 伊犁扩展类别包装脚本
路径:
/root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_multi_object/classify_chips_with_gemma4_batch10_yili8cls_20260421.py
这是在稳定底座脚本上做的“场景版包装”。
扩展类别为:
CLASS_NAME_MAP = {
-1: "ERROR",
0: "无法判断",
1: "建筑",
2: "耕地",
3: "道路",
4: "水体",
5: "林地/防护林",
6: "草地",
7: "裸地",
8: "果园/园地",
}
改动重点:
- 类别集合扩展为更适合新疆伊犁农区
- 提示词重写,更强调类别边界
- 仍然保留自由
reason - 底层批量逻辑不重写,只复用稳定版
5.3 结果合并脚本
路径:
/root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_multi_object/merge_gemma_batch_results_20260421.py
用途:
- 双卡并行后,两路结果写进两个不同 CSV
- 最后用这个脚本合并
- 同时回写最终 shp
6. Open WebUI / Ollama 双卡问题复盘
为了让两张显卡都利用起来,搭建过双 ollama serve + 双 Open WebUI。
6.1 一开始的问题
看起来都启动了,但实际配置是错的:
- 两个
Open WebUI都指向同一个 Ollama 端口 - 两个
ollama serve实际都绑在同一张卡上
也就是说:
- 页面看起来有两个
- 实际还是同一个后端
6.2 正确的双卡结构
目标结构应该是:
- GPU0 ->
ollama serveon11434 - GPU1 ->
ollama serveon11435 - WebUI
3000->11434 - WebUI
3001->11435
注意一个关键点:
如果 Docker 容器中的 Open WebUI 要访问宿主机 Ollama,OLLAMA_HOST 不能只绑 127.0.0.1,最好绑 0.0.0.0。
6.3 重要结论
一个 Python 识别脚本只会访问一个 --ollama-url。
所以“同时用两张卡”的正确方式不是:
- 一个脚本自动吃两张卡
而是:
- 开两个识别进程
- 每个进程连不同的 Ollama 端口
- 各自写自己的 CSV
- 最后合并
7. 双卡并行识别的实际组织方式
以伊犁扩展类别版为例,双卡并行建议拆成前后两半。
7.1 第一张卡跑前半段
python /root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_multi_object/classify_chips_with_gemma4_batch10_yili8cls_20260421.py \
--chips-csv /root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_multi_object/chips_512/chips_index.csv \
--src-shp /root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_multi_object/shp_result/sam21_remote_sensing_v2style_union.shp \
--ollama-url http://127.0.0.1:11434 \
--model gemma4:31b \
--batch-size 10 \
--limit 984 \
--results-csv /root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_multi_object/gemma4_chip_results_yili8cls_gpu0_part1.csv \
--log-jsonl /root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_multi_object/gemma4_chip_results_yili8cls_gpu0_part1.jsonl \
--out-shp /root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_multi_object/shp_result/tmp_gpu0_part1.shp \
--overwrite
7.2 第二张卡跑后半段
python /root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_multi_object/classify_chips_with_gemma4_batch10_yili8cls_20260421.py \
--chips-csv /root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_multi_object/chips_512/chips_index.csv \
--src-shp /root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_multi_object/shp_result/sam21_remote_sensing_v2style_union.shp \
--ollama-url http://127.0.0.1:11435 \
--model gemma4:31b \
--batch-size 10 \
--start-fid 985 \
--results-csv /root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_multi_object/gemma4_chip_results_yili8cls_gpu1_part2.csv \
--log-jsonl /root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_multi_object/gemma4_chip_results_yili8cls_gpu1_part2.jsonl \
--out-shp /root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_multi_object/shp_result/tmp_gpu1_part2.shp \
--overwrite
7.3 两路结果合并
python /root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_multi_object/merge_gemma_batch_results_20260421.py \
--input-csv /root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_multi_object/gemma4_chip_results_yili8cls_gpu0_part1.csv \
--input-csv /root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_multi_object/gemma4_chip_results_yili8cls_gpu1_part2.csv \
--src-shp /root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_multi_object/shp_result/sam21_remote_sensing_v2style_union.shp \
--out-csv /root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_multi_object/gemma4_chip_results_batch10_yili8cls_20260421_merged.csv \
--out-shp /root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_multi_object/shp_result/sam21_remote_sensing_v2style_union_gemma4_batch10_yili8cls_20260421_merged.shp
这个流程才是真正的“双卡都用上”。
8. 霍城县全县切图:为什么又改回单对象切图
后来开始切霍城县全县数据。
输入:
/root/sam21file/sam21_huocheng_v2style_union_out/huocheng_opt.tif/root/sam21file/sam21_huocheng_v2style_union_out/sam_result/sam21_huocheng_v2style_union_1.shp
其中:
shp要素数:192965- 栅格尺寸:
77164 x 87634
一开始延续参考脚本思路,写了霍城县专用单线程版:
/root/sam21file/sam21_huocheng_v2style_union_out/gemma4result/cut_feature_chips_512_huocheng_20260421.py
这个脚本的切法很简单:
- 对每个要素取
bbox - 取
bbox中心点 - 以中心点为中心裁一张
512 x 512 - 画红框
- 左上角写
fid - 保存图片并写
chips_index.csv
优点:
- 与前面伊犁数据主线完全一致
- 后面给 Gemma 很方便
- 一对象一图,最容易和
fid对齐
问题:
- 全县 19 万多个要素,顺序切太慢
9. 霍城县并行切图脚本
为了解决霍城县切图太慢的问题,又新建了并行版:
/root/sam21file/sam21_huocheng_v2style_union_out/gemma4result/cut_feature_chips_512_huocheng_parallel_20260421.py
9.1 并行逻辑
这版不是让多个进程一起写同一个 CSV,而是:
- 主进程顺序读取
shp - 把每个要素转成一个切图任务
- 多个 worker 进程各自打开大图
tif - worker 并行裁图并保存 PNG
- 主进程统一把结果写进
chips_index.csv
这样做的好处:
- 不容易把
csv写坏 - 仍然保留断点续跑能力
- 对 19 万级数据更稳
9.2 为什么不能简单把 worker 开到 64 或 128
这类任务虽然吃 CPU,但更容易先被下面两个瓶颈限制:
- 大图随机读取
- PNG 写盘
所以不是 worker 越多越快。
机器硬件信息:
- CPU:
Intel Xeon Gold 6530 - 物理核心:
64 - 线程:
128 - 内存:
125 GiB
但实际建议不要一上来就开很大,而是试:
workers 8workers 12workers 16
通常比较稳的建议是:
--workers 12 --max-inflight 48
如果磁盘也很强,再试:
--workers 16 --max-inflight 64
9.3 并行切图示例命令
source /root/miniconda3/etc/profile.d/conda.sh
conda activate sam21
python /root/sam21file/sam21_huocheng_v2style_union_out/gemma4result/cut_feature_chips_512_huocheng_parallel_20260421.py \
--output-dir /root/sam21file/sam21_huocheng_v2style_union_out/gemma4result/chips_512_parallel \
--workers 12 \
--max-inflight 48 \
--progress-every 500 \
--overwrite
如果只想先测速:
python /root/sam21file/sam21_huocheng_v2style_union_out/gemma4result/cut_feature_chips_512_huocheng_parallel_20260421.py \
--output-dir /root/sam21file/sam21_huocheng_v2style_union_out/gemma4result/chips_512_parallel_test \
--workers 12 \
--max-inflight 48 \
--limit 5000 \
--overwrite
10. 这轮代码清单
10.1 识别相关
/root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_multi_object/classify_chips_with_gemma4_batch10_20260421.py/root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_multi_object/classify_chips_with_gemma4_batch10_yili8cls_20260421.py/root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_multi_object/merge_gemma_batch_results_20260421.py/root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_multi_object/start_inference_gemma
10.2 霍城县切图相关
/root/sam21file/sam21_huocheng_v2style_union_out/gemma4result/cut_feature_chips_512_huocheng_20260421.py/root/sam21file/sam21_huocheng_v2style_union_out/gemma4result/cut_feature_chips_512_huocheng_parallel_20260421.py
10.3 参考代码
/root/sam21file/cut_feature_chips_512.py/root/sam21file/sam21_remote_sensing_v2style_union_out/gemma4_single/classify_chips_with_gemma4_v2.py
11. 最后总结
这轮最重要的经验,不是“把代码写出来”,而是把工程边界摸清楚了:
-
单对象 chips 是主线
对模型最稳,最容易做fid对齐。 -
多对象一张图虽然省请求,但容易串号
在密集目标遥感场景里,编号和对象边界容易互相干扰。 -
批量送图是有效提速点,但程序端必须强校验返回
不能只相信模型返回 JSON 看起来像对的。 -
Ollama 的结构化输出不能一味加码 schema
约束太强,可能直接把服务打成500。 -
双卡并行的正确姿势是双进程 + 双端口 + 双结果文件 + 最后合并
不是一个进程自动“吃满两张卡”。 -
全县切图必须考虑并行和断点续跑
19 万级要素如果没有并行和断点能力,基本不可用。 -
CPU 强不代表 worker 可以无限加
大图随机读取和写盘会先成为瓶颈。
这轮真正落地后的体系可以概括成一句话:
用最简单、最稳定的对象级 chips 组织识别任务;
用批量请求、双卡分流和结果合并提升吞吐;
用程序端严格校验和断点续跑保证工程可控。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)