Python的矩阵传播机制(Broadcasting)

最近在学习神经网络。我们知道在深度学习中经常要操作各种矩阵(matrix)。
回想一下,我们在操作数组(list)的时候,经常习惯于用for循环(for-loop)来对数组的每一个元素进行操作。例如:

my_list = [1,2,3,4]
new_list = []
for each in my_list:
new_list.append(each*2)
print(new_list)
# 输出 [2,3,4,5]

如果是矩阵呢:

my_matrix = [[1,2,3,4],
[5,6,7,8]]
new_matrix = [[],[]]
for i in range(2):
for j in range(4):
new_matrix[i].append(my_matrix[i][j]*2)
print(new_matrix)
# 输出 [[2, 4, 6, 8], [10, 12, 14, 16]]

实际上,上面的做法是十分的低效的!数据量小的话还不明显,如果数据量大了,尤其是深度学习中我们处理的矩阵往往巨大,那用for循环去跑一个矩阵,可能要你几个小时甚至几天。

Python考虑到了这一点,这也是本文主要想介绍的“Python的broadcasting”即传播机制。
先说一句,python中定义矩阵、处理矩阵,我们一般都用numpy这个库。

下面展示什么是python的传播机制:

import numpy as np

# 先定义一个3×3矩阵 A:
A = np.array(
[[1,2,3],
[4,5,6],
[7,8,9]]) print("A:\n",A)
print("\nA*2:\n",A*2) # 直接用A乘以2
print("\nA+10:\n",A+10) # 直接用A加上10

运行结果:

A:
[[1 2 3]
[4 5 6]
[7 8 9]] A*2:
[[ 2 4 6]
[ 8 10 12]
[14 16 18]] A+10:
[[11 12 13]
[14 15 16]
[17 18 19]]

接着,再看看矩阵×(+)矩阵:

#定义一个3×1矩阵(此时也可叫向量了)
B = np.array([[10],
[100],
[1000]])
print("\nB:\n",B)
print("\nA+B:\n",A+B)
print("\nA*B:\n",A*B)

运行结果:

B:
[[ 10]
[ 100]
[1000]] A+B:
[[ 11 12 13]
[ 104 105 106]
[1007 1008 1009]] A*B:
[[ 10 20 30]
[ 400 500 600]
[7000 8000 9000]]

可见,虽然A和B的形状不一样,一个是3×3,一个是3×1,但是我们在python中可以直接相加、相乘,相减相除也可以。

也许看到这,大家都对broadcasting有感觉了。
用一个图来示意一下:

 
传播机制示意图

所谓“传播”,就是把一个数或者一个向量进行“复制”,从而作用到矩阵的每一个元素上。

有了这种机制,那进行向量和矩阵的运算,就太方便了!
理解了传播机制,就可以随心所欲地对矩阵进行各种便捷的操作了。

利用numpy的内置函数对矩阵进行操作:

numpy内置了很多的数学函数,例如np.log(),np.abs(),np.maximum()等等上百种。直接把矩阵丢进去,就可以算出新矩阵!
示例:

print(np.log(A))

输出把A矩阵每一个元素求log后得到的新矩阵:

array([[0.        , 0.69314718, 1.09861229],
[1.38629436, 1.60943791, 1.79175947],
[1.94591015, 2.07944154, 2.19722458]])

再比如深度学习中常用的ReLU激活函数,就是y=max(0,x),

 
ReLU函数

也可以对矩阵直接运算:

X = np.array([[1,-2,3,-4],
[-9,4,5,6]])
Y = np.maximum(0,X)
print(Y)

得到:

[[1 0 3 0]
[0 4 5 6]]

更多的numpy数学函数,可以参见文档:
https://docs.scipy.org/doc/numpy-1.13.0/reference/routines.math.html

定义自己的函数来处理矩阵

其实这才是我写下本文的目的。。。前面扯了这么多,只是做个铺垫(/ω\)

我昨天遇到个问题,就是我要对ReLU函数求导,易知,y=max(0,x)的导函数是:
y' = 0 if x<0
y' = 1 if x>0
但是这个y'(x)numpy里面没有定义,需要自己构建。
即,我需要将矩阵X中的小于0的元素变为0,大于0的元素变为1。
搞了好久没弄出来,后来在StackOverflow上看到了解决办法:

def relu_derivative(x):
x[x<0] = 0
x[x>0] = 1
return x X = np.array([[1,-2,3,-4],
[-9,4,5,6]]) print(relu_derivative(X))

输出:

[[1 0 1 0]
[0 1 1 1]]

居然这么简洁就出来了!!!ミ゚Д゚彡 (゚Д゚#)

这个函数relu_derivative中最难以理解的地方,就是x[x>0]了。
于是我试了一下:

X = np.array([[1,-2,3,-4],
[-9,4,5,6]])
print(X[X>0])
print(X[X<0])

输出:

[1 3 4 5 6]
[-2 -4 -9]

它直接把矩阵X中满足条件的元素取了出来!原来python对矩阵还有这种操作!

 

震惊了我好久~
所以可以这么理解,X[X>0]相当于一个“选择器”,把满足条件的元素选出来,然后直接全部赋值。
用这种方法,我们便可以定义各种各样我们需要的函数,然后对矩阵整体进行更新操作了!

综上

可以看出,python以及numpy对矩阵的操作简直神乎其神,方便快捷又实惠。其实上面忘了写一点,那就是计算机进行矩阵运算的效率要远远高于用for-loop来运算,
不信可以用跑一跑:

# vetorization vs for loop
# define two arrays a, b:
a = np.random.rand(1000000)
b = np.random.rand(1000000) # for loop version:
t1 = time.time()
c = 0
for i in range(1000000):
c += a[i]*b[i]
t2 = time.time()
print(c)
print("for loop version:"+str(1000*(t2-t1))+"ms")
time1 = 1000*(t2-t1) # vectorization version:
t1 = time.time()
c = np.dot(a,b)
t2 = time.time()
print(c)
print("vectorization version:"+str(1000*(t2-t1))+"ms")
time2 = 1000*(t2-t1) print("vectorization is faster than for loop by "+str(time1/time2)+" times!")

运行结果:

249765.8415288075
for loop version:627.4442672729492ms
249765.84152880745
vectorization version:1.5032291412353516ms
vectorization is faster than for loop by 417.39762093576525 times!

可见,用for方法和向量化方法,计算结果是一样,但是后者比前者快了400多倍!
因此,在计算量很大的时候,我们要尽可能想办法对数据进行Vectorizing,即“向量化”,以便让计算机进行矩阵运算。

原文 https://www.jianshu.com/p/e26f381f82ad

Python的矩阵传播机制&矩阵运算的更多相关文章

  1. 用 python 解决线性代数中的矩阵运算

    用 python 解决线性代数中的矩阵运算 矩阵叉乘 矩阵求逆 矩阵转置 假定AX=B,求解未知矩阵X 矩阵的行列式值|matrix| 未完待续..... import sys from PyQt5. ...

  2. python的内存管理机制

    先从较浅的层面来说,Python的内存管理机制可以从三个方面来讲 (1)垃圾回收 (2)引用计数 (3)内存池机制 一.垃圾回收: python不像C++,Java等语言一样,他们可以不用事先声明变量 ...

  3. python 的 from import 机制

    [A.py] from B import D class C:pass [B.py] from A import C class D:pass 为什么执行A的时候不能加载D呢? 如果将A.py改为:i ...

  4. spring事务传播机制实例讲解

    http://kingj.iteye.com/blog/1680350   spring事务传播机制实例讲解 博客分类:   spring java历险     天温习spring的事务处理机制,总结 ...

  5. Spring事务传播机制和数据库隔离级别

    Spring事务传播机制和数据库隔离级别 转载 2010年06月26日 10:52:00 标签: spring / 数据库 / exception / token / transactions / s ...

  6. python 的字符串驻留机制

    我们都知道python中的引用计数机制,相同对象的引用其实都是指向内存中的同一个位置,这个也叫做“python的字符串驻留机制”.其他的就不多说了,自行研究. 重点!!!!!! python的引用计数 ...

  7. spring 事务传播机制

    spring 事务 传播机制 描述的 事务方法直接相互调用,父子事物开启,挂起,回滚 等的处理方式. 绿色的 那几个 我认为比较重要. 1 , @Transactional(propagation=P ...

  8. 详解python的垃圾回收机制

    python的垃圾回收机制 一.引子 我们定义变量会申请内存空间来存放变量的值,而内存的容量是有限的,当一个变量值没有用了(简称垃圾)就应该将其占用的内存空间给回收掉,而变量名是访问到变量值的唯一方式 ...

  9. 数据库事务的隔离以及spring的事务传播机制

    数据库的事务隔离: MySQL InnoDB事务的隔离级别有四级,默认是“可重复读”RR(REPEATABLE READ). oracle默认的是提交读.RC 未提交读(READ UNCOMMITTE ...

随机推荐

  1. Struts CRUD

    Struts CRUD 利用struts完成增删改查 思路: 1.导入相关的pom依赖(struts.自定义标签库的依赖) 2.分页的tag类导入.z.tld.完成web.xml的配置 3.dao层去 ...

  2. 【转】SkipList跳表基本原理

    增加了向前指针的链表叫作跳表.跳表全称叫做跳跃表,简称跳表.跳表是一个随机化的数据结构,实质就是一种可以进行二分查找的有序链表.跳表在原有的有序链表上面增加了多级索引,通过索引来实现快速查找.跳表不仅 ...

  3. Mysql之配置双主热备+keeepalived.md

    准备 1 1. 双主 master1 192.168.199.49 2 master2 192.168.199.50 3 VIP 192.168.199.52 //虚拟IP 4 2.环境 master ...

  4. 认识随机函数rand()和srand(unsigned int )

    rand函数 int rand( void ); 函数名:   rand 功   能:   随机数发生器 用   法:   int rand(void); 所在头文件: stdlib.h 函数说明 : ...

  5. CentOS 7搭建本地yum源和局域网yum源

    这两天在部署公司的测试环境,在安装各种中间件的时候,发现各种依赖都没有:后来一检查,发现安装的操作系统是CentOS Mini版,好吧,我认了:为了完成测试环境的搭建,我就搭建了一个局域网的yum源. ...

  6. Maven 教程(21)— maven-compiler-plugin 插件详解--

    原文地址:https://blog.csdn.net/liupeifeng3514/article/details/80236077 maven是个项目管理工具,如果我们不告诉它我们的代码要使用什么样 ...

  7. Java8 新特性 默认方法

    默认方法为什么出现 默认方法的出现是因为在java8设计的过程中,因为加入了Lamdba表达式,和函数式接口,所以在非常多的接口里面要加入新的方法,但是如果在接口里面直接加入新的方法,那么以前写的所有 ...

  8. Windows域的创建与加入教程

    一.说明 以前看书的时候时常看到“域”这个词,后来听一些渗透的演讲通常会说进入内网后首先要找域控.在认知中“域控”应该是域管理服务器一类的东西,但毕竟没有实现过所以还是不太懂长什么样. 前段时间朋友电 ...

  9. 递推 + 高精度 --- Tiling

    Tiling Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7264   Accepted: 3528 Descriptio ...

  10. 【拆分版】Docker-compose构建Kibana单实例,基于7.1.0

    写在前边 今凌晨的时候已经把这整个Docker-compose构建的ELK集群跑起来了,有点没熬住,所以早上起来补文档,今天就上到公司测试服务器上测试了,好开森. 本文内容就是红框的部分,只是启动个K ...