Pytorch学习_01 NumPy(上):核心数据结构详解
目录
为什么选择 PyTorch 框架?
从19年起,无论是学术界还是工程界 PyTorch 已经霸占了半壁江山,可以说 PyTorch 已经是现阶段的主流框架了。
这里的Py我们不陌生,它就是Python,那Torch是什么?从字面翻译过来是一个“火炬”。
什么是火炬呢?其实这跟TensorFlow中的Tensor是一个意思,我们可以把它看成是能在GPU中计算的矩阵。
机器跟人类的“语言”并不相通,想要让机器替我们完成对数据的复杂计算,就得先把数据翻译成机器能够理解的内容。无论是图像数据、文本数据还是数值数据,都要转换成矩阵才能进行后续的变化和运算。
搞定了读入数据这一步,我们就要靠PyTorch搞定后面各种复杂的计算功能。这些所有的计算功能,包括了从前向传播到反向传播,甚至还会涉及其它非常复杂的计算,而这些计算统统要交给 PyTorch 框架实现。
PyTorch会把我们需要计算的矩阵传入到GPU(或CPU)当中,在GPU(或CPU)中实现各种我们所需的计算功能。因为GPU做矩阵运算比较快,所以在神经网络中的计算一般都首选使用GPU,但对于学习来说,我们用CPU就可以了。
而我们要做的就是,设计好整个任务的流程、整个网络架构,这样PyTorch才能顺畅地完成后面的计算流程,从而帮我们正确地计算。
什么是NumPy
NumPy是用于Python中科学计算的一个基础包。它提供了一个多维度的数组对象(稍后展开),以及针对数组对象的各种快速操作,例如排序、变换,选择等。NumPy的安装方式非常简单,可以使用Conda安装,命令如下:
conda install numpy
或使用pip进行安装,命令如下:
pip install numpy
NumPy数组
-
N维数组:
ndarray
是 “N-dimensional array”的缩写,可以是1维、2维或更高维度的数组。- 维度(Dimension)指的是数组的轴数,例如:
- 1-D数组:如
[1, 2, 3]
- 2-D数组:如
[[1, 2, 3], [4, 5, 6]]
- 3-D数组:如
[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
- 1-D数组:如
-
固定大小:
- NumPy数组在创建时具有固定的大小,不能动态改变。如果需要改变数组的大小,必须创建一个新的数组并删除原数组。
-
统一的数据类型:
- NumPy数组中的所有元素必须具有相同的数据类型(dtype),这使得数组在内存中的存储更加高效。
- Python列表可以包含不同类型的元素,例如整数、浮点数和字符串等。
-
高效的运算:
- NumPy对数组的运算进行了高度优化,允许对整个数组进行元素级的操作(如加法、乘法等),而无需使用循环,这使得计算速度更快。
- NumPy数组的操作通常比Python列表更节省内存和计算资源。
NumPy 数组与 Python 列表的对比
特性 | NumPy 数组 | Python 列表 |
---|---|---|
大小 | 固定大小,不能动态改变 | 动态大小,可以随时添加或删除元素 |
数据类型 | 所有元素必须相同 | 可以包含不同类型的元素 |
性能 | 针对数值运算进行了优化,速度较快 | 对于数值运算性能较低 |
内存使用 | 更加高效,节省内存 | 内存使用相对较高 |
操作方式 | 支持向量化操作,简洁高效 | 通常需要使用循环进行操作 |
创建数组
最简单的方法就是把一个列表传入到np.array()或np.asarray()中,这个列表可以是任意维度的。np.array()属于深拷贝,np.asarray()则是浅拷贝。(它们的区别后面再细讲)
先试着创建一个一维的数组
再创建一个二维数组:
数组的属性
作为一个数组,NumPy有一些固有的属性,我们今天来介绍非常常用且关键的数组维度、形状、size与数据类型。
ndim
ndim表示数组维度(或轴)的个数。刚才创建的数组arr_1_d的轴的个数就是1,arr_2_d的轴的个数就是2
shape
shape表示数组的维度或形状, 是一个整数的元组,元组的长度等于ndim。
arr_1_d的形状就是(1,)(一个向量), arr_2_d的形状就是(2, 2)(一个矩阵)。
shape这个属性在实际中用途还是非常广的。比如说,我们现在有这样的数据(B, W, H, C),这代表一个batch size 为B的(W,H,C)数据。
现在我们需要根据(W,H,C)对数据进行变形或者其他处理,这时我们可以直接使用input_data.shape[1:3]获取到数据的形状,而不需要直接在程序中硬编程、直接写好输入数据的宽高以及通道数。
在实际当中,如果经常需要对数组的形状进行变换,就可以使用arr.reshape()函数,在不改变数组元素内容的情况下变换数组的形状。但是你需要注意的是,变换前与变换后数组的元素个数需要是一样的,因为 reshape
只是重新组织元素的位置,而没有添加或删除任何元素。
例如,如果一个数组有 6 个元素,可以将它重新塑造成 2 行 3 列、3 行 2 列,或 6 行 1 列,但不能将它变为 4 行 2 列,因为那样会增加或减少元素的数量。请看下面的代码。
我们还可以使用np.reshape(a, newshape, order)对数组a进行reshape,新的形状在newshape中指定。
这里需要注意的是,reshape函数有个order参数,它是指以什么样的顺序读写元素,其中有这样几个参数:
- ‘C’:默认参数,使用类似C-like语言(行优先)中的索引方式进行读写。
- ‘F’:使用类似Fortran-like语言(列优先)中的索引方式进行读写。
- ‘A’:原数组如果是按照‘C’的方式存储数组,则用‘C’的索引对数组进行reshape,否则使用’F’的索引方式。
reshape的过程你可以这样理解,首先需要根据指定的方式(‘C’或’F’)将原数组展开,然后再根据指定的方式写入到新的数组中
size
size,也就是数组元素的总数,它就等于shape属性中元素的乘积。
请看下面的代码,arr_2_d的size是4
dtype
最后要说的是dtype,它是一个描述数组中元素类型的对象。使用dtype属性可以查看数组所属的数据类型。
NumPy中大部分常见的数据类型都是支持的,例如int8、int16、int32、float32、float64等。dtype是一个常见的属性,在创建数组,数据类型转换时都可以看到它。
首先我们看看arr_2_d的数据类型:
刚才创建arr_2_d的时候,我们并没有指定数据类型,如果没有指定数据类型,NumPy会自动进行判断,然后给一个默认的数据类型。
可以在创建arr_2_d时,对数据类型进行了指定。
数组的数据类型当然也可以改变,我们可以使用astype()改变数组的数据类型,不过改变数据类型会创建一个新的数组,而不是改变原数组的数据类型。
注意:不能通过直接修改数据类型来修改数组的数据类型,这样代码虽然不会报错,但是数据会发生改变:
1个float64相当于2个int32,所以原有的4个float64,会变为8个int32,然后直接输出这个8个int32。
其他创建数组的方式
np.ones() 与np.zeros()
np.ones()用来创建一个全1的数组,必须参数是指定数组的形状,可选参数是数组的数据类型,你可以结合下面的代码进行理解。
创建全0的数组是np.zeros(),用法与np.ones()类似。
那这两个函数一般什么时候用呢?例如,如果需要初始化一些权重的时候就可以用上,比如说生成一个2x3维的数组,每个数值都是0.5,可以这样做。
np.arange()
我们还可以使用np.arange([start, ]stop, [step, ]dtype=None)创建一个在[start, stop)区间的数组,元素之间的跨度是step。
start是可选参数,默认为0。stop是必须参数,区间的终点,请注意,刚才说的区间是一个左闭右开区间,所以数组并不包含stop。step是可选参数,默认是1。
np.linspace()
最后,我们也可以用np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)创建一个数组,具体就是创建一个从开始数值到结束数值的等差数列。
- start:必须参数,序列的起始值。
- stop:必须参数,序列的终点。
- num:序列中元素的个数,默认是50。
- endpoint:默认为True,如果为True,则数组最后一个元素是stop。
- retstep:默认为False,如果为True,则返回数组与公差。
np.arange与np.linspace也是比较常见的函数,比如你要作图的时候,可以用它们生成x轴的坐标。例如,我要生成一个的图片,x轴可以用np.linespace()来生成。
数组的轴
这是一个非常重要的概念,也是NumPy数组中最不好理解的一个概念。它经常出现在np.sum()、np.max()这样关键的聚合函数中。
我们用这样一个问题引出,同一个函数如何根据轴的不同来获得不同的计算结果呢?比如现在有一个(4,3)的矩阵,存放着4名同学关于3款游戏的评分数据。
第一个需求是,计算每一款游戏的评分总和。
这个问题如何解决呢? 数组的轴即数组的维度,它是从0开始的。对于我们这个二维数组来说,有两个轴,分别是代表行的0轴与代表列的1轴。如下图所示。(数值随机)
我们的问题是要计算每一款游戏的评分总和,也就是沿着0轴的方向进行求和。所以,我们只需要在求和函数中指定沿着0轴的方向求和即可。
第二个问题是要计算每名同学的评分总和,也就是要沿着1轴方向对二维数组进行操作。所以,我们只需要将axis参数设定为1即可。
计算方向如绿色箭头所示。
二维数组还是比较好理解的,那多维数据该怎么办呢?
其实当 axis = i 时,就是按照第 i 个轴的方向进行计算的,或者可以理解为第 i 个轴的数据将会被折叠或聚合到一起。
形状为(a, b, c)的数组,沿着0轴聚合后,形状变为(b, c);沿着1轴聚合后,形状变为(a, c);
沿着2轴聚合后,形状变为(a, b);更高维数组以此类推。
接下来,我们再看一个多维数组的例子。对数组a,求不同维度上的最大值。
- 数组有 3 个层(或称为深度)
- 每个层中有 2 行
- 每行有 3 列
我们可以将同一个轴上的数据看做同一个单位,那聚合的时候,我们只需要在同级别的单位上进行聚合就可以了。
如下图所示,绿框代表沿着0轴方向的单位,蓝框代表着沿着1轴方向的单位,红框代表着2轴方向的单位。
当axis=0时,就意味着将三个绿框的数据聚合在一起,结果是一个(2,3)的数组,数组内容为:
在这个情况下,每个位置的值是从三个层中取最大值,例如:
max(0, 6, 12) = 12
max(1, 7, 13) = 13
max(2, 8, 14) = 14
- 依此类推。
当axis=1时,就意味着每个绿框内的蓝框聚合在一起,这表示沿着第二个轴(行方向)进行聚合,返回一个形状为 (3, 3)
的数组,数组内容为:
每个层内的行被分别分析并取最大值,例如:
max(0, 3) = 3
max(1, 4) = 4
max(2, 5) = 5
- 依此类推。
当axis=2时,就意味着每个蓝框中的红框聚合在一起,这表示沿着第三个轴(列方向)进行聚合,结果是一个(3,2)的数组。
在这个情况下,每一行(在每个层内部)被分别分析并取最大值,例如:
max(0, 1, 2) = 2
max(3, 4, 5) = 5
- 依此类推。
axis参数非常常见,不光光出现在刚才介绍的sum与max,还有很多其他的聚合函数也会用到,例如min、mean、argmin(求最小值下标)、argmax(求最大值下标)等。
小结
NumPy是用于Python中科学计算的一个基础包。它提供了一个多维度的数组对象,以及针对数组对象的各种快速操作。学习了创建数组的四种方式。
其中要掌握的方法,就是如何使用np.asarray创建一个数组。这里涉及数组属性(ndim、shape、dtype、size)的灵活使用,特别是数组的形状变化与数据类型转换。
最后,介绍了数组轴的概念,我们需要在数组的聚合函数中灵活运用它。虽然这个概念十分常用,但却不好理解,我还需要仔细揣摩一下,从2维数组一步步推理到多维数组,根据轴的不同,数组聚合的方向是如何变化的。
后面会继续学习NumPy中常用且重要的功能。
原文地址:https://blog.csdn.net/2301_77254487/article/details/144398484
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!