张量运算
- 一、逐元素运算
- 1.加法运算
- 2.relu运算
- 二、张量点积
- 1.向量间的点积
- 2.矩阵和向量间的点积
- 3.矩阵间的点积
- 三、张量变形
- 四、广播
- 1.加法运算
- 2.maximum运算
- 总结
一、逐元素运算
**逐元素运算独立地应用于张量的每个元素。**为了更好地理解逐元素运算,下面给出relu运算和加法运算的逐元素实现,使用for循环。
1.加法运算
def naive_add(x,y):
assert len(x.shape) == 2 #x,y是Numpy的2D张量
assert x.shape == y.shape
x = x.copy()
for i in range(x.shape[0]):
for j in range(x.shape[1]):
x[i,j] += y[i,j]
return x
a = np.array([[1,2,3],
[2,4,6]])
b = np.array([[1,0,3],
[1,1,1]])
print("result:",naive_add(a,b))
result:
[[2 2 6]
[3 5 7]]
在Numpy中之间进行逐元素加法运算
import numpy as np
z = x + y
2.relu运算
def naive_relu(x):
assert len(x.shape) == 2
x = x.copy()
for i in range(x.shape[0]):
for j in range(x.shape[1]):
x[i,j] = max(x[i,j], 0)
return x
c = np.array([[-1,0,3],
[1,-1,1]])
print(naive_relu(c))
[[0 0 3]
[1 0 1]]
在Numpy中之间进行逐元素relu运算
import numpy as np
z = np.maximum(z, 0.)
二、张量点积
张量的点积运算与逐元素的乘积元素不同,是最常见的张量运算。在Numpy中使用 ***** 实现逐元素乘积,使用dot运算符实现点积。
1.向量间的点积
def naive_vector_dot(x,y):
assert len(x.shape) == 1 #x和y都是Numpy向量
assert len(y.shape) == 1
assert x.shape[0] == y.shape[0]
z = 0.
for i in range(x.shape[0]):
z += x[i] * y[i]
return z
a = np.array([1,2,3])
b = np.array([2,1,1])
c = naive_vector_dot(a,b)
print("c的类型为:",type(c),"c的值为:",c)
注:两个向量间的点积是一个标量。而且只有元素个数相同的向量之间才能做点积。
c = a . b = 1 * 2 + 2 * 1 + 3 * 1 = 7
c的类型为: <class 'numpy.float64'> c的值为: 7.0
2.矩阵和向量间的点积
def naive_matrix_vector_dot(x,y):
assert len(x.shape) == 2 #x是一个Numpy矩阵
assert len(y.shape) == 1 #y是一个Numpy向量
assert x.shape[1] == y.shape[0]
z = np.zeros(x.shape[0])
for i in range(x.shape[0]):
for j in range(x.shape[1]):
z[i] += x[i,j] * y[j]
return z
a = np.array([[1,2,3],
[4,7,9]])
b = np.array([2,1,1])
c = naive_matrix_vector_dot(a,b)
print("c的类型为:",type(c),"\n",
"c的形状为:",c.shape,"\n",
"c的维度为:",c.ndim,"\n","c的值为:",c)
矩阵a和向量b做点积,返回值是一个向量,其中每个元素是向量b和矩阵a的每一行之间的点积。
c的类型为: <class 'numpy.ndarray'>
c的形状为: (2,)
c的维度为: 1
c的值为: [ 7. 24.]
如果复用之前向量间点积的代码,则有:
def naive_matrix_vector_dot(x,y):
z = np.zeros(x.shape[0])
for i in range(x.shape[0]):
z[i] = naive_vector_dot(x[i, : ], y)
return z
3.矩阵间的点积
def naive_matrix_dot(x,y):
assert len(x.shape) == 2
assert len(y.shape) == 2
assert x.shape[1] == y.shape[0]
z = np.zeros((x.shape[0],y.shape[1]))
for i in range(x.shape[0]):
for j in range(y.shape[1]):
for k in range(y.shape[0]):
z[i][j] += x[i][k] * y[k][j]
return z
复用之前向量间点积的代码,则有:
def naive_matrix_dot1(x,y):
assert len(x.shape) == 2
assert len(y.shape) == 2 #x,y都是Numpy矩阵
assert x.shape[1] == y.shape[0]
z = np.zeros((x.shape[0],y.shape[1]))
for i in range(x.shape[0]): #遍历x的所有行
for j in range(y.shape[1]): #遍历y的所有列
row_x = x[i, : ]
column_y = y[ : , j]
z[i][j] = naive_vector_dot(row_x, column_y)
return z
矩阵a和矩阵b做点积,得到的结果是一个形状为(x.shape[0], y.shape[1])的矩阵,其元素为x的行与y的列之间的点积。
a = np.array([[1,2,3],
[4,7,9]])
b = np.array([[1,1,1],
[2,2,2],
[0,4,0]])
c = naive_matrix_dot(a,b)
d = naive_matrix_dot1(a,b)
print("c的类型为:",type(c),"\n",
"c的形状为:",c.shape,"\n",
"c的维度为:",c.ndim,"\n","c的值为:",c)
print("d的类型为:",type(d),"\n",
"d的形状为:",d.shape,"\n",
"d的维度为:",d.ndim,"\n","d的值为:",d)
运行结果如下:
c的类型为: <class 'numpy.ndarray'>
c的形状为: (2, 3)
c的维度为: 2
c的值为: [[ 5. 17. 5.]
[18. 54. 18.]]
d的类型为: <class 'numpy.ndarray'>
d的形状为: (2, 3)
d的维度为: 2
d的值为: [[ 5. 17. 5.]
[18. 54. 18.]]
三、张量变形
张量变形是指改变张量的行和列,以得到想要的形状。变形后张量的元素总个数与初始张量相同。下面给出张量变形的例子。
a = np.array([[1,2,3],
[4,7,9]])
print(a.shape)
b = a.reshape((6,1))
print(b)
c = b.reshape(3,2)
print(c)
运行结果如下:
(2, 3)
[[1]
[2]
[3]
[4]
[7]
[9]]
[[1 2]
[3 4]
[7 9]]
转置(transposition)是一种特殊的张量变形,对矩阵做转置是指将行和列互换,使x[ i , : ]变为x[ : , i ]。下面给出一个转置的例子。
e = np.zeros((300,20)) #创建一个形状为(300,20)的零矩阵
e = np.transpose(e)
print(e.shape) #(20, 300)
四、广播
如果将两个形状不同的张量相加,则:
较小的张量会被广播(broadcast),以匹配较大张量的形状。
广播包含以下两步:
(1)向较小的张量添加轴(叫做广播轴),使其ndim与较大的张量相同。
(2)将较小的张量沿着新轴重复,使其形状与较大的张量相同。
假设 x.shape 为(32,10),y.shape为(10, )。首先,给y添加空的第一个轴,则y.shape为(1,10)。然后,将y 沿新轴重复32次,则得到张量y.shape为(32,10)。
1.加法运算
下面给出一种加法的简单实现
def naive_add_matrix_and_vector(x,y):
assert len(x.shape) == 2
assert len(y.shape) == 1
assert x.shape[1] == y.shape[0]
x = x.copy()
for i in range(x.shape[0]):
for j in range(x.shape[1]):
x[i, j] += y[j]
return x
a = np.array([[1,2,3],
[4,7,9]])
b = np.array([1,1,1])
c = a + b
print(c)
下面是矩阵a和向量b相加的结果
[[ 2 3 4]
[ 5 8 10]]
2.maximum运算
利用广播将逐元素的maximum运算应用于两个形状不同的张量。
import numpy as np
a = np.random.random((64,3,32,10))
b = np.random.random((32,10))
c = np.maximum(a,b)
print(c.shape)
a为形状是(64, 3, 32, 10)的随机张量
b是形状为(32,10)的随机张量
输出c的形状是(64, 3, 32, 10),与a相同
(64, 3, 32, 10)
总结
本文主要介绍了张量的几种常用运算:
逐元素运算、张量点积、张量变形、张量广播。