个人吐槽区:上一篇文章的学习是纯看书学的,后来发现这样有些看不进去,于是在B站上找了网课.......

Element-wise operations(逐点运算)

逐点运算,顾名思义,也就是两个同等规模的张量进行运算时,相同位置的数值进行同样的运算。

举个栗子:

import numpy as np
>>> x = np.array([ 1, 2, 5, 3])
>>> y = np.array([ 2, 1, 0, 2])
>>> z = x + y
>>> z
array([3, 3, 5, 5])

同样的加、减、乘、除、与、或、异或、取余等等都可以。

 

瞎搞的时候弄了一个  ~ 

>>> x = np.array([1,2])
>>> z = ~x
>>> z
array([-2, -3], dtype=int32)

我以前一个~是非,然后发这里~的作用是取反-1.

 

Broadcasting(广播)

广播的作用是,当两个shape不同的张量进行运算时,会将维度较小的张量以复制的方式扩充得与另一个张量shape相同,再进行计算

比如

>>> x = np.random.randint(4,size=(2,4)) #产生一组大小为[0,4],size = (2,4)的张量
>>> x
array([[2, 2, 0, 0],
       [2, 1, 3, 3]])
>>> y = np.random.randint(4,size=(4)) #与上同理
>>> y
array([0, 2, 0, 0])
>>> z = x+y
>>> z
array([[2, 4, 0, 0],
       [2, 3, 3, 3]])

将两者进行加法运算:

>>> z = x+y
>>> z
array([[2, 4, 0, 0],
       [2, 3, 3, 3]])

x = array([[2, 2, 0, 0],

                [2, 1, 3, 3]])

这里相当于把y变为了:

y = array([[0, 2, 0, 0],

                [0, 2, 0, 0]])

再进行逐点相加。

但这里有一点需要注意的是:并不是任何情况都能扩充。

比如一下shape的情况就不行:

  1. (2,3,4)与(2)、(3)
  2. (2,3,4)与(2,4)、(2,3)

但与之相反,以下情况是可以的:

  1. (2,3,4)与(4)
  2. (2,3,4)与(3,4)
  3. (2,3,4,5)与(3,4,5)

也就是说:只有小shape与大shape的末尾几位相同时,才能扩充,等于中间的或者前面的都不行。

下面是一些小拓展(针对前面用到的随机数函数)


随机数方法:


random() 方法返回随机生成的一个实数,它在[0,1)范围内。参数填size

语法:

import numpy as np

random.random()


uniform()方法在指令范围内生成随机数。参数填[a,b],size

语法:

import numpy as np

random.uniform()


randint()方法在指令范围内生成随机整数。参数填[a,b],size

语法:

import numpy as np

random.randint()


等等.....想看更多可以看这篇博客 

 

玩一玩

针对上面的知识我们来做一个小应用,问题描述如下:

随机给定一组(3,4)的整数张量,我们需要算出每一个数据在所在列中的占比

比如,       array([[1,1],

                            [1,1]])

对应结果:array([[0.5, 0.5],

                            [0.5, 0.5]])

思路很简单:

  1. 每一列都进行累加,得到张量y
  2. 再用原张量对得到的z进行除法

代码如下:

#对x进行定义和初始化
>>> x = np.random.randint(10,size=(3,4))
>>> x
array([[3, 2, 4, 7],
       [9, 3, 5, 4],
       [5, 3, 9, 8]])

#axis=0 按列求和
#axis=1 按行求和
>>> y = x.sum(axis=0) 
>>> y
array([17,  8, 18, 19])

>>> z = x/y
>>> z
array([[0.17647059, 0.25      , 0.22222222, 0.36842105],
       [0.52941176, 0.375     , 0.27777778, 0.21052632],
       [0.29411765, 0.375     , 0.5       , 0.42105263]])

一个人瞎bb:我试了一下让axis=1,使得y得到x按行求和的结果:array([16, 21, 25]),如果想求出x中每一个数在所在列中的占比时,就不能直接除了(因为此时是shape分别为(3,4)和(3)进行的运算),那如果想实现这个目的该怎么做呢?(把x转置?)

查百度发现还真有转置函数

transpose()

>>> i = x.sum(axis=1)
>>> i
array([16, 21, 25])

>>> x = np.transpose(x) #把矩阵x转置
>>> x
array([[3, 9, 5],
       [2, 3, 3],
       [4, 5, 9],
       [7, 4, 8]])

>>> z = x/i
>>> z
array([[0.1875    , 0.42857143, 0.2       ],
       [0.125     , 0.14285714, 0.12      ],
       [0.25      , 0.23809524, 0.36      ],
       [0.4375    , 0.19047619, 0.32      ]])

(PS:我这段时间同时也在准备CCF,但我目前还是习惯C++写题,如果遇见一个需要我实现转置的题,那该怎么写呢?)

   其实这也思路很简单:索引对换

  伪代码如下:

for i:0->n
    for j:0->m

cin >> array[i][j]; 

result[j][i] = array[i][j];//这里存的便是转置后的结果

 


 

Tensor dot(张量点积)

这一部分主要是讲到了函数 dot() 的运用,分为了多种情况:向量之间的矩阵与向量矩阵与矩阵

Vector dot(向量点积)

向量点积的运算过程就是将相同位置的元素进行相乘,再将所有结果求和,得到一个值。

>>> import numpy as np
>>> x = np.random.randint(5,size=(3))
>>> x
array([2, 1, 3])

>>> y = np.random.randint(5,size=(3))
>>> y
array([3, 3, 2])

>>> z = np.dot(x,y)
>>> z
15

(注意,向量长度应当一致

Matrix_vector dot(矩阵与向量点积)

需要矩阵的列数与向量长度相等,做的事情也就是:将矩阵的一整行与向量做点积(像向量与向量一样),然后得到的结果,每一行放上矩阵对应行和向量的点积结果。(这里有点“难看”没关系,我后面放一张图就好理解了)

>>> x = np.random.randint(5,size = (3,5))
>>> x
array([[4, 0, 4, 1, 4],
       [2, 0, 4, 2, 3],
       [0, 1, 2, 0, 2]])
>>> y = np.random.randint(5,size = (5,))
>>> y
array([0, 1, 4, 2, 2])
>>> z = np.dot(x,y)
>>> z
array([26, 26, 13])

Maxtrix dot(矩阵点积)

张量乘法pytorch 张量python_深度学习

这个就是矩阵运算规律(向量也可以看成是 n*1 的矩阵)

>>> x = np.random.randint(5,size = (2,3))
>>> x
array([[2, 0, 2],
       [0, 3, 2]])
>>> y = np.random.randint(5,size = (3,2))
>>> y
array([[1, 2],
       [4, 4],
       [2, 1]])
>>> z = np.dot(x,y)
>>> z
array([[ 6,  6],
       [16, 14]])

 

More generally(更多情况)

这里主要是考虑下面两种情况的点积:

  • (a,b,c,d) . (d, ) -> (a,b,c)
  • (a,b,c,d) . (d,e) -> (a,b,c,e)
>>> x = np.random.randint(5,size = (2,3,4,5))
>>> y = np.random.randint(5,size = (5))
>>> z = np.dot(x,y)
>>> z.shape
(2, 3, 4)
>>> y = np.random.randint(5,size = (5,9))
>>> z = np.dot(x,y)
>>> z.shape
(2, 3, 4, 9)

其实也可以当成是y和x的末尾几个轴做点积,比如

  • case1 : x末尾的4*5矩阵和向量y(5*1)做点积之后,得到的张量shape为(4*1),这个1是可以省略的,所以结果是(2,3,4)
  • case2 : 与上同理,(4,5)*(5,9)得到(4,9),所以结果是(2,3,4,9)

Tensor reshaping

rashape()  : 

np.reshape(a, newshape, order='C')
#Gives a new shape to an array without changing its data.

他的作用是,在不增减,不改变原有数据的情况下,改变原张量的形状。

>>> x = np.random.randint(5,size=(2,3))
>>> x
array([[4, 2, 3],
       [4, 2, 0]])
>>> x = x.reshape((6,1))
>>> x
array([[4],
       [2],
       [3],
       [4],
       [2],
       [0]])

他做法就是按顺序挨个取出来,然后再挨个摆放。

书中和视频上还提到了转置函数(就是我上面用的那个),以及一些我不知道的用法和理解。

  1. 如果对超过2维的张量进行转置,会如何进行呢?
  2. 能否进行部分转置呢?

先回答前者:

在shape上:比如z.shape=(2,3,4,5),转置后z.shape=(5,4,3,2),也就是“倒过来”

在运算结果上,新张量每一个位置的值,其实和原张量对应位置的值的关系,也是“倒过来”

再回答后者:

>>> x = np.arange(12)
>>> x = x.reshape((2,3,2))
>>> x
array([[[ 0,  1],
        [ 2,  3],
        [ 4,  5]],

       [[ 6,  7],
        [ 8,  9],
        [10, 11]]])

>>> z = np.transpose(x,(0,2,1))#这里只对最后两个轴进行调换,1号轴和2号轴,两者交换
>>> z
array([[[ 0,  2,  4],
        [ 1,  3,  5]],

       [[ 6,  8, 10],
        [ 7,  9, 11]]])