梶研 [mocopiとaction slam(SVM)]
2024年01月30日
mocopiとaction slam(SVM)
出席率
- 3年セミナー:??%
スケジュール
短期的な予定
- [ ] mocopi と action slam2
- [x] シーンとランドマークを決める(~2月上旬)
- [x] SVM で動作判別する
- [ ] ?
- [ ] 論文書く
- [ ] 発表
長期的な予定
- ~?月 シーン検知?をする
- ~?月 論文を書く
- ~?月 論文発表したい
進捗報告
mocopiとaction slam(SVM)
梶研でいろんな動作をする中で冷蔵庫を開け閉めする動作をランドマークとする(仮)
センシング
<iframe width="1139" height="641" src="https://www.youtube.com/embed/YAV4htI3wwY" title="mocopiセンシング 冷蔵庫開け閉め+他の動作" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
特徴量
HASC2010corpusを用いた被験者数と 人間行動認識率の相関 .
https://nagoya.repo.nii.ac.jp/record/13543/files/dt_hiro.pdf
認識の際には, 平均, エネルギー, エントロピー, 相関が特徴量として使用されている
>> [2. 関連研究の紹介(p.2)]
>> Bao, L. and Intille, S. S. Activity Recognition from User-Annotated Acceleration Data. Proc of PERVASIVE 2004, pp. 1-17, 2004.
認識の際には, 特徴量として, 窓幅 5.12 秒毎の平均,標準偏差,エネルギー,相関が用いられており
>> [2. 関連研究の紹介(p.3)]
>> Ravi, N., Dandekar, N., Mysore, P. and Littman, L. M. Activity Recognition From Accelerometer Data. Proc of IAAI, pp. 1541-1546, 2005.
ノルムを計 算し, 得られた波形の平均と分散を特徴量として抽出
加速度のノルムに対して, 平均, 分散, 周波数帯域毎のエネルギー, 零点交差率 の 7 つの特徴量を用いた行動認識に関する評価実験も行った
加速度の積分値を 8 つ目の特徴量とした場合の評価実験を行った
>> [4.2 特徴量]
行動認識の特徴量
- 平均
- 分散
- 相関
- エネルギー
- ?
- エントロピー
- 情報源がどれだけ情報を出しているか
- https://www.mnc.toho-u.ac.jp/v-lab/yobology/entropy/entropy.htm
- 零点交差率
- 一定区間内で0を横切る頻度
- 加速度の積分値
窓ごとの特徴量を出す
窓幅は3秒とする
<details>
<summary>bvhから特徴量のcsvを出力する</summary>
# 窓ごとの特徴量を抽出
## データの読み込み
bvhp = BVHparser('./logs/refrigerator.bvh')
df = bvhp.get_motion_df()
# 窓ごとの特徴量を抽出する関数
def calculate_features(window):
features = []
# 中央値の計算
median_time = window['time'].mean()
# 平均、分散、相関、ゼロ交差数、エネルギー、エントロピーの計算
for joint in columns:
X_rotate = window[joint + '_Xrotation'].values
Y_rotate = window[joint + '_Yrotation'].values
Z_rotate = window[joint + '_Zrotation'].values
# 平均
mean_value = np.mean([X_rotate, Y_rotate, Z_rotate])
# 分散
variance_value = np.var([X_rotate, Y_rotate, Z_rotate])
# 相関
correlation_value = np.corrcoef([X_rotate, Y_rotate, Z_rotate])[0, 1]
# ゼロ交差数
zero_crossings = np.sum(np.diff(np.signbit([X_rotate, Y_rotate, Z_rotate])) != 0)
# エネルギー
energy_value = np.sum(np.square([X_rotate, Y_rotate, Z_rotate]))
# エントロピー
# entropy_value = entropy([X_rotate, Y_rotate, Z_rotate])
# features.extend([mean_value, variance_value, correlation_value, zero_crossings, energy_value, entropy_value])
features.extend([mean_value, variance_value, correlation_value, zero_crossings, energy_value])
return [median_time] + features
# 窓ごとの特徴量を計算し、結果をデータフレームに格納
window_size = 3
window_stride = 1
columns = [j for j in bvhp.get_joints() if not j.startswith('_')]
windows = [df.iloc[i:i + window_size] for i in range(0, len(df), window_stride) if i + window_size <= len(df)]
# result_columns = ['time'] + [f'{joint}_{metric}' for joint in columns for metric in ['mean', 'var', 'corr', 'zero_cross', 'energy', 'entropy']]
result_columns = ['time'] + [f'{joint}_{metric}' for joint in columns for metric in ['mean', 'var', 'corr', 'zero_cross', 'energy']]
result_data = [calculate_features(window) for window in windows]
result_df = pd.DataFrame(result_data, columns=result_columns)
# ラベル情報をもとにstateカラムを追加
labels = [
{'title': '冷蔵庫を開ける', 'num': 1, 'times': [[10, 12], [33, 35], [39, 41], [55, 57], [77.5, 79.5], [104, 106], [133, 135]]},
{'title': '冷蔵庫を閉める', 'num': 2, 'times': [[14, 16], [36, 38], [42, 45], [58, 60], [82, 84], [106.5, 108.5], [135, 137]]},
]
result_df['state'] = 0 # 初期値として全ての行に0を設定
for label in labels:
for time_range in label['times']:
start_time, end_time = time_range
result_df.loc[(result_df['time'] >= start_time) & (result_df['time'] <= end_time), 'state'] = label['num']
# 結果をCSVファイルに書き出し
result_df.to_csv('./logs/refrigerator_with_state.csv', index=False) </details>
特徴量を学習させる
df = pd.read_csv('./logs/refrigerator_with_state.csv')
# data の 'state' 'time' 以外を取得し, NaN を 0 で埋める
data = df.drop(['state', 'time'], axis=1).fillna(0)
target = df['state']
# 学習
clf = svm.SVC(gamma="scale")
clf.fit(data, target) 正答率を出す
# 正答率
test_data = df.drop(['time', 'state'], axis=1).fillna(0)
ans = clf.predict(test_data)
# ans と df['state'] を比較し、一致した割合を出力
print(sum(ans == df['state']) / len(df['state'])) 正答率: 0.9063168562098862 (約90.6%)
誤差の原因
ラベル付けが雑かった?
大まかな1s単位で付けた
背景は手動でラベル付けした結果
青: 冷蔵庫を開ける
黄: 冷蔵庫を閉める
0: その他
1: 冷蔵庫を開ける
2: 冷蔵庫を閉める
正解(理想)
予測
正解と予測の差
丁寧にラベル付けした結果
正答率: 0.8908906654656007(約89.1%)
下がった
原因
- 動作を始める瞬間 から 終える瞬間 までなるべく広めに取ったのが悪い?
- 確実に動作している
- ウィンドウサイズが大きい?
- 1回の開ける・閉めるは1~2s に対して ウィンドウは3s
- 特徴量はこれだけでいいのか?
- データが少ない?
1. 確実に動作している部分だけにした
正答率: 0.9225312464812521 (約92.3%)
- 正答率が上がったのはそもそも正解部分が少ないからだと思われる
- 開け閉め中もその他に含まれたり、含まれなかったりするため良くない
2. ウィンドウサイズを変える
window_size = 1
window_size = 2
window_size = 3
window_size = 4
window_size = 5
window_size = 10
変わらない
→ 60fps だから大差ない
window_size = 30 (0.5s)
細切れの部分が減った
TODO
データを沢山取ってやってみる
進路関係
余談
プロフィールサイトをアップデートした
技術力の問題で Next.js でブログを作れなかったため HUGO で別サイトにしていた(半年前)
- プロフィール と ブログ を統合した!
- カスタマイズ性が上がり、esa から記事を追加できるようになった
- 画像を全て webp & 幅820px に変換し、パフォーマンスが向上した