本帖最后由 Daniel-Wu 于 2018-9-1 22:58 编辑
国内鲜有基于Movidius的教程,国外开源的项目也寥寥无几,本教程结合了一些国外优秀的教程和自己的一些实践经历。我想通过这个教程帮助大家尽可能快速上手使用Movidius。
在本教程中我会向您展示培训简单的MNIST Keras模型并将其部署到树莓派+Movidius中。 需要的材料有movidius + 树莓派或其他ubuntu电脑 + 摄像头(树莓派官方的摄像头和usb的均可) 同时你还需要在树莓派上安装好Movidius ncsdk,有机会我会再写一个专门介绍movidius安装的教程 有几个步骤, - 在Keras训练模型(TensorFlow后端)
- 在Keras中保存模型文件和权重
- 将Keras模型转换为TensorFlow
- 将TensorFlow模型编译为NCS graph (不知道graph是啥的请百度tensorflow的文档)
- 在NCS上部署并运行graph
-我使用的平台是up board(ubuntu)+神经计算棒+摄像头,均可以在爱板商城购买到
一.什么是Keras?
在keras中文wiki里面介绍了Keras是一个高层神经网络API,Keras由纯Python编写而成并基Tensorflow、Theano以及CNTK后端。Keras 为支持快速实验而生,能够把你的idea迅速转换为结果,如果你有如下需求,请选择Keras: - 简易和快速的原型设计(keras具有高度模块化,极简,和可扩充特性)
- 支持CNN和RNN,或二者的结合
- 无缝CPU和GPU切换
简而言之,Keras就是简单易上手的神经网络,将Tensorflow、Theano以及CNTK等作为后端,将复杂的APi简单化,方便小白上手,小伙伴们可以百度keras中文文档进行学习,当然也可以你看我给大家的英文原版书籍,我会上传到附件,英文书籍正好可以练练阅读能力,学人工智能,英语阅读能力少不了的。
二,培训与输出模型
了解了Keras的基本使用后
再来看看如何培训Keras的模型的
直接上培训与输出部分的代码,这部分在电脑上运行,windows和linux均可
- from keras import layers, models
- from keras.models import load_model
- from keras.datasets import mnist
- from keras.utils import to_categorical
- from keras import backend as K
- import tensorflow as tf
- (x_train, y_train), (x_test, y_test) = mnist.load_data()
复制代码
正确训练完后控制台打印如下
并且应该有三个文件生成
三.将Keras转变为TensorFlow模型
查看Movidius官网的WIki,由于Movidius NCSDK2仅编译TensorFlow或Caffe模型。现在tensorflow正好官方支持了树莓派平台,那就使用tensorflow来做吧。
- from keras.models import model_from_json
- from keras import backend as K
- import tensorflow as tf
- model_file = "model.json"
- weights_file = "weights.h5"
- with open(model_file, "r") as file:
- config = file.read()
- K.set_learning_phase(0)
- model = model_from_json(config)
- model.load_weights(weights_file)
- saver = tf.train.Saver()
- sess = K.get_session()
- saver.save(sess, "./TF_Model/tf_model")
- fw = tf.summary.FileWriter('logs', sess.graph)
- fw.close()
复制代码
第一 我们关闭学习阶段,然后从我们先前保存的两个单独文件以标准Keras方式加载模型。 通过 调用 K.get_session() 从使用基于TensorFlow后端的 Keras,将提供默认的TensorFlow session 。您甚至可以调用 sess.graph.get_operations()进一步了解TensorFlow graph中的内容 它将返回一列模型中TensorFlow操作。这对于查找计算棒不支持的操作非常有用,众所周知,movidius的限制还是太多,希望国产的角峰鸟可以解决一些限制。最后,TensorFlow Saver类将模型保存到指定路径中的四个文件中。 每个文件都有不同的用途, - checkpoint定义模型检查点路径,在我们的例子中是“tf_model”。
- .meta存储图形结构,
- .data存储图中每个变量的值
- .index标识检查点。
四.使用mvNCCompile编译TensorFlow模型
在装有ncsdk的树莓派或主机上,使用mvNCCompile。mvNCCompile命令行工具自带NCSDK2工具包,可以转换来自Caffe或Tensorflow网络到graph,也就是可由Movidius计算棒使用的文件。我们将' conv2d_1_input '作为输入节点,将' dense_2 / Softmax '作为输出节点。一行命令即可在当前目录生成名为”graph“的文件。
- mvNCCompile TF_Model / tf_model.meta -in = conv2d_1_input -on = dense_2 / Softmax
复制代码
五.部署graph并进行预测
- from mvnc import mvncapi as mvnc
- # 获取计算棒的设备名
- devices = mvnc.enumerate_devices()
- dev = mvnc.Device(devices[0])
- # 从文件中读取已编译的网络图(为图形文件正确设置graph_filepath)
- with open("graph", mode='rb') as f:
- graphFileBuff = f.read()
- graph = mvnc.Graph('graph1')
- # 在设备上分配图形并创建输入和输出
- in_fifo, out_fifo = graph.allocate_with_fifos(dev, graphFileBuff)
- # 将输入写入input_fifo缓冲区并在一次调用中对推理进行排队
- graph.queue_inference_with_fifo_elem(in_fifo, out_fifo, input_img.astype('float32'), 'user object')
- # 将结果读取到输出Fifo
- output, userobj = out_fifo.read_elem()
- print('Predicted:',output.argmax())
复制代码
六.使用Raspberry Pi上的摄像头实时图像进行预测
训练MNIST模型以识别28×28分辨率的灰度图像的手写数字,所以必需转换摄像头捕获的图像,下面是一些预处理步骤。 - 裁剪图像的中心区域
- 使用边缘检测找到图像的边缘,此步骤也可以将图像转换为灰度
- 扩大边缘,使边缘更厚,以填充两个紧密平行边缘之间的区域。
- 将图像大小调整为28 x 28
对于每个捕获的帧,我们将其传递给图像预处理函数,然后输入NCS graph,该graph返回最终的预测概率。从那里,我们将最终预测的结果呈现为在显示器上显示的图像上。 图像处理过程的代码片段如下
- import numpy as np
- import cv2
- class ImageProcessor:
- """
- A singleton class for ImageProcessor
- """
- p1 = 90
- p2 = 30
- ROI_ratio = 0.2
- label_text_color = (0, 120, 0)
- min_score_percent = 60
- def __new__(cls, min_score_percent=60):
- if not hasattr(cls, 'instance'):
- cls.instance = super(ImageProcessor, cls).__new__(cls)
- return cls.instance
- def __init__(self, min_score_percent=60):
- self.min_score_percent = min_score_percent
- def preprocess_image(self, input_image):
- self.sz = input_image.shape
- self.cx = self.sz[0]//2
- self.cy = self.sz[1]//2
- self.ROI = int(self.sz[0]*self.ROI_ratio)
- edges = cv2.Canny(input_image,self.p1,self.p2)
- cropped = edges[self.cx-self.ROI:self.cx+self.ROI,self.cy-self.ROI:self.cy+self.ROI]
- kernel = np.ones((4,4),np.uint8)
- cropped = cv2.dilate(cropped,kernel,iterations = 2)
- cropped_input = cv2.resize(cropped,(28,28)) / 255.0
- cv2.rectangle(input_image, (self.cy-self.ROI, self.cx-self.ROI), (self.cy+self.ROI, self.cx+self.ROI),(255,255,0), 5)
- return cropped_input, cropped
- def postprocess_image(self, input_image, percentage, label_text, cropped=None):
- if cropped is not None:
- cropped = np.stack((cropped,)*3, -1)
- input_image[-cropped.shape[0]:, -cropped.shape[1]:] = cropped
- if percentage >= self.min_score_percent:
- cv2.putText(input_image, label_text, (self.cy-self.ROI - 1, self.cx-self.ROI - 1),cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255), 2)
- else:
- cv2.putText(input_image, '?', (self.cy-self.ROI - 1, self.cx-self.ROI - 1),cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255), 2)
复制代码 下面就是重头戏使用movidius ncs进行摄像头拍摄识别- #!/usr/bin/env python3
- from mvnc import mvncapi as mvnc
- import numpy as np
- from ImageProcessor import ImageProcessor
- import cv2
- cv_window_name = "predict-mnist"
- CAMERA_INDEX = 0
- REQUEST_CAMERA_WIDTH = 640
- REQUEST_CAMERA_HEIGHT = 480
- def handle_keys(raw_key):
- global processor
- ascii_code = raw_key & 0xFF
- if ((ascii_code == ord('q')) or (ascii_code == ord('Q'))):
- return False
- elif (ascii_code == ord('w')):
- processor.p1 +=10
- print('processor.p1:' + str(processor.p1))
- elif (ascii_code == ord('s')):
- processor.p1 -=10
- print('processor.p1:' + str(processor.p1))
- elif (ascii_code == ord('a')):
- processor.p2 +=10
- print('processor.p2:' + str(processor.p2))
- elif (ascii_code == ord('d')):
- processor.p2 -=10
- print('processor.p1:' + str(processor.p2))
- return True
- processor = ImageProcessor()
- # 检测有没有连接上计算棒
- devices = mvnc.enumerate_devices()
- if len(devices) == 0:
- print('No devices found')
- quit()
- dev = mvnc.Device(devices[0])
- # 尝试打开设备。 如果其他进程已经打开它,这将报异常
- try:
- dev.open()
- except:
- print("Error - Could not open NCS device.")
- quit()
- # 从文件中读取已编译的graph
- with open("graph", mode='rb') as f:
- graphFileBuff = f.read()
- graph = mvnc.Graph('graph1')
- # 在设备上分配graph并创建输入和输出Fifos
- in_fifo, out_fifo = graph.allocate_with_fifos(dev, graphFileBuff)
- cv2.namedWindow(cv_window_name)
- cv2.moveWindow(cv_window_name, 10, 10)
- cap = cv2.VideoCapture(CAMERA_INDEX)
- cap.set(cv2.CAP_PROP_FRAME_WIDTH, REQUEST_CAMERA_WIDTH)
- cap.set(cv2.CAP_PROP_FRAME_HEIGHT, REQUEST_CAMERA_HEIGHT)
- actual_frame_width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
- actual_frame_height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
- print ('actual video resolution: ' + str(actual_frame_width) + ' x ' + str(actual_frame_height))
- if ((cap == None) or (not cap.isOpened())):
- print ('Could not open camera. Make sure it is plugged in.')
- print ('Also, if you installed python opencv via pip or pip3 you')
- print ('need to uninstall it and install from source with -D WITH_V4L=ON')
- print ('Use the provided script: install-opencv-from_source.sh')
- exit_app = True
- exit()
- exit_app = False
- while(True):
- ret, input_image = cap.read()
- if (not ret):
- print("No image from from video device, exiting")
- break
- # 程序自检,看看检测窗口可被叉掉了
- prop_val = cv2.getWindowProperty(cv_window_name, cv2.WND_PROP_ASPECT_RATIO)
- if (prop_val < 0.0):
- exit_app = True
- break
- cropped_input, cropped = processor.preprocess_image(input_image)
- # 将输入写入input_fifo缓冲区并在一次调用中对推理进行排队
- graph.queue_inference_with_fifo_elem(in_fifo, out_fifo, cropped_input.astype('float32'), 'user object')
- # 将结果读取到输出Fifo
- output, userobj = out_fifo.read_elem()
- predict_label = output.argmax()
- percentage = int(output[predict_label] * 100)
- label_text = str(predict_label) + " (" + str(percentage) + "%)"
- print('Predicted:',label_text)
- processor.postprocess_image(input_image, percentage, label_text, cropped)
- cv2.imshow(cv_window_name, input_image)
- raw_key = cv2.waitKey(1)
- if (raw_key != -1):
- if (handle_keys(raw_key) == False):
- exit_app = True
- break
- cap.release()
- # 取消分配并清除fifo和图形,关闭设备
- try:
- in_fifo.destroy()
- out_fifo.destroy()
- graph.destroy()
- dev.close()
- dev.destroy()
- except:
- print("Error - could not close/destroy Graph/NCS device.")
- quit()
复制代码
下面是实际运行的照片:
Deep Learning with Keras.zip
(8.71 MB, 下载次数: 12, 售价: 20 与非币)
|