cs231n-two_layer_net-note


import numpy as np
?np.maximum

np.maximum 是 element-wise 取最大,同时也有broadcasting 机制

np.maximum([1,2,5],[2,3,4])
array([2, 3, 5])

比较下面会发现,列表与numpy 数组是具有一样的效果的

np.maximum(np.eye(2), [0.5,2])
array([[1. , 2. ],
       [0.5, 2. ]])
np.maximum(np.eye(2), np.array([0.5,2]))
array([[1. , 2. ],
       [0.5, 2. ]])
np.maximum(np.eye(2), np.array([[0.5,2]]))
array([[1. , 2. ],
       [0.5, 2. ]])
np.maximum(0, np.array([[1,-1],[-1,2]]))
array([[1, 0],
       [0, 2]])
np.array([[1,2],[3,4]]) + 1
array([[2, 3],
       [4, 5]])
np.array([[1,2],[3,4]]) + np.array([1,2])
array([[2, 4],
       [4, 6]])
a = np.array([[1,2],[3,4]])
a.reshape(-1,1)
array([[1],
       [2],
       [3],
       [4]])

np.nditer

简单的数组迭代

我们可以用nditer 来访问数组的每个元素,每个元素都被提供一个标准python 迭代器接口

a = np.arange(6).reshape(2,3)
a
array([[0, 1, 2],
       [3, 4, 5]])
for x in np.nditer(a):
    print(x, end = ' ')
0 1 2 3 4 5 
b = np.array([[3,2,4],[1,6,7],[9,8,5]])
for x in np.nditer(b):
    print(x, end = ' ')
3 2 4 1 6 7 9 8 5 

比较下列异同

a.T
array([[0, 3],
       [1, 4],
       [2, 5]])
for x in np.nditer(a.T):
    print(x, end = ' ')
0 1 2 3 4 5 
for x in np.nditer(a.T.copy(order='C')):
    print(x, end = ' ')
0 3 1 4 2 5 
b.T
array([[3, 1, 9],
       [2, 6, 8],
       [4, 7, 5]])
for x in np.nditer(b.copy(order='C')):
    print(x, end = ' ')
3 2 4 1 6 7 9 8 5 
for x in np.nditer(b.T):
    print(x, end = ' ')
3 2 4 1 6 7 9 8 5 
for x in np.nditer(b.T.copy()):
    print(x, end = ' ')
3 1 9 2 6 8 4 7 5 
for x in np.nditer(b.T.copy(order='C')):
    print(x, end = ' ')
3 1 9 2 6 8 4 7 5 
for x in np.nditer(b.T.copy(order='F')):
    print(x, end = ' ')
3 2 4 1 6 7 9 8 5 

由上面可知选择顺序与内存布局相合,order 为 ‘C’ 时,选择顺序为按行, order 为 ‘F’ 时选择顺序为列;copy 过后就是新的列表,有新的布局,而a 和 a.T 仍然是同一个布局。

修改数组值

默认 nditer 是只读的,若要写,需要更改一些参数,然后nditer 会返回可写的缓冲数组

a = np.arange(6).reshape(2,3)
a
array([[0, 1, 2],
       [3, 4, 5]])
for x in np.nditer(a, op_flags=['readwrite']):
    x[...] = 2 * x
a
array([[ 0,  2,  4],
       [ 6,  8, 10]])

追踪索引

在 nditer 中增加 flags (‘f_index’ 或 ‘multi_index’) ,那么当前的 iterator 中的值可以用索引访问,被追踪的索引在方法 index 或者 multi_index 中

a = np.arange(6).reshape(2,3)
a
array([[0, 1, 2],
       [3, 4, 5]])
it = np.nditer(a, flags=['f_index'])
while not it.finished:
    print('%d <%s>' %(it[0], it.index))
    it.iternext()
0 <0>
1 <2>
2 <4>
3 <1>
4 <3>
5 <5>
it = np.nditer(a, flags=['multi_index'])
while not it.finished:
    print('%d <%s>' %(it[0], it.multi_index))
    it.iternext()
0 <(0, 0)>
1 <(0, 1)>
2 <(0, 2)>
3 <(1, 0)>
4 <(1, 1)>
5 <(1, 2)>
it = np.nditer(a, flags=['multi_index'], op_flags=['readwrite'])
while not it.finished:
    it[0] = it.multi_index[1] - it.multi_index[0]
    it.iternext()
a
array([[ 0,  1,  2],
       [-1,  0,  1]])

对比

a = np.arange(6).reshape(2,3)
it = np.nditer(a, flags=['multi_index'], op_flags=['readwrite'])
while not it.finished:
    it[0] *= 2
    it.iternext()
a
array([[ 0,  2,  4],
       [ 6,  8, 10]])
a = np.arange(6).reshape(2,3)
for x in np.nditer(a, op_flags=['readwrite']):
    x[...] = 2 * x
a
array([[ 0,  2,  4],
       [ 6,  8, 10]])

特定数据类型

我们有时会想更改我们原本数据的类型,通常来说我们使用copy 或者 buffer 的模式,直接对原始数据操作会报错,而更好的是 buffer 模式,这种模式内存使用量较小

a = np.arange(6).reshape(2,3) - 3
a
array([[-3, -2, -1],
       [ 0,  1,  2]])
for x in np.nditer(a, op_flags=['readonly', 'copy'], op_dtypes=['complex128']):
    print(np.sqrt(x))
1.7320508075688772j
1.4142135623730951j
1j
0j
(1+0j)
(1.4142135623730951+0j)
for x in np.nditer(a, flags=['buffered'], op_dtypes=['complex128']):
    print(np.sqrt(x))
1.7320508075688772j
1.4142135623730951j
1j
0j
(1+0j)
(1.4142135623730951+0j)

广播

np.nditer() 具有广播机制

a = np.arange(3)
b = np.arange(6).reshape(2,3)
for x,y in np.nditer([a,b]):
    print('%d:%d' % (x,y))
0:0
1:1
2:2
0:3
1:4
2:5
a = np.arange(2)
b = np.arange(6).reshape(2,3)
for x,y in np.nditer([a,b]):
    print('%d:%d' % (x,y))
---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)

<ipython-input-81-b7cbf77d4db0> in <module>()
      1 a = np.arange(2)
      2 b = np.arange(6).reshape(2,3)
----> 3 for x,y in np.nditer([a,b]):
      4     print('%d:%d' % (x,y))


ValueError: operands could not be broadcast together with shapes (2,) (2,3) 

迭代器分配的输出数组

在 numpy 数组中,常见基于输入的广播的输出分配

def square(a):
    it = np.nditer([a, None])
    for x,y in it:
        y[...] = x*x
    return it.operands[1]
square([1,2,3])
array([1, 4, 9])
def square(a):
    it = np.nditer([a, None])
    for x, y in it:
        y[...] = x*x
    return it.operands[0]

square([1,2,3])
array([1, 2, 3])

当operands 传入的为 None 默认 flags 为 ‘allocate’ 和 ‘writeonly’,当增加一个 out 参数,默认flags 为 ‘readonly’,所以如果我们相对它进行操作,需要显式指定一些参数

def square(a, out=None):
    it = np.nditer([a, out], flags=['external_loop', 'buffered'], op_flags=[['readonly'],['writeonly'
                                                                                         ,'allocate','no_broadcast']] )
    for x, y in it:
        y[...] = x*x
    return it.operands[1]
square([1,2,3])
array([1, 4, 9])
b = np.zeros((3,))
square([1,2,3], out=b)
array([1., 4., 9.])
b
array([1., 4., 9.])

文章作者: lovelyfrog
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 lovelyfrog !
 上一篇
训练神经网络part1 训练神经网络part1
激活函数 Sigmoid 将输入压缩至[0,1] 三个问题: 饱和神经元会杀死梯度 输出不是 0-centered,这样会导致梯度是恒正或恒负 exp() 计算量大 ReLU(Rectified Linear Un
2018-12-02
下一篇 
cs231n-softmax-note cs231n-softmax-note
import numpy as np np.log(10) 2.302585092994046 np.exp([1,2]) array([2.71828183, 7.3890561 ])比较下列的异同,通常broadcasting是
2018-11-27
  目录