基于PyTorch框架实现深度学习之numpy基础

文章目录

前言

一、Numpy简介

二、Numpy使用

1.从已有数据中创建数组

2.利用random模块生成数组

3.创建特定形状的多维数组

 4.利用arange、linspace函数生成数组

 5.获取元素

 6.Numpy的算术运算

 7.合并数组

8.批量处理

总结


前言

近期在摸索深度学习,本系列博客将会围绕基于PyTorch框架实现算法网络,后续中所谈到的内容均来自有关资料书籍,予以记录与诸君分享,当然也欢迎大家批评指正。


一、Numpy简介

在机器学习和深度学习中,图像、声音、文本等输入数据最终都要转换 为数组或矩阵。如何有效地进行数组和矩阵的运算?这就需要充分利用 Numpy。Numpy是数据科学的通用语言,而且与PyTorch关系非常密切,它 是科学计算、深度学习的基石。尤其对PyTorch而言,其重要性更加明显。 PyTorch中的Tensor与Numpy非常相似,它们之间可以非常方便地进行转 换,故此掌握好Numpy是掌握好Pytorch的重要基础。

二、Numpy使用

1.从已有数据中创建数组

直接对Python的基础数据类型(如列表、元组等)进行转换来生成 ndarray:

1)将列表转换成ndarray:

import numpy as np

#将列表转换成ndarray:
lst1 = [3.14, 2.17, 0, 1, 2]  #注意列表有逗号
nd1 = np.array(lst1)
print(nd1)  # [3.14 2.17 0. 1. 2. ]#数组没有逗号
print(type(nd1))  # <class 'numpy.ndarray'>

2)嵌套列表可以转换成多维ndarray:

lst2 = [[3.14, 2.17, 0, 1, 2], [1, 2, 3, 4, 5]]  #注意这里是二维,一维可以看作表格中的一行,二维则是两行
nd2 = np.array(lst2)
print(nd2)  # [[3.14 2.17 0. 1. 2. ] # [1. 2. 3. 4. 5. ]]
print(type(nd2)) # <class 'numpy.ndarray'>

注:如果把上面示例中的列表换成元组也同样适用。

2.利用random模块生成数组

在深度学习中,我们经常需要对一些参数进行初始化,因此为了更有效 地训练模型,提高模型的性能,有些初始化还需要满足一定的条件,如满足 正态分布或均匀分布等。这里介绍了几种常用的方法,如表1-1所示列举了 np.random模块常用的函数。

 下面来看一些函数的具体使用:

nd3 = np.random.random([3, 3])
print(nd3)
# [[0.43007219 0.87135582 0.45327073] 
# [0.7929617 0.06584697 0.82896613] 
# [0.62518386 0.70709239 0.75959122]] 
# print("nd3的形状为:",nd3.shape) # nd3的形状为: (3, 3)

#为了每次生成同一份数据,可以指定一个随机种子,使用shuffle函数打乱生成的随机数
nd4 = np.random.randn(2, 3)
print(nd4)
np.random.shuffle(nd4)
print("随机打乱后数据:")
print(nd4)
print(type(nd4))
# [[-0.23042745  0.67994083 -1.45989658]
#  [ 1.56310165 -1.07267341  0.54721811]]
# 随机打乱后数据:
# [[ 1.56310165 -1.07267341  0.54721811]
#  [-0.23042745  0.67994083 -1.45989658]]
# <class 'numpy.ndarray'>

3.创建特定形状的多维数组

参数初始化时,有时需要生成一些特殊矩阵,如全是0或1的数组或矩 阵,这时我们可以利用np.zeros、np.ones、np.diag来实现,具体函数如下表所示

下面通过几个示例说明:

# 生成全是 0 的 3x3 矩阵
nd5 =np.zeros([3, 3])
print(nd5)
print("*"*20,"分隔符","*"*20)
# #生成与nd5形状一样的全0矩阵
nd6=np.zeros_like(nd5)
print(nd6)
print("*"*20,"分隔符","*"*20)

# 生成全是 1 的 3x3 矩阵
nd7 = np.ones([3, 3])
print(nd7)
print("*"*20,"分隔符","*"*20)

# 生成 3 阶的单位矩阵
nd8 = np.eye(3)
print(nd8)
print("*"*20,"分隔符","*"*20)

# 生成 3 阶对角矩阵
nd9 = np.diag([1, 2, 3])
print(nd9)

# [[0. 0. 0.]
#  [0. 0. 0.]
#  [0. 0. 0.]]
# ******************** 分隔符 ********************
# [[0. 0. 0.]
#  [0. 0. 0.]
#  [0. 0. 0.]]
# ******************** 分隔符 ********************
# [[1. 1. 1.]
#  [1. 1. 1.]
#  [1. 1. 1.]]
# ******************** 分隔符 ********************
# [[1. 0. 0.]
#  [0. 1. 0.]
#  [0. 0. 1.]]
# ******************** 分隔符 ********************
# [[1 0 0]
#  [0 2 0]
#  [0 0 3]]

有时还可能需要把生成的数据暂时保存起来,以便后续使用

nd9 =np.random.random([5, 5])
np.savetxt(X=nd9, fname='./test1.txt')
nd10 = np.loadtxt('./test1.txt')
print("查看文件数据:",nd10)

 4.利用arange、linspace函数生成数组

arange是numpy模块的函数,定义为:arange([start,] stop[,step,], dtype=None)。其中start与stop用来指定范围,step用来设定步长。在生成一个ndarray 时,start默认为0,步长step可为小数。Python有个内置函数range,其功能与 此类似。

print(np.arange(10))
# [0 1 2 3 4 5 6 7 8 9]
print(np.arange(0, 10))
# [0 1 2 3 4 5 6 7 8 9]
print(np.arange(1, 4, 0.5))
# [1. 1.5 2. 2.5 3. 3.5]
print(np.arange(9, -1, -1))
# [9 8 7 6 5 4 3 2 1 0]

linspace也是numpy模块中常用的函数,其格式为:np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)

linspace可以根据输入的指定数据范围以及等份数量,自动生成一个线 性等分向量,其中endpoint(包含终点)默认为True,等分数量num默认为 50。如果将retstep设置为True,则会返回一个带步长的ndarray。

print(np.linspace(0, 1, 10))
#[0. 0.11111111 0.22222222 0.33333333 0.44444444 0.55555556 # 0.66666667 0.77777778 0.88888889 1. ]

值得一提的是,这里并没有像我们预期的那样,生成0.1,0.2,...,1.0这样 步长为0.1的ndarray,这是因为linspace必定会包含数据起点和终点,那么其 步长则为(1-0)/9=0.11111111。如果需要产生0.1,0.2,...,1.0这样的数据,只需 要将数据起点0修改为0.1即可。 除了上面介绍到的arange和linspace,Numpy还提供了logspace函数,该 函数的使用方法与linspace的使用方法一样

 5.获取元素

前面介绍了生成ndarray的几种方法。那么在数据生成之后,如何获取到我们所需要的数据呢?接下来将会介绍几种常用获取数据的方法。

np.random.seed(2019)
nd11 = np.random.random([10])
nd11[3]  #获取指定位置的数据,获取第4个元素
nd11[3:6]  #截取一段数据

nd11[1:6:2]  #截取固定间隔数据

nd11[::-2]  #倒序取数

nd12 = np.arange(25).reshape([5, 5])
print(nd12)
nd12[1:3, 1:3]  #截取一个多维数组的一个区域内数据

nd12[(nd12 > 3) & (nd12 < 10)]  #截取一个多维数组中,数值在一个值域之内的数据

nd12[1:3, :]  #截取多维数组中,指定的行,如读取第2,3行

nd12[:, 1:3]  #截取多维数组中,指定的列,如读取第2,3列

 获取数组中的部分元素除了通过指定索引标签来实现外,还可以通过使 用一些函数来实现,如通过random.choice函数从指定的样本中随机抽取数 据

from numpy import random as nr

a = np.arange(1, 25, dtype=float)
c1 = nr.choice(a, size=(3, 4))
#size指定输出数组形状
c2 = nr.choice(a, size=(3, 4), replace=False)  #replace缺省为True,即可重复抽取。
#下式中参数p指定每个元素对应的抽取概率,缺省为每个元素被抽取的概率相同。
c3 = nr.choice(a, size=(3, 4), p=a / np.sum(a))
print("随机可重复抽取:")
print(c1)
print("随机但不重复抽取:")
print(c2)
print("随机但按制度概率抽取:")
print(c3)
随机可重复抽取:
# [[ 1. 11.  1. 12.]
#  [ 4. 12. 12. 20.]
#  [10. 11. 12. 10.]]
# 随机但不重复抽取:
# [[12. 19. 16. 10.]
#  [23. 24.  4. 18.]
#  [ 9.  7.  6. 13.]]
# 随机但按制度概率抽取:
# [[18. 17. 22. 20.]
#  [22. 24. 21. 23.]
#  [21. 20. 20. 14.]]

 6.Numpy的算术运算

在机器学习和深度学习中,涉及大量的数组或矩阵运算,本节我们将重 点介绍两种常用的运算。一种是对应元素相乘,又称为逐元乘法(Element- Wise Product),运算符为np.multiply(),或*。另一种是点积或内积元素,运 算符为np.dot()。

1)对应运算相乘

对应元素相乘(Element-Wise Product)是两个矩阵中对应元素乘积。 np.multiply函数用于数组或矩阵对应元素相乘,输出与相乘数组或矩阵的大 小一致,其格式如下:numpy.multiply(x1, x2, /, out=None, *, where=True,casting='same_kind', order='K', dtype=N)其中x1、x2之间的对应元素相乘遵守广播规则,Numpy的广播规则在 将在后续通过一些示例来进一步说明

A = np.array([[1, 2], [-1, 4]])
B = np.array([[2, 0], [3, 4]])
print(A * B)
print("*" * 20, "分隔符", "*" * 20)
# #或另一种表示方法
print(np.multiply(A, B))  
#运算结果
# [[ 2  0]
#  [-3 16]]
# ******************** 分隔符 ********************
# [[ 2  0]
#  [-3 16]]

Numpy数组不仅可以和数组进行对应元素相乘,还可以和单一数值(或 称为标量)进行运算。运算时,Numpy数组中的每个元素都和标量进行运 算,其间会用到广播机制

print(A*2.0)
print("*" * 20, "分隔符", "*" * 20)
print(A/2.0)
# [[ 2.  4.]
#  [-2.  8.]]
# ******************** 分隔符 ********************
# [[ 0.5  1. ]
#  [-0.5  2. ]]

2)点积运算

点积运算(Dot Product)又称为内积,在Numpy用np.dot表示,其一般 格式为:

numpy.dot(a, b, out=None)
以下通过一个示例来说明dot的具体使用方法及注意事项。
X1=np.array([[1,2],[3,4]])
X2=np.array([[5,6,7],[8,9,10]])
X3=np.dot(X1,X2)
print(X3)
# [[21 24 27]
#  [47 54 61]]

图示:可理解为线性代数当中的矩阵乘法

 7.更改数组的形状

 修改指定数组的形状是Numpy中最常见的操作之一,常见的方法有很 多,下表列出了一些常用函数。

1)reshape:改变向量的维度(不修改向量本身):

arr =np.arange(10)
print(arr)
# 将向量 arr 维度变换为2行5列
print(arr.reshape(2, 5))
# 指定维度时可以只指定行数或列数, 其他用 -1 代替
print(arr.reshape(5, -1)) #指定行数
print(arr.reshape(-1, 5))#指定列数
# [0 1 2 3 4 5 6 7 8 9]
# [[0 1 2 3 4]
#  [5 6 7 8 9]]
# [[0 1]
#  [2 3]
#  [4 5]
#  [6 7]
#  [8 9]]
# [[0 1 2 3 4]
#  [5 6 7 8 9]]

 2)resize:改变向量的维度(修改向量本身):

arr =np.arange(10)
print(arr)
# 将向量 arr 维度变换为2行5列
arr.resize(2, 5)
print(arr)
# [0 1 2 3 4 5 6 7 8 9]
# [[0 1 2 3 4]
#  [5 6 7 8 9]]

 3)T:向量转置

arr = np.arange(12).reshape(3, 4)  # 向量 arr 为3行4列
print(arr) 
# 将向量 arr 进行转置为4行3列
print(arr.T)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]
# [[ 0  4  8]
#  [ 1  5  9]
#  [ 2  6 10]
#  [ 3  7 11]]

 4)ravel:向量展平

arr =np.arange(6).reshape(2, -1)
print(arr)
# 按照列优先,展平
print("按照列优先,展平")
print(arr.ravel('F'))
# 按照行优先,展平
print("按照行优先,展平")
print(arr.ravel())
# [[0 1 2]
#  [3 4 5]]
# 按照列优先,展平
# [0 3 1 4 2 5]
# 按照行优先,展平
# [0 1 2 3 4 5]

 5)flatten:把矩阵转换为向量,这种需求经常出现在卷积网络与全连接层之间

a =np.floor(10*np.random.random((3,4)))
print(a)
print(a.flatten())
# [[6. 7. 4. 0.]
#  [3. 6. 1. 2.]
#  [9. 4. 6. 8.]]
# [6. 7. 4. 0. 3. 6. 1. 2. 9. 4. 6. 8.]

6)squeeze:主要用来降维的函数,把矩阵中含1的维度去掉。在PyTorch中 还有一种与之相反的操作——torch.unsqueeze

arr = np.arange(3).reshape(3, 1)
print(arr.shape)  #(3,1)
print(arr.squeeze().shape)  #(3,)
arr1 = np.arange(6).reshape(3, 1, 2, 1)
print(arr1.shape)  #(3, 1, 2, 1)
print(arr1.squeeze().shape)  #(3, 2)

 7.合并数组

合并数组也是最常见的操作之一,下表列举了常见的用于数组或向量 合并的方法。

说明:

1)append、concatenate以及stack都有一个axis参数,用于控制数组的合并方式是按行还是按列。

2)对于append和concatenate,待合并的数组必须有相同的行数或列数。

3)stack、hstack、dstack,要求待合并的数组必须具有相同的形状

 下面举一些例子:

1).append:合并一维数组

#合并一维
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
c = np.append(a, b)
print(c)
print("*" * 20, "分隔符", "*" * 20)
#合并多维
a = np.arange(4).reshape(2, 2)
print(a)
print("*" * 20, "分隔符", "*" * 20)
b = np.arange(4).reshape(2, 2)  #按行合并
print(b)
c = np.append(a, b, axis=0)
print('按行合并后的结果')
print(c)
print('合并后数据维度', c.shape)  #按列合并
d = np.append(a, b, axis=1)
print('按列合并后的结果')
print(d)
print('合并后数据维度', d.shape)
# [1 2 3 4 5 6]
# ******************** 分隔符 ********************
# [[0 1]
#  [2 3]]
# ******************** 分隔符 ********************
# [[0 1]
#  [2 3]]
# 按行合并后的结果
# [[0 1]
#  [2 3]
#  [0 1]
#  [2 3]]
# 合并后数据维度 (4, 2)
# 按列合并后的结果
# [[0 1 0 1]
#  [2 3 2 3]]
# 合并后数据维度 (2, 4)

2).concatenate:沿指定轴连接数组或矩阵

a=np.array([[1,2],[3,4]])
b=np.array([[5,6]])
c=np.concatenate((a,b),axis=0)
print(c)
d=np.concatenate((a,b.T),axis=1)
print(d)
# [[1 2]
#  [3 4]
#  [5 6]]
# [[1 2 5]
#  [3 4 6]]

8.批量处理

1)在深度学习中,由于源数据都比较大,所以通常需要用到批处理。如利用批量来计算梯度的随机梯度法就是一个典型应用。深度学习的计算一般比较复杂,并且数据量一般比较大,如果一次处理整个数据,较大概率会出现资源瓶颈。为了更有效地计算,一般将整个数据集分批次处理。与处理整个数据集相反的另一个极端是每次只处理一条记录,这种方法也不科学,一次处理一条记录无法充分发挥GPU、Numpy的平行处理优势。因此,在实际使用中往往采用批量处理(Mini-Batch)的方法。

如何把大数据拆分成多个批次呢?可采用如下步骤:

1)得到数据集

2)随机打乱数据

3)定义批大小

4)批处理数据集

下面我们通过一个示例来具体说明:

import numpy as np

#生成10000个形状为2X3的矩阵
data_train = np.random.randn(10000, 2, 3)
#这是一个3维矩阵,第1个维度为样本数,后两个是数据形状
print(data_train.shape)
#(10000,2,3)
#打乱这10000条数据
np.random.shuffle(data_train)
#定义批量大小
batch_size = 100
#进行批处理
for i in range(0, len(data_train), batch_size):
    x_batch_sum = np.sum(data_train[i:i + batch_size])
    print("第{}批次,该批次的数据之和:{}".format(i, x_batch_sum))

 2.循环与向量运算比较

充分使用Python的Numpy库中的内建函数(Built-inFunction),来实现计算的向量化,可大大地提高运行速度。Numpy库中的内建函数使用了 SIMD指令。如下使用的向量化要比使用循环计算速度快得多。如果使用 GPU,其性能将更强大,不过Numpy不支持GPU,PyTorch支持GPU。


总结

本章主要介绍了Numpy模块的常用操作,尤其涉及对矩阵的操作,这些 操作在后续程序中经常使用。Numpy内容很丰富,这里只列了一些主要内容,如果你想了解更多内容,可登录Numpy官网http://www.Numpy.org/,查看更多感兴趣内容。

  • 18
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值