我深夜用 Python 跑神经网络,只为关掉台灯!
Posted Python高校
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我深夜用 Python 跑神经网络,只为关掉台灯!相关的知识,希望对你有一定的参考价值。
文末有干货 “Python高校”,马上关注
真爱,请置顶或星标
对于上了床就再也不想下来的人来说,关灯成为睡觉前面临的最大挑战!
然而这一届网友永远不会让人失望,他们开发出了各种关灯大法:
当然少不了憨豆先生最简单粗暴的关灯方式:
然而,一个来自意大利拉不勒斯的小哥哥,决定利用“舞步”(身体姿势)来控制自己家的灯,整个过程利用一个神经网络实现,就像这样:
下面是小哥哥写的教程,文摘菌在不改变原意的基础上进行了编译。
在今天的文章里,我将手把手教大家训练一个神经网络模型,用来识别摄像头拍下的“舞步”,从而控制灯的开关。
我们将在已有的OpenPose深度学习模型之上建立我们自己的模型来识别身体的位置,然后,我们会建立一些样本来代表各种身体的各种姿态。
当我们建立好舞步(包括嘻哈超人舞步、T-Pose舞步)和其他身体姿态的样本后,我们会清理数据集,然后利用这些样例训练我们的神经网络。
当神经网络训练好之后,我们会用它来控制灯光。
今天的文章包括很多步骤,不过,所有的代码都在Github上,上面还包括了我已经搜集到的原始数据样例。
GitHub链接:
https://github.com/burningion/dab-and-tpose-controlled-lights
编写“编写软件”的软件:怎样训练你的神经网络?
首先就是数据——大量数据。
我们今天即将采用的神经网络模型卡内基梅隆大学的团队也曾经使用过,他们用自己的全景数据集来训练该模型。该数据集包括五个半小时的视频,视频中包含了150万个手动添加的代表人体骨骼位置的标签。
整个全景工作室的圆屋顶上装有500个摄像头,所有摄像头都对准人,从不同角度记录他们的动作。
这个全景工作室用构造训练数据集几乎是完美的,很方便进行计算机视觉的实验。
今天,我们将在他们的工作基础之上开始我们的工作。
首先我们会用他们的工具来创建一个很小的数据集。我们最终的神经网络只会使用171个姿态,包括记录的嘻哈超人舞步、T-Pose舞步和其他姿态。每一个姿态样例都是从卡耐基梅隆大学已有的工作中提取出来的。
神经网络的一个好处就是你可以使用别人已经建成的模型,然后加入一些新的神经网络层,以此来扩展该模型。这个过程被称之为迁移学习,因此我们可以用有限的资源来进行迁移学习。
从技术上来说,我们不会在这个项目中使用迁移学习,因为我们会对OpenPose的工作做一些细微的修改,然后创建一个独立的神经网络。
那么问题来了,我们该如何获取数据呢?
写一个程序并利用OpenCV来收集带标签的数据
使用OpenPose的成果,我们得到了25个代表人体骨骼架构的标签。我们可以写一个程序来控制网络摄像头,在图像上运行OpenPose,然后将动作与键盘上的按键相对应。
也就是说,我们做出一个T-Pose的动作,然后在键盘上点击m键,那么这个动作就被归到T-Pose那一类里。我们按照这个方法去添加171个不同的姿势,这样一来,我们就有数据训练神经网络了。以下是用于数据收集的代码的示例:
# create lists for dab, tpose, other examplesdabs = []tposes = []other = []fps_time = 0# loop forever, reading webcam each timewhile True: ret_val, frame = vs.read() datum.cvInputData = frame opWrapper.emplaceAndPop([datum]) # need to be able to see what's going on image = datum.cvOutputData cv2.putText(image, "FPS: %f" % (1.0 / (time.time() - fps_time)), (10, 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2) cv2.imshow("Openpose", image) fps_time = time.time() # quit with a q keypress, b or m to save data key = cv2.waitKey(1) & 0xFF if key == ord("q"): break elif key == ord("b"): print("Dab: " + str(datum.poseKeypoints)) dabs.append(datum.poseKeypoints[0]) elif key == ord("m"): print("TPose: " + str(datum.poseKeypoints)) tposes.append(datum.poseKeypoints[0]) elif key == ord("/"): print("Other: " + str(datum.poseKeypoints)) other.append(datum.poseKeypoints[0])# write our data as numpy binary files# for analysis laterdabs = np.asarray(dabs)tposes = np.asarray(tposes)other = np.asarray(other)np.save('dabs.npy', dabs)np.save('tposes.npy', tposes)np.save('other.npy', other)
然后用NumPy的数组来储存特征,并用np.save函数把特征保存为二进制文件以便后续使用。我个人倾向于使用Jupyter notebook来观察和处理数据。
当数据收集好之后,我们可以观察并清理数据以便更好地去训练模型。
观察数据、清理数据以及使用数据训练模型
这部分看上去很复杂,但是通过使用Jupyter notebook、NumPy和Keras,我们就可以很直观地去观察数据、清理数据,并且使用数据来训练神经网络。
根据我们的截图,我们可以发现npy文件中保存的数据和OpenPose模型本身都有三个维度,25个已知的身体位置坐标点,X、Y、以及Confidence。
我们的模型训练工作不需要用到confidence。如果某个身体位置坐标点被命名了,我们就保留它,否则,我们就直接让它为0。
我们已经把(绝大部分)数据梳理好了,现在我们需要把数据特征和标签结合起来。
我们用0代表其他姿势,1代表嘻哈超人舞步、2代表T-Pose舞步。
labels = np.zeros(len(otherDataset))
labels = np.append(labels, np.full((len(dabDataset)), 1))
labels = np.append(labels, np.full((len(tposeDataset)), 2))
print(labels)
print("%i total examples for training." % len(labels))
接下来,我们可以使用独热编码处理我们的数字标签。也就是说,我们将标签0、1、2转换成[1,0,0]、[0,1,0]、[0,0,1]。之后,我们可以使用sklearn的shuffle函数将数据标签和特征打乱(数据标签和特征仍保持原有的对应关系)
# now, let's shuffle labels and the array, the same wayfrom sklearn.utils import shuffleX1, y1 = shuffle(dataset, labels)# now let's label them for 'one hot'from keras.utils.np_utils import to_categoricaly1 = to_categorical(y1, 3) # we have 3 categories, dab, tpose, otherprint(y1.shape[1)]
我们的输入数据代表着鼻子、手等等的位置,而它们的是介于0到720和0到1280之间的像素值,所以我们需要把数据归一化。这样一来,我们可以重复使用我们的模型而不用考虑输入图片数据的分辨率。
# now, let's shuffle labels and the array, the same way
from sklearn.utils import shuffle
X1, y1 = shuffle(dataset, labels)
# now let's label them for 'one hot'
from keras.utils.np_utils import to_categorical
y1 = to_categorical(y1, 3) # we have 3 categories, dab, tpose, other
print(y1.shape[1)]
在最后一步中,我们将把我们的多维数据变成一维。我们会分批向模型输入50个位置信息(25个部位,每个部位的X和Y值)。
构建并训练我们的模型
在Jupyter notebook中使用Keras可以把训练和测试神经网络模型的工作变得十分简单,这也是我最喜欢Keras的地方。
现在我们的数据已经贴上标签准备就绪了,我们可以开始训练一个简单的模型了,只需要几行代码。
现在我们导入Keras库然后训练一个简单的神经网络模型。
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.optimizers import SGD
model = Sequential()
model.add(Dense(128, activation='relu', input_shape=(50,)))
model.add(Dropout(0.5))
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(y1.shape[1], activation='softmax'))
model.compile(optimizer='Adam',
loss='categorical_crossentropy',
metrics=['accuracy'])
model.fit(X1, y1, epochs=2000,batch_size=25)
搞定!
这里有个稍微需要注意的地方,输入层的大小为50,提醒大家一下,这个数字是OpenPose模型中位置点的X坐标和Y坐标数量之和。
最后我们用到了Softmax层,它是用来分类的。我们将y.shape[1]传入该层,这样我们的模型就知道不同类别的数量了。
最后的最后,我们使用输入数据,用model.fit()的方法去训练模型。这里,我已经做了2000次迭代(全部样本训练一次为一次迭代)。2000次迭代貌似有点多了,500次左右的迭代可能更好,因为迭代次数过多可能使我们的模型出现一些过拟合问题。但是不论是哪一种情况,你都需要经过多次尝试来确定迭代次数。
当我们运行这段代码时,我们会看到准确度在提高。如果你看不到,请再次确认当你打乱数据时,数据标签和数据特征的对应关系是不变的。此外,也要确认数据里的数值是不是在0到1之间。
最后,我们可以保存训练后的模型,也可以使用样本数据集来测试该模型,保存模型的代码很简单:
model.save('data/dab-tpose-other.h5') # save our model as h5
# in our other code, or inline, load the model and test against sample dab dataset
import keras
modello = keras.models.load_model('data/dab-tpose-other.h5')
dabDataset = np.load('data/test-dabs.npy')
dabDataset[:,:,0] = dabDataset[:,:,0] / 720 # I think the dimensions are 1280 x 720 ?
dabDataset[:,:,1] = dabDataset[:,:,1] / 1280 # let's see?
dabDataset = dabDataset[:,:,1:]
dabDataset = dabDataset.reshape(len(dabDataset), 50)
modello.predict_classes(dabDataset) # returns array([1, 1, 1, 1, 1, 1])
用模型来控制灯光
我们现在已经有了可以识别姿势的模型,接下来要做的只是把这个模型和无线灯光控制关联起来就行了。
在我的这个例子中,我使用Aeotec Z-Stick来发送Z-Wave指令,并配有两个GE Z-Wave的室外开关。USB接口接入到NVIDIA TX2人工智能模块,其实NVIDIA的Jestson Nano也能胜任,尽管Jetson Nano所能提供的分辨率要低于我样例中1280x720的分辨率。当Z-Stick插入到ARM设备后,你首先需要把开关调到Z-Wave模式,可能需要多按几下USB Stick上的按钮和灯的开关。
代码并不复杂,基本上就是训练环境再加上一个额外的步骤。现在,我们导入Keras,然后使用清理过的数据训练模型。
import cv2import pyopenpose as opfrom imutils import translate, rotate, resizeimport openzwavefrom openzwave.option import ZWaveOptionfrom openzwave.network import ZWaveNetwork# make sure these commands get flushed by doing them first, then loading tensorflow...# tensorflow should take enough time to start for these commands to flushoptions = ZWaveOption('/dev/ttyACM0')options.lock()network = ZWaveNetwork(options)import timeimport numpy as npnp.random.seed(1337)import tensorflow as tf# make sure tensorflow doesn't take up all the gpu memoryconf = tf.ConfigProto()conf.gpu_options.allow_growth=Truesession = tf.Session(config=conf)import keras# Custom Params (refer to include/openpose/flags.hpp for more parameters)params = dict()params["model_folder"] = "../../models/"# built in TX2 video capture sourcevs = cv2.VideoCapture("nvarguscamerasrc ! video/x-raw(memory:NVMM), width=(int)1280, height=(int)720,format=(string)NV12, framerate=(fraction)24/1 ! nvvidconv flip-method=0 ! video/x-raw, format=(string)BGRx ! videoconvert ! video/x-raw, format=(string)BGR ! appsink")tposer = keras.models.load_model('dab-tpose-other.h5')# Starting OpenPoseopWrapper = op.WrapperPython()opWrapper.configure(params)opWrapper.start()datum = op.Datum()np.set_printoptions(precision=4)fps_time = 0DAB = 1TPOSE = 2OTHER = 0LIGHTS = 0bounced = time.time()debounce = 3 # wait 3 seconds before allowing another commandwhile True: ret_val, frame = vs.read() datum.cvInputData = frame opWrapper.emplaceAndPop([datum]) # need to be able to see what's going on image = datum.cvOutputData cv2.putText(image, "FPS: %f" % (1.0 / (time.time() - fps_time)), (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2) cv2.imshow("Openpose", image) if datum.poseKeypoints.any(): first_input = datum.poseKeypoints try: first_input[:,:,0] = first_input[:,:,0] / 720 first_input[:,:,1] = first_input[:,:,1] / 1280 first_input = first_input[:,:,1:] first_input = first_input.reshape(len(datum.poseKeypoints), 50) except: continue output = tposer.predict_classes(first_input) for j in output: if j == 1: print("dab detected") if LIGHTS == 0 or (time.time() - bounced) < debounce: continue for node in network.nodes: for val in network.nodes[node].get_switches(): network.nodes[node].set_switch(val, False) LIGHTS = 0 bounced = time.time() elif j == 2: print("tpose detected") if LIGHTS == 1 or (time.time() - bounced) < debounce: continue for node in network.nodes: for val in network.nodes[node].get_switches(): network.nodes[node].set_switch(val, True) LIGHTS = 1 bounced = time.time() fps_time = time.time() # quit with a q keypress, b or m to save data key = cv2.waitKey(1) & 0xFF if key == ord("q"): break# clean up after yourselfvs.release()cv2.destroyAllWindows()
到了这一步,工作基本上就算完成了!
我们成功地训练了一个用于识别嘻哈超人舞步、T-Pose舞步的神经网络模型,然后我们可以让它根据我们的舞步来制造可互动的灯。
太棒了,给自己点个赞!
后记
所有代码、模型以及训练数据都免费公布在Github上。
我建议你们在Jupyter notebook上试试这个项目。我的代码中有个漏洞,我一直无法从自己的工作簿中找出来。这个漏洞导致我的原始的X和Y标签并没有被正确地标记。如果你找到了解决这个漏洞的方法,记得在Github上创建一个Pull Request(PR)。
另外,我们今天构建的基础模型可以用来训练很多类型的舞蹈动作。尽管我的模型每秒只能捕捉很少的画面,但我们可以开始建立一个有关舞步的数据集,然后再构建一个能识别这些不同舞步的神经网络模型。
我还为刚开始学习编程的人写了本书,欢迎你们来看看这本书。
相关报道:
https://www.makeartwithpython.com/blog/dab-and-tpose-controlled-lights/
《神经网络与深度学习》排在首位的特点就是它是完全的中文教程。我相信大部分深度学习入门学者面对英文教程的时候,战斗力多半会削减大半。而邱锡鹏老师的这本书恰恰为中国学生而著,大大降低了深度学习的语言门槛,让大家有更多的精力放在核心知识内容的学习上。
关于本书
关于本书,邱锡鹏是这样评价的:
近年来,以机器学习、知识图谱为代表的人工智能技术逐渐变得普及。从车牌识别、人脸识别、语音识别、智能问答、推荐系统到自动驾驶,人们在日常生活中都可能有意无意地使用到了人工智能技术。这些技术的背后都离不开人工智能领域研究者们的长期努力。特别是最近这几年,得益于数据的增多、计算能力的增强、学习算法的成熟以及应用场景的丰富,越来越多的人开始关注这一个“崭新”的研究领域:深度学习。深度学习以神经网络为主要模型,一开始用来解决机器学习中的表示学习问题。但是由于其强大的能力,深度学习越来越多地用来解决一些通用人工智能问题,比如推理、决策等。目前,深度学习技术在学术界和工业界取得了广泛的成功,受到高度重视,并掀起新一轮的人工智能热潮。
这本书的作者邱锡鹏老师,目前是复旦大学计算机科学技术学院的博士生导师、自然语言处理与深度学习组的副教授。
《神经网络与深度学习》主要介绍神经网络与深度学习中的基础知识、主要模型(卷积神经网络、递归神经网络等)以及在计算机视觉、自然语言处理等领域的实际应用。
主要内容
这本书目前已经更新完毕,总共包含了 15 章。内容涉及神经网络集基础知识以及经典的 CNN、RNN 模型,还有其在 CV 和 NLP 方面的应用。15 章内容分为三大部分:第一部分为入门篇,包括 1~3 章;第二部分为基础模型,包括 4~10 章;第三部分为进阶模型,包括 11~15 章。
完整书籍目录如下:
第 1 章:绪论
第 2 章:机器学习概述
第 3 章:线性模型
第 4 章:前馈神经网络
第 5 章:卷积神经网络
第 6 章:循环神经网络
第 7 章:网络优化与正则化
第 8 章:注意力机制与外部记忆
第 8 章:无监督学习
第 10 章:模型独立的学习方式
第 11 章:概率图模型
第 12 章:深度信念网络
第 13 章:深度生成模型
第 14 章:深度强化学习
第 15 章:序列生成模型
除了 15 章正文内容外,作者还为我们提供了详细的数学基础知识,放在了附录部分。数学基础总共包含 4 方面内容:
附录 A:线性代数
附录 B:微积分
附录 C:数学优化
附录 D:概率论
这些数学基础知识,可谓是神经网络与深度学习的内功心法!也是本书的最大亮点之一,能够极大提升我们在阅读本书的效率。
课程资源
目前,邱锡鹏老师已经开源了该课程所有的资源,包括书籍 pdf,课程 ppt,书籍相关习题参考代码等。
课程主页:
https://nndl.github.io/
全书 pdf:
https://nndl.github.io/nndl-book.pdf
3 小时课程概要:
https://nndl.github.io/ppt/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E4%B8%8E%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0-3%E5%B0%8F%E6%97%B6.pdf
示例代码:
https://github.com/nndl/nndl-codes
课程练习:
https://github.com/nndl/exercise
关于课程练习,作者大都提供了最热门的 PyTorch 和 TensorFlow 两种框架的实现方式。
开源万岁!这份优秀的深度学习资源,赶快试试吧~
资源下载:
为了节约大家的时间,小编爱码士已经将这份《神经网络与深度学习》电子版 PDF 打包好了。获取步骤如下:
以上是关于我深夜用 Python 跑神经网络,只为关掉台灯!的主要内容,如果未能解决你的问题,请参考以下文章
使程序在Linux下后台运行 (关掉终端继续让程序运行的方法)
使程序在Linux下后台运行 (关掉终端继续让程序运行的方法)