自学内容网 自学内容网

Pytorch学习_01 NumPy(上):核心数据结构详解

目录

​什么是NumPy

NumPy数组

NumPy 数组与 Python 列表的对比

创建数组

数组的属性

ndim

shape

size

dtype

其他创建数组的方式

np.ones() 与np.zeros()

np.arange()

np.linspace()

数组的轴

小结


为什么选择 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数组

  1. 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]]]
  2. 固定大小

    • NumPy数组在创建时具有固定的大小,不能动态改变。如果需要改变数组的大小,必须创建一个新的数组并删除原数组。
  3. 统一的数据类型

    • NumPy数组中的所有元素必须具有相同的数据类型(dtype),这使得数组在内存中的存储更加高效。
    • Python列表可以包含不同类型的元素,例如整数、浮点数和字符串等。
  4. 高效的运算

    • 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轴的坐标。例如,我要生成一个y= x^2的图片,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)!