赞
踩
在创建Jupyter笔记本之后,我们先来学习一下Numpy。Numpy是python中最常见的用于科学计算的基础包,有对数组进行快速操作的一系列方法,包括数学运算、逻辑运算、分片操作、排序、选择、输入输出、离散傅里叶变换、基本线性代数、基本统计运算、随机模拟等。
Numpy的核心是ndarray对象,它封装了相同数据类型的n维数组。
基本概念
Numpy的数组类为ndarray,通常也被称作数组。ndarray对象的属性有:
ndarray.ndim: 数组轴的个数
ndarray.shape: 数组的维度,这是一个指示数组在每个维度上大小的整数元组
ndarray.size: 数组元素的总个数
ndarray.dtype: 一个用来描述数组中元素类型的对象
ndarray.itemsize: 数组中每个元素的字节大小
创建数组
创建数组时,最常见的错误就是用多个数值参数调用array,而不是提供一个由数值组成的列表作为一个参数。
a=np.array(1,2,3,4) # 错误
a=np.array([1,2,3,4]) #正确
数组将两层序列嵌套的形式转化为二维的数组,三层序列嵌套的形式转化为三维数组,以此类推,数组类型可以在创建时显示指定。
b=np.array([(1.5,2,3),(4,5,6)])
b
array([[1.5, 2. , 3. ],
[4. , 5. , 6. ]])
c=np.array([[1,2],[3,4]],dtype=complex
c
Out[12]:
array([[1.+0.j, 2.+0.j],
[3.+0.j, 4.+0.j]])
函数zeros创建一个全是0的数组,函数ones创建一个全是1的数组,函数empty创建一个内容随机且依赖于内存状态的数组,注意,默认创建的数组类型(dtype)都是float64
In [13]:
np.zeros((3,4))
Out[13]:
array([[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]])
In [14]:
np.ones((2,3,4),dtype=np.int16)
Out[14]:
array([[[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]],
[[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]]], dtype=int16)
Numpy提供了一个类似arange()的函数返回数组而不是列表,有浮点参数时,最好用linespace去接收我们想要的元素个数来代替range指定步长。
In [15]:
np.arange(10,30,5)
Out[15]:
array([10, 15, 20, 25])
x=np.linspace(0,2*pi,100)#从0到2pi的100个数
f=np.sin(x)
import matplotlib.pyplot as plt
plt.plot(x,f)
基本运算
Numpy中数组的算术运算是按元素位置执行的,运算会创建新的数组并且填充相应位置的结果。不像许多矩阵运算语言那样,Numpy中矩阵的乘法运算符是按元素位置计算,矩阵乘法可以使用dot函数或创建新的矩阵对象方式实现。
a=np.array([20,30,40,50])
b=np.arange(4)
c=a-b
print(c)
output:
[20 29 38 47]
a=np.array([[1,1],[0,1]])
b=np.array([[2,0],[3,4]])
a*b
output:
array([[2, 0],
[0, 4]])
a.dot(b)
output:
array([[5, 4],
[3, 4]])
还有一类统计类的运算,比如对数组所有元素求和,求最大值,最小值,是以ndarray类的方法提供的。这些运算默认到数组是对数组的形状不敏感的,把多维的数组当做一维的数组。当指定了axis参数时,可以把运算应用到数组指定的轴上。
a=np.random.random((2,3)) a.sum() output: 3.334520436509896 a.max() output: 0.9876908056456332 a.min() output: 0.09762931121610963 b=np.arange(12).reshape(3,4) output: array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]]) b.sum(axis=1) output: array([ 6, 22, 38]) b.min(axis=0) output: array([0, 1, 2, 3]) b.cumsum(axis=1) output: array([[ 0, 1, 3, 6], [ 4, 9, 15, 22], [ 8, 17, 27, 38]], dtype=int32)
** 索引、切片和迭代**
Numpy的一维数组就像列表和其他python序列一样,可以被索引、切片和迭代。多维数组可以每个轴有一个索引,这些索引由一个逗号分割的元组给出。当少于轴数的索引被提供时,缺失的索引被认为是整个切片。
b=np.array([[0,1,2,3],
[10,11,12,13],
[20,21,22,23],
[40,41,42,43]])
b[0:5,1]#每行第二个元素
output:
array([ 1, 11, 21, 41])
b[:,1]#与上一个例子等价
output:
array([ 1, 11, 21, 41])
b[-1]#最后一行,等价于b[-1,:]
output:
array([40, 41, 42, 43])
Numpy中也允许使用连续的“点”来表示,如b[i,…]。连续的点(…)代表不显示地产生一个完整的索引元组必要的分号。
c=np.array([[[0,1,2],[10,12,13]],
[[100,101,102],[110,111,112]]])
c.shape
output:
(2, 2, 3)
c[1,...]#等价于c[1,:,:]或c[1]
output:
array([[100, 101, 102],
[110, 111, 112]])
c[...,2]#等价于c[ :,:,2]
output:
array([[ 2, 13],
[102, 112]])
数组还可以被整数数组和布尔数组索引,通过数组进行索引,这个数组索引的值指的是在目标数组的位置,当被索引数组a是多维的时候,每一个唯一的索引数列指向a的第一维。
a=np.arange(12)**2 i=np.array([1,1,3,8,5]) a[i] output: array([[ 9, 16], [81, 49]], dtype=int32) palette=np.array([[0,0,0],#黑色 [255,0,0],#红色 [0,255,0],#绿色 [0,0,255],#蓝色 [255,255,255]])#白色 image=np.array([[0,1,2,0],[0,3,4,0]])#每个元素代表palette的某行 palette[image] output: array([[[ 0, 0, 0], [255, 0, 0], [ 0, 255, 0], [ 0, 0, 0]], [[ 0, 0, 0], [ 0, 0, 255], [255, 255, 255], [ 0, 0, 0]]])
当然也可以给出不止一维的索引,但是要保证每一维的索引数组必须有相同的形状。我们还可以把数组i和j定义成类似[i,j]放在序列中,但要注意,不能把[i,j]放在一个ndarray数组中用这个ndarray数组当索引,因为这个ndarray数组将被解释成索引的第一维
a=np.arange(12).reshape(3,4) i=np.array([[0,1],[1,2]]) j=np.array([[2,1],[3,3]]) a[i,j]#相对应元素取值 output: array([[ 2, 5], [ 7, 11]]) a[i,2] output: array([[ 2, 6], [ 6, 10]]) a[:,j] output: array([[[ 2, 1], [ 3, 3]], [[ 6, 5], [ 7, 7]], [[10, 9], [11, 11]]]) l=[i,j] a[l] output: array([[ 2, 5], [ 7, 11]])
下面是用bool索引的例子:
a=np.arange(12).reshape(3,4) b=a>4 b output: array([[False, False, False, False], [False, True, True, True], [ True, True, True, True]]) a[b] output: array([ 5, 6, 7, 8, 9, 10, 11]) a=np.arange(12).reshape(3,4) b1=np.array([False,True,True]) b2=np.array([True,False,True,False]) a[b1,:] output: array([[ 4, 5, 6, 7], [ 8, 9, 10, 11]]) a[b1] output: array([[ 4, 5, 6, 7], [ 8, 9, 10, 11]]) a[:,b2] output: array([[ 0, 2], [ 4, 6], [ 8, 10]]) a[b1,b2]#只有True的会匹配 output: array([ 4, 10])
如果说索引是对ndarray确定位置的访问,那么对ndarray又是怎样进行迭代的呢?
多维ndarray数组的迭代就是对第一个轴而言的,如果想对ndarray数组中的每个元素进行运算,我们可以使用flat属性,该属性是数组元素的一个迭代器。
b=np.arange(12).reshape(3,4) for row in b: print(row) output: [0 1 2 3] [4 5 6 7] [ 8 9 10 11] for element in b.flat: print(element) output: 0 1 2 3 4 5 6 7 8 9 10 11
数组赋值
a=np.arange(5) a[[1,3,4]]=0 a output: array([0, 0, 2, 0, 0]) a=np.arange(5) a[[0,0,2]]=[1,2,3]#当一个索引列表中有重复值时,赋值被多次完成,仅保留最后的值 a output: array([2, 1, 3, 3, 4]) a[[0,0,2]]+=1#索引为0的元素仅仅增加一次 a output: array([3, 1, 4, 3, 4])
另外一种技巧是利用布尔索引进行赋值操作,只需要对相应的位置进行标识,对于不便指定索引值的情况非常有用:
a=np.arange(12).reshape(3,4)
b=a>4
b
output:
array([[False, False, False, False],
[False, True, True, True],
[ True, True, True, True]])
a[b]=0
a
output:
array([[0, 1, 2, 3],
[4, 0, 0, 0],
[0, 0, 0, 0]])
更改数组的形状
ndarray数组的形状可以被多种函数修改,使用ravel函数能够将ndarray数组展开成扁平化的形式,reshape函数则会要求指定新的轴大小,将ndarray数组改变为其它形状。Numpy的ravel函数和shape函数通常会**新建(也就是不改变原来的值)**一个符合目标形状的ndarray数组保存数据。
a=np.floor(10*np.random.random((3,4))) a output: array([[6., 4., 9., 4.], [9., 3., 9., 1.], [4., 4., 3., 9.]]) a.shape output: (3, 4) a.reshape(6,2) output: array([[6., 4.], [9., 4.], [9., 3.], [9., 1.], [4., 4.], [3., 9.]]) a.T output: array([[6., 9., 4.], [4., 3., 4.], [9., 9., 3.], [4., 1., 9.]]) a.T.shape output: (4, 3) a.shape output: (3, 4) a.reshape(3,-1)#在改变形状操作中某一个维度被设置为-1,该维度将自动被计算 output: array([[6., 4., 9., 4.], [9., 3., 9., 1.], [4., 4., 3., 9.]])
这么多例子,充分说明了shape和ravel不会改变原始数组的维度。
除了以上两种函数外,resize也能实现相同功能,区别是resize函数仅仅改变数组本身,并不会创建新的ndarray数组。
组合、拆分数组
vstack函数使得多个ndarray数组沿着第一个轴组合,而hstack函数则是沿着第二个轴组合。
a=np.floor(10*np.random.random((2,2))) a output: array([[5., 6.], [3., 1.]]) b=np.floor(10*np.random.random((2,2))) b output: array([[6., 0.], [3., 0.]]) np.vstack((a,b)) output: array([[5., 6.], [3., 1.], [6., 0.], [3., 0.]]) np.hstack((a,b)) output: array([[5., 6., 6., 0.], [3., 1., 3., 0.]])
函数column_stack仅支持以序列的顺序将多个一维数组或者一个二维数组按对位组合成新的二维数组。
a=np.array([1,2,3])
b=np.array([2,3,4])
np.column_stack((a,b))
output:
array([[1, 2],
[2, 3],
[3, 4]])
既然能按照不同的轴组合,同样numpy也能方便地拆分数组,vsplit和hsplit可以!!vsplit函数将ndarray数组沿着纵向的轴分割,hsplit函数沿着水平轴分割,允许指定返回相同形状数组的个数,或者指定在哪些列后发生分割:
a=np.floor(10*np.random.random((2,12))) a output: array([[0., 0., 4., 8., 3., 5., 9., 0., 5., 4., 6., 6.], [6., 9., 4., 8., 3., 7., 3., 0., 5., 0., 0., 2.]]) np.hsplit(a,3) output: [array([[0., 0., 4., 8.], [6., 9., 4., 8.]]), array([[3., 5., 9., 0.], [3., 7., 3., 0.]]), array([[5., 4., 6., 6.], [5., 0., 0., 2.]])] np.hsplit(a,(3,4)) output: [array([[0., 0., 4.], [6., 9., 4.]]), array([[8.], [8.]]), array([[3., 5., 9., 0., 5., 4., 6., 6.], [3., 7., 3., 0., 5., 0., 0., 2.]])] x=np.arange(16.0).reshape(4,4) x output: array([[ 0., 1., 2., 3.], [ 4., 5., 6., 7.], [ 8., 9., 10., 11.], [12., 13., 14., 15.]]) np.vsplit(x,2) output: [array([[0., 1., 2., 3.], [4., 5., 6., 7.]]), array([[ 8., 9., 10., 11.], [12., 13., 14., 15.]])] np.vsplit(x,np.array([3,6])) output: [array([[ 0., 1., 2., 3.], [ 4., 5., 6., 7.], [ 8., 9., 10., 11.]]), array([[12., 13., 14., 15.]]), array([], shape=(0, 4), dtype=float64)]
还有一个函数split函数,他对拆分的自由度更高一些
x=np.arange(8.0)
x
output:
array([0., 1., 2., 3., 4., 5., 6., 7.])
np.split(x,[3,5,6,10]
output:
[array([0., 1., 2.]),
array([3., 4.]),
array([5.]),
array([6., 7.]),
array([], dtype=float64)]
广播
广播的原则能使函数有意义地处理不具有相同形状的输入。应用广播之后,所有数组的大小必须匹配。广播的第一原则是,如果所偶的输入数组维度不都相同,数值“1”将被重复地添加在维度较小的数组上,直至所有的数组拥有一样的维度。广播的第二原则是:确定长度为1的数组沿着特殊的方向向最大形状伸展。对数组来说,沿着哪个维度二数组元素的值理应相同。
x=np.arange(4) xx=x.reshape(4,1) y=np.ones(5) z=np.ones((3,4)) x.shape output: (4,) y.shape output: (5,) xx.shape output: (4, 1) y.shape output: (5,) (xx+y).shape output: (4, 5) xx+y output: array([[1., 1., 1., 1., 1.], [2., 2., 2., 2., 2.], [3., 3., 3., 3., 3.], [4., 4., 4., 4., 4.]]) x.shape output: (4,) z.shape output: (3, 4) (x+z).shape output: (3, 4) x+z output: array([[1., 2., 3., 4.], [1., 2., 3., 4.], [1., 2., 3., 4.]])
PyTorch的许多函数在使用上和Numpy几乎一样,能够平滑地结合使用,PyTorch的特色之一就是提供构建动态计算图的框架,这样网络就不再是一成不变的了,甚至可以在运行时修正它们。
Tensor简介
Tensor是PyTorch中的基本对象,意思为张量,表示多维的矩阵,是PyTorch中基本操作对象之一。与Numpy的ndarray类似,Tensor的声明和获取size可以这样:
import torch
x=torch.Tensor(5,3)
x.size()
output:
torch.Size([5, 3])
Tensor的算术运算和选取操作与Numpy一样,因此与Numpy相似的运算操作都可以迁移过来:
x=torch.rand(5,3)
y=torch.rand(5,3)
x+y
output:
tensor([[1.7860, 0.8658, 1.4470],
[1.6161, 0.7316, 1.8847],
[1.3463, 0.8556, 1.8224],
[0.5932, 0.7870, 1.3776],
[0.5092, 0.8524, 0.7935]])
x[:,1]
output:
tensor([0.5798, 0.6298, 0.7893, 0.7489, 0.0383])
Tensor与Numpy的array还可以进行互相转换,有专门的转化函数:
x=torch.rand(5,3)
y=x.numpy()
z=torch.from_numpy(y)
Variable简介
Variable是PyTorch的另一个基本对象,可以把它理解为是对Tensor的一个封装。
Variable在计算图中用于 前向传播、 反向传播 、和自动求导。
Variable中有3个重要属性:data grad creator。
data表示包含的Tensor数据部分
grad表示传播方向的梯度
creator表示创建这个Variable的Function的引用。
from torch.autograd import variable
x=torch.rand(4)
x=variable(x,requires_grad=True)
y=x*3
grad_variables=torch.FloatTensor([1,2,3,4])
y.backward(grad_variables)
x.grad
output:
tensor([ 3., 6., 9., 12.])
CUDA简介
模型的保存与加载
随后在补充把~~~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。