现如今要问什么行业最火最有前景,非人工智能莫属了,这项技术掀起的风暴不亚于18世纪的工业革命。
但是一提到人工智能,就会听到Python,这门计算机编程语言,为什么总是在蹭热度?它和人工智能之间到底什么关系?
先看下面2张图:
可以看出,人工智能包含机器学习和深度学习两个很重要的模块,而python拥有matplotlib、Numpy、sklearn、keras等大量的库。
像pandas、sklearn、matplotlib这些库都是做数据处理、数据分析、数据建模和绘图的库,而机器学习中对数据的爬取(scrapy)、对数据的处理和分析(pandas)、对数据的绘图(matplotlib)和对数据的建模(sklearn)在python中全都能找到对应的库来进行处理。
可以说,要想学习AI而不懂python,那就相当于想学英语而不认识单词,所以,你要是不懂点AI、机器学习和python就无法真正理解人工智能。
下面我们通过几个实操项目给你展示一下Python具体是如何实现人工智能的。
智能聊天机器人
这个项目运用到的库有wxpy和chatterbot。
wxpy是在 itchat库 的基础上,通过大量接口优化,让模块变得简单易用,并进行了功能上的扩展。
什么是接口优化呢?简单来说就是用户直接调用函数,并输入几个参数,就可以使用了,不需要关心函数的底层实现。
Chatterbot是一个基于机器学习的聊天机器人引擎,基于python编写而成,它可以自己从已有的对话中进行记忆匹配。
Wxpy因为采用大量的接口集成,所以在使用的时候非常方便,下图是简单的wxpy使用,通过进入交互式界面,可以与指定的好友进行交谈。
代码及效果如下图所示:
上述的代码中print_msg函数采用了wxpy库的装饰器,装饰器在这里的作用可以查阅其源码进行查看,主要是用于注册消息的配置。
例如print_msg函数,可以将对方的回复消息进行输出。
而在手机微信上我们同样看到了双方之间交流,所以从某个层面上来讲,wxpy就是PC端的微信。
图灵聊天机器人
下面我们将会实现第一个聊天机器人,该机器人是wxpy内集成的图灵机器人,由于图灵机器人的高度专业,所以制作出来的聊天机器人交流也非常的顺畅。
那如何将图灵机器人嵌入到我们的交流中呢?
首先我们需要去图灵机器人官网注册得到我们自己的机器人,注册完成后,我们便可以生成图灵机器人,并得到一个api_key,如下图所示:
这个api_key便是我们后续制作聊天机器人的关键。
图灵聊天机器人的代码和效果图如下图所示:
由上图右边的聊天记录来看,依托图灵机器人的聊天机器人效果非常的出色,而且还可以进行天气查询等功能。
自己训练的聊天机器人
下面我们不依托于图灵机器人,而是依靠ChatterBot来制作一款机器人,这款机器人,虽然效果较上一款性能差距较大,但是它可以训练我们自己的语料库,下面是代码和效果的展示:
由上图可以看出,或许是受制于语料库资源过少,而且也不能够主动上网查询。所以要想使其能够回答和提问基本吻合还需要大量的工作。
难道除了这些我们就没有其它可以做的了吗?
当然不是,ChatterBot为我们提供了可以训练的方式,我们可以提供素材来让其进行训练。
代码和效果如下图所示:
我们首先定义了一个chatbot,然后将训练数据加入进去,让模型匹配我们的问题,得到训练的结果。
右边的图展示了我们的结果,由结果可以看出,由于我们的训练集中没有“在”这个数据,所以得到的回答很莫名其妙,而对于“你好”和“你叫什么名字?”这两个问题的回答则得到了很完美的答复,这就是加入训练数据集的优势所在。
trainer.train([ "你好", "你好,很高兴认识你", "你叫什么名字?", "我叫chat-robot-2.", ])
(训练集的数据)
你也可以加入你想要训练的语料库进行训练,一样会得到不错的效果。
有的同学可能会问这是如何训练的呢?
答案就在chatterbot的源码里,打开源码,我们这里的chatbot选择的训练方法是“BestMatch”,也即最匹配方式,从训练的对话中找到最相识的语句,然后根据对话提供回答。
Python做聊天机器人的项目是不是很有趣?你也赶快动手设计一款属于自己的聊天机器人吧!
人脸识别
看似高大上的人脸识别技术,其实在Python里有很多种方法可以实现。依赖于python胶水语言的特性,我们通过调用包可以快速准确地达成这一目的。
这里介绍的是准确性比较高的一种。
首先梳理一下实现人脸识别需要进行的步骤:
流程大致如此,在此之前,要先让人脸被准确地找出来,也就是能准确区分人脸的分类器,在这里我们可以用已经训练好的分类器,网上种类较全,分类准确度也比较高,我们也可以节约在这方面花的时间。
既然用的是python,那自然少不了包的使用了,在看代码之前,我们先将整个项目所需要的包罗列一下:
· CV2(Opencv):图像识别,摄像头调用
· os:文件操作
· numpy:NumPy(Numerical Python) 是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库
· PIL:Python Imaging Library,Python平台事实上图像处理的标准库
接下来,就是见证奇迹的时刻!
对照人脸获取
#-----获取人脸样本----- import cv2 #调用笔记本内置摄像头,参数为0,如果有其他的摄像头可以调整参数为1,2 cap = cv2.VideoCapture(0) #调用人脸分类器,要根据实际路径调整3 face_detector = cv2.CascadeClassifier(r'X:/Users/73950/Desktop/FaceRec/haarcascade_frontalface_default.xml') #待更改 #为即将录入的脸标记一个id face_id = input('\n User data input,Look at the camera and wait ...') #sampleNum用来计数样本数目 count = 0 while True: #从摄像头读取图片 success,img = cap.read() #转为灰度图片,减少程序符合,提高识别度 if success is True: gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) else: break #检测人脸,将每一帧摄像头记录的数据带入OpenCv中,让Classifier判断人脸 #其中gray为要检测的灰度图像,1.3为每次图像尺寸减小的比例,5为minNeighbors faces = face_detector.detectMultiScale(gray, 1.3, 5) #框选人脸,for循环保证一个能检测的实时动态视频流 for (x, y, w, h) in faces: #xy为左上角的坐标,w为宽,h为高,用rectangle为人脸标记画框 cv2.rectangle(img, (x, y), (x+w, y+w), (255, 0, 0)) #成功框选则样本数增加 count += 1 #保存图像,把灰度图片看成二维数组来检测人脸区域 #(这里是建立了data的文件夹,当然也可以设置为其他路径或者调用数据库) cv2.imwrite("data/User."+str(face_id)+'.'+str(count)+'.jpg',gray[y:y+h,x:x+w]) #显示图片 cv2.imshow('image',img) #保持画面的连续。waitkey方法可以绑定按键保证画面的收放,通过q键退出摄像 k = cv2.waitKey(1) if k == '27': break #或者得到800个样本后退出摄像,这里可以根据实际情况修改数据量,实际测试后800张的效果是比较理想的 elif count >= 800: break #关闭摄像头,释放资源 cap.realease() cv2.destroyAllWindows()
Tips:
经测试,在执行
“face_detector = cv2.CascadeClssifier(r'C:\Users\admin\Desktop\python\data\haarcascade_frontalface_default.xml')”此语句时,实际路径中的目录名尽量不要有中文字符出现,否则容易报错。
通过算法建立对照模型
本次所用的算法为opencv中所自带的算法,opencv较新版本中(我使用的是2.4.8)提供了一个FaceRecognizer类,里面有相关的一些人脸识别的算法及函数接口,其中包括三种人脸识别算法(我们采用的是第三种)
1.eigenface
2.fisherface
3.LBPHFaceRecognizer
LBP是一种特征提取方式,能提取出图像的局部的纹理特征,最开始的LBP算子是在3X3窗口中,取中心像素的像素值为阀值,与其周围八个像素点的像素值比较,若像素点的像素值大于阀值,则此像素点被标记为1,否则标记为0。
这样就能得到一个八位二进制的码,转换为十进制即LBP码,于是得到了这个窗口的LBP值,用这个值来反映这个窗口内的纹理信息。
LBPH是在原始LBP上的一个改进,在opencv支持下我们可以直接调用函数直接创建一个LBPH人脸识别的模型。
我们在前一部分的同目录下创建一个Python文件,文件名为trainner.py,用于编写数据集生成脚本。
同目录下,创建一个文件夹,名为trainner,用于存放我们训练后的识别器。
#-----建立模型、创建数据集----- import os import cv2 import numpy as np from PIL import Image #导入pillow库,用于处理图像 #设置之前收集好的数据文件路径 path = 'data' #初始化识别的方法 recog = cv2.face.LBPHFaceRecognizer_create() #调用熟悉的人脸分类器 detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') #创建一个函数,用于从数据集文件夹中获取训练图片,并获取id #注意图片的命名格式为User.id.sampleNum def get_images_and_labels(path): image_paths = [os.path.join(path,f) for f in os.listdir(path)] #新建连个list用于存放 face_samples = [] ids = [] #遍历图片路径,导入图片和id添加到list中 for image_path in image_paths: #通过图片路径将其转换为灰度图片 img = Image.open(image_path).convert('L') #将图片转化为数组 img_np = np.array(img,'uint8') if os.path.split(image_path)[-1].split(".")[-1] != 'jpg': continue #为了获取id,将图片和路径分裂并获取 id = int(os.path.split(image_path)[-1].split(".")[1]) faces = detector.detectMultiScale(img_np) #将获取的图片和id添加到list中 for(x,y,w,h) in faces: face_samples.append(img_np[y:y+h,x:x+w]) ids.append(id) return face_samples,ids #调用函数并将数据喂给识别器训练 print('Training...') faces,ids = get_images_and_labels(path) #训练模型 recog.train(faces,np.array(ids)) #保存模型 recog.save('trainner/trainner.yml')
这就让电脑认识到你是与众不同的那颗星~
识别
检测,校验,输出其实都是识别的这一过程,与前两个过程不同,这是涉及实际使用的过程,所以我们把他整合放在一个统一的一个文件内。
#-----检测、校验并输出结果----- import cv2 #准备好识别方法 recognizer = cv2.face.LBPHFaceRecognizer_create() #使用之前训练好的模型 recognizer.read('trainner/trainner.yml') #再次调用人脸分类器 cascade_path = "haarcascade_frontalface_default.xml" face_cascade = cv2.CascadeClassifier(cascade_path) #加载一个字体,用于识别后,在图片上标注出对象的名字 font = cv2.FONT_HERSHEY_SIMPLEX idnum = 0 #设置好与ID号码对应的用户名,如下,如0对应的就是初始 names = ['初始','admin','user1','user2','user3'] #调用摄像头 cam = cv2.VideoCapture(0) minW = 0.1*cam.get(3) minH = 0.1*cam.get(4) while True: ret,img = cam.read() gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #识别人脸 faces = face_cascade.detectMultiScale( gray, scaleFactor = 1.2, minNeighbors = 5, minSize = (int(minW),int(minH)) ) #进行校验 for(x,y,w,h) in faces: cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2) idnum,confidence = recognizer.predict(gray[y:y+h,x:x+w]) #计算出一个检验结果 if confidence < 100: idum = names[idnum] confidence = "{0}%",format(round(100-confidence)) else: idum = "unknown" confidence = "{0}%",format(round(100-confidence)) #输出检验结果以及用户名 cv2.putText(img,str(idum),(x+5,y-5),font,1,(0,0,255),1) cv2.putText(img,str(confidence),(x+5,y+h-5),font,1,(0,0,0),1) #展示结果 cv2.imshow('camera',img) k = cv2.waitKey(20) if k == 27: break #释放资源 cam.release() cv2.destroyAllWindows()
现在,你的电脑就能识别出你来啦!
测试结果
上图为转换为灰度图片之后保存在data目录下的照片
成功识别
国际象棋AI机器人
AI在人类棋牌类任务中的优异表现吸引了越来越多的关注,我们今天的第三个项目要介绍一个简洁的结合了alpha-β剪枝和棋盘评估方法的国际围棋AI算法。
首先,让我们来熟悉一些简单的国际象棋AI的基本步骤,在每一步中我们将优化项目代码,你可以在Github中查看到最后的源代码。
本步骤将使用 chess.js库来进行移动迭代,并使用chessboard.js库来对棋盘进行可视化,chess.js库基本上包含了所有国际象棋的规则算法,在两个库的基础上,我们可以实现对特定的棋局进行所有可行走法的计算。
通过以上库的运用,我们可以算出最优棋局走法。我们首先通过构建一个函数,使它可以基于所有可行走法返回一个随机的棋局走法:
虽然此算法不是一个棋风稳健的“选手”,但它确是个不错的对手。
本部分可以判断棋局哪一方更有优势,最简单的方法就是使用如下的表格计算棋盘中每个棋子的相对强度值(relative strength):
通过以下的评估函数,我们可以基于计算评估值来得到能让此分值最大化的走法:
我们的算法对于先前的改善在于可以实现吃棋子的功能。
上图是黑子在简洁优化函数的指导下进行对弈的情况,读者可以在 https://jsfiddle.net/lhartikk/m5q6fgtb/1/中自己尝试。
算法通过构造一个搜索树来选择最优走法,使用了极小化极大法(以下简称Minimax),极小化极大算法是一种广泛应用在决策理论、博弈论、统计学科的方法,它的基本原理是在可能的最糟糕的情况(也就是可能的最大损失)下最小化损失,详细请见
https://en.wikipedia.org/wiki/Minimax的维基百科的介绍。
此算法基于给定的深度来对递归树的所有可能路径进行搜寻并在“叶”端给出评估。在那之后,算法会根据是白字还是黑子来从子节点返回最小值和最大值到母节点。
如上图所示,对于白字(我方)来说,最好的走法是b2-c3,因为我们能够最小化损失到-50。
接下来,算法需要结合一些基本的象棋技巧。
Minimax算法的有效性主要基于我们实现的搜索深度,我们将继续优化它。
Apha-beta剪枝是Minimax算法的优化方法,也就是在搜索过程中减去一些分支。这能够节省运算资源,加深算法深度。
此剪枝算法在发现如果前段路径会导致更坏的结果时就会放弃这个分支。
此方法不会影响Minimax算法,但是会加快算法速度。当然,如果能够一开始就发现最优的路径,alpha-beta算法就会更有效。
如下图,通过剪枝方法,我们加强了Minimax算法。
在此链https://jsfiddle.net/Laa0p1mh/3/中你能发现加强了的算法。
为了优化函数,我们为函数增加了一个评估棋子位置的因子。例如,在棋盘中间的骑士knight比在角落的更好(因为它有更多可走的步,更加活跃)。
我们基于此微调了在链接
https://chessprogramming.wikispaces.com/Simplified+evaluation+function?responseToken=a946f6563c930b32a32daaacdb1c5818中提供的棋盘。
在上图中可视化的棋盘中,我们根据棋子的位置减少或增加了评估工作。
我们经过更多的改善工作得到了更好的棋盘,如下图所示:
上图显示了使用改善的评估函数和剪枝方法,并基于3的搜索深度的对局情况。可在https://jsfiddle.net/q76uzxwe/1/中查看详细代码。
通过这个方法,我们能够构建一个基础的能够与人类玩家对弈的国际象棋程序。其中的AI部分(排除移动迭代move-generation)的最终代码只有200行,非常简洁。
由以上几个实操案例可见,Python之所以成为人工智能语言与其本身特点有很大的关系:
一、Python是解释语言,有天生的优势——不需要编译时间,这对机器学习这种需要大量prototyping和迭代的研究方向是非常有益工作效率的,写起来非常方便。
二、Python的开发生态成熟,有很多有用的库可以用,这也是Python良性生态背后的一大原因。
三、Python效率超高,解释语言的发展已经大大超过许多人的想象。
四、得益于Python对C的接口,很多像gnumpy, theano这样高效、Python接口友好的库可以加速程序的运行,在强大团队的支撑下,这些库的效率可能比一个不熟练的程序员用C写一个月调优的效率还要高。
可以预见,未来十年Python语言的发展前景形势一片大好,人才缺口也将越来越大,我们应当认准时机,把握机遇,创造无限可能!