TDengine+OpenVINO+AIxBoard助力时序数据分类

时间序列数据分析在工业,能源,医疗,交通,金融,零售等多个领域都有广泛应用。其中时间序列数据分类是分析时序数据的常见任务之一。本文将通过一个具体的案例,介绍 intel 团队如何使用 tdengine 作为基础软件存储实验数据,并通过 tdengine 高效的查询能力在 openvino 部署深度学习模型,最终在 aixboard 开发板上实时运行分类任务。
01模型简介
近年来机器学习和深度学习在时序数据分类任务中取得了显著进展,hive-cote 和 inceptiontime 模型都取得了不错的成果。相比基于 nearest neighbor 和 dtw 算法的 hive-cote 模型,基于一维卷积 (conv1d) 的 inceptiontime 模型成果更为显著,其在极大降低计算复杂度的基础上,还达到了与 hive-cote 相当的分类精度。
如下图所示,inception 模块是 inceptiontime 模型的基本组成模块,由多个一维卷积 (conv1d) 操作堆叠,并于残差连接而成。
完整的 inceptiontime 模型由多个 inception 模块连接而成。 关于 inceptiontime 的更多细节请参考论文:https://arxiv.org/abs/1909.04939。
02数据集
 本文采用的数据集来自 http://timeseriesclassification.com/tsc.zip,由 128 个时间序列分类任务组成。其中的 wafer 数据集包含 1000 条训练数据和和 6164 条测试数据,每条数据均包含标签值和长度 152 的时间序列数据。数据通过程序提前写入到 tdengine 中。
这里描述的时序数据是晶片生成过程中同一个工具通过单个传感器记录的时间序列数据。下图展示了正常 (class 1) 和异常 (class 0) 两种标签对应的时序数据示例。
不难看出,这是一个标准的监督学习分类任务。我们希望找到一个模型,在每输入长度 152 的时序数据时,模型输出 0 或 1,以此判断输入时序数据对应的晶片在生成过程是否存在异常。
03模型训练
  本文中我们将使用 wafer 数据集训练一个 inceptiontime 模型。训练得到的模型可以根据晶片生产过程中传感器记录的时序数据,判断某个晶片的生产过程是否存在异常。
inceptiontime 的作者开源了基于 tensorflow.keras 的实现,本文的模型代码基于 inceptiontime 开源版本并集成 tdengine 支持 https://github.com/sangshuduo/inceptiontime。
首先加载 python 库。
from os import pathimport numpy as npfrom sklearn import preprocessingfrom tensorflow import kerasfrom tensorflow.keras.layers import ( activation, add, batchnormalization, concatenate, conv1d, dense, input, globalaveragepooling1d, maxpool1d)from sqlalchemy import create_engine, text然后使用 tdengine 的 sqlalchemy 驱动加载 wafer 数据集并进行预处理。def readucr(conn, dbname, tablename): data = pd.read_sql( text( select * from + dbname + . + tablename ), conn, ) y = data[:, 0] x = data[:, 1:] return x, ydef load_data(db): engine = create_engine(taos://root:taosdata@localhost:6030/ + db) try: conn = engine.connect() except exception as e: print(e) exit(1) if conn is not none: print(connected to the tdengine ...) else: print(failed to connect to taos) exit(1) x_train, y_train = readucr(conn, db + '_train.tsv') x_test, y_test = readucr(conn, db + '_test.tsv') n_classes = len(np.unique(y_train)) enc = preprocessing.onehotencoder() y = np.concatenate((y_train, y_test), axis=0).reshape(-1,1) enc.fit(y) y_tr = enc.transform(y_train.reshape(-1,1)).toarray() y_te = enc.transform(y_test.reshape(-1,1)).toarray() x_tr, x_te = map(lambda x: x.reshape(x.shape[0], x.shape[1], 1), [x_train, x_test]) return x_tr, y_tr, x_te, y_te, n_classesx_tr, y_tr, x_te, y_te, n_classes = load_data('wafer')  
再使用 tensorflow.keras 实现 incetiontime,并创建模型。
def inception_module(input_tensor, filters, kernel_size, bottleneck_size, activation='relu', use_bottleneck=true): if use_bottleneck and int(input_tensor.shape[-1]) > 1: input_inception = conv1d(filters=bottleneck_size, kernel_size=1, padding='same', activation=activation, use_bias=false)(input_tensor) else: input_inception = input_tensor kernel_size_s = [kernel_size // (2 ** i) for i in range(3)] # [40, 20, 10] conv_list = [] for i in range(len(kernel_size_s)): conv = conv1d(filters=filters, kernel_size=kernel_size_s[i], strides=1, padding='same', activation=activation, use_bias=false)(input_inception) conv_list.append(conv) max_pool = maxpool1d(pool_size=3, strides=1, padding='same')(input_tensor) conv_6 = conv1d(filters=filters, kernel_size=1, padding='same', activation=activation, use_bias=false)(max_pool) conv_list.append(conv_6) x = concatenate(axis=2)(conv_list) x = batchnormalization()(x) x = activation(activation='relu')(x) return xdef shortcut_layer(input_tensor, output_tensor): y = conv1d(filters=int(output_tensor.shape[-1]), kernel_size=1, padding='same', use_bias=false)(input_tensor) y = batchnormalization()(y) x = add()([y, output_tensor]) x = activation(activation='relu')(x) return xdef build_model(input_shape, n_classes, depth=6, filters=32, kernel_size=40, bottleneck_size=32, use_residual=true): input_layer = input(input_shape) x = input_layer input_res = input_layer for d in range(depth): x = inception_module(x, filters, kernel_size, bottleneck_size) if use_residual and d % 3 == 2: x = shortcut_layer(input_res, x) input_res = x gap_layer = globalaveragepooling1d()(x) output_layer = dense(n_classes, activation=softmax)(gap_layer) model = keras.model(input_layer, output_layer) return modelmodel = build_model(x_tr.shape[1:], n_classes)model.compile( optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])  
训练模型:
ckpt_path = path.sep.join(['.', 'models', 'inception_wafer.h5'])callbacks = [ keras.callbacks.reducelronplateau( monitor='val_loss', factor=0.5, patience=20, min_lr=0.0001 ), keras.callbacks.earlystopping(monitor='val_loss', patience=20, verbose=1), keras.callbacks.modelcheckpoint( filepath=ckpt_path, monitor='val_loss', save_best_only=true )]batch_size = 32epochs = 500history = model.fit(x_tr, y_tr, batch_size, epochs, verbose='auto', shuffle=true, validation_split=0.2, callbacks=callbacks)简单显示一下训练过程:metric = 'accuracy'plt.figure(figsize=(10, 5))plt.plot(history.history[metric])plt.plot(history.history['val_'+metric])plt.title(model + metric)plt.ylabel(metric, fontsize='large')plt.xlabel('epoch', fontsize='large')plt.legend([train, val], loc=best)plt.show()plt.close()   
使用测试数据验证模型的推理精度。
classifier = keras.models.load_model(ckpt_path)test_loss, test_acc = classifier.evaluate(x_te, y_te)print(test accuracy: , test_acc)print(test loss: , test_loss)193/193 [==============================] - 2s 11ms/step - loss: 0.0142 - accuracy: 0.9958test accuracy: 0.9957819581031799test loss: 0.014155667275190353  
我们的模型在 wafer 测试数据上取得了 99.58% 的精度。
04模型转换
为了达成使用 openvino runtime 进行推理计算的目的,我们需要将 tensorflow 模型转换为 openvino ir 格式。
from pathlib import pathfrom openvino.tools import mofrom tensorflow import kerasmodel = keras.models.load_model('models/inception_wafer.h5')model_path = path('models/inception.0_float')model.save(model_path)model_dir = path(ov)model_dir.mkdir(exist_ok=true)ir_path = path(ov/inception.xml)input_shape = [1, 152, 1]if not ir_path.exists(): print(exporting tensorflow model to ir...) ov_model = mo.convert_model(saved_model_dir=model_path, input_shape=input_shape, compress_to_fp16=true) serialize(ov_model, ir_path)else: print(fir model {ir_path} already exists.)  
转换完成后,生成的 ir 格式模型被存储为模型定义文件 inception.xml 和二进制文件 inception.bin。
05模型部署
  接下来我们在 aixboard 开发板上部署刚刚训练的 incetpiontime 模型。首先将 inception.bin、inception.xml 和  wafer_test.tsv 几个文件复制到 aixboard 板上。
加载 python 库。
from pathlib import pathimport numpy as npfrom openvino.runtime import core, serialize  
使用 openvino 运行 inception 模型。
ir_path = path(inception.xml)core = core()model = core.read_model(ir_path)import ipywidgets as widgetsdevice = widgets.dropdown( options=core.available_devices + [auto], value='auto', description='device:', disabled=false)devicedef readucr(filename, delimiter=' '): data = np.loadtxt(filename, delimiter=delimiter) y = data[:, 0] x = data[:, 1:] y[y==-1] = 0 return np.expand_dims(x, axis=2), yx, y = readucr('wafer_test.tsv')compiled_model = core.compile_model(model, device_name=device.value)input_key = compiled_model.input(0)output_key = compiled_model.output(0)network_input_shape = input_key.shapecounter = 0for idx, i in enumerate(x): i = np.expand_dims(i, axis=0) r = compiled_model(i)[output_key] counter += 1 if r.argmax() == y[idx] else 0print('{:.6f}'.format(counter/len(y)))0.995782  
使用 openvino 推理的精度跟 tensorflow 模型推理精度一致,同样达到了 99.58%。我们在模型转换时将原模型数据格式压缩为 fp16,这一操作并没有导致精度下降。
性能测试
使用 openvino 自带的 benchmark 工具可以轻松地在 aixboard 上进行性能测试。
benchmark_app -m inception.xml -hint latency -d cpu[ info ] first inference took 8.59 ms[step 11/11] dumping statistics report[ info ] execution devices:['cpu'][ info ] count: 8683 iterations[ info ] duration: 60012.27 ms[ info ] latency:[ info ] median: 6.44 ms[ info ] average: 6.81 ms[ info ] min: 6.34 ms[ info ] max: 37.13 ms[ info ] throughput: 144.69 fpsbenchmark_app -m inception.xml -hint latency -d gpu[ info ] first inference took 10.58 ms[step 11/11] dumping statistics report[ info ] execution devices:['gpu.0'][ info ] count: 7151 iterations[ info ] duration: 60026.34 ms[ info ] latency:[ info ] median: 7.50 ms[ info ] average: 8.23 ms[ info ] min: 7.04 ms[ info ] max: 21.78 ms[ info ] throughput: 119.13 fps从上面结果可以看出,使用 aixboard 的 cpu 运行 inceptiontime 模型推理,平均时长为 6.81ms。使用集成 gpu 推理,平均时长为 8.23ms。  
06总结
本文介绍了如何利用 tdengine 支持时间序列数据的底层存储,以及如何通过分类模型 inceptiontime 在 ucr 时序数据集的 wafer 分类任务上进行训练。最后,我们使用 openvino 将该模型部署在 aixboard 开发板上,实现了高效的实时时序数据分类任务。希望本文的内容能够帮助大家在项目中利用 tdengine、openvino 和 aixboard 来解决更多的时间序列分析问题。
01关于 aixboard
英特尔开发者套件 aixboard(爱克斯开发板)是专为支持入门级边缘 ai 应用程序和设备而设计,能够满足人工智能学习、开发、实训等应用场景。该开发板是类树莓派的 x86 主机,可支持 linux ubuntu 及完整版 windows 操作系统,板载一颗英特尔 4 核处理器,最高运行频率可达 2.9 ghz,且内置核显(igpu),板载 64gb emmc 存储及 lpddr4x 2933mhz(4gb/6gb/8gb),内置蓝牙和 wi-fi 模组,支持 usb 3.0、hdmi 视频输出、3.5mm 音频接口,1000mbps 以太网口,完全可把它作为一台 mini 小电脑来看待,且其可集成一块 arduino leonardo 单片机,可外拓各种传感器模块。此外,其接口与 jetson nano 载板兼容,gpio 与树莓派兼容,能够最大限度地复用树莓派、jetson nano 等生态资源,无论是摄像头物体识别,3d 打印,还是 cnc 实时插补控制都能稳定运行,不仅可作为边缘计算引擎用于人工智能产品验证、开发,也可作为域控核心用于机器人产品开发。
02关于 tdengine
tdengine 核心是一款高性能、集群开源、云原生的时序数据库(time series database,tsdb),专为物联网、工业互联网、电力、it 运维等场景设计并优化,具有极强的弹性伸缩能力。同时它还带有内建的缓存、流式计算、数据订阅等系统功能,能大幅减少系统设计的复杂度,降低研发和运营成本,是一个高性能、分布式的物联网、工业大数据平台。当前 tdengine 主要提供两大版本,分别是支持私有化部署的 tdengine enterprise 以及全托管的物联网、工业互联网云服务平台 tdengine cloud,两者在开源时序数据库 tdengine oss 的功能基础上有更多加强,用户可根据自身业务体量和需求进行版本选择。
03关于作者
冯伟,英特尔软件架构师,16 年软件研发经验,涵盖浏览器、计算机视觉、虚拟机等多个领域。2015 年加入英特尔,近年来专注于边缘计算、深度学习模型落地,以及时序数据分析等方向。


中小学食堂快检室综合性建设方案是针对什么进行设计?
英伟达重磅发布CMNP HX系列专用矿卡
中芯国际SN1项目建成后将提大地提升国内14nm及以下工艺的制造能力
最酷惠普可穿戴式VR背包电脑
电气系统的PCB设计:组件放置策略和功能
TDengine+OpenVINO+AIxBoard助力时序数据分类
解析车载半导体供给不足的真正原因
华虹半导体第三代 90nm eFlash工艺平台实现量产!
制造业升级路径:机器人到工业互联网
SIA:2月全球半导体销售额年降7.3%
导热双面胶常见的4大问题
苹果AR眼镜进展揭秘,有望2020 年发货
如何计算单头电热管表面负荷?
雷柏V29S幻彩RGB电竞鼠标评测 手感和性能都令人满意
什么情况下对极几何约束会不成立?
纸张表面缺陷在线检测系统的工作原理
瑞萨电子推出新型全塑封型数字电源模块系列
苹果服务营收增速放缓 苹果代工厂满地鸡毛
利用MCP3008实现水传感器控制系统的设计
利用LS-SVM回归算法辨识模型参数实现传感器非线性校正的研究