今天是新专栏《AI白身境》的第三篇,所谓白身,就是什么都不会,还没有进入角色。
上一篇给大家介绍了如何正确使用Linux,如何利用shell,vim,git这三大神器。相信大家也掌握的差不多了,今天就和大家分享下对于python,我们应该如何掌握,如何正确把它和深度学习完美的结合起来。
作者 | 汤兴旺 言有三
编辑 | 汤兴旺 言有三
01
基础操作
人生苦短,必须学好python!python现在火的程度已经不需要我多言了,它为什么为火,我认为有两个原因,第一是人工智能这个大背景,第二是它真的太容易学了,没有任何一门语言比它好上手,接下来我将和大家分享下python的基础操作。另外请注意,我的所有操作都是基于python3!
1.1 python核心内容之函数
如果你想要学好python,务必学好function,不然就相当于没学过python。
1.1.1 函数定义
在python函数定义时有五个要点,分别是def、函数名、函数体、参数、返回值、以及两个英文版符号:小括号(括号内为参数)和冒号。下面对这5点分别解释下:
def:函数关键字。必须要有,系统看到它,就知道下面是个函数了。
函数名:函数的名称。就是给函数起了个名字,当你调用函数时,用函数名就可以直接调用了。
函数体:函数中进行的具体操作。就是你这个函数想要实现的功能。
参数:提供给函数体。
返回值:当函数执行完毕后,可以给调用者返回想要的数据。
下面通过一个具体的实例来说明下:
def get_image(picture_path):
img = cv2.imread("picture_path")
return img
上面实例中,get_image是这个函数的函数名,这个函数的参数是picture_path,就是图片的路径,这个参数会传到函数体中。如果你的图片路径是d://01.jpg,这时候函数体就会变成img = cv2.imread("d://01.jpg"),最后返回图片。
1.1.2 函数参数
相信你已经知道函数应该如何定义了,接下来再说说函数中最难理解也是最重要的一点,那就是函数参数。
首先我们说说位置参数。
def sum(x):
z = x+x
return z
>>>sum(10)
20
这里的x可以认为是一个位置参数,顾名思义,x先占一个位置,当给予它一个值时,它会传到函数体中,注意像这种位置参数,务必要给予一个值,不然程序会报错。
接下来说说默认参数。
def sum(x,y=12):
z = x+y
return z
>>>sum(10)
22
>>>sum(10,13)
23
这个实例中,y = 12就是个默认参数,当该参数没有传入相应的值时,该参数就使用默认值。但有点需要注意:默认参数必须在位置参数后面,否则会报错。
哈哈,报错了,千万不要放这样的错误哟,想避免这样的错误很简单,就从你定义的顺序从前往后写就行。
然后再说说可变参数。
在使用python函数时,有时候我们不知道我们需要传入多少个参数,于是就有了可变参数的这个概念。为了更好的理解这个概念,先抛出一个问题:计算a+b+c+d+...的和,因为不知道有几个数字,所以是个可变的问题。那么如何用python函数来解决这个问题呢,如下:
def sum(*numbers):
sum = 0
for n in numbers:
sum =sum +n*n
return sum
>>>sum(10,2,12,3,4)
我们在参数前面加了一个*号。这样这个参数就变成了可变参数。在调用该函数时,可以传入任意个参数,包括0个参数。
最后说一下关键字参数。
什么是关键字参数,对于这个概念我们先看下面的代码:
def penson(name,age,**kw):
print('name:',name,'age:',age,'other:',kw)
>>>person('zhang san',24,city='changchun')
name:zhang san age:24 other:{'city':'changchun'}
通过上面的例子你应该明白了关键字参数是什么了吧,实际上就是你传入的参数比你之前定义的参数会多,注意位置参数必须要给它传值。
这就是python函数的一些基本的方法,更复杂的函数实际上也就是上面的组合而已,只要多加练习,一定能够很好的掌握它。
1.2 python 缩进规则
你可能已经注意到上面我写python函数时用到了许多缩进,你可能也会问自己为什么要采用缩进,应该如何缩进这些问题,下面请看我一一道来。
1.2.1 python缩进的由来
我们在大学时可能都学过c语言,在c中主要通过{}来区分代码快,但我们初学者往往忘记打{},而且花括号多了,我们就晕了。而python就不会出现这种问题,python中的缩进可以理解为c中的{}。我们来看下下面这个例子:
def SayHello():
print("hello world")
SayHello()
你会发现此时不能输出任何结果,我们再看下面一段代码
def SayHello():
print("hello world")
SayHello()
这样就成功了,为什么会这样呢,下面我介绍一种画框法。如下图所示相同颜色框在一起说明它们是属于同一代码块。
这段代码只是定义了一个函数并未执行它,正确的写法如下:
以后大家可以用这种画框法确定缩进是否正确。
02
矩阵库——NumPy
NumPy(Numerical Python) 是 Python语言的一个扩展程序库,支持高维数组与矩阵运算,提供了大量的数学函数库。
对于深度学习来说,高维数组我们用的很多,因此要想学好深度学习,必须对NumPy了如指掌。
2.1 ndarray对象
在NumPy中我们用ndarray表示数组,可以说它是整个库的核心。下面我们将从以下几个方面来理解ndarray。
2.2 创建数组
要想对数组进行运算操作,我们必须先创建个数组。方法如下:
import numpy as np#导入numpy这个包
a0 = np.array([1,2,3,4])#采用列表方式
a1 = np.array((1,2,3,4))#采用元组方式
对于多维数组的创建(注意中括号),如下:
import numpy as np
a = np.array([[1,2,3],[2,3,4],[4,5,6]])
上面我们创建的数组里面的元素都是我们指定的,那么如何自动生成数组?又如何随机的生成一个数组呢?我们首先看第一个方法arange(),如下:
import numpy as np
a = np.arange(0,1,0.1)
在上面这个数组中,arange()的第一个值代表开始值,第二个值代表终值(不包括这个值),最后一个值代表步长(间隔),如arange(1,10,1)代表一个从0-9,步长为1的数组。这就是arange(),经常用的到!我们再看第二个方法linspace(),如下:
import numpy as np
a = np.linspace(0,10,10)
对于linspace(),它的前两个值和arange()一样,代表开始值和终值,但有个区别是linspace()默认包括终值,如果你不想包括终值,加上endpoint = False即可,对于第三个值它是指元素的个数,这个和arange不一样,一定不要混淆。
最后我们再说下如何创建一个随机数组。
在NumPy中有一庞大的函数库,对于随机数我们可以采用numpy.random模块,该模块中有大量和随机数相关的函数。一些函数如下:
我们可以利用这些函数来创建你想要的随机数,一些实例如下:
import numpy as np
a = np.random.rand(2,2)
b = np.random.randn(2,2)
c = np.random.randint(0,9,(2,2))
创建随机数是不是很简单,其实对于数组的创建还有许多方法,如下面所示:
np.zeros() :生成元素全是0的数组
np.ones():生成元素全是1的数组
np.zeros_like(a):生成形状和a一样且元素全是0的数组
np.ones_like(a):生成形状和a一样且元素全是1的数组
...
相信通过上面的介绍你已经掌握了如何创建一个数组了,很好!那么我们再思考一个问题,若碰到一个元素很多的数组,但却不知道它的形状等参数,这时该怎么办呢?对于这个问题我们可以通过下面的一些方法来解决。
获取数组a的shape:a.shape
获取数组a的元素类型:a.dtype
获取数组a的维度:a.ndim
....
2.3 存取数组
当一个数组创建好后,我们有时候可能需要对一个数组中的一些具体元素进行运算,或者更改数组中一些元素的值。进行这些操作的前提是先能存取数组,为了解决这个问题,这里我们主要介绍切片法和整数列表来存取数组元素,这种方法其实也是最常见的。
import numpy as np
a = np.array([4,2,3,5,9,0,,6,8,7])
>>>[4,2,3,5,9,0,6,8,7]
对于上面这个数组,如果我想要得到5这个元素该怎么办呢?很简单,在ndarray中第一个元素的位置是0,本例中5在第四个位置,所以a[3] = 5。
我们还可以用切片获取数组的一部分,如a[3:5]表示获取第四个位置和第五个位置的元素,a[3:5]=[5,9];a[::-1]表示从最后一个元素到第一个元素,该方法省略了开始下标和结束下标,这时候开始下标就是对应第一个元素,结束下标就对应着最后一个数,-1表示步长为1,负号从后往前数。
上面说的都是一维数组的存取,我们再来说一下二维数组。其实二维数组和一维数组数组类似,只是二维数组有2个轴,所以下标自然需要2个值来表示。请看下面的实例:
在二维数组中竖轴表示第0轴,横轴表示第1轴,读取元素时我们通过逗号把0轴和1轴隔开,这样就可以通过一维数组的方法来读取,最后两者的交集就是我们需要读取的元素。
我们再看下三维数组,这也是最复杂的,在深度学习特征数据处理时用的是最多的。我们先创建一个3行5列3通道的数组,看看效果。
再来分析下这个生成的数组。我们知道这个三维数组有下图所示的三块,而第几块又代表通道的第几行数据,图中圈的那个块就是通道的第2行数据,另外在每一个块里面每行数据代表通道的第几列数据。图中圈的那个块5有行数据,则代表着这个通道有5列数据。
其次在这个三维数组中,有下面图示的这样三列,一列代表一个通道。另外要注意所有的数据位置的下标都是从0开始。
下面我要把图示的元素改成8该怎么办呢?如下:
通过上面的例子你是否理解了三维数组应该怎样存取数据了呢?理解了的话就打开vim多写写基本就能深刻的掌握了。
2.4 NumPy常见函数使用
现在我们已经学会了创建数组和数组的存取,那么我们该如何对数组进行函数运算呢,这也是NumPy的核心内容。
2.4.1 数组维度变换
我们首先说一下如何对数组的形状进行整理,即将一个任意形状的矩阵转化我们想要转化的任意形状,当然要想完成这个操作,元素个数必须要满足。请看下面实例:
import numpy as np
a = np.arange(0,10,1)
b = a.reshape(2,5)
print(a)
print(b)
上面的实例通过reshape()函数把一个1维数组,变成了一个2行5列的一个数组。reshape()里面的参数就是你想要转换成的数组的形状。再看一个实例对reshape()熟练下,如下:
import numpy as np
a = np.arange(0,10,1)
b = a.reshape(2,-1)
c = a.reshape(-1,5)
print(a)
print(b)
print(c)
b和c的结果是一样的,而且和上一个实例的结果也一样,这是为什么呢?其实这里面的-1代表自动生成的意思,意思就是对于b我已经指定了数组的行是2行,那么系统就会自动生成一个5列,因为是10个数,必须是5列,所以b和c仍然是2行5列的数组,这就是数组形状变换。
说完数组形状变换我们再看下如何对数组进行维度交换。请看下面实例:
import numpy as np
a = np.arange(10).reshape(2,5)
b = a.swapaxes(0,1)
print(a)
print(b)
通过上面实例我们看出通过swapaxes()将一个数组的第0轴和第1轴进行了交换,由2行5列变成了5列2行。这是二维数组的维度交换,我们再看一个三维数组的例子,如下:
import numpy as np
a = np.arange(24).reshape(2,3,4)
b = a.swapaxes(0,1)
print(a)
print(b)
这个实例我将三维数组的第0轴和第1轴进行了交换,第0轴就是我在上面2.3存取数组这一节中说的块,第1轴就是块中的行,下面我将我对三维数组维度交换的理解和大家分享下。
如下,我们首先将第一块第一行的[0,1,2,3]的位置记为(1,1),第一块第二行的[4,5,6,7]的位置记为(1,2),第二块第三行的[20,21,22,23]记为(2,3),其它几个位置坐标类推。现在我们需要将第0轴和第1轴交换,所以第一块第一行的[0,1,2,3]的位置变为(1,1),就是第一块第一行;第一块第二行的[4,5,6,7]的位置变为为(2,1),就是第二块第一行;第二块第三行的[20,21,22,23]变为(3,2),就是第三块第二行。通过这样的理解你对上面实例输出的结果明白了吗?明白的话,请继续往下学如何对数组进行降维。
对于数组降维,我们继续通过实例来分析,如下:
import numpy as np
a = np.arange(10).reshape(2,5)
b =np.flatten()
c = a.reshape(-1)
d = a.ravel()
print(a)
print(b)
print(c)
print(d)
可以看出我们通过reshape(-1)、flatten()和ravel()函数将多维很容易就变成了1维数组。
2.4.2 堆叠数组
我们再说一下数组的堆叠,这个也是经常会用的。数组的堆叠通常有水平叠加和垂直叠加,分别用到hstack()和vstack()函数,请看下面的实例:
import numpy as np
a = np.array([1,2,3,4])
b = np.array([5,6,7,8])
c = np.hstack((a,b))
d = np.vstack((a,b))
print(c)
print(d)
通过这个例子我们也看出通过hstack()和vstack()将数组a和b堆叠成了一个数组。
上面就是我对NumPy在深度学习中最常见的几点的介绍,其实还有许多,平时多多积累就行。
03
数据可视化——matplotlib
说完python我们再说说深度学习中用的比较多的matplotlib。matplotlib是python中最常用的可视化工具之一,用处非常大。
3.1 使用pyplot模块绘图
我们先通过matplotlib和NumPy绘制一个图像。
import matplotlib.pyplot as plt
import numpy as np
x= np.linspace(0,10,100)
y=np.sin(x)
plt.figure(figsize=(8,4))
plt.plot(x,y)
plt.show()
在这个实例中,我们首先通过import matplotlib的绘图块pyplot,并重新命名为plt。然后用figure调出一个画布,figsize参数指定画布的宽度和高度,单位是英寸(1英寸为25.4毫米)。创建好画布后,我们就可以用plot()在画布上画图了,plot()的前两个参数分别代表X,Y轴数据的对象。另外plot()参数还可以指定曲线的标签,颜色,线宽等。
其实我们还能对坐标轴通过下面的方法进行一些参数的设置:
xlabel,ylabel:分别设置X,Y轴的标题文字
title:设置标题
xlim,ylim:分别设置X,Y轴的显示范围
legend:显示图例
请看下面一个标准的图形:
接下来我们再看看如何画直方图,直方图在图像处理中经常会用到。
在用plt.hist()画直方图时,第一个参数是绘图数据,这是必须要有的;另外bins代表直方图的长条形数目,默认为10;normed表示是否将得到的直方图向量归一化,默认为0,代表不归一;facecolor代表长条形的颜色;edgecolor代表长条行边框的颜色;alpha代表透明度。
3.2 matlibplot读取图像
matplotlib的imread和imshow()提供了图像的读取和显示功能,另外imread()从图像文件中读入数据得到的是一个图像的NumPy数组。
现在我们用matlibplot读取上面这一张可爱的猫图,方法如下:
import matplotlib.pyplot as plt
img = plt.imread("02.jpg")
plt.imshow(img)
plt.show()
可以看出,很容易就能读取一张图片。我们可以通过下面一些方法查看这张图片的属性。
print(img.shape)
print(img.dtype)
我们再看看matplotlib读取的图像是不是NumPy数组,如下:
可以明显看到这是ndarray格式,总共三个通道,分别代表RGB。
3.3 matplotlib工具栏
从上面的例子中就可以看到,当显示一张图片时,菜单栏自动生成了一些按钮,这些按钮都有各自的功能。
3.3.1 前进后退按钮
这三个按钮就像是我们使用的浏览器中的主页和前进后退按钮一样,一开始这三个图是没有什么用的,因为它本来就处于主页,既不能前进也不能后退,当你使用平移和缩放功能后,每一次操作就相当于在浏览器中点开了一个网页一样,这时候你就可以使用前进后退和回到最开始状态的按钮了。
3.3.2 平移缩放按钮
这个按钮也比较简单,按住鼠标左键在图片区域左右移动可以实现图像的左右平移,上下移动就可以使图像上下平移,按住X或者Y键移动即只能在X或者Y方向上平移。同理按住鼠标右键就是缩放。如果按住Ctrl键再进行上述操作,则是XY轴成比例平移或缩放。
3.3.3 缩放到指定矩形按钮
按住鼠标左键或者右键,选定一个矩形区域,即可将图形放大或者缩小到制定的矩形区域中。
在放大局部细节图时经常使用。
3.3.4 设置子图参数按钮
点击该按钮可以设置子绘图区域的长度和宽度,还可以设置各个子图之间的距离。
3.3.5 保存按钮
该按钮可以将图像保存为png、pdf等格式。
matplotlib的一些基础知识就介绍到这里,大家一定要多加实践,这样才能更好的掌握。
04
必备的python库
要想深度学习学的好,必须非常好的掌握python各种库,这是进行深度学习的基础。下面我和大家分享下一些常用的库,其实上面我已经介绍了两个了那就是NumPy和matplotlib,还有一些其他的库,请继续往下看。
4.1 科学计算与数据处理库
说到科学计算和数据处理,我们可能马上就会想到NumPy但其实还有两个其他的库,那就是SciPy和Pandas。
Scipy在Numpy的基础上增加了众多的数学计算、科学计算及工程计算中常用的模块,例如线性代数、图像处理等。在Scipy中的ndimage子模块就是致力于进行图像处理的。
Pandas是基于NumPy开发,提供了众多更高级的数据处理工能。Pandas中包含许多用于分组,过滤和组合数据的内置方法,以及时间序列功能。
有机会我们再说说这两个库。
4.2 深度学习框架
目前深度学习框架已经呈百家争鸣之态势,有Caffe、TensorFlow、Pytorch、Keras等等,对于我们来说,不可能都能掌握,但市面上主流的框架我们还是必须要熟练的掌握。
这些深度学习框架,我们在公众号的往期文章已经说过大半,大家可以自行翻阅。
4.3 服务端Flask
Flask是一个微型的服务端框架,它旨在保持核心的简单,但同时又易于扩展。默认情况下,Flask不包含数据库抽象层、表单验证,或是其他任何已有多种库可以胜任的功能。然而,Flask 支持用扩展来给应用添加这些功能。众多的扩展提供了数据库集成、表单验证、上传处理、各种各样的开放认证技术等功能。Flask 的这些特性,使得它在 Web 开发方面变得非常流行。
4.4 前端urilib等
urllib是Python自带的标准库,无需安装,直接可以用。提供了如下功能:网页请求、响应获取、代理和cookie设置、异常处理和URL解析,主要用于前端爬虫,对于获取和整理数据是必备的。
前后端的这些框架,我们在公众号的往期文章都已经说过,大家可以自行翻阅。
总结
AI白身境第三讲结束了,但学习的路永无止境,python、NumPy、matplotlib、深度学习框架的知识还有很多,需要我们不断的学习。期待我们的下期吧。