32GB内存下超大卫星影像深度学习语义分割的分块创建方法求助
兄弟,我太懂你这种内存不够用的崩溃感了——之前小AOI跑的顺风顺水,一放大数据量直接把32GB内存干趴,确实头疼!你现在遇到的核心问题是直接把整幅84632x37000x9的影像加载成numpy数组需要120GB左右的内存,远超过你32GB的物理内存,直接硬刚整数组肯定走不通,得换“边读边处理,绝不一次性吃进内存”的思路,给你几个亲测有效的方案:
方案一:用rasterio原生分块读取,完全绕开整数组加载
别再想着把整个影像读进内存了,直接用rasterio的window参数按固定大小的块逐块读取处理。比如你之前用patchify做小AOI的patch,现在可以先遍历影像的所有分块window,每读一块就用patchify切分成训练用的小patch,处理完就把patch存到磁盘(比如npy文件或者TFRecord),处理完当前window就自动释放内存,接着干下一块。
给你贴段伪代码参考:import rasterio from rasterio.windows import Window import patchify # 用rasterio打开影像,默认是懒加载,不会直接读进内存 with rasterio.open("your_sat_image.tif") as src: # 定义和内存匹配的分块大小,比如2048x2048,单块内存占用≈144MB,完全hold住 block_width, block_height = 2048, 2048 # 遍历所有分块的位置 for y in range(0, src.height, block_height): for x in range(0, src.width, block_width): # 处理最后一块可能超出影像范围的情况 win_width = min(block_width, src.width - x) win_height = min(block_height, src.height - y) window = Window(x, y, win_width, win_height) # 只读取当前window的影像数据,内存占用极低 img_block = src.read(window=window) # 把当前block切成训练用的小patch(比如256x256,步长128) patches = patchify.patchify(img_block, (9, 256, 256), step=128) # 这里可以把patches存到磁盘,或者直接喂给模型做流式训练 # 处理完当前块,变量自动回收,内存释放这个方案的核心就是只在内存里留当前处理的那一小块影像和对应的patch,完全规避大内存需求,适配你的32GB内存。
方案二:用xarray/rioxarray懒加载+Dask分块计算
如果你需要先做一些预处理(比如归一化、波段运算)再切patch,可以用rioxarray打开影像,它会自动用Dask做分块懒加载,内存占用几乎为0。之后可以直接在Dask数组上做分块处理,甚至并行计算:import rioxarray import patchify # 用rioxarray打开影像,默认生成Dask分块数组,不占内存 img = rioxarray.open_rasterio("your_sat_image.tif", chunks=(9, 2048, 2048)) # 转成Dask数组 dask_img = img.data # 遍历每个Dask分块,逐块处理 for block in dask_img.to_delayed().flatten(): # 触发实际读取(只加载当前分块到内存) img_block = block.compute() # 切patch并处理 patches = patchify.patchify(img_block, (9, 256, 256), step=128) # 存patch或喂模型这个方案适合需要全局预处理的场景,Dask还能帮你并行处理多个分块,加快效率。
踩坑提醒:别碰numpy.memmap
你之前尝试的memmap其实不太适合这个场景,它本质是把120GB的文件映射到虚拟内存,处理时会频繁触发内存换页,速度慢到离谱,还容易因为虚拟内存不足触发OOM,完全不如上面的分块流式处理靠谱。
最后给你个小建议:提前把所有patch生成好存在磁盘上,训练的时候用PyTorch的Dataset或者TensorFlow的tf.data.Dataset流式读取,每次只加载当前batch的patch,训练阶段的内存压力也会很小。
备注:内容来源于stack exchange,提问作者BenWright

