NumPy提供了两种基本的对象,即ndarray和ufunc对象。前面我们对ndarray做了简单介绍,本节将介绍它的另一个对象ufunc。ufunc(通用函数)是universal function的缩写,它是一种能对数组的每个元素进行操作的函数。许多ufunc函数都是在C语言级别实现的,因此它们的计算速度非常快。此外,功能比math模块中的函数更灵活。math模块的输入一般是标量,但NumPy中的函数可以是向量或矩阵,而利用向量或矩阵可以避免循环语句,这点在机器学习、深度学习中经常使用。表1-2为NumPy中的常用几个通用函数。
表1-2 NumPy几个常用通用函数
import time import math import numpy as np x = [i * 0.001 for i in np.arange(1000000)] start = time.clock() for i, t in enumerate(x): x[i] = math.sin(t) print ("math.sin:", time.clock() - start ) x = [i * 0.001 for i in np.arange(1000000)] x = np.array(x) start = time.clock() np.sin(x) print ("numpy.sin:", time.clock() - start )
打印结果:
math.sin: 0.5169950000000005 numpy.sin: 0.05381199999999886
由此可见,numpy.sin比math.sin快近10倍。
充分使用Python的NumPy库中的内建函数(built-in function),实现计算的向量化,可大大提高运行速度。NumPy库中的内建函数使用了SIMD指令。例如下面所示在Python中使用向量化要比使用循环计算速度快得多。如果使用GPU,其性能将更强大,不过NumPy不提供GPU支持。TensorFlow支持GPU,在本书第8章将介绍TensorFlow如何使用GPU来加速算法。
import time import numpy as np x1 = np.random.rand(1000000) x2 = np.random.rand(1000000) ##使用循环计算向量点积 tic = time.process_time() dot = 0 for i in range(len(x1)): dot+= x1[i]*x2[i] toc = time.process_time() print ("dot = " + str(dot) + "\n for loop----- Computation time = " + str(1000*(toc - tic)) + "ms") ##使用numpy函数求点积 tic = time.process_time() dot = 0 dot = np.dot(x1,x2) toc = time.process_time() print ("dot = " + str(dot) + "\n verctor version---- Computation time = " + str(1000*(toc - tic)) + "ms")
打印结果:
dot = 250215.601995 for loop----- Computation time = 798.3389819999998ms dot = 250215.601995 verctor version---- Computation time = 1.885051999999554ms
从程序运行结果上来看,该例子使用for循环的运行时间是使用向量运算的运行时间的约400倍。因此,深度学习算法中,一般都使用向量化矩阵运算。