本文帶你使用移動(dòng)傳感器產(chǎn)生的原始數(shù)據(jù)來識(shí)別人類活動(dòng)。 人體活動(dòng)識(shí)別(HAR)是一種使用人工智能(AI)從智能手表等活動(dòng)記錄設(shè)備產(chǎn)生的原始數(shù)據(jù)中識(shí)別人類活動(dòng)的方法。當(dāng)人們執(zhí)行某種動(dòng)作時(shí),人們佩戴的傳感器(智能手表、手環(huán)、專用設(shè)備等)就會(huì)產(chǎn)生信號(hào)。這些收集信息的傳感器包括加速度計(jì)、陀螺儀和磁力計(jì)。人類活動(dòng)識(shí)別有各種各樣的應(yīng)用,從為病人和殘疾人提供幫助到像游戲這樣嚴(yán)重依賴于分析運(yùn)動(dòng)技能的領(lǐng)域。我們可以將這些人類活動(dòng)識(shí)別技術(shù)大致分為兩類:固定傳感器和移動(dòng)傳感器。在本文中,我們使用移動(dòng)傳感器產(chǎn)生的原始數(shù)據(jù)來識(shí)別人類活動(dòng)。

在本文中,我將使用LSTM (Long - term Memory)和CNN (Convolutional Neural Network)來識(shí)別下面的人類活動(dòng):
- 下樓
- 上樓
- 跑步
- 坐著
- 站立
- 步行
概述
你可能會(huì)考慮為什么我們要使用LSTM-CNN模型而不是基本的機(jī)器學(xué)習(xí)方法? 機(jī)器學(xué)習(xí)方法在很大程度上依賴于啟發(fā)式手動(dòng)特征提取人類活動(dòng)識(shí)別任務(wù),而我們這里需要做的是端到端的學(xué)習(xí),簡化了啟發(fā)式手動(dòng)提取特征的操作。
?我將要使用的模型是一個(gè)深神經(jīng)網(wǎng)絡(luò),該網(wǎng)絡(luò)是LSTM和CNN的組合形成的,并且具有提取活動(dòng)特征和僅使用模型參數(shù)進(jìn)行分類的能力。 這里我們使用WISDM數(shù)據(jù)集,總計(jì)1.098.209樣本。通過我們的訓(xùn)練,模型的F1得分為0.96,在測(cè)試集上,F(xiàn)1得分為0.89。
導(dǎo)入庫
首先,我們將導(dǎo)入我們將需要的所有必要庫。
我們將使用Sklearn,Tensorflow,Keras,Scipy和Numpy來構(gòu)建模型和進(jìn)行數(shù)據(jù)預(yù)處理。使用PANDAS 進(jìn)行數(shù)據(jù)加載,使用matplotlib進(jìn)行數(shù)據(jù)可視化。from pandas import read_csv, uniqueimport numpy as npfrom scipy.interpolate import interp1dfrom scipy.stats import modefrom sklearn.preprocessing import LabelEncoderfrom sklearn.metrics import classification_report, confusion_matrix, ConfusionMatrixDisplayfrom tensorflow import stackfrom tensorflow.keras.utils import to_categoricalfrom keras.models import Sequentialfrom keras.layers import Dense, GlobalAveragePooling1D, BatchNormalization, MaxPool1D, Reshape, Activationfrom keras.layers import Conv1D, LSTMfrom keras.callbacks import ModelCheckpoint, EarlyStoppingimport matplotlib.pyplot as plt%matplotlib inlineimport warningswarnings.filterwarnings("ignore")
數(shù)據(jù)集加載和可視化
WISDM是由個(gè)人腰間攜帶的移動(dòng)設(shè)備上的加速計(jì)記錄下來。該數(shù)據(jù)收集是由個(gè)人監(jiān)督的可以確保數(shù)據(jù)的質(zhì)量。我們將使用的文件是WISDM_AR_V1.1_RAW.TXT。使用PANDAS,可以將數(shù)據(jù)集加載到DataAframe中,如下面代碼:
def read_data(filepath):df = read_csv(filepath, header=None, names=['user-id','activity','timestamp','X','Y','Z'])## removing ';' from last column and converting it to floatdf['Z'].replace(regex=True, inplace=True, to_replace=r';', value=r'')df['Z'] = df['Z'].apply(convert_to_float)return dfdef convert_to_float(x):try:return np.float64(x)except:return np.nandf = read_data('Dataset/WISDM_ar_v1.1/WISDM_ar_v1.1_raw.txt')df

plt.figure(figsize=(15, 5))plt.xlabel('Activity Type')plt.ylabel('Training examples')df['activity'].value_counts().plot(kind='bar',title='Training examples by Activity Types')plt.show()plt.figure(figsize=(15, 5))plt.xlabel('User')plt.ylabel('Training examples')df['user-id'].value_counts().plot(kind='bar',title='Training examples by user')plt.show()
?現(xiàn)在我將收集的三個(gè)軸上的加速度計(jì)數(shù)據(jù)進(jìn)行可視化。
def axis_plot(ax, x, y, title):ax.plot(x, y, 'r')ax.set_title(title)ax.xaxis.set_visible(False)ax.set_ylim([min(y) - np.std(y), max(y) + np.std(y)])ax.set_xlim([min(x), max(x)])ax.grid(True)for activity in df['activity'].unique():limit = df[df['activity'] == activity][:180]fig, (ax0, ax1, ax2) = plt.subplots(nrows=3, sharex=True, figsize=(15, 10))axis_plot(ax0, limit['timestamp'], limit['X'], 'x-axis')axis_plot(ax1, limit['timestamp'], limit['Y'], 'y-axis')axis_plot(ax2, limit['timestamp'], limit['Z'], 'z-axis')plt.subplots_adjust(hspace=0.2)fig.suptitle(activity)plt.subplots_adjust(top=0.9)plt.show()

數(shù)據(jù)預(yù)處理
數(shù)據(jù)預(yù)處理是一項(xiàng)非常重要的任務(wù),它使我們的模型能夠更好地利用我們的原始數(shù)據(jù)。這里將使用的數(shù)據(jù)預(yù)處理方法有:
- 標(biāo)簽編碼
- 線性插值
- 數(shù)據(jù)分割
- 歸一化
- 時(shí)間序列分割
- 獨(dú)熱編碼
- Downstairs [0]
- Jogging [1]
- Sitting [2]
- Standing [3]
- Upstairs [4]
- Walking [5]
label_encode = LabelEncoder()df['activityEncode'] = label_encode.fit_transform(df['activity'].values.ravel())df
?線性插值 利用線性插值可以避免采集過程中出現(xiàn)NaN的數(shù)據(jù)丟失的問題。它將通過插值法填充缺失的值。雖然在這個(gè)數(shù)據(jù)集中只有一個(gè)NaN值,但為了我們的展示,還是需要實(shí)現(xiàn)它。
數(shù)據(jù)分割 根據(jù)用戶id進(jìn)行數(shù)據(jù)分割,避免數(shù)據(jù)分割錯(cuò)誤。我們?cè)谟?xùn)練集中使用id小于或等于27的用戶,其余的在測(cè)試集中使用。interpolation_fn = interp1d(df['activityEncode'] ,df['Z'], kind='linear')null_list = df[df['Z'].isnull()].index.tolist()for i in null_list:y = df['activityEncode'][i]value = interpolation_fn(y)df['Z']=df['Z'].fillna(value)print(value)
歸一化 在訓(xùn)練之前,需要將數(shù)據(jù)特征歸一化到0到1的范圍內(nèi)。我們用的方法是:df_test = df[df['user-id'] > 27]df_train = df[df['user-id'] <= 27]
?
df_train['X'] = (df_train['X']-df_train['X'].min())/(df_train['X'].max()-df_train['X'].min())df_train['Y'] = (df_train['Y']-df_train['Y'].min())/(df_train['Y'].max()-df_train['Y'].min())df_train['Z'] = (df_train['Z']-df_train['Z'].min())/(df_train['Z'].max()-df_train['Z'].min())df_train
?時(shí)間序列分割 因?yàn)槲覀兲幚淼氖菚r(shí)間序列數(shù)據(jù), 所以需要?jiǎng)?chuàng)建一個(gè)分割的函數(shù),標(biāo)簽名稱和每個(gè)記錄的范圍進(jìn)行分段。此函數(shù)在x_train和y_train中執(zhí)行特征的分離,將每80個(gè)時(shí)間段分成一組數(shù)據(jù)。
這樣,x_train和y_train形狀變?yōu)椋?/span>def segments(df, time_steps, step, label_name):N_FEATURES = 3segments = []labels = []for i in range(0, len(df) - time_steps, step):xs = df['X'].values[i:i+time_steps]ys = df['Y'].values[i:i+time_steps]zs = df['Z'].values[i:i+time_steps]label = mode(df[label_name][i:i+time_steps])[0][0]segments.append([xs, ys, zs])labels.append(label)reshaped_segments = np.asarray(segments, dtype=np.float32).reshape(-1, time_steps, N_FEATURES)labels = np.asarray(labels)return reshaped_segments, labelsTIME_PERIOD = 80STEP_DISTANCE = 40LABEL = 'activityEncode'x_train, y_train = segments(df_train, TIME_PERIOD, STEP_DISTANCE, LABEL)
這里還存儲(chǔ)了一些后面用到的數(shù)據(jù):時(shí)間段(time_period),傳感器數(shù)(sensors)和類(num_classes)的數(shù)量。print('x_train shape:', x_train.shape)print('Training samples:', x_train.shape[0])print('y_train shape:', y_train.shape)x_train shape: (20334, 80, 3)Training samples: 20334y_train shape: (20334,)
最后需要使用Reshape將其轉(zhuǎn)換為列表,作為keras的輸入:time_period, sensors = x_train.shape[1], x_train.shape[2]num_classes = label_encode.classes_.sizeprint(list(label_encode.classes_))['Downstairs', 'Jogging', 'Sitting', 'Standing', 'Upstairs', 'Walking']
最后需要將所有數(shù)據(jù)轉(zhuǎn)換為float32。input_shape = time_period * sensorsx_train = x_train.reshape(x_train.shape[0], input_shape)print("Input Shape: ", input_shape)print("Input Data Shape: ", x_train.shape)Input Shape: 240Input Data Shape: (20334, 240)
獨(dú)熱編碼 這是數(shù)據(jù)預(yù)處理的最后一步,我們將通過編碼標(biāo)簽并將其存儲(chǔ)到y(tǒng)_train_hot中來執(zhí)行。x_train = x_train.astype('float32')y_train = y_train.astype('float32')
y_train_hot = to_categorical(y_train, num_classes)print("y_train shape: ", y_train_hot.shape)y_train shape: (20334, 6)
模型
?我們使用的模型是一個(gè)由8層組成的序列模型。模型前兩層由LSTM組成,每個(gè)LSTM具有32個(gè)神經(jīng)元,使用的激活函數(shù)為Relu。然后是用于提取空間特征的卷積層。 在兩層的連接處需要改變LSTM輸出維度,因?yàn)檩敵鼍哂?個(gè)維度(樣本數(shù),時(shí)間步長,輸入維度),而CNN則需要4維輸入(樣本數(shù),1,時(shí)間步長,輸入)。 第一個(gè)CNN層具有64個(gè)神經(jīng)元,另一個(gè)神經(jīng)元有128個(gè)神經(jīng)元。在第一和第二CNN層之間,我們有一個(gè)最大池層來執(zhí)行下采樣操作。然后是全局平均池(GAP)層將多D特征映射轉(zhuǎn)換為1-D特征向量,因?yàn)樵诖藢又胁恍枰獏?shù),所以會(huì)減少全局模型參數(shù)。然后是BN層,該層有助于模型的收斂性。 最后一層是模型的輸出層,該輸出層只是具有SoftMax分類器層的6個(gè)神經(jīng)元的完全連接的層,該層表示當(dāng)前類的概率。
model = Sequential()model.add(LSTM(32, return_sequences=True, input_shape=(input_shape,1), activation='relu'))model.add(LSTM(32,return_sequences=True, activation='relu'))model.add(Reshape((1, 240, 32)))model.add(Conv1D(filters=64,kernel_size=2, activation='relu', strides=2))model.add(Reshape((120, 64)))model.add(MaxPool1D(pool_size=4, padding='same'))model.add(Conv1D(filters=192, kernel_size=2, activation='relu', strides=1))model.add(Reshape((29, 192)))model.add(GlobalAveragePooling1D())model.add(BatchNormalization(epsilon=1e-06))model.add(Dense(6))model.add(Activation('softmax'))print(model.summary())

訓(xùn)練和結(jié)果
經(jīng)過訓(xùn)練,模型給出了98.02%的準(zhǔn)確率和0.0058的損失。訓(xùn)練F1得分為0.96。
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])history = model.fit(x_train,y_train_hot,batch_size= 192,epochs=100)
?可視化訓(xùn)練的準(zhǔn)確性和損失變化圖。
plt.figure(figsize=(6, 4))plt.plot(history.history['accuracy'], 'r', label='Accuracy of training data')plt.plot(history.history['loss'], 'r--', label='Loss of training data')plt.title('Model Accuracy and Loss')plt.ylabel('Accuracy and Loss')plt.xlabel('Training Epoch')plt.ylim(0)plt.legend()plt.show()y_pred_train = model.predict(x_train)max_y_pred_train = np.argmax(y_pred_train, axis=1)print(classification_report(y_train, max_y_pred_train))

?在測(cè)試數(shù)據(jù)集上測(cè)試它,但在通過測(cè)試集之前,需要對(duì)測(cè)試集進(jìn)行相同的預(yù)處理。
在評(píng)估我們的測(cè)試數(shù)據(jù)集后,得到了89.14%的準(zhǔn)確率和0.4647的損失。F1測(cè)試得分為0.89。df_test['X'] = (df_test['X']-df_test['X'].min())/(df_test['X'].max()-df_test['X'].min())df_test['Y'] = (df_test['Y']-df_test['Y'].min())/(df_test['Y'].max()-df_test['Y'].min())df_test['Z'] = (df_test['Z']-df_test['Z'].min())/(df_test['Z'].max()-df_test['Z'].min())x_test, y_test = segments(df_test,TIME_PERIOD,STEP_DISTANCE,LABEL)x_test = x_test.reshape(x_test.shape[0], input_shape)x_test = x_test.astype('float32')y_test = y_test.astype('float32')y_test = to_categorical(y_test, num_classes)
score = model.evaluate(x_test, y_test)print("Accuracy:", score[1])print("Loss:", score[0])
?下面繪制混淆矩陣更好地理解對(duì)測(cè)試數(shù)據(jù)集的預(yù)測(cè)。
predictions = model.predict(x_test)predictions = np.argmax(predictions, axis=1)y_test_pred = np.argmax(y_test, axis=1)cm = confusion_matrix(y_test_pred, predictions)cm_disp = ConfusionMatrixDisplay(confusion_matrix= cm)cm_disp.plot()plt.show()
?還可以在測(cè)試數(shù)據(jù)集上評(píng)估的模型的分類報(bào)告。
print(classification_report(y_test_pred, predictions))

總結(jié)
LSTM-CNN模型的性能比任何其他機(jī)器學(xué)習(xí)模型要好得多。本文的代碼可以在GitHub上找到。 https://github.com/Tanny1810/Human-Activity-Recognition-LSTM-CNN 您可以嘗試自己實(shí)現(xiàn)它,通過優(yōu)化模型來提高F1分?jǐn)?shù)。 另:這個(gè)模型是來自于Xia Kun, Huang Jianguang, and Hanyu Wang在IEEE期刊上發(fā)表的論文LSTM-CNN Architecture for Human Activity Recognition。 https://ieeexplore.ieee.org/abstract/document/9043535 審核編輯 :李倩
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。
舉報(bào)投訴
-
傳感器
+關(guān)注
關(guān)注
2576文章
55041瀏覽量
791288 -
神經(jīng)網(wǎng)絡(luò)
+關(guān)注
關(guān)注
42文章
4838瀏覽量
107758 -
機(jī)器學(xué)習(xí)
+關(guān)注
關(guān)注
66文章
8553瀏覽量
136940 -
移動(dòng)傳感器
+關(guān)注
關(guān)注
0文章
8瀏覽量
8690
原文標(biāo)題:基于LSTM-CNN的人體活動(dòng)識(shí)別
文章出處:【微信號(hào):vision263com,微信公眾號(hào):新機(jī)器視覺】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
熱點(diǎn)推薦
探索XENSIV? 連接傳感器套件:開啟快速物聯(lián)網(wǎng)體驗(yàn)
詳細(xì)了解一下這個(gè)套件。 文件下載: Infineon Technologies XENSIV? BGT60TR13C聯(lián)網(wǎng)傳感器套件.pdf 套件概述 XENSIV? 連接傳感器套件旨在解決物聯(lián)網(wǎng)設(shè)備開發(fā)和部署中的四大關(guān)鍵挑戰(zhàn),即感知周圍環(huán)境(感知)、處理
角度傳感器原理、技術(shù)與實(shí)用指南
移動(dòng),改變輸出電壓來反映角度變化。 示例: 某電位器式角度傳感器,在旋轉(zhuǎn) 360 度時(shí),輸出電壓在 0 到 5 伏之間線性變化。 光電式角度傳感器
?VL53L7CH飛行時(shí)間傳感器:開啟人工智能感知新紀(jì)元的技術(shù)解析
STMicroelectronics VL53L7CH飛行時(shí)間 (ToF) 傳感器是一款8x8(64區(qū))多區(qū)域傳感器,具有超寬90°對(duì)角線視場(chǎng) (FoV)。該傳感器為需要ToF傳感器多
新品 | Unit Fingerprint2,高性能指紋識(shí)別傳感器單元
UnitFingerprint2是一款高性能指紋識(shí)別傳感器單元,內(nèi)部集成STM32核心主控與A-K323CP一體化指紋識(shí)別模組,采用半導(dǎo)體電容式傳感器,具備指紋采集、特征提取、注冊(cè)、比對(duì)、存儲(chǔ)、檢索
MTCH9010液體檢測(cè)芯片技術(shù)解析:雙模傳感與低功耗設(shè)計(jì)的完美結(jié)合
Microchip Technology MTCH9010液體檢測(cè)器提供數(shù)字和原始數(shù)據(jù)輸出,是一種在不同傳感器上檢測(cè)液體是否存在的靈活方式。該檢測(cè)器支持各種形狀和尺寸的
監(jiān)測(cè)氣象會(huì)用到哪些傳感器
監(jiān)測(cè)氣象需要使用多種傳感器來精確測(cè)量不同氣象要素,這些傳感器基于物理、化學(xué)或電子原理,能夠?qū)崟r(shí)、連續(xù)地采集數(shù)據(jù)。以下是監(jiān)測(cè)氣象時(shí)常用的傳感器
邊緣計(jì)算網(wǎng)關(guān)的數(shù)據(jù)過濾功能體現(xiàn)在哪
體現(xiàn)如下: 1. 本地數(shù)據(jù)清洗與冗余剔除 原始數(shù)據(jù)過濾 :邊緣計(jì)算網(wǎng)關(guān)在數(shù)據(jù)源頭(如傳感器、設(shè)備)附近對(duì)采集到的原始數(shù)據(jù)進(jìn)行初步清洗,剔除重
如何使用 CYW20829 將獲得的傳感器數(shù)據(jù)發(fā)送到廣播中?
我計(jì)劃使用外部傳感器將原始數(shù)據(jù)輸出到藍(lán)牙模塊的閃存中,然后通過藍(lán)牙發(fā)送原始數(shù)據(jù),與我個(gè)人筆記本電腦的藍(lán)牙配對(duì),并在我的個(gè)人電腦中獲取這些原始數(shù)據(jù)。 我計(jì)劃先用 python 獲取
發(fā)表于 07-02 07:16
Analog Devices Inc. EV-STRUCTURAL-ARDZ活動(dòng)傳感器評(píng)估板特性/應(yīng)用/框圖
Analog Devices Inc. EV-STRUCTURAL-ARDZ活動(dòng)傳感器評(píng)估板是一款振動(dòng)傳感器,使用ADXL343數(shù)字輸出MEMS加速計(jì)芯片和ADIS16203可編程360° 傾角儀
太陽誘電氣味傳感器:致力于模仿人類的嗅覺系統(tǒng)進(jìn)行研發(fā)
本文概述氣味傳感器的核心功能與精巧結(jié)構(gòu)。太陽誘電致力于模仿人類的嗅覺系統(tǒng),研發(fā)氣味傳感器。
AMEYA360:太陽誘電氣味傳感器致力于模仿人類的嗅覺系統(tǒng)進(jìn)行研發(fā)
能夠吸附多種氣味分子的膜是關(guān)鍵所在。檢測(cè)到的氣味分子會(huì)通過傳感器轉(zhuǎn)換成電信號(hào)并進(jìn)行量化。 QCM型氣味傳感器量化頻率變化。MEMS型氣味傳感器則量化電阻變化。通過機(jī)器學(xué)習(xí)從量化數(shù)據(jù)中
MAX32664超低功耗生物識(shí)別傳感器集中器技術(shù)手冊(cè)
MAX32664為傳感器集中器家族,帶有適合可穿戴設(shè)備的嵌入式固件和算法。器件無縫支持客戶所需的傳感器功能,包括與Maxim的光學(xué)傳感器方案通信,以及為外部提供
MAX32674C超低功耗生物識(shí)別算法/傳感器中樞技術(shù)手冊(cè)
MAX32674C是一款算法/傳感器中樞,提供嵌入式軟件和先進(jìn)的算法,適用于健身和醫(yī)療可穿戴設(shè)備市場(chǎng),可直接與ADI的光學(xué)傳感器進(jìn)行接口。配置為算法中樞時(shí),MAX32674C可處理原始數(shù)據(jù)并輸出
如何將 ADAM 采集模塊的 Modbus 原始值轉(zhuǎn)換成物理值?
在工業(yè)數(shù)據(jù)采集領(lǐng)域,ADAM系列模塊的Modbus原始值轉(zhuǎn)換是工程師常見的技術(shù)挑戰(zhàn)。本文蘇州研訊電子科技有限公司將通過具體案例,解析16位數(shù)據(jù)轉(zhuǎn)換的底層邏輯與實(shí)操步驟,幫助您快速實(shí)現(xiàn)原始數(shù)據(jù)
傳感器諧波頻率產(chǎn)生原因解析
傳感器諧波頻率(通常指的是傳感器的諧振頻率及其相關(guān)諧波)的產(chǎn)生原因可以從以下幾個(gè)方面進(jìn)行解析。 一、傳感器機(jī)械結(jié)構(gòu)特性 1. 一階諧振頻率:對(duì)于壓電式
使用移動(dòng)傳感器產(chǎn)生的原始數(shù)據(jù)來識(shí)別人類活動(dòng)
評(píng)論