为深度学习人员准备的Python快速入门教程

更新日志

2017.11.13 创建

2017.11.18 增加numpy入门教程

2017.12.06 增加opencv相关内容

人生苦短,你需要Python

Life is short, Have an Affair you need Python

— Bruce Eckel

Python简介

Python是一门解释型的高级编程语言,特点是简单明确。Python作者是荷兰人Guido van Rossum,1982年他获得数学和计算机硕士学位后,在荷兰数学与计算科学研究所(Centrum Wiskunde & Informatica, CWI)谋了份差事。在CWI期间,Guido参与到了一门叫做ABC的语言开发工作中。
1989年的圣诞假期,闲得蛋疼的Guido决定设计一门简单易用的新语言,要介于C和Shell之间,同时吸取ABC语法中的优点。Guido用自己喜欢的一部喜剧电视剧来命名这门语言:《Monty Python’s Flying Circus》。

Python简史

  • 1989年的圣诞节,Guido开始编写Python语言的编译器。
  • 1991年,第一个Python编译器(同时也是解释器)诞生。它是用C语言实现的,并能够调用C库(.so文件)。
  • Python 2.0 - 2000/10/16,加入了内存回收机制,构成了现在Python语言框架的基础
  • Python 3.0 - 2008/12/03
  • Python 2.7 - 2010/07/03

2014年11月,Python2.7将在2020年停止支持的消息被发布,所有的最新的标准库的更新改进,只会在3.x的版本里出现。并且不会在发布2.8版本,建议用户尽可能的迁移到3.4+

为什么要python

入门比较简单:搞机器学习的,大部分都不会写代码,人家是学数学的,你要人家用c++写cuda,写出来的代码效率高不高是次要,学习成本有多高

开发生态成熟:说的直接点就是库多,NumPy,还有SciPy,NLTK,OpenCV,MatplotLib,更不用说linux自带python

效率高:这个效率是开发效率,python因为是高级解释型语言,所以在性能方面当然是无法满足大规模数据训练的,但是因为技术进步,计算的的成本大大降低,反而开发的时间成为瓶颈。
学术界所探讨的是可能性问题,而工业界是实现性问题。所以,学术界的代码灵活性很高!经常提出新的想法和实现再加上python的主流框架caffe,tensorflow,pytorch和更上次层的封装keras,
你可以毫不费力的通过这条路复现学术论文的结果

jupyter notebook:这个绝对可以算作一个重要原因,做个笔记什么就不是事,开会的时候做展示,也是萌萌哒

python 入门

python安装

刚才已经说了Python有两个大版本,但是建议安装python3,这里推荐安装anaconda,专门为机器学习制作的整合包,里面基本上包都全了,再装个tensorflow和keras就可以开工了

Python基本语法

基本数据类型

Python中最基本的数据类型包括整型,浮点数,布尔值和字符串。类型是不需要声明的,其中#是行内注释的意思。最后一个None是NoneType

1
2
3
4
5
a = 1 # 整数
b = 1.2 # 浮点数
c = True # 布尔类型
d = "False" # 字符串
e = None # NoneType

变量和引用

Python中基本变量的赋值一般建立的是个引用

1
2
3
4
5
6
a = 1
b = a
c = 1
id(a) # 35556792L
id(b) # 35556792L
id(c) # 35556792L

a赋值为1后,b=a执行时并不会将a的值复制一遍,然后赋给b,而是简单地为a所指的值,也就是1建立了一个引用,相当于a和b都是指向包含1这个值的这块内存的指针。所以c=1执行的也是个引用建立,这三个变量其实是三个引用,指向同一个值。.Python内置了id函数,可以返回一个对象的地址,用id函数可以让我们知道每个变量指向的是不是同一个值

运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
a = 2
b = 2.3
c = 3
a + b # 2 + 2.3 = 4.3
c – a # 3 - 2 = 1
a / b # 整数除以浮点数,运算以浮点数为准,2 / 2.3 = 0.8695652173913044
a / c # Python2中,整数除法,向下取整 2 / 3 = 0
a ** c # a的c次方,结果为8
a += 1 # Python中没有i++的用法,自增用+=
c -= 3 # c变成0了
d = 'Hello'
d + ' world!' # 相当于字符串拼接,结果为'Hello world!'
d += ' "world"!'# 相当于把字符串接在当前字符串尾,d变为'Hello "world"!'
e = r'\n\t\\'
print(e) # '\\n\\t\\\\'
# 布尔值和逻辑的运算
a = True
b = False
a and b # False
a or b # True
not a # False
# 位操作
~8 # 按位翻转,1000 --> -(1000+1)
8 >> 3 # 右移3位,1000 --> 0001
1 << 3 # 左移3位,0001 --> 1000
5 & 2 # 按位与,101 & 010 = 000
5 | 2 # 按位或,101 | 010 = 111
4 ^ 1 # 按位异或,100 ^ 001 = 101

相等或不等

==和!=比较引用指向的内存中的内容,而is判断两个变量是否指向一个地址

1
2
3
4
5
6
a = 1
b = 1.0
c = 1
a == b # True,值相等
a is b # False,指向的不是一个对象,这个语句等效于 id(a) == id(b)
a is c # True,指向的都是整型值1

模块导入

1
2
3
4
5
6
7
8
9
10
11
12
# 直接导入Python的内置基础数学库
import math
print(math.cos(math.pi))
# 从math中导入cos函数和pi变量
from math import cos, pi
print(cos(pi))
# 如果是个模块,在导入的时候可以起个别名,避免名字冲突或是方便懒得打字的人使用
import math as m
print(m.cos(m.pi))
# 从math中导入所有东西
from math import *
print(cos(pi))

容器

主要包括列表(list),元组(tuple),字典(dict)和集合(set)

列表(list)

列表对类型没什么限制

1
2
3
4
5
6
7
8
9
10
11
a = [1, 2, 3, 4]
b = [1]
c = [1]
d = b
e = [1, "Hello world!", c, False]
print(id(b), id(c)) # (194100040L, 194100552L)
print(id(b), id(d)) # (194100040L, 194100040L)
print(b == c) # True
f = list("abcd")
print(f) # ['a', 'b', 'c', 'd']
g = [0]*3 + [1]*4 + [2]*2 # [0, 0, 0, 1, 1, 1, 1, 2, 2]
元组(tuple)

元组和列表有很多相似的地方,最大的区别在于不可变

1
2
3
4
5
6
7
8
a = (1, 2)
b = tuple(['3', 4]) # 也可以从列表初始化
c = (5,)
print(c) # (5,)
d = (6)
print(d) # 6
e = 3, 4, 5
print(e) # (3, 4, 5)
集合(set)
1
2
3
4
5
6
7
8
9
A = set([1, 2, 3, 4])
B = {3, 4, 5, 6}
C = set([1, 1, 2, 2, 2, 3, 3, 3, 3])
print(C) # 集合的去重效果,set([1, 2, 3])
print(A | B) # 求并集,set([1, 2, 3, 4, 5, 6])
print(A & B) # 求交集,set([3, 4])
print(A - B) # 求差集,属于A但不属于B的,set([1, 2])
print(B - A) # 求差集,属于B但不属于A的,set([5, 6])
print(A ^ B) # 求对称差集,相当于(A-B)|(B-A),set([1, 2, 5, 6])
字典(dict)

键-值”(key-value)映射结构,键无重复,一个键不能对应多个值,不过多个键可以指向一个值。
初始化字典和集合很像,的确如此,集合就像是没有值只有键的字典

1
2
3
4
5
6
7
8
9
10
11
12
13
a = {'Tom': 8, 'Jerry': 7}
print(a['Tom']) # 8
b = dict(Tom=8, Jerry=7) # 一种字符串作为键更方便的初始化方式
print(b['Tom']) # 8
if 'Jerry' in a: # 判断'Jerry'是否在keys里面
print(a['Jerry']) # 7
print(a.get('Spike')) # None,通过get获得值,即使键不存在也不会报异常
a['Spike'] = 10
a['Tyke'] = 3
a.update({'Tuffy': 2, 'Mammy Two Shoes': 42})
print(a.values()) # dict_values([8, 2, 3, 7, 10, 42])
print(a.pop('Mammy Two Shoes')) # 移除'Mammy Two Shoes'的键值对,并返回42
print(a.keys()) # dict_keys(['Tom', 'Tuffy', 'Tyke', 'Jerry', 'Spike'])

分支和循环

for循环
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
a = ['This', 'is', 'a', 'list', '!']
b = ['This', 'is', 'a', 'tuple', '!']
c = {'This': 'is', 'an': 'unordered', 'dict': '!'}
# 依次输出:'This', 'is', 'a', 'list', '!'
for x in a:
print(x)
# 依次输出:'This', 'is', 'a', 'tuple', '!'
for x in b:
print(x)
# 键的遍历。不依次输出:'This', 'dict', 'an'
for key in c:
print(key)
# 依次输出0到9
for i in range(10):
print(i)

每个for循环中,print都有缩进,这是Python中一个让人非常 讨厌 喜爱的特点:强行缩进来表明成块的代码。

if和分支结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
pets =['dog', 'cat', 'droid', 'fly']
for pet in pets:
if pet == 'dog': # 狗粮
food = 'steak' # 牛排
elif pet == 'cat': # 猫粮
food = 'milk' # 牛奶
elif pet == 'droid': # 机器人
food = 'oil' # 机油
elif pet == 'fly': # 苍蝇
food = 'sh*t' #
else:
pass # 空语句,什么也不做
print(food)
if -1 < x < 1: # 相较于 if x > -1 and x < 1:
print('The absolute value of x is < 1')
if x in ['piano', 'violin', 'drum']: # 相较于 if x == 'piano' or x == 'violin' or x =='drum':
print("It's an instrument!")

隐式表达式为False的是如下状况:

  • None
  • False
  • 数值0
  • 空的容器或序列(字符串也是一种序列)
  • 用户自定义类中,如果定义了__len__()或者__nonzero__(),并且被调用后返回0或者False
while循环
1
2
3
4
5
6
i = 0
while i < 100: # 笑100遍
print("ha")
while True: # 一直笑
print("ha")

函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#定义函数
def say_hello():
print('Hello!')
say_hello() #调用
# 默认参数项必须放后面
def create_a_list(x, y=2, z=3):
return [x, y, z]
b = create_a_list(1) # [1, 2, 3]
c = create_a_list(3, 3) # [3, 3, 3]
d = create_a_list(6, 7, 8) # [6, 7, 8]
def traverse_args(*args):
for arg in args:
print(arg)
traverse_args(1, 2, 3) # 依次打印1, 2, 3
traverse_args('A', 'B', 'C', 'D') # 依次打印A, B, C, D
```
Python中万物皆对象,所以一些情况下函数也可以当成一个变量似的使用(JS类似,C里边函数指针)
```python
moves = ['up', 'left', 'down', 'right']
def move_up(x): # 定义向上的操作
x[1] += 1
def move_down(x): # 定义向下的操作
x[1] -= 1
def move_left(x): # 定义向左的操作
x[0] -= 1
def move_right(x): # 定义向右的操作
x[0] += 1
# 动作和执行的函数关联起来,函数作为键对应的值
actions = {
'up': move_up,
'down': move_down,
'left': move_left,
'right': move_right
}
coord = [0, 0]
for move in moves:
actions[move](coord)
print(coord)

生成器(Generator)

生成器是迭代器的一种,形式上看和函数很像,只是把return换成了yield,在每次调用的时候,都会执行到yield并返回值,同时将当前状态保存,等待下次执行到yield再继续

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 从10倒数到0
def countdown(x):
while x >= 0:
yield x
x -= 1
for i in countdown(10):
print(i)
# 打印小于100的斐波那契数
def fibonacci(n):
a = 0
b = 1
while b < n:
yield b
a, b = b, a + b
for x in fibonacci(100):
print(x)
# Python3.3以上可以return返回异常的说明
def another_fibonacci(n):
a = 0
b = 1
while b < n:
yield b
a, b = b, a + b
return "No more ..."
a = another_fibonacci(3)
print(next(a)) # 1
print(next(a)) # 1
print(next(a)) # 2
print(next(a)) # 抛出StopIteration异常并打印No more消息

类(Class)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class A:
"""Class A"""
def __init__(self, x, y, name):
self.x = x
self.y = y
self._name = name
def introduce(self):
print(self._name)
def greeting(self):
print("What's up!")
def __l2norm(self):
return self.x**2 + self.y**2
def cal_l2norm(self):
return self.__l2norm()
a = A(11, 11, 'Leonardo')
print(A.__doc__) # "Class A"
a.introduce() # "Leonardo"
a.greeting() # "What's up!"
print(a._name) # 可以正常访问
print(a.cal_l2norm()) # 输出11*11+11*11=242
print(a._A__l2norm()) # 仍然可以访问,只是名字不一样
print(a.__l2norm()) # 报错: 'A' object has no attribute '__l2norm'
# 继承用括号
class B(A):
"""Class B inheritenced from A"""
def greeting(self):
print("How's going!")
b = B(12, 12, 'Flaubert')
b.introduce() # Flaubert
b.greeting() # How's going!
print(b._name()) # Flaubert
print(b._A__l2norm()) # “私有”方法,必须通过_A__l2norm访问

异常

1
2
3
4
5
6
7
8
9
10
11
for filepath in filelist: # filelist中是文件路径的列表
try:
with open(filepath, 'r') as f:
# 执行数据处理的相关工作
...
print('{} is processed!'.format(filepath))
except IOError:
print('{} with IOError!'.format(filepath))
# 异常的相应处理
...

pip

pip 是一个安装和管理 Python 包的工具,提供了对 Python 包的查找、下载、安装、卸载的功能。

1
2
3
4
pip install requests
pip search xml
pip show beautifulsoup4
pip uninstall requests

科学计算包 – Numpy

numpy(Numerical Python extensions)是一个第三方的Python包,用于科学计算。这个库的前身是1995年就开始开发的一个用于数组运算的库。经过了长时间的发展,基本上成了绝大部分Python科学计算的基础包,当然也包括所有提供Python接口的深度学习框架。

最新的消息是Numpy将于2020年结束python2.7的支持,所以还是尽快迁移到3.x吧

Numpy 基本类型(array)

array,也就是数组,是numpy中最基础的数据结构,最关键的属性是维度和元素类型,在numpy中,可以非常方便地创建各种不同类型的多维数组,并且执行一些基本基本操作,来看例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import numpy as np #在导入numpy的时候,将np作为numpy的别名。这是一种习惯性的用法,包括吴恩达老师在内的很多大神都是这种习惯。
a = [1, 2, 3, 4] #
b = np.array(a) # array([1, 2, 3, 4])
type(b) # <type 'numpy.ndarray'>
b.shape # (4,)
b.argmax() # 3
b.max() # 4
b.mean() # 2.5
c = [[1, 2], [3, 4]] # 二维列表
d = np.array(c) # 二维numpy数组
d.shape # (2, 2)
d.size # 4
d.max(axis=0) # 找维度0,也就是最后一个维度上的最大值,array([3, 4])
d.max(axis=1) # 找维度1,也就是倒数第二个维度上的最大值,array([2, 4])
d.mean(axis=0) # 找维度0,也就是第一个维度上的均值,array([ 2., 3.])
d.flatten() # 展开一个numpy数组为1维数组,array([1, 2, 3, 4])
np.ravel(c) # 展开一个可以解析的结构为1维数组,array([1, 2, 3, 4])
# 3x3的浮点型2维数组,并且初始化所有元素值为1
e = np.ones((3, 3), dtype=np.float)
# 创建一个一维数组,元素值是把3重复4次,array([3, 3, 3, 3])
f = np.repeat(3, 4)
# 2x2x3的无符号8位整型3维数组,并且初始化所有元素值为0
g = np.zeros((2, 2, 3), dtype=np.uint8)
g.shape # (2, 2, 3)
h = g.astype(np.float) # 用另一种类型表示
l = np.arange(10) # 类似range,array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
m = np.linspace(0, 6, 5)# 等差数列,0到6之间5个取值,array([ 0., 1.5, 3., 4.5, 6.])
p = np.array(
[[1, 2, 3, 4],
[5, 6, 7, 8]]
)
np.save('p.npy', p) # 保存到文件
q = np.load('p.npy') # 从文件读取

array的数组相关操作也非常的丰富,包括:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import numpy as np
'''
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]])
'''
a = np.arange(24).reshape((2, 3, 4))
b = a[1][1][1] # 17
'''
array([[ 8, 9, 10, 11],
[20, 21, 22, 23]])
'''
c = a[:, 2, :]
''' 用:表示当前维度上所有下标
array([[ 1, 5, 9],
[13, 17, 21]])
'''
d = a[:, :, 1]
''' 用...表示没有明确指出的维度
array([[ 1, 5, 9],
[13, 17, 21]])
'''
e = a[..., 1]
'''
array([[[ 5, 6],
[ 9, 10]],
[[17, 18],
[21, 22]]])
'''
f = a[:, 1:, 1:-1]
'''
平均分成3份
[array([0, 1, 2]), array([3, 4, 5]), array([6, 7, 8])]
'''
g = np.split(np.arange(9), 3)
'''
按照下标位置进行划分
[array([0, 1]), array([2, 3, 4, 5]), array([6, 7, 8])]
'''
h = np.split(np.arange(9), [2, -3])
l0 = np.arange(6).reshape((2, 3))
l1 = np.arange(6, 12).reshape((2, 3))
'''
vstack是指沿着纵轴拼接两个array,vertical
hstack是指沿着横轴拼接两个array,horizontal
更广义的拼接用concatenate实现,horizontal后的两句依次等效于vstack和hstack
stack不是拼接而是在输入array的基础上增加一个新的维度
'''
m = np.vstack((l0, l1))
p = np.hstack((l0, l1))
q = np.concatenate((l0, l1))
r = np.concatenate((l0, l1), axis=-1)
s = np.stack((l0, l1))
'''
按指定轴进行转置
array([[[ 0, 3],
[ 6, 9]],
[[ 1, 4],
[ 7, 10]],
[[ 2, 5],
[ 8, 11]]])
'''
t = s.transpose((2, 0, 1))
'''
默认转置将维度倒序,对于2维就是横纵轴互换
array([[ 0, 4, 8],
[ 1, 5, 9],
[ 2, 6, 10],
[ 3, 7, 11]])
'''
u = a[0].transpose() # 或者u=a[0].T也是获得转置
'''
逆时针旋转90度,第二个参数是旋转次数
array([[ 3, 2, 1, 0],
[ 7, 6, 5, 4],
[11, 10, 9, 8]])
'''
v = np.rot90(u, 3)
'''
沿纵轴左右翻转
array([[ 8, 4, 0],
[ 9, 5, 1],
[10, 6, 2],
[11, 7, 3]])
'''
w = np.fliplr(u)
'''
沿水平轴上下翻转
array([[ 3, 7, 11],
[ 2, 6, 10],
[ 1, 5, 9],
[ 0, 4, 8]])
'''
x = np.flipud(u)
'''
按照一维顺序滚动位移
array([[11, 0, 4],
[ 8, 1, 5],
[ 9, 2, 6],
[10, 3, 7]])
'''
y = np.roll(u, 1)
'''
按照指定轴滚动位移
array([[ 8, 0, 4],
[ 9, 1, 5],
[10, 2, 6],
[11, 3, 7]])
'''
z = np.roll(u, 1, axis=1)

numpy的基础数学运算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import numpy as np
# 绝对值,1
a = np.abs(-1)
# sin函数,1.0
b = np.sin(np.pi/2)
# tanh逆函数,0.50000107157840523
c = np.arctanh(0.462118)
# e为底的指数函数,20.085536923187668
d = np.exp(3)
# 2的3次方,8
f = np.power(2, 3)
# 点积,1*3+2*4=11
g = np.dot([1, 2], [3, 4])
# 开方,5
h = np.sqrt(25)
# 求和,10
l = np.sum([1, 2, 3, 4])
# 平均值,5.5
m = np.mean([4, 5, 6, 7])
# 标准差,0.96824583655185426
p = np.std([1, 2, 3, 2, 1, 3, 2, 0])

numpy中的广播(broadcasting)

多个array的对位运算需要array的维度一致,如果一个array的维度和另一个array的子维度一致,则在没有对齐的维度上分别执行对位运算,这种机制叫做广播(broadcasting),吴恩达老师在他的deeplearning教程中想系介绍过这种机制,这里就不细说了,只看例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import numpy as np
a = np.array([
[1, 2, 3],
[4, 5, 6]
])
b = np.array([
[1, 2, 3],
[1, 2, 3]
])
'''
维度一样的array,对位计算
array([[2, 4, 6],
[5, 7, 9]])
'''
a + b
'''
array([[0, 0, 0],
[3, 3, 3]])
'''
a - b
'''
array([[ 1, 4, 9],
[ 4, 10, 18]])
'''
a * b
'''
array([[1, 1, 1],
[4, 2, 2]])
'''
a / b
'''
array([[ 1, 4, 9],
[16, 25, 36]])
'''
a ** 2
'''
array([[ 1, 4, 27],
[ 4, 25, 216]])
'''
a ** b
c = np.array([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[10, 11, 12]
])
d = np.array([2, 2, 2])
'''
广播机制让计算的表达式保持简洁
d和c的每一行分别进行运算
array([[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11],
[12, 13, 14]])
'''
c + d
'''
array([[ 2, 4, 6],
[ 8, 10, 12],
[14, 16, 18],
[20, 22, 24]])
'''
c * d
'''
1和c的每个元素分别进行运算
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11]])
'''
c - 1

线性代数模块(linalg)

线性代数模块(linalg)是深度学习中最常用的模块之一,
numpy提供的基本函数,可以对向量,矩阵,或是说多维张量进行一些基本的运算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import numpy as np
a = np.array([3, 4])
np.linalg.norm(a)
b = np.array([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
])
c = np.array([1, 0, 1])
# 矩阵和向量之间的乘法
np.dot(b, c) # array([ 4, 10, 16])
np.dot(c, b.T) # array([ 4, 10, 16])
np.trace(b) # 求矩阵的迹,15
np.linalg.det(b) # 求矩阵的行列式值,0
np.linalg.matrix_rank(b) # 求矩阵的秩,2,不满秩,因为行与行之间等差
d = np.array([
[2, 1],
[1, 2]
])
'''
对正定矩阵求本征值和本征向量
本征值为u,array([ 3., 1.])
本征向量构成的二维array为v,
array([[ 0.70710678, -0.70710678],
[ 0.70710678, 0.70710678]])
是沿着45°方向
eig()是一般情况的本征值分解,对于更常见的对称实数矩阵,
eigh()更快且更稳定,不过输出的值的顺序和eig()是相反的
'''
u, v = np.linalg.eig(d)
# Cholesky分解并重建
l = np.linalg.cholesky(d)
'''
array([[ 2., 1.],
[ 1., 2.]])
'''
np.dot(l, l.T)
e = np.array([
[1, 2],
[3, 4]
])
# 对不镇定矩阵,进行SVD分解并重建
U, s, V = np.linalg.svd(e)
S = np.array([
[s[0], 0],
[0, s[1]]
])
'''
array([[ 1., 2.],
[ 3., 4.]])
'''
np.dot(U, np.dot(S, V))

随机模块(random)

随机模块包含了随机数产生和统计分布相关的基本函数,Python本身也有随机模块random,不过功能更丰富,一般情况下都是用来对神经网络参数进行初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import numpy as np
import numpy.random as random
# 设置随机数种子
random.seed(42)
# 产生一个1x3,[0,1)之间的浮点型随机数
# array([[ 0.37454012, 0.95071431, 0.73199394]])
# 后面的例子就不在注释中给出具体结果了
random.rand(1, 3)
# 产生一个[0,1)之间的浮点型随机数
random.random()
# 下边4个没有区别,都是按照指定大小产生[0,1)之间的浮点型随机数array,不Pythonic…
random.random((3, 3))
random.sample((3, 3))
random.random_sample((3, 3))
random.ranf((3, 3))
# 产生10个[1,6)之间的浮点型随机数
5*random.random(10) + 1
random.uniform(1, 6, 10)
# 产生10个[1,6)之间的整型随机数
random.randint(1, 6, 10)
# 产生2x5的标准正态分布样本
random.normal(size=(5, 2))
# 产生5个,n=5,p=0.5的二项分布样本
random.binomial(n=5, p=0.5, size=5)
a = np.arange(10)
# 从a中有回放的随机采样7个
random.choice(a, 7)
# 从a中无回放的随机采样7个
random.choice(a, 7, replace=False)
# 对a进行乱序并返回一个新的array
b = random.permutation(a)
# 对a进行in-place乱序
random.shuffle(a)
# 生成一个长度为9的随机bytes序列并作为str返回
# '\x96\x9d\xd1?\xe6\x18\xbb\x9a\xec'
random.bytes(9)

可视化包 – Matplotlib

Matplotlib是Python中最常用的可视化工具之一,可以非常方便地创建海量类型地2D图表和一些基本的3D图表。Matplotlib最早是为了可视化癫痫病人的脑皮层电图相关的信号而研发,因为在函数的设计上参考了MATLAB,所以叫做Matplotlib。Matplotlib首次发表于2007年,在开源和社区的推动下,现在在基于Python的各个科学计算领域都得到了广泛应用。

2D图表

2D图表是最简单的图表,也是在机器学习和深度学习中用到最多的,
Matplotlib中最基础的模块是pyplot。先从最简单的点图和线图开始,比如我们有一组数据,还有一个拟合模型,通过下面的代码图来可视化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
# 通过rcParams设置全局横纵轴字体大小
mpl.rcParams['xtick.labelsize'] = 24
mpl.rcParams['ytick.labelsize'] = 24
np.random.seed(42)
# x轴的采样点
x = np.linspace(0, 5, 100)
# 通过下面曲线加上噪声生成数据,所以拟合模型就用y了……
y = 2*np.sin(x) + 0.3*x**2
y_data = y + np.random.normal(scale=0.3, size=100)
# figure()指定图表名称
plt.figure('data')
# '.'标明画散点图,每个散点的形状是个圆
plt.plot(x, y_data, '.')
# 画模型的图,plot函数默认画连线图
plt.figure('model')
plt.plot(x, y)
# 两个图画一起
plt.figure('data & model')
# 通过'k'指定线的颜色,lw指定线的宽度
# 第三个参数除了颜色也可以指定线形,比如'r--'表示红色虚线
# 更多属性可以参考官网:http://matplotlib.org/api/pyplot_api.html
plt.plot(x, y, 'k', lw=3)
# scatter可以更容易地生成散点图
plt.scatter(x, y_data)
# 将当前figure的图保存到文件result.png
plt.savefig('result.png')
# 一定要加上这句才能让画好的图显示在屏幕上
plt.show()

点和线图表只是最基本的用法,其实这对于机器学习领域已经差不多够了,但是有的时候我们在分析时可能会需要对数据进行对比,这就需要用到柱状或饼状类型的图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.rcParams['axes.titlesize'] = 20
mpl.rcParams['xtick.labelsize'] = 16
mpl.rcParams['ytick.labelsize'] = 16
mpl.rcParams['axes.labelsize'] = 16
mpl.rcParams['xtick.major.size'] = 0
mpl.rcParams['ytick.major.size'] = 0
# 包含了狗,猫和猎豹的最高奔跑速度,还有对应的可视化颜色
speed_map = {
'dog': (48, '#7199cf'),
'cat': (45, '#4fc4aa'),
'cheetah': (120, '#e1a7a2')
}
# 整体图的标题
fig = plt.figure('Bar chart & Pie chart')
# 在整张图上加入一个子图,121的意思是在一个1行2列的子图中的第一张
ax = fig.add_subplot(121)
ax.set_title('Running speed - bar chart')
# 生成x轴每个元素的位置
xticks = np.arange(3)
# 定义柱状图每个柱的宽度
bar_width = 0.5
# 动物名称
animals = speed_map.keys()
# 奔跑速度
speeds = [x[0] for x in speed_map.values()]
# 对应颜色
colors = [x[1] for x in speed_map.values()]
# 画柱状图,横轴是动物标签的位置,纵轴是速度,定义柱的宽度,同时设置柱的边缘为透明
bars = ax.bar(xticks, speeds, width=bar_width, edgecolor='none')
# 设置y轴的标题
ax.set_ylabel('Speed(km/h)')
# x轴每个标签的具体位置,设置为每个柱的中央
ax.set_xticks(xticks+bar_width/2)
# 设置每个标签的名字
ax.set_xticklabels(animals)
# 设置x轴的范围
ax.set_xlim([bar_width/2-0.5, 3-bar_width/2])
# 设置y轴的范围
ax.set_ylim([0, 125])
# 给每个bar分配指定的颜色
for bar, color in zip(bars, colors):
bar.set_color(color)
# 在122位置加入新的图
ax = fig.add_subplot(122)
ax.set_title('Running speed - pie chart')
# 生成同时包含名称和速度的标签
labels = ['{}\n{} km/h'.format(animal, speed) for animal, speed in zip(animals, speeds)]
# 画饼状图,并指定标签和对应颜色
ax.pie(speeds, labels=labels, colors=colors)
plt.show()

3D图表

Matplotlib中也能支持一些基础的3D图表,比如曲面图,散点图和柱状图。这些3D图表需要使用mpl_toolkits模块

生成一个所有值均为0的复数array作为初始频谱,然后把频谱中央部分用随机生成,但同时共轭关于中心对称的子矩阵进行填充。这相当于只有低频成分的一个随机频谱。最后进行反傅里叶变换就得到一个随机波动的曲面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import matplotlib.pyplot as plt
import numpy as np
# 3D图标必须的模块,project='3d'的定义
from mpl_toolkits.mplot3d import Axes3D
np.random.seed(42)
n_grids = 51 # x-y平面的格点数
c = n_grids / 2 # 中心位置
nf = 2 # 低频成分的个数
# 生成格点
x = np.linspace(0, 1, n_grids)
y = np.linspace(0, 1, n_grids)
# x和y是长度为n_grids的array
# meshgrid会把x和y组合成n_grids*n_grids的array,X和Y对应位置就是所有格点的坐标
X, Y = np.meshgrid(x, y)
# 生成一个0值的傅里叶谱
spectrum = np.zeros((n_grids, n_grids), dtype=np.complex)
# 生成一段噪音,长度是(2*nf+1)**2/2
noise = [np.complex(x, y) for x, y in np.random.uniform(-1,1,((2*nf+1)**2/2, 2))]
# 傅里叶频谱的每一项和其共轭关于中心对称
noisy_block = np.concatenate((noise, [0j], np.conjugate(noise[::-1])))
# 将生成的频谱作为低频成分
spectrum[c-nf:c+nf+1, c-nf:c+nf+1] = noisy_block.reshape((2*nf+1, 2*nf+1))
# 进行反傅里叶变换
Z = np.real(np.fft.ifft2(np.fft.ifftshift(spectrum)))
# 创建图表
fig = plt.figure('3D surface & wire')
# 第一个子图,surface图
ax = fig.add_subplot(1, 2, 1, projection='3d')
# alpha定义透明度,cmap是color map
# rstride和cstride是两个方向上的采样,越小越精细,lw是线宽
ax.plot_surface(X, Y, Z, alpha=0.7, cmap='jet', rstride=1, cstride=1, lw=0)
# 第二个子图,网线图
ax = fig.add_subplot(1, 2, 2, projection='3d')
ax.plot_wireframe(X, Y, Z, rstride=3, cstride=3, lw=0.5)
plt.show()

散点图也是常常用来查看空间样本分布的一种手段,并且画起来比表面图和网线图更加简单,先采样了一堆3维的正态分布样本,保证方向上的均匀性。然后归一化,让每个样本到原点的距离为1,相当于得到了一个均匀分布在球面上的样本。再接着把每个样本都乘上一个均匀分布随机数的开3次方,这样就得到了在球体内均匀分布的样本,最后根据判别平面3x+2y-z-1=0对平面两侧样本用不同的形状和颜色画出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
np.random.seed(42)
# 采样个数500
n_samples = 500
dim = 3
# 先生成一组3维正态分布数据,数据方向完全随机
samples = np.random.multivariate_normal(
np.zeros(dim),
np.eye(dim),
n_samples
)
# 通过把每个样本到原点距离和均匀分布吻合得到球体内均匀分布的样本
for i in range(samples.shape[0]):
r = np.power(np.random.random(), 1.0/3.0)
samples[i] *= r / np.linalg.norm(samples[i])
upper_samples = []
lower_samples = []
for x, y, z in samples:
# 3x+2y-z=1作为判别平面
if z > 3*x + 2*y - 1:
upper_samples.append((x, y, z))
else:
lower_samples.append((x, y, z))
fig = plt.figure('3D scatter plot')
ax = fig.add_subplot(111, projection='3d')
uppers = np.array(upper_samples)
lowers = np.array(lower_samples)
# 用不同颜色不同形状的图标表示平面上下的样本
# 判别平面上半部分为红色圆点,下半部分为绿色三角
ax.scatter(uppers[:, 0], uppers[:, 1], uppers[:, 2], c='r', marker='o')
ax.scatter(lowers[:, 0], lowers[:, 1], lowers[:, 2], c='g', marker='^')
plt.show()

图像显示

Matplotlib也支持图像的存取和显示,读取一个本地图片并显示,还可以对图片进行简单的处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import matplotlib.pyplot as plt
# 读取一张小白狗的照片并显示
plt.figure('A Little White Dog')
little_dog_img = plt.imread('little_white_dog.jpg')
plt.imshow(little_dog_img)
# Z是上小节生成的随机图案,img0就是Z,img1是Z做了个简单的变换
img0 = Z
img1 = 3*Z + 4
# cmap指定为'gray'用来显示灰度图
fig = plt.figure('Auto Normalized Visualization')
ax0 = fig.add_subplot(121)
ax0.imshow(img0, cmap='gray')
ax1 = fig.add_subplot(122)
ax1.imshow(img1, cmap='gray')
plt.show()

OpenCV

OpenCV是计算机视觉领域应用最广泛的开源工具包,OpenCV最早源于Intel公司1998年的一个研究项目,当时在Intel从事计算机视觉的工程师盖瑞·布拉德斯基(Gary Bradski)访问一些大学和研究组时发现学生之间实现计算机视觉算法用的都是各自实验室里的内部代码或者库,这样新来实验室的学生就能基于前人写的基本函数快速上手进行研究。于是OpenCV旨在提供一个用于计算机视觉的科研和商业应用的高性能通用库。

windows环境下安装

1
pip install opencv_python

验证:如果没报错,说明安装问没问题

1
import cv2

模块介绍

calib3d : Calibration(校准)加3D这两个词的组合缩写。这个模块主要是相机校准和三维重建相关的内容。基本的多视角几何算法,单个立体摄像头标定,物体姿态估计,立体相似性算法,3D信息的重建等等。

contrib : Contributed/Experimental Stuf的缩写, 该模块包含了一些最近添加的不太稳定的可选功能,不用去多管。2.4.8以后新增了新型人脸识别,立体匹配,人工视网膜模型等技术。
 
core——核心功能模块,包含如下内容:

  • OpenCV基本数据结构
  • 动态数据结构
  • 绘图函数
  • 数组操作相关函数
  • 辅助功能与系统函数和宏
  • 与OpenGL的互操作

imgproc: Image和Processing这两个单词的缩写组合。图像处理模块,这个模块包含了如下内容:

  • 线性和非线性的图像滤波
  • 图像的几何变换
  • 其它(Miscellaneous)图像转换
  • 直方图相关
  • 结构分析和形状描述
  • 运动分析和对象跟踪
  • 特征检测
  • 目标检测等内容

features2d:Features2D, 2D功能框架 ,包含如下内容:

  • 特征检测和描述
  • 特征检测器(Feature Detectors)通用接口
  • 描述符提取器(Descriptor Extractors)通用接口
  • 描述符匹配器(Descriptor Matchers)通用接口
  • 通用描述符(Generic Descriptor)匹配器通用接口
  • 关键点绘制函数和匹配功能绘制函数

flann:Fast Library for Approximate Nearest Neighbors,高维的近似近邻快速搜索算法库,包含两个部分:

  • 快速近似最近邻搜索
  • 聚类

gpu:运用GPU加速的计算机视觉模块

highgui:high gui,高层GUI图形用户界面,包含媒体的I / O输入输出,视频捕捉、图像和视频的编码解码、图形交互界面的接口等内容

legacy:一些已经废弃的代码库,保留下来作为向下兼容,包含如下相关的内容:

  • 运动分析
  • 期望最大化
  • 直方图
  • 平面细分(C API)
  • 特征检测和描述(Feature Detection and Description)
  • 描述符提取器(Descriptor Extractors)的通用接口
  • 通用描述符(Generic Descriptor Matchers)的常用接口
  • 匹配器

ml : Machine Learning,机器学习模块, 基本上是统计模型和分类算法,包含如下内容:

  • 统计模型 (Statistical Models)
  • 一般贝叶斯分类器 (Normal Bayes Classifier)
  • K-近邻 (K-NearestNeighbors)
  • 支持向量机 (Support Vector Machines)
  • 决策树 (Decision Trees)
  • 提升(Boosting)
  • 梯度提高树(Gradient Boosted Trees)
  • 随机树 (Random Trees)
  • 超随机树 (Extremely randomized trees)
  • 期望最大化 (Expectation Maximization)
  • 神经网络 (Neural Networks)
  • MLData

nonfree:一些具有专利的算法模块 ,包含特征检测和GPU相关的内容。最好不要商用,可能会被告哦。

objdetect:目标检测模块,包含Cascade Classification(级联分类)和Latent SVM这两个部分。

ocl:OpenCL-accelerated Computer Vision,运用OpenCL加速的计算机视觉组件模块

photo:Computational Photography,包含图像修复和图像去噪两部分

stitching:images stitching,图像拼接模块,包含如下部分:

  • 拼接流水线
  • 特点寻找和匹配图像
  • 估计旋转
  • 自动校准
  • 图片歪斜
  • 接缝估测
  • 曝光补偿
  • 图片混合

superres:SuperResolution,超分辨率技术的相关功能模块

ts:opencv测试相关代码

vide:视频分析组件,该模块包括运动估计,背景分离,对象跟踪等视频处理相关内容。

Videostab:Video stabilization,视频稳定相关的组件

与tf整合

1.TensorFlow与OpenCV,读取图片,进行简单操作并显示
1 OpenCV读入图片,使用tf.Variable初始化为tensor,加载到tensorflow对图片进行转置操作,然后opencv显示转置后的结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import tensorflow as tf
import cv2
filename = "a.jpg"
image = cv2.imread(filename, 1)
cv2.namedWindow('image'0)
cv2.imshow('image', image)
# Create a TensorFlow Variable
x = tf.Variable(image, name='x')
model = tf.initialize_all_variables()
with tf.Session() as session:
  x = tf.transpose(x, perm=[102])
  session.run(model)
  result = session.run(x)
cv2.namedWindow('result'0)
cv2.imshow('result', result)
cv2.waitKey(0)

2.OpenCV读入图片,使用tf.placeholder符号变量加载到tensorflow里,然后tensorflow对图片进行剪切操作,最后opencv显示转置后的结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import tensorflow as tf
import cv2
# First, load the image again
filename = "a.jpg"
raw_image_data = cv2.imread(filename)
image = tf.placeholder("uint8", [NoneNone3])
slice = tf.slice(image, [100000], [3000-1-1])
with tf.Session() as session:
    result = session.run(slice, feed_dict={image: raw_image_data})
    print(result.shape)
cv2.namedWindow('image'0)
cv2.imshow('image', result)
cv2.waitKey(0)