1.Cesium地形切片--CTB(cesium-terrain-builder)填坑指南
2.深入 Python —— 切片(Slice)原理
3.PyTorch源码学习系列 - 2. Tensor
4.List的切片切片拆分的几种方式
Cesium地形切片--CTB(cesium-terrain-builder)填坑指南
面临全中国Cesium地形数据制作需求,原计划使用cesiumlab进行操作,程序程序但处理数千张DEM数据时,源码源码面临性能和数据管理问题,切片切片导致项目效率低下。程序程序
随后发现CTB(cesium-terrain-builder)工具,源码源码共振副图源码能有效提升处理速度,切片切片且不占用个人办公资源,程序程序便于数据处理与后期发布。源码源码然而,切片切片使用过程中遇到编译问题,程序程序GDAL环境部署后,源码源码CTB的切片切片cmake编译不通过,经排查后发现是程序程序GDAL版本与CTB需求不符,调整至GDAL-2.4.4后,源码源码问题解决。
在验证CTB使用效果时,发现cesium无法直接使用CTB输出的gzip压缩地形文件,为了解决瓦片压缩问题,通过修改CTB源代码,将CTBZFileOutputStream改为CTBFileOutputStream,完成对输出文件格式的调整,使cesium能直接利用输出结果进行数据展示。
对于多数据同时处理问题,神龙趋势线源码采用Python脚本按顺序处理文件夹下数据,并结合GDAL生成虚拟数据集(vrt)的方法,以简化层.json文件的合并过程,提升工作效率。最终,通过此方案,不仅成功解决了技术难题,还有效提升了项目处理效率,实现自动化与标准化流程。
深入 Python —— 切片(Slice)原理
在深入探讨 Python 切片原理之前,我们先检验一下对切片的基本理解。请尝试回答以下几个问题:
不借助Python解释器,能迅速给出答案的,说明你对切片掌握得不错。许多人可能对其中一个问题不完全确定。没关系,本文将从底层实现角度全面掌握切片机制,学完之后,再回头来看这些问题就不再是难题。
让我们从字节码层面开始。这段字节码分为两部分,前半部分构建列表 a,后半部分通过 a 切片得到列表 b。c 源码执行步骤与本文主题相关的关键字节码指令在后半部分,它们是:
BUILD_SLICE
在执行 BUILD_SLICE 之前,解释器将切片的两个关键参数 start 和 stop 压入栈,然后执行 BUILD_SLICE 指令。传入参数为 2,这意味着构建的切片对象只包含两个参数,即没有指定第三个参数 step。
这段代码简明,首先根据传入参数个数判断切片是否包含 step,如果有,它会成为最后一个被压入栈的参数。接下来,从栈中取出 start 和 stop,并将这三个参数传入 PySlice_New 函数创建切片对象,再将此对象放回栈中。
现在,让我们进一步探索切片对象的内部结构:
现在明白了吗?当我们对序列进行切片时,解释器会根据传入的 start、stop、step 创建切片对象,该对象与要切片的原序列之间没有直接关联。
Python 提供内置函数 slice 来创建切片对象:
这两种获取切片方式等价:
BINARY_SUBSCR
这个指令称为二元下标,即 a[0] 的Tomcat源码maven配置方式是一元下标。那么,通过切片对象对序列进行切片与通过索引对序列取值是否有关联?继续查看源码:
从栈中取出的对象是前面构建的切片对象,而 container 对象则是要切片的原列表,它们被传给了 PyObject_GetItem 函数。
答案显而易见,二元下标即切片通过 PyObject_GetItem 函数处理,它同样用于处理一元下标!
PyObject_GetItem 实现了多态性,根据要切片的对象不同,调用对象的特定函数以进行不同的处理。列表的处理将在后续讨论,现在我们需要理解,序列的下标可以是整数或切片对象,它们的处理接口相同。
切片参数的处理涉及 start、stop 和 step 的值,这些值可以是整数,可以是负数,start 和 stop 可能超过列表长度。特殊 step、stop 值决定了切片结果,这些处理在 PySlice_GetIndicesEx 函数中完成。理解切片行为的买源码被骗5000核心在于理解这个函数的逻辑。
记住以下几点:
深入列表切片处理:
切片适用于所有序列对象:列表、字符串、元组。我们日常最常使用的列表切片就在这里进行深入探讨,其他两种处理方式也类似。
通过查看列表对象源码,我们发现, o->ob_type->tp_as_mapping->mp_subscript 和 list.__getitem__ 指向同一个函数——list_subscript,列表切片正是在这里处理的:
其中的 list_slice 函数在 step 等于 1 时简化版:
总结:
本文从源码层面深入分析了切片对象、对 start、stop、step 值的处理,以及虚拟机生成列表切片的全过程。理解 Python 对 start、stop、step 的处理逻辑后,文章开始处的问题将不再能给出答案。
PyTorch源码学习系列 - 2. Tensor
本系列文章同步发布于微信公众号小飞怪兽屋及知乎专栏PyTorch源码学习-知乎(zhihu.com),欢迎关注。
若问初学者接触PyTorch应从何学起,答案非神经网络(NN)或自动求导系统(Autograd)莫属,而是看似平凡却无所不在的张量(Tensor)。正如编程初学者在控制台输出“Hello World”一样,Tensor是PyTorch的“Hello World”,每个初学者接触PyTorch时,都通过torch.tensor函数创建自己的Tensor。
编写上述代码时,我们已步入PyTorch的宏观世界,利用其函数创建Tensor对象。然而,Tensor是如何创建、存储、设计的?今天,让我们深入探究Tensor的微观世界。
Tensor是什么?从数学角度看,Tensor本质上是多维向量。在数学里,数称为标量,一维数据称为向量,二维数据称为矩阵,三维及以上数据统称为张量。维度是衡量事物的方式,例如时间是一种维度,销售额相对于时间的关系可视为一维Tensor。Tensor用于表示多维数据,在不同场景下具有不同的物理含义。
如何存储Tensor?在计算机中,程序代码、数据和生成数据都需要加载到内存。存储Tensor的物理媒介是内存(GPU上是显存),内存是一块可供寻址的存储单元。设计Tensor存储方案时,需要先了解其特性,如数组。创建数组时,会向内存申请一块指定大小的连续存储空间,这正是PyTorch中Strided Tensor的存储方式。
PyTorch引入了步伐(Stride)的概念,表示逻辑索引的相对距离。例如,一个二维矩阵的Stride是一个大小为2的一维向量。Stride用于快速计算元素的物理地址,类似于C/C++中的多级指针寻址方式。Tensor支持Python切片操作,因此PyTorch引入视图概念,使所有Tensor视图共享同一内存空间,提高程序运行效率并减少内存空间浪费。
PyTorch将Tensor的物理存储抽象成一个Storage类,与逻辑表示类Tensor解耦,建立Tensor视图和物理存储Storage之间多对一的联系。Storage是声明类,具体实现在实现类StorageImpl中。StorageImp有两个核心成员:Storage和StorageImpl。
PyTorch的Tensor不仅用Storage类管理物理存储,还在Tensor中定义了很多相关元信息,如size、stride和dtype,这些信息都存在TensorImpl类中的sizes_and_strides_和data_type_中。key_set_保存PyTorch对Tensor的layout、device和dtype相关的调度信息。
PyTorch创建了一个TensorBody.h的模板文件,在该文件中创建了一个继承基类TensorBase的类Tensor。TensorBase基类封装了所有与Tensor存储相关的细节。在类Tensor中,PyTorch使用代码自动生成工具将aten/src/ATen/native/native_functions.yaml中声明的函数替换此处的宏${ tensor_method_declarations}
Python中的Tensor继承于基类_TensorBase,该类是用Python C API绑定的一个C++类。THPVariable_initModule函数除了声明一个_TensorBase Python类之外,还通过torch::autograd::initTorchFunctions(module)函数声明Python Tensor相关的函数。
torch.Tensor会调用C++的THPVariable_tensor函数,该函数在文件torch/csrc/autograd/python_torch_functions_manual.cpp中。在经过一系列参数检测之后,在函数结束之前调用了torch::utils::tensor_ctor函数。
torch::utils::tensor_ctor在文件torch/csrc/utils/tensor_new.cpp中,该文件包含了创建Tensor的一些工具函数。在该函数中调用了internal_new_from_data函数创建Tensor。
recursive_store函数的核心在于
Tensor创建后,我们需要通过函数或方法对其进行操作。Tensor的方法主要通过torch::autograd::variable_methods和extra_methods两个对象初始化。Tensor的函数则是通过initTorchFunctions初始化,调用gatherTorchFunctions来初始化函数,主要分为两种函数:内置函数和自定义函数。
List的拆分的几种方式
在开发过程中,处理大型集合时常常需要将其拆分成小块,这种操作被称作分片或List的分割。其实,许多大神已经为我们提供了现成的工具,省去了自定义代码的繁琐。以下是Java中常用的三种分片实现方法:
1. Google的Guava框架:在pom.xml中添加Guava支持后,通过Lists.partition()方法实现切片,代码示例如下:
...
2. Apache的commons框架:同样在pom.xml添加支持,使用ListUtils.partition(),代码示例如下:
...
3. Hutool工具类:引入Hutool框架后,利用ListUtil.partition()完成切片,代码示例如下:
...
值得注意的是,选择哪种方法取决于项目的实际需求和已有的依赖。例如,批量数据处理时,如果数据量大,可以考虑将数据拆分以避免一次性插入数据库导致的性能问题或超限错误。具体操作时,可以根据数据库的配置进行调整。
这些工具包如Guava、Apache Commons和Hutool,提供了丰富的实用工具,性能优良,是开发者的得力助手。无需深入源码,直接使用即可大大简化工作。
以上内容源于程序员xiaozhang的文章,原文链接:cnblogs.com/scott/p...