2018年7月1日星期日

搭建模型第一步:你需要预习的 NumPy 基础都在这了

基础知识

NumPy 主要的运算对象为同质的多维数组,即由同一类型元素(一般是数字)组成的表格,且所有元素通过正整数元组进行索引。在 NumPy 中,维度 (dimension) 也被称之为轴线(axes)。

比如坐标点 [1, 2, 1] 有一个轴线。这个轴上有 3 个点,所以我们说它的长度(length)为 3。而如下数组(array)有 2 个轴线,长度同样为 3。

[[ 1., 0., 0.], [ 0., 1., 2.]] 

NumPy 的数组类(array class)叫做 ndarray,同时我们也常称其为数组(array)。注意 numpy.array 和标准 Python 库中的类 array.array 是不同的。标准 Python 库中的类 array.array 只处理一维的数组,提供少量的功能。ndarray 还具有如下很多重要的属性:

  • ndarray.ndim:显示数组的轴线数量(或维度)。

  • ndarray.shape:显示在每个维度里数组的大小。如 n 行 m 列的矩阵,它的 shape 就是(n,m)。

>>> b = np.array([[1,2,3],[4,5,6]]) >>> b.shape (2, 3) 
  • ndarray.size:数组中所有元素的总量,相当于数组的 shape 中所有元素的乘积,例如矩阵的元素总量为行与列的乘积。

>>> b = np.array([[1,2,3],[4,5,6]]) >>> b.size 6 
  • ndarray.dtype:显示数组元素的类型。Python 中的标准 type 函数同样可以用于显示数组类型,NumPy 有它自己的类型如:numpy.int32, numpy.int16, 和 numpy.float64,其中「int」和「float」代表数据的种类是整数还是浮点数,「32」和「16」代表这个数组的字节数(存储大小)。

  • ndarray.itemsize:数组中每个元素的字节存储大小。例如元素类型为 float64 的数组,其 itemsize 为 8(=64/8)。

>>> import numpy as np >>> a = np.arange(15).reshape(3, 5) >>> a array([[ 0,  1,  2,  3,  4],        [ 5,  6,  7,  8,  9],        [10, 11, 12, 13, 14]]) >>> a.shape (3, 5) >>> a.ndim 2 >>> a.dtype.name 'int64' >>> a.itemsize 8 >>> a.size 15 >>> type(a)  >>> b = np.array([6, 7, 8]) >>> b array([6, 7, 8]) >>> type(b)  

创建数组

NumPy 有很多种创建数组的方法。比如,你可以用 Python 的列表(list)来创建 NumPy 数组,其中生成的数组元素类型与原序列相同。

>>> import numpy as np >>> a = np.array([2,3,4]) >>> a array([2, 3, 4]) >>> a.dtype dtype('int64') >>> b = np.array([1.2, 3.5, 5.1]) >>> b.dtype dtype('float64') 

一个常见的误差(error)在于调用 array 时使用了多个数值参数,而正确的方法应该是用「[]」来定义一个列表的数值而作为数组的一个参数

>>> a = np.array(1,2,3,4)    # WRONG >>> a = np.array([1,2,3,4])  # RIGHT 

array 将序列中的序列转换为二维的数组,序列中的序列中的序列转换为三维数组,以此类推。

>>> b = np.array([(1.5,2,3), (4,5,6)]) >>> b array([[ 1.5,  2. ,  3. ],        [ 4. ,  5. ,  6. ]]) 

数组的类型也可以在创建时指定清楚:

>>> b = np.array([(1.5,2,3), (4,5,6)]) >>> c = np.array( [ [1,2], [3,4] ], dtype=complex ) >>> c array([[ 1.+0.j,  2.+0.j],        [ 3.+0.j,  4.+0.j]]) 

一般数组的内部元素初始是未知的,但它的大小是已知的。因此,NumPy 提供了一些函数可以创建有初始数值的占位符数组,这样可以减少不必要的数组增长及运算成本。

函数 zeros 可创建一个内部元素全是 0 的数组,函数 ones 可创建一个内部元素全是 1 的数组,函数 empty 可创建一个初始元素为随机数的数组,具体随机量取决于内存状态。默认状态下,创建数组的数据类型(dtype)一般是 float64。

>>> np.zeros( (3,4) ) array([[ 0.,  0.,  0.,  0.],        [ 0.,  0.,  0.,  0.],        [ 0.,  0.,  0.,  0.]]) >>> np.ones( (2,3,4), dtype=np.int16 )   # dtype can also be specified 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) >>> np.empty( (2,3) )                    # uninitialized, output may vary array([[  3.73603959e-262,   6.02658058e-154,   6.55490914e-260],        [  5.30498948e-313,   3.14673309e-307,   1.00000000e+000]]) 

为了创建数列,NumPy 提供一个与 range 类似的函数来创建数组:arange。

>>> np.arange( 10, 30, 5 ) array([10, 15, 20, 25]) >>> np.arange( 0, 2, 0.3 )                 # it accepts float arguments array([ 0. ,  0.3,  0.6,  0.9,  1.2,  1.5,  1.8]) 

当 arange 使用浮点型参数时,因为浮点精度的有限性,arange 不能判断有需要创建的数组多少个元素。在这种情况下,换成 linspace 函数可以更好地确定区间内到底需要产生多少个数组元素。

>>> from numpy import pi >>> np.linspace( 0, 2, 9 )                 # 9 numbers from 0 to 2 array([ 0.  ,  0.25,  0.5 ,  0.75,  1.  ,  1.25,  1.5 ,  1.75,  2.  ]) >>> x = np.linspace( 0, 2*pi, 100 )        # useful to evaluate function at lots of points >>> f = np.sin(x) 

array, zeros, zeros_like, ones, ones_like, empty, empty_like, arange, linspace, numpy.random.rand, numpy.random.randn, fromfunction, fromfile (这些函数也可以创建数组,有时间可以尝试解释)

输出数组

当你输出一个数组时,NumPy 显示这个数组的方式和嵌套列表是相似的。但将数组打印到屏幕需要遵守以下布局:

  • 最后一个轴由左至右打印

  • 倒数第二个轴为从上到下打印

  • 其余的轴都是从上到下打印,且每一块之间都通过一个空行分隔

如下所示,一维数组输出为一行、二维为矩阵、三维为矩阵列表。

>>> a = np.arange(6)                         # 1d array >>> print(a) [0 1 2 3 4 5] >>> >>> b = np.arange(12).reshape(4,3)           # 2d array >>> print(b) [[ 0  1  2]  [ 3  4  5]  [ 6  7  8]  [ 9 10 11]] >>> >>> c = np.arange(24).reshape(2,3,4)         # 3d array >>> print(c) [[[ 0  1  2  3]   [ 4  5  6  7]   [ 8  9 10 11]]  [[12 13 14 15]   [16 17 18 19]   [20 21 22 23]]] 

上述使用的 reshape 函数可指定数组的行列数,并将所有元素按指定的维度数排列,详细介绍请看后面章节。在数组的打印中,如果一个数组所含元素数太大,NumPy 会自动跳过数组的中间部分,只输出两边。

>>> print(np.arange(10000)) [   0    1    2 ..., 9997 9998 9999] >>> >>> print(np.arange(10000).reshape(100,100)) [[   0    1    2 ...,   97   98   99]  [ 100  101  102 ...,  197  198  199]  [ 200  201  202 ...,  297  298  299]  ...,  [9700 9701 9702 ..., 9797 9798 9799]  [9800 9801 9802 ..., 9897 9898 9899]  [9900 9901 9902 ..., 9997 9998 9999]] 

如果想要 NumPy 输出整个数组,你可以用 set_printoptions 改变输出设置。

>>> np.set_printoptions(threshold=np.nan) 

基础运算

数组中的算术运算一般是元素级的运算,运算结果会产生一个新的数组。如下所示减法、加法、平方、对应元素乘积和逻辑运算都是元素级的操作。

>>> a = np.array( [20,30,40,50] ) >>> b = np.arange( 4 ) >>> b array([0, 1, 2, 3]) >>> c = a-b >>> c array([20, 29, 38, 47]) >>> b**2 array([0, 1, 4, 9]) >>> 10*np.sin(a) array([ 9.12945251, -9.88031624,  7.4511316 , -2.62374854]) >>> a<35 array([ True, True, False, False]) 

不同于许多科学计算语言,乘法算子 * 或 multiple 函数在 NumPy 数组中用于元素级的乘法运算,矩阵乘法可用 dot 函数或方法来执行。

>>> A = np.array( [[1,1], ...             [0,1]] ) >>> B = np.array( [[2,0], ...             [3,4]] ) >>> A*B                         # elementwise product array([[2, 0],        [0, 4]]) >>> A.dot(B)                    # matrix product array([[5, 4],        [3, 4]]) >>> np.dot(A, B)                # another matrix product array([[5, 4],        [3, 4]]) 

有一些操作,如 += 和 *=,其输出结果会改变一个已存在的数组,而不是如上述运算创建一个新数组。

>>> a = np.ones((2,3), dtype=int) >>> b = np.random.random((2,3)) >>> a *= 3 >>> a array([[3, 3, 3],        [3, 3, 3]]) >>> b += a >>> b array([[ 3.417022  ,  3.72032449,  3.00011437],        [ 3.30233257,  3.14675589,  3.09233859]]) >>> a += b                  # b is not automatically converted to integer type Traceback (most recent call last):   ... TypeError: Cannot cast ufunc add output from dtype('float64') to dtype('int64') with casting rule 'same_kind' 

当操作不同数据类型的数组时,最后输出的数组类型一般会与更普遍或更精准的数组相同(这种行为叫做 Upcasting)。

>>> a = np.ones(3, dtype=np.int32) >>> b = np.linspace(0,pi,3) >>> b.dtype.name 'float64' >>> c = a+b >>> c array([ 1.        ,  2.57079633,  4.14159265]) >>> c.dtype.name 'float64' >>> d = np.exp(c*1j) >>> d array([ 0.54030231+0.84147098j, -0.84147098+0.54030231j,        -0.54030231-0.84147098j]) >>> d.dtype.name 'complex128' 

许多一元运算,如计算数组中所有元素的总和,是属于 ndarray 类的方法。

>>> a = np.random.random((2,3)) >>> a array([[ 0.18626021,  0.34556073,  0.39676747],        [ 0.53881673,  0.41919451,  0.6852195 ]]) >>> a.sum() 2.5718191614547998 >>> a.min() 0.1862602113776709 >>> a.max() 0.6852195003967595 

默认状态下,这些运算会把数组视为一个数列而不论它的 shape。然而,如果在指定 axis 参数下,你可以指定针对哪一个维度进行运算。如下 axis=0 将针对每一个列进行运算,例如 b.sum(axis=0) 将矩阵 b 中每一个列的所有元素都相加为一个标量。

>>> b = np.arange(12).reshape(3,4) >>> b array([[ 0,  1,  2,  3],        [ 4,  5,  6,  7],        [ 8,  9, 10, 11]]) >>> >>> b.sum(axis=0)                            # sum of each column array([12, 15, 18, 21]) >>> >>> b.min(axis=1)                            # min of each row array([0, 4, 8]) >>> >>> b.cumsum(axis=1)                         # cumulative sum along each row array([[ 0,  1,  3,  6],        [ 4,  9, 15, 22],        [ 8, 17, 27, 38]]) 

索引、截取和迭代

一维数组可以被索引、截取(Slicing)和迭代,就像 Python 列表和元组一样。注意其中 a[0:6:2] 表示从第 1 到第 6 个元素,并对每两个中的第二个元素进行操作。

>>> a = np.arange(10)**3 >>> a array([  0,   1,   8,  27,  64, 125, 216, 343, 512, 729]) >>> a[2] 8 >>> a[2:5] array([ 8, 27, 64]) >>> a[:6:2] = -1000    # equivalent to a[0:6:2] = -1000; from start to position 6, exclusive, set every 2nd element to -1000 >>> a array([-1000,     1, -1000,    27, -1000,   125,   216,   343,   512,   729]) >>> a[ : :-1]                                 # reversed a array([  729,   512,   343,   216,   125, -1000,    27, -1000,     1, -1000]) >>> for i in a: ...     print(i**(1/3.)) ... nan 1.0 nan 3.0 nan 5.0 6.0 7.0 8.0 9.0 

多维数组每个轴都可以有一个索引。这些索引在元组中用逗号分隔:

>>> def f(x,y): ...     return 10*x+y ... >>> b = np.fromfunction(f,(5,4),dtype=int) >>> b array([[ 0,  1,  2,  3],        [10, 11, 12, 13],        [20, 21, 22, 23],        [30, 31, 32, 33],        [40, 41, 42, 43]]) >>> b[2,3] 23 >>> b[0:5, 1]                       # each row in the second column of b array([ 1, 11, 21, 31, 41]) >>> b[ : ,1]                        # equivalent to the previous example array([ 1, 11, 21, 31, 41]) >>> b[1:3, : ]                      # each column in the second and third row of b array([[10, 11, 12, 13],        [20, 21, 22, 23]]) 

当有些维度没有指定索引时,空缺的维度被默认为取所有元素。

>>> b[-1]                                  # the last row. Equivalent to b[-1,:] array([40, 41, 42, 43]) 

如上因为省略了第二维,b[i] 表示输出第 i 行。当然我们也可以用「:」表示省略的维度,例如 b[i] 等价于 b[i, :]。此外,NumPy 还允许使用 dots (...) 表示足够多的冒号来构建完整的索引元组。

比如,如果 x 是 5 维数组:

  • x[1,2,...] 等于 x[1,2,:,:,:],

  • x[...,3] 等于 x[:,:,:,:,3] 

  • x[4,...,5,:] 等于 x[4,:,:,5,:]

>>> c = np.array( [[[  0,  1,  2],               # a 3D array (two stacked 2D arrays) ...                 [ 10, 12, 13]], ...                [[100,101,102], ...                 [110,112,113]]]) >>> c.shape (2, 2, 3) >>> c[1,...]                                   # same as c[1,:,:] or c[1] array([[100, 101, 102],        [110, 112, 113]]) >>> c[...,2]                                   # same as c[:,:,2] array([[  2,  13],        [102, 113]]) 

多维数组中的迭代以第一条轴为参照完成,如下每一次循环都输出一个 b[i]:

>>> for row in b: ...     print(row) ... [0 1 2 3] [10 11 12 13] [20 21 22 23] [30 31 32 33] [40 41 42 43] 

然而,如果想在数组的每个元素上进行操作,可以用 flat 方法。flat 是一个在数组所有元素中运算的迭代器,如下将逐元素地对数组进行操作。

>>> for element in b.flat: ...     print(element) ... 0 1 2 3 10 11 12 13 20 21 22 23 30 31 32 33 40 41 42 43 

Shape 变换

改变数组的 shape

一个数组的 shape 是由轴及其元素数量决定的,它一般由一个整型元组表示,且元组中的整数表示对应维度的元素数。

>>> a = np.floor(10*np.random.random((3,4))) >>> a array([[ 2.,  8.,  0.,  6.],        [ 4.,  5.,  1.,  1.],        [ 8.,  9.,  3.,  6.]]) >>> a.shape (3, 4) 

一个数组的 shape 可以由许多方法改变。例如以下三种方法都可输出一个改变 shape 后的新数组,它们都不会改变原数组。其中 reshape 方法在实践中会经常用到,因为我们需要改变数组的维度以执行不同的运算。

>>> a.ravel()  # returns the array, flattened array([ 2.,  8.,  0.,  6.,  4.,  5.,  1.,  1.,  8.,  9.,  3.,  6.]) >>> a.reshape(6,2)  # returns the array with a modified shape array([[ 2.,  8.],        [ 0.,  6.],        [ 4.,  5.],        [ 1.,  1.],        [ 8.,  9.],        [ 3.,  6.]]) >>> a.T  # returns the array, transposed array([[ 2.,  4.,  8.],        [ 8.,  5.,  9.],        [ 0.,  1.,  3.],        [ 6.,  1.,  6.]]) >>> a.T.shape (4, 3) >>> a.shape (3, 4) 

ravel() 和 flatten() 都是将多维数组降位一维,flatten() 返回一份新的数组,且对它所做的修改不会影响原始数组,而 ravel() 返回的是 view,会影响原始矩阵。

在矩阵的转置中,行和列的维度将交换,且矩阵中每一个元素将沿主对角线对称变换。此外,reshape 如下所示返回修改过维度的新数组,而 resize 方法将直接修改原数组本身的维度。

>>> a array([[ 2.,  8.,  0.,  6.],        [ 4.,  5.,  1.,  1.],        [ 8.,  9.,  3.,  6.]]) >>> a.resize((2,6)) >>> a array([[ 2.,  8.,  0.,  6.,  4.,  5.],        [ 1.,  1.,  8.,  9.,  3.,  6.]]) 

如果在 shape 变换中一个维度设为 - 1,那么这一个维度包含的元素数将会被自动计算。如下所示,a 一共有 12 个元素,在确定一共有 3 行后,-1 会自动计算出应该需要 4 列才能安排所有的元素。

>>> a.reshape(3,-1) array([[ 2.,  8.,  0.,  6.],        [ 4.,  5.,  1.,  1.],        [ 8.,  9.,  3.,  6.]]) 

数组堆叠

数组可以在不同轴上被堆叠在一起。如下所示 vstack 将在第二个维度(垂直)将两个数组拼接在一起,而 hstack 将在第一个维度(水平)将数组拼接在一起。

>>> a = np.floor(10*np.random.random((2,2))) >>> a array([[ 8.,  8.],        [ 0.,  0.]]) >>> b = np.floor(10*np.random.random((2,2))) >>> b array([[ 1.,  8.],        [ 0.,  4.]]) >>> np.vstack((a,b)) array([[ 8.,  8.],        [ 0.,  0.],        [ 1.,  8.],        [ 0.,  4.]]) >>> np.hstack((a,b)) array([[ 8.,  8.,  1.,  8.],        [ 0.,  0.,  0.,  4.]]) 

column_stack 函数可堆叠一维数组为二维数组的列,作用相等于针对二维数组的 hstack 函数。

>>> from numpy import newaxis >>> np.column_stack((a,b))     # with 2D arrays array([[ 8.,  8.,  1.,  8.],        [ 0.,  0.,  0.,  4.]]) >>> a = np.array([4.,2.]) >>> b = np.array([3.,8.]) >>> np.column_stack((a,b))     # returns a 2D array array([[ 4., 3.],        [ 2., 8.]]) >>> np.hstack((a,b))           # the result is different array([ 4., 2., 3., 8.]) >>> a[:,newaxis]               # this allows to have a 2D columns vector array([[ 4.],        [ 2.]]) >>> np.column_stack((a[:,newaxis],b[:,newaxis])) array([[ 4.,  3.],        [ 2.,  8.]]) >>> np.hstack((a[:,newaxis],b[:,newaxis]))   # the result is the same array([[ 4.,  3.],        [ 2.,  8.]]) 

与 column_stack 相似,row_stack 函数相等于二维数组中的 vstack。一般在高于二维的情况中,hstack 沿第二个维度堆叠、vstack 沿第一个维度堆叠,而 concatenate 更进一步可以在任意给定的维度上堆叠两个数组,当然这要求其它维度的长度都相等。concatenate 在很多深度模型中都有应用,例如权重矩阵的堆叠或 DenseNet 特征图的堆叠

在复杂情况中,r_ 和 c_ 可以有效地在创建数组时帮助沿着一条轴堆叠数值,它们同样允许使用范围迭代「:」生成数组。

>>> np.r_[1:4,0,4] array([1, 2, 3, 0, 4]) 

当用数组为参数时,r_ 和 c_ 在默认行为下与 vstack 和 hstack 相似,但它们如 concatenate 一样允许给定需要堆叠的维度。

拆分数组

使用 hsplit 可以顺着水平轴拆分一个数组,我们指定切分后输出的数组数,或指定在哪一列拆分数组:

>>> a = np.floor(10*np.random.random((2,12))) >>> a array([[ 9.,  5.,  6.,  3.,  6.,  8.,  0.,  7.,  9.,  7.,  2.,  7.],        [ 1.,  4.,  9.,  2.,  2.,  1.,  0.,  6.,  2.,  2.,  4.,  0.]]) >>> np.hsplit(a,3)   # Split a into 3 [array([[ 9.,  5.,  6.,  3.],        [ 1.,  4.,  9.,  2.]]), array([[ 6.,  8.,  0.,  7.],        [ 2.,  1.,  0.,  6.]]), array([[ 9.,  7.,  2.,  7.],        [ 2.,  2.,  4.,  0.]])] >>> np.hsplit(a,(3,4))   # Split a after the third and the fourth column [array([[ 9.,  5.,  6.],        [ 1.,  4.,  9.]]), array([[ 3.],        [ 2.]]), array([[ 6.,  8.,  0.,  7.,  9.,  7.,  2.,  7.],        [ 2.,  1.,  0.,  6.,  2.,  2.,  4.,  0.]])] 

vsplit 沿着垂直轴拆分,array_split 可指定顺着哪一条轴拆分。

复制与 views

在进行数组运算或操作时,入门者经常很难判断数据到底是复制到了新的数组还是直接在原始数据上修改。这对进一步的运算有很大的影响,因此有时候我们也需要复制内容到新的变量内存中,而不能仅将新变量指向原内存。目前一般有三种复制方法,即不复制内存、浅复制以及深复制。

实际不复制

简单的任务并不会复制数组目标或它们的数据,如下先把变量 a 赋值于 b,然后修改变量 b 就会同时修改变量 a,这种一般的赋值方法会令变量间具有关联性。

>>> a = np.arange(12) >>> b = a            # no new object is created >>> b is a           # a and b are two names for the same ndarray object True >>> b.shape = 3,4    # changes the shape of a >>> a.shape (3, 4) 

Pythan 将不定对象作为参照(references)传递,所以调用函数不会产生目标识别符的变化,也不会发生实际的内容复制。

>>> def f(x): ...     print(id(x)) ... >>> id(a)                           # id is a unique identifier of an object 148293216 >>> f(a) 148293216 

View 或浅复制

不同数组对象可以共享相同数据,view 方法可以创建一个新数组对象来查看相同数据。如下 c 和 a 的目标识别符并不一致,且改变其中一个变量的 shape 并不会对应改变另一个。但这两个数组是共享所有元素的,所以改变一个数组的某个元素同样会改变另一个数组的对应元素。

>>> c = a.view() >>> c is a False >>> c.base is a                        # c is a view of the data owned by a True >>> c.flags.owndata False >>> >>> c.shape = 2,6                      # a's shape doesn't change >>> a.shape (3, 4) >>> c[0,4] = 1234                      # a's data changes >>> a array([[   0,    1,    2,    3],        [1234,    5,    6,    7],        [   8,    9,   10,   11]]) 

分割数组输出的是它的一个 view,如下将数组 a 分割为子数组 s,那么 s 就是 a 的一个 view,修改 s 中的元素同样会修改 a 中对应的元素。

>>> s = a[ : , 1:3]     # spaces added for clarity; could also be written "s = a[:,1:3]" >>> s[:] = 10           # s[:] is a view of s. Note the difference between s=10 and s[:]=10 >>> a array([[   0,   10,   10,    3],        [1234,   10,   10,    7],        [   8,   10,   10,   11]]) 

深复制

copy 方法可完整地复制数组及数据,这种赋值方法会令两个变量有不一样的数组目标,且数据不共享。

>>> d = a.copy()                          # a new array object with new data is created >>> d is a False >>> d.base is a                           # d doesn't share anything with a False >>> d[0,0] = 9999 >>> a array([[   0,   10,   10,    3],        [1234,   10,   10,    7],        [   8,   10,   10,   11]]) 

深入理解 NumPy

广播机制

广播操作是 NumPy 非常重要的一个特点,它允许 NumPy 扩展矩阵间的运算。例如它会隐式地把一个数组的异常维度调整到与另一个算子相匹配的维度以实现维度兼容。例如将一个维度为 [3,2] 的矩阵与另一个维度为 [3,1] 的矩阵相加是合法的,NumPy 会自动将第二个矩阵扩展到等同的维度。

为了定义两个形状是否是可兼容的,NumPy 从最后开始往前逐个比较它们的维度大小。在这个过程中,如果两者的对应维度相同,或者其一(或者全是)等于 1,则继续进行比较,直到最前面的维度。若不满足这两个条件,程序就会报错。

如下展示了一个广播操作:

>>>a = np.array([1.0,2.0,3.0,4.0, 5.0, 6.0]).reshape(3,2) >>>b = np.array([3.0]) >>>a * b  array([[  3.,   6.],        [  9.,  12.],        [ 15.,  18.]]) 

高级索引

NumPy 比一般的 Python 序列提供更多的索引方式。除了之前看到的用整数和截取的索引,数组可以由整数数组和布尔数组 indexed。

通过数组索引

如下我们可以根据数组 i 和 j 索引数组 a 中间的元素,其中输出数组保持索引的 shape。

>>> a = np.arange(12)**2                       # the first 12 square numbers >>> i = np.array( [ 1,1,3,8,5 ] )              # an array of indices >>> a[i]                                       # the elements of a at the positions i array([ 1,  1,  9, 64, 25])  >>> j = np.array( [ [ 3, 4], [ 9, 7 ] ] )      # a bidimensional array of indices >>> a[j]                                       # the same shape as j array([[ 9, 16],        [81, 49]]) 

当使用多维数组作为索引时,每一个维度就会索引一次原数组,并按索引的 shape 排列。下面的代码展示了这种索引方式,palette 可以视为简单的调色板,而数组 image 中的元素则表示索引对应颜色的像素点。

>>> palette = np.array( [ [0,0,0],                # black ...                       [255,0,0],              # red ...                       [0,255,0],              # green ...                       [0,0,255],              # blue ...                       [255,255,255] ] )       # white >>> image = np.array( [ [ 0, 1, 2, 0 ],           # each value corresponds to a color in the palette ...                     [ 0, 3, 4, 0 ]  ] ) >>> palette[image]                            # the (2,4,3) color image 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]]])        [81, 49]]) 

我们也可以使用多维索引获取数组中的元素,多维索引的每个维度都必须有相同的形状。如下多维数组 i 和 j 可以分别作为索引 a 中第一个维度和第二个维度的参数,例如 a[i, j] 分别从 i 和 j 中抽取一个元素作为索引 a 中元素的参数

>>> a = np.arange(12).reshape(3,4) >>> a array([[ 0,  1,  2,  3],        [ 4,  5,  6,  7],        [ 8,  9, 10, 11]]) >>> i = np.array( [ [0,1],                        # indices for the first dim of a ...                 [1,2] ] ) >>> j = np.array( [ [2,1],                        # indices for the second dim ...                 [3,3] ] ) >>> >>> a[i,j]                                     # i and j must have equal shape array([[ 2,  5],        [ 7, 11]]) >>> >>> a[i,2] array([[ 2,  6],        [ 6, 10]]) >>> >>> a[:,j]                                     # i.e., a[ : , j] array([[[ 2,  1],         [ 3,  3]],        [[ 6,  5],         [ 7,  7]],        [[10,  9],         [11, 11]]]) 

同样,我们把 i 和 j 放在一个序列中,然后用它作为索引:

>>> l = [i,j] >>> a[l]                                       # equivalent to a[i,j] array([[ 2,  5],        [ 7, 11]]) 

然而,我们不能如上把 i 和 j 放在一个数组中作为索引,因为数组会被理解为索引 a 的第一维度。

>>> s = np.array( [i,j] ) >>> a[s]                                       # not what we want Traceback (most recent call last):   File "", line 1, in ? IndexError: index (3) out of range (0<=index<=2) in dimension 0 >>> >>> a[tuple(s)]                                # same as a[i,j] array([[ 2,  5],        [ 7, 11]]) 

另一个将数组作为索引的常用方法是搜索时间序列的最大值:

>>> time = np.linspace(20, 145, 5)                 # time scale >>> data = np.sin(np.arange(20)).reshape(5,4)      # 4 time-dependent series >>> time array([  20.  ,   51.25,   82.5 ,  113.75,  145.  ]) >>> data array([[ 0.        ,  0.84147098,  0.90929743,  0.14112001],        [-0.7568025 , -0.95892427, -0.2794155 ,  0.6569866 ],        [ 0.98935825,  0.41211849, -0.54402111, -0.99999021],        [-0.53657292,  0.42016704,  0.99060736,  0.65028784],        [-0.28790332, -0.96139749, -0.75098725,  0.14987721]]) >>> >>> ind = data.argmax(axis=0)                  # index of the maxima for each series >>> ind array([2, 0, 3, 1]) >>> >>> time_max = time[ind]                       # times corresponding to the maxima >>> >>> data_max = data[ind, range(data.shape[1])] # => data[ind[0],0], data[ind[1],1]... >>> >>> time_max array([  82.5 ,   20.  ,  113.75,   51.25]) >>> data_max array([ 0.98935825,  0.84147098,  0.99060736,  0.6569866 ]) >>> >>> np.all(data_max == data.max(axis=0)) True 

你也可以用数组索引作为一个分配目标:

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

然而,当索引列表中有重复时,赋值任务会执行多次,并保留最后一次结果。

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

这是合理的,但注意如果你使用 Python 的 += 创建,可能不会得出预期的结果:

>>> a = np.arange(5) >>> a[[0,0,2]]+=1 >>> a array([1, 1, 3, 3, 4]) 

虽然 0 在索引列表中出现两次,第 0 个元素只会增加一次。这是因为 Python 中「a+=1」等于「a = a + 1」.

用布尔数组做索引

当我们索引数组元素时,我们在提供索引列表。但布尔值索引是不同的,我们需要清楚地选择被索引数组中哪个元素是我们想要的哪个是不想要的。

布尔索引需要用和原数组相同 shape 的布尔值数组,如下只有在大于 4 的情况下才输出 True,而得出来的布尔值数组可作为索引。

>>> a = np.arange(12).reshape(3,4) >>> b = a > 4 >>> b                                          # b is a boolean with a's shape array([[False, False, False, False],        [False,  True,  True,  True],        [ True,  True,  True,  True]]) >>> a[b]                                       # 1d array with the selected elements array([ 5,  6,  7,  8,  9, 10, 11]) 

这个性质在任务中非常有用,例如在 ReLu 激活函数中,只有大于 0 才输出激活值,因此我们就能使用这种方式实现 ReLU 激活函数

>>> a[b] = 0                                   # All elements of 'a' higher than 4 become 0 >>> a array([[0, 1, 2, 3],        [4, 0, 0, 0],        [0, 0, 0, 0]]) 

第二种使用布尔索引的方法与整数索引更加相似的;在数组的每个维度中,我们使用一维布尔数组选择我们想要的截取部分:

>>> a = np.arange(12).reshape(3,4) >>> b1 = np.array([False,True,True])             # first dim selection >>> b2 = np.array([True,False,True,False])       # second dim selection >>> >>> a[b1,:]                                   # selecting rows array([[ 4,  5,  6,  7],        [ 8,  9, 10, 11]]) >>> >>> a[b1]                                     # same thing array([[ 4,  5,  6,  7],        [ 8,  9, 10, 11]]) >>> >>> a[:,b2]                                   # selecting columns array([[ 0,  2],        [ 4,  6],        [ 8, 10]]) >>> >>> a[b1,b2]                                  # a weird thing to do array([ 4, 10]) 

注意一维布尔数组的长度必须和想截取轴的长度相同。在上面的例子中,b1 的长度 3、b2 的长度为 4,它们分别对应于 a 的第一个维度与第二个维度。

线性代数

简单的数组运算

如下仅展示了简单的矩阵运算更多详细的方法可在实践中遇到在查找 API。如下展示了矩阵的转置、求逆、单位矩阵、矩阵乘法、矩阵的迹、解线性方程和求特征向量等基本运算:

>>> import numpy as np >>> a = np.array([[1.0, 2.0], [3.0, 4.0]]) >>> print(a) [[ 1.  2.]  [ 3.  4.]]  >>> a.transpose() array([[ 1.,  3.],        [ 2.,  4.]])  >>> np.linalg.inv(a) array([[-2. ,  1. ],        [ 1.5, -0.5]])  >>> u = np.eye(2) # unit 2x2 matrix; "eye" represents "I" >>> u array([[ 1.,  0.],        [ 0.,  1.]]) >>> j = np.array([[0.0, -1.0], [1.0, 0.0]])  >>> np.dot (j, j) # matrix product array([[-1.,  0.],        [ 0., -1.]])  >>> np.trace(u)  # trace 2.0  >>> y = np.array([[5.], [7.]]) >>> np.linalg.solve(a, y) array([[-3.],        [ 4.]])  >>> np.linalg.eig(j) (array([ 0.+1.j,  0.-1.j]), array([[ 0.70710678+0.j        ,  0.70710678-0.j        ],        [ 0.00000000-0.70710678j,  0.00000000+0.70710678j]]))  Parameters:     square matrix Returns     The eigenvalues, each repeated according to its multiplicity.     The normalized (unit "length") eigenvectors, such that the     column ``v[:,i]`` is the eigenvector corresponding to the     eigenvalue ``w[i]`` . 


原文档链接:https://ift.tt/2KzBYba

]]> 原文: https://ift.tt/2Kp8QY8
RSS Feed

机器知心

IFTTT

学完了在线课程?如何开启深度学习论文的阅读模式

在一个 Quora 问答《I want to pursue machine learning as a career but not sure if I am qualified. How can I test myself?》中,问到如何测试某人是否达到了从事机器学习职业的标准。吴恩达说(只要不断学习)任何人都可胜任机器学习的工作。他说,在完成一些机器学习课程之后,「进一步的学习,阅读研究论文。最好是尝试复现研究论文中的结果。」


OpenAI 的研究员 Dario Amodei 说,「为了测试自己是否适合从事 AI 安全或者机器学习的工作,只要尝试快速实现大量模型。从最近的论文中找到一个机器学习模型,实现它,快速的让它能跑起来。」


这表明,读研究论文,对个人进一步了解这个领域极为重要。


每个月都有大量的论文被发表,任何认真学习 ML 的人,都不能只是依靠别人把最新研究分解过的教程类文章或者课程。新的、独创性的研究都是在读文章的时候做出来的。机器学习领域的研究节奏从未如此快过,你能跟上节奏的唯一方法就是养成阅读论文的习惯。


在此文章中,我会尝试给出阅读论文的可行性建议。最后,我会尝试分解一篇论文,从此开始读论文。


如何读论文


arXiv.org


arXiv 是预印本论文的网上发布平台,研究者一般在著名的学术期刊或会议论文发表之前就先将其发布到该平台。


那么为什么先发到 arXiv 上呢?其实事实证明,研究和实际撰写论文并不是终点,将论文提交给某个学术期刊发表是非常漫长的过程。在一篇论文提交给学术期刊后,同行审议的过程一般需要数月甚至一年多的时间。而现在它对于机器学习领域来说是不可取的,因为这个领域发展从未如此迅速。


所以,研究者在预印本资源库 arXiv 上发表论文以快速传播他们的研究,并获得快速反馈。


Arxiv Sanity Preserver


让研究者能轻松的预印论文自然很不错。但对于阅读的人而言,预印论文的数量太多了,对于新手而言肯定不适合(个人观点,想试试也无妨)。


所以,我要向你推荐 Arxiv Sanity Preserver:https://ift.tt/1P6Rxl9




Arxiv Sanity Preserver 由 Andrej Karpathy 建立。


arXiv Sanity 对于 arXiv 而言,正如 Twitter 的 newsfeed 对于 Twitter 的作用。在 newsfeed 中,你能看到最有趣的符合你个人口味的推文,arXiv Sanity 也一样。它能让你基于研究趋势、你的过去喜好以及你关注的人的喜好来排序论文。




Machine Learning-Reddit 上的 WAYR thread

WAYR 是 What Are You Reading 的简写。这是一个 Reddit 的子网站(subreddit)Machine Learning 上的一个 thread,其中人们在上面推送近期阅读的机器学习论文,并讨论他们发现的有趣结果。

如我所说,每周在 arXiv 上发表的机器学习领域的研究论文数量非常多。这意味着几乎不可能让个人每周都把它们全部读完,同时还能兼顾其它事情。同时,也不是所有论文都值得一读的。

因此,你需要把精力集中在最有潜力的论文上,而以上介绍的 thread 就是我推荐的一种方式。

Newsletter、Newsletter、Newsletter!

Newsletter 是我个人最喜欢的追踪 AI 最新进展的资源。你只需要订阅它们,就可以定期在电子邮件里收到推送。然后,你就能了解到这周里和 AI 相关的最有趣的新闻、文章和研究论文。

我已经订阅了以下 Newsletter:

  • Import AI(Jack Clark):这是我的最爱,因为除了推送以上我介绍的那些信息之外,它还拥有称为「Tech Tales」的特色栏目。这个栏目包含新的 AI 相关的基于上周时间的短篇科幻小说。

  • 地址:https://jack-clark.net/

  • Machine Learning(Sam DeBrule):他也以相同的名字在 Medium 上发表文章,其中有一些非常有趣的文章,推荐阅读。

  • 地址:https://ift.tt/2jOkQC9

  • Nathan.ai(Nathan Benaich):以上两个快讯是周报形式,而这个是季刊形式。因此,你能在每三个月收到一封长邮件,其中总结了过去三个月里最有趣的领域进展。

  • 地址:https://ift.tt/1XRovvH

  • The Wild Week(Denny Britz):这个快讯的展示很简洁,但在过去两个月里似乎没那么活跃了。总之我也在这里提一下,万一 Denny 又继续更新了呢。

  • 地址:https://ift.tt/2oQmtl8

在 Twitter 上关注「AI 大牛」

另一种追踪领域最前沿的方式是在 Twitter 上关注著名的研究者和研究机构的账号。以下是我的关注列表:

  • Michael Nielsen

  • Andrej Karpathy

  • Francois Chollet

  • Yann LeCun

  • Chris Olah

  • Jack Clark

  • Ian Goodfellow

  • Jeff Dean

  • OpenAI

但我要怎么「开始」?

没错,这才是更加迫切的问题。

首先,确保你理解机器学习的基础,例如回归和其它算法;理解深度学习的基础,一般神经网络、反向传播、正则化,以及一些进阶内容,例如卷积网络(CNN)、循环网络(RNN)和长短期记忆网络(LSTM)的工作方式。我不认为阅读研究论文是理清基础的好办法,有很多其它资源可以用来打好基础。比如吴恩达的《Machine Learning》、《Deep Learning》在线课程,周志华的《机器学习》(西瓜书)、Bengio 等著的《深度学习》教材。

学好基础后,你应该从阅读引入那些基本概念、思想的研究论文开始。从而你可以聚焦于习惯研究论文的形式,不要太担心对第一篇研究论文的真正理解,你已经对那些概念很熟悉了。

我推荐从 AlexNet 这篇论文开始。

论文地址:https://ift.tt/2mltHxK

为什么推荐这一篇?看看下图:

我们可以看到,计算机视觉模式识别Computer Vision and Patter Recognition)的论文发表数从 2012 年开始暴涨,而这一切都源于 AlexNet 这篇论文。

AlexNet 的作者是 Alex Krizhevsky、Ilya Sutskever 和 Geoffrey Hinton,论文标题为《ImageNet Classification with Deep Convolutional Networks》。这篇论文被认为是该领域中影响力最大的论文。它介绍了研究者如何使用称为 AlexNet 的卷积神经网络赢得了 2012 年的 ImageNet 大规模视觉识别挑战赛(ILSVRC)的冠军。

让计算机观察和识别目标是计算机科学最早期的研究目标之一。ILSVRC 就像是计算机视觉的奥林匹克,其中参赛者(计算机算法)需要准确识别图像属于 1000 个类别的哪一个。而且,在 2012 年,AlexNet 在这项竞赛中远远超越了竞争对手:

它获得了 15.3% 的 top-5 准确率,第二名仅获得 26.2% 的 top-5 准确率

毋庸置疑,整个计算机视觉社区都非常令人兴奋,该领域的研究正前所未有地向前加速。人们开始意识到深度神经网络的强大力量,你也可以在该领域尝试获得更多的成果。只要你们了解一些卷积网络的基础,那么掌握 AlexNet 论文的内容就会很简单,它们将会给你带来更多的知识与力量。

完成这一篇论文后,你可以尝试其它与 CNN 相关的开创性论文,也可以转而了解其它如 RNN、LSTM 和 GAN 等流行的架构。

当然目前还有很多渠道获取重要的研究论文,例如在 GitHub 中就有非常多的论文集合。

论文集合:https://ift.tt/2IGH8Ba

此外,最后还有一个非常优秀的平台 Distill,是一个现代的交互、视觉化期刊平台,面向现有以及新的机器学习研究成果。Distill 使用了现代用户界面,注重对研究的理解与诠释。

Distill 地址:https://distill.pub (https://distill.pub/)

虽然 Distill 更新非常慢,但它的每一篇都非常经典。

原文链接:https://ift.tt/2Kf0J09

]]> 原文: https://ift.tt/2KylDa8
RSS Feed

机器知心

IFTTT

2018年6月30日星期六

CV专家田奇教授加入华为诺亚方舟实验室,任计算视觉首席科学家


据介绍,田奇教授早年毕业于清华大学电子工程系,后赴美国伊利诺伊大学香槟分校学习,师从计算视觉之父 Thomas S.Huang 教授,获博士学位。后任美国德克萨斯大学圣安东尼奥分校计算机系正教授,并于 2010 年获 Google Faculty Research Award,2017 年 UTSA 校长杰出研究奖(每年一名),2016 年获评多媒体领域 10 大最具影响力的学者。他同时是国家教育部长江学者讲座教授,海外杰青,中国科学院海外评审专家,曾任国家自然科学基金会评专家,在清华大学神经与认知计算中心、中科院计算所、中科大、浙江大学、上海交通大学、西安交通大学、西安电子科技大学等任讲席教授或者客座教授,并曾在 Microsoft Research Asia、UIUC、NEC Lab 等多个单位访问工作。由于在多媒体信息检索(for contributions to Multimedia Information Retrieval)方面的贡献,他于 2016 年初获评 IEEE Fellow。

田奇教授是 2015 年 ACM International Conference on Multimedia 的大会主席,同时在 2009 年任会务主席,2012 年任技术演示主席,并在 2011-2014、2016-2018 等多次会议中任领域主席。在其它计算视觉顶会如 CVPR、ICCV、ECCV 等也多次任领域主席。他同时是 IEEE Transactions on Multimedia(TMM)、IEEE Transactions on Circuits and Systems for Video Technology(TCSVT)、ACM Transactions on Multimedia Computing,Communications,and Applications(TOMM)、Multimedia Systems Journal 等多个期刊的 Associate Editor。他拥有多项美国专利,在计算视觉及多媒体方向顶级期刊及会议如 IEEE TPAMI,IJCV,TIP,TMM,CVPR,ICCV,ECCV,ACM MM 上发表文章约 420 余篇,Google 引用次数超过 11000 余次,h-index 为 56,有多篇论文获最佳论文奖或者最佳学生论文。

]]> 原文: https://ift.tt/2tV9Xnv
RSS Feed

机器知心

IFTTT

IBM漂浮机器人,被马斯克的火箭送去太空了,还提前学了太空黑话

栗子球 发自 海景方量子位 报道 | 公众号 QbitAI

昨天,IBM和空客一同开发的智能机器人,跟着Space X的龙号飞船,一起进入了太空。

这个球,名字叫CIMON,是宇航员交互式移动伴侣 (Crew Interactive Mobile Companion) 的简称。

机器球就这样飘在半空,以一种灵异的姿势陪在人类身边。

毕竟,宇航员在太空的生活,还是有些单调,有些寂寞。

你不理它的时候,CIMON就在那里做微弱的运动。

当然,作为拥有智能的存在,此球并不简单。

陪伴是最长情的......

CIMON只有头,没有身子。不过,仅有的头部,依然搭载了摄像头、麦克风,还有音箱,能看能听能讲话。

另外,为了能在失重的航天器里面,自如地飞来飞去,机器人还有一枚超声波传感器,给它一些肌肉运动知觉 (Proprioception) ——

就好像,人类闭上眼也能感知,自己身体各部所在的位置。

除此之外,作为陪伴型机器人,CIMON还需要有点社交能力。

你说一句话,沃森就会回答 (并辅以简单的表情) ,还会从人类的话里面学到东西,以便日后更加顺滑地交流。

机器人的智能,来自IBM的沃森 (Watson) ,一只在银行,在车里,在医院,在各行各业经验丰富的,AI老司机。

但在国际空间站 (ISS) 里工作,沃森也是第一次。

要学太空黑话

所以,在跟着火箭上太空之前,它要先学一些"行话"。

比如,宇航员不说"Yes",要说"Affirmative"。简化一下,就是"a-firm"。

这些东西如果不学,AI就会以为,人类在说一个公司的事情。

IBM的攻城狮也不懂舱里的事。于是,就要请教今年新上任的ISS指令长Alexander Gerst。

就是刚才那个,吃着东西就抢了镜的大叔。

他可能就是CIMON在太空里,最亲近的人类了。

还有科研技能

有三个任务,是要他们两个一起做的。

如此说来,不只有陪伴那么简单。

第一个任务,是研究微重力的环境下,晶体是怎样形成的。要做实验。

关于实验步骤和实验工具,不记得的话,可以问问CIMON。

忘了介绍,亚历山大叔叔还是一个地球物理学家。

第二个任务,是解 (大) 魔方。

最后一个任务,是个医学实验。CIMON充当移动摄像机,视角就不用担心了。

除此之外,如果空间站的设备出现了技术问题,机器人会立刻变身报警装置

看你有多寂寞了

作为IBM和空客的爱情结晶,漂浮机器人是在德国航空航天中心 (DLR) 的资金支持之下,诞生的。

开发者们希望,太空人们能爱上有机器人陪伴的日子。

不过,有个球一直在旁边,记录人类的数据,他们可能还是会有点介意。

毕竟,空间站的生活,原本已经不是很自在了。

寂寞和机器人,你选哪一个?

欢迎大家关注我们的专栏:量子位 - 知乎专栏

诚挚招聘

量子位正在招募编辑/记者,工作地点在北京中关村。期待有才气、有热情的同学加入我们!相关细节,请在量子位公众号(QbitAI)对话界面,回复"招聘"两个字。

量子位 QbitAI · 头条号签约作者

վ'ᴗ' ի 追踪AI技术和产品新动态



via 量子位 - 知乎专栏 https://ift.tt/2lNewg2
RSS Feed

RSS5

IFTTT

IBM漂浮机器人,被马斯克的火箭送去太空了,还提前学了太空黑话

栗子球 发自 海景方量子位 报道 | 公众号 QbitAI

昨天,IBM和空客一同开发的智能机器人,跟着Space X的龙号飞船,一起进入了太空。

这个球,名字叫CIMON,是宇航员交互式移动伴侣 (Crew Interactive Mobile Companion) 的简称。

机器球就这样飘在半空,以一种灵异的姿势陪在人类身边。

毕竟,宇航员在太空的生活,还是有些单调,有些寂寞。

你不理它的时候,CIMON就在那里做微弱的运动。

当然,作为拥有智能的存在,此球并不简单。

陪伴是最长情的......

CIMON只有头,没有身子。不过,仅有的头部,依然搭载了摄像头、麦克风,还有音箱,能看能听能讲话。

另外,为了能在失重的航天器里面,自如地飞来飞去,机器人还有一枚超声波传感器,给它一些肌肉运动知觉 (Proprioception) ——

就好像,人类闭上眼也能感知,自己身体各部所在的位置。

除此之外,作为陪伴型机器人,CIMON还需要有点社交能力。

你说一句话,沃森就会回答 (并辅以简单的表情) ,还会从人类的话里面学到东西,以便日后更加顺滑地交流。

机器人的智能,来自IBM的沃森 (Watson) ,一只在银行,在车里,在医院,在各行各业经验丰富的,AI老司机。

但在国际空间站 (ISS) 里工作,沃森也是第一次。

要学太空黑话

所以,在跟着火箭上太空之前,它要先学一些"行话"。

比如,宇航员不说"Yes",要说"Affirmative"。简化一下,就是"a-firm"。

这些东西如果不学,AI就会以为,人类在说一个公司的事情。

IBM的攻城狮也不懂舱里的事。于是,就要请教今年新上任的ISS指令长Alexander Gerst。

就是刚才那个,吃着东西就抢了镜的大叔。

他可能就是CIMON在太空里,最亲近的人类了。

还有科研技能

有三个任务,是要他们两个一起做的。

如此说来,不只有陪伴那么简单。

第一个任务,是研究微重力的环境下,晶体是怎样形成的。要做实验。

关于实验步骤和实验工具,不记得的话,可以问问CIMON。

忘了介绍,亚历山大叔叔还是一个地球物理学家。

第二个任务,是解 (大) 魔方。

最后一个任务,是个医学实验。CIMON充当移动摄像机,视角就不用担心了。

除此之外,如果空间站的设备出现了技术问题,机器人会立刻变身报警装置

看你有多寂寞了

作为IBM和空客的爱情结晶,漂浮机器人是在德国航空航天中心 (DLR) 的资金支持之下,诞生的。

开发者们希望,太空人们能爱上有机器人陪伴的日子。

不过,有个球一直在旁边,记录人类的数据,他们可能还是会有点介意。

毕竟,空间站的生活,原本已经不是很自在了。

寂寞和机器人,你选哪一个?

欢迎大家关注我们的专栏:量子位 - 知乎专栏

诚挚招聘

量子位正在招募编辑/记者,工作地点在北京中关村。期待有才气、有热情的同学加入我们!相关细节,请在量子位公众号(QbitAI)对话界面,回复"招聘"两个字。

量子位 QbitAI · 头条号签约作者

վ'ᴗ' ի 追踪AI技术和产品新动态



via 量子位 - 知乎专栏 https://ift.tt/2lNewg2
RSS Feed

RSS5

IFTTT

北京自动驾驶路测名单更新:蔚来和Pony.ai也获准上路了

郭一璞 发自 沙滩滩 量子位 报道 | 公众号 QbitAI

越来越多的自动驾驶公司已经可以在北京路测了。

根据北京市智能车联产业创新中心公布的信息,截至6月28日,百度、蔚来、北汽、戴姆勒、pony.ai五家公司已经获取了在北京进行路测的资格。

从该中心的数据可见,截至今年6月,北京已经成为国内开放测试道路最长的城市,安全行驶记录超过26000公里,共开放33条道路,总长105公里。

开放的道路都在五环外。其中,74.4公里道路集中分布在亦庄的北京经济技术开发区,另外在海淀稻香湖附近及六环外的中关村顺义园地区也分别有十余公里的道路开放。

申请路测,先准备500万保险

申请在北京路测的必须是中国境内注册的独立法人单位,需要具备赔偿能力,可以选择购买不低于五百万人民币的交通事故责任保险,或提供不少于五百万元人民币的自动驾驶道路测试事故赔偿保函。

并且申请路测对提前在封闭测试场测试也有要求,需要在封闭测试场中进行过不少于5000公里里程与规定测试用例的测试。

当然,一个必备的功能是申请的车辆必须具备自动驾驶功能,能在自动、人工驾驶两种模式中切换。

因此车上的测试驾驶员十分重要,要求必须与测试主体签订劳动合同,无毒驾、酒驾经历,应具备随时接管测试车辆的能力,有50个小时以上自动驾驶经历,并有10个小时以上危情场景条件下接管测试车辆的测试经验。并且,自动驾驶车辆内需要设有装置来监测驾驶员行为。

最快只要半个月

申请的流程从受理开始,测试主体递交材料,在10个工作日内发放初审结果,现场审查后进行专家评估及联系工作小组会议,会后五个工作日内,如果通过的话,申请测试的主体就可以去车管所办手续了。

如果出事故,驾驶员背锅

由于测试驾驶员必须随时注意驾驶状况,准备接管车辆,所以测试驾驶员身上负有重大的责任。

根据《北京市关于加快推进自动驾驶车辆道路测试有关工作的指导意见(试行)》的规定,一旦出现事故或违章,测试驾驶员会被认定为车辆驾驶员,由北京市公安交管部门按照现行道路交通安全法律法规的规定进行处理,由测试驾驶员承担相应法律责任。

最后,关于北京自动驾驶路测法规,量子位之前还有相关报道:

《刚刚,北京正式允许无人车上路路测!准入门槛500万元》

《无人车路测在北京or去加州?不比不知道》

《国内最开明路测法规将出炉,广州在用行动召唤无人车企落地》

欢迎大家关注我们的专栏:量子位 - 知乎专栏

诚挚招聘

量子位正在招募编辑/记者,工作地点在北京中关村。期待有才气、有热情的同学加入我们!相关细节,请在量子位公众号(QbitAI)对话界面,回复"招聘"两个字。

量子位 QbitAI · 头条号签约作者

վ'ᴗ' ի 追踪AI技术和产品新动态



via 量子位 - 知乎专栏 https://ift.tt/2N9od4K
RSS Feed

RSS5

IFTTT

入职仅一年,套现5000多万后背刺马斯克搬走 Grok 核心代码库!-InfoQ 每周精要894期

「每周精要」 NO. 894 2025/09/06 头条 HEADLINE 入职仅一年,套现 5000 多万搬走 Grok 核心代码库! 业内专家:拥有菜谱不等于能做出同样的菜 精选 SELECTED AI 公司创始人现跑路迪拜! 80% 收入烧广告、假账骗投资人,微...