質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.44%
Keras

Kerasは、TheanoやTensorFlow/CNTK対応のラッパーライブラリです。DeepLearningの数学的部分を短いコードでネットワークとして表現することが可能。DeepLearningの最新手法を迅速に試すことができます。

CNN (Convolutional Neural Network)

CNN (Convolutional Neural Network)は、全結合層のみではなく畳み込み層とプーリング層で構成されるニューラルネットワークです。画像認識において優れた性能を持ち、畳み込みニューラルネットワークとも呼ばれています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

1285閲覧

CNNとLSTMの組み合わせ方

colan

総合スコア1

Keras

Kerasは、TheanoやTensorFlow/CNTK対応のラッパーライブラリです。DeepLearningの数学的部分を短いコードでネットワークとして表現することが可能。DeepLearningの最新手法を迅速に試すことができます。

CNN (Convolutional Neural Network)

CNN (Convolutional Neural Network)は、全結合層のみではなく畳み込み層とプーリング層で構成されるニューラルネットワークです。画像認識において優れた性能を持ち、畳み込みニューラルネットワークとも呼ばれています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2022/12/17 14:05

前提

機械学習初心者です。
間違っている点があればご指摘いただけるとありがたいです。

実現したいこと

CNNとLSTMを組み合わせてた、脳波の3状態分類を行いたいです。
データは[試行回数、バッチサイズ、時間、周波数、電極数]の5次元データです。

試行回数:6000
バッチサイズ:1
時間:250
周波数:29
電極:7

現状はval_accが33.3%のまま一定です。
データの入れ方に問題があるのか、モデルのつくりからに問題があるのかわかりません。

発生している問題

Model: "sequential_13" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= time_distributed_48 (TimeDis (None, 1, 250, 29, 64) 4096 _________________________________________________________________ time_distributed_49 (TimeDis (None, 1, 125, 14, 64) 0 _________________________________________________________________ time_distributed_50 (TimeDis (None, 1, 125, 14, 64) 36928 _________________________________________________________________ time_distributed_51 (TimeDis (None, 1, 62, 7, 64) 0 _________________________________________________________________ time_distributed_52 (TimeDis (None, 1, 27776) 0 _________________________________________________________________ lstm_10 (LSTM) (None, 128) 14287360 _________________________________________________________________ dense_9 (Dense) (None, 3) 387 ================================================================= Total params: 14,328,771 Trainable params: 14,328,771 Non-trainable params: 0 _________________________________________________________________ Epoch 1/1000 34/34 [==============================] - 15s 455ms/step - loss: 1.1557 - accuracy: 0.3375 - val_loss: 1.1155 - val_accuracy: 0.3333 Epoch 2/1000 34/34 [==============================] - 15s 442ms/step - loss: 1.1020 - accuracy: 0.3298 - val_loss: 1.0996 - val_accuracy: 0.3333 Epoch 3/1000 34/34 [==============================] - 15s 451ms/step - loss: 1.0989 - accuracy: 0.3405 - val_loss: 1.0996 - val_accuracy: 0.3333 Epoch 4/1000 34/34 [==============================] - 15s 453ms/step - loss: 1.1001 - accuracy: 0.3330 - val_loss: 1.1003 - val_accuracy: 0.3333 Epoch 5/1000 34/34 [==============================] - 15s 454ms/step - loss: 1.0993 - accuracy: 0.3420 - val_loss: 1.1009 - val_accuracy: 0.3333 Epoch 6/1000 34/34 [==============================] - 16s 468ms/step - loss: 1.1004 - accuracy: 0.3336 - val_loss: 1.0998 - val_accuracy: 0.3333 Epoch 7/1000 34/34 [==============================] - 17s 487ms/step - loss: 1.0994 - accuracy: 0.3238 - val_loss: 1.0986 - val_accuracy: 0.3333 Epoch 8/1000 34/34 [==============================] - 15s 452ms/step - loss: 1.0993 - accuracy: 0.3253 - val_loss: 1.0990 - val_accuracy: 0.3333 Epoch 9/1000 34/34 [==============================] - 15s 455ms/step - loss: 1.0990 - accuracy: 0.3420 - val_loss: 1.0995 - val_accuracy: 0.3333 Epoch 10/1000 34/34 [==============================] - 16s 459ms/step - loss: 1.1002 - accuracy: 0.3187 - val_loss: 1.0988 - val_accuracy: 0.3333 Epoch 11/1000 34/34 [==============================] - 16s 457ms/step - loss: 1.0998 - accuracy: 0.3241 - val_loss: 1.0991 - val_accuracy: 0.3333 Epoch 12/1000 34/34 [==============================] - 16s 458ms/step - loss: 1.0996 - accuracy: 0.3262 - val_loss: 1.0996 - val_accuracy: 0.3333 Epoch 00012: early stopping 0.3333333333333333 test_loss: 1.100, test_acc: 0.333

該当のソースコード

data = np.load('data.npy') ans_1 = np.array([1]*2000) ans_2 = np.array([2]*2000) ans_0 = np.array([0]*2000) y_ans = np.append(ans_r, [ans_l, ans_n]) X_train = np.reshape(data, [6000, 1, 250, 29, 7]) y_train = y_ans X_train, X_test, y_train, y_test = train_test_split(X_train, y_train, test_size=0.3,random_state=1,stratify=y_train) X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=0.2,random_state=1,stratify=y_train) model = Sequential() model.add(TimeDistributed(Conv2D(64,(3,3), padding='same', activation='relu'), input_shape=(1, 250, 29, 7))) model.add(TimeDistributed(MaxPooling2D(pool_size=(2, 2)))) model.add(TimeDistributed(Conv2D(64,(3,3),padding='same',activation='relu'))) model.add(TimeDistributed(MaxPooling2D(pool_size=(2, 2)))) model.add(TimeDistributed(Flatten())) model.add(LSTM(units=128, return_sequences=False)) model.add(Dense(3, kernel_initializer='glorot_normal', activation='softmax')) model.summary() optimizer = optimizers.Adam(learning_rate=0.001, beta_1=0.9, beta_2=0.999, amsgrad=True) model.compile(loss='sparse_categorical_crossentropy', optimizer=optimizer, metrics=['accuracy']) es = EarlyStopping(monitor='val_loss', patience=5, verbose=1) hist = model.fit(X_train, y_train, epochs=1000, batch_size=100, verbose=1, validation_data=(X_val, y_val), callbacks=[es]) loss, acc = model.evaluate(X_test, y_test, verbose=0) print('test_loss: {:.3f}, test_acc: {:.3f}'.format( loss, acc ))

試したこと

kaggleで書かれているプログラムを参考に書いたのですが、うまくいきませんでした。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

PondVillege

2022/12/17 15:07 編集

Kaggleのどのプログラムを参考にしたのか,リンクを教えていただけますでしょうか. 入力のshapeに対するTimeDistributedの使い方やConv2Dを使っていることに少し違和感があります. 試行回数(6000)がデータ数,時間(250)というのがシーケンス長(タイムスタンプ),電極(7)というのは, 7つの電極を用いて250回の値取得を,合計6000サンプル分だけ繰り返したデータ.と理解しております. しかし,周波数(29)はどういった意味になるのでしょうか.
colan

2022/12/17 15:08

すみません、説明が不十分でした。 周波数は1-30Hzを周波数分解したデータです。 時間はサンプリング周波数125Hzで取得した2秒間のデータです。
colan

2022/12/17 15:52

7電極を用いて250(2秒間)サンプリングしたデータが6000回あります。 それぞれ1‐30Hzの区間で1Hzずつ周波数分解しています。
PondVillege

2022/12/17 22:21 編集

やはり,shape周りとConv2Dの使い方が少し変に思います. TimeDistributedは,(Batch, TimeStamp, Feature, ...)のうち,TimeStampに対して展開されるもので,TimeStamp = 1として扱われる現状は,TimeDistributedを使う意味が全くないです. とりあえず,TimeDistributedを正しく使うとしたら,shapeは(6000, 250, 29, 7)になるべきで,使うのはConv1Dになると思います.ここでConv2Dを使うと,電極が連続した並びに意味を持っているものとして扱うことになります.例えば今3x3のカーネルで畳み込んでいるので,1-3, 2-4, ..., 5-7番の電極情報を畳み込むことになって意味不明です. 逆に,TimeDistributedを使わず,shape = (6000, 250, 29, 7)の情報を扱うならConv2Dが正しいです. どちらで解析を進めたいですか? また,入出力データの整合性も気になります.特にnp.reshapeなんかは危険で,思った動作と異なる場合があります.reshape後の1つデータをプロットしてみて,正しくスペクトルを表現出来ているか確認願います.
colan

2022/12/18 04:04

TimeDistributedを用いたほうが高い精度を実現できるのでしょうか。 可能ならば2つの方法を試してみたいです。 また、reshapeの前後でデータを確認しましたが、問題はありませんでした。
PondVillege

2022/12/18 14:24

なるほど,入力データの方はちゃんと正規化されましたか?正規化している場合は,どの方向に正規化したか,またどの値域で正規化したか教えてください.特にフーリエ変換している今回のデータは,低周波数の強度が強く出て歪になると思います.
colan

2022/12/18 15:39

入力データは正規化ではなく各周波数ごとに標準化しています。
PondVillege

2022/12/18 15:49

わかりました.変数dataのshapeは何になってますか?
colan

2022/12/18 15:53

dataのshapeは[6000, 250, 29, 7]です。
guest

回答1

0

ベストアンサー

時系列データを扱う場合は,入力の形状が(BatchAxis, TimeStampAxis, FeatureAixs1, FeatureAxis2, ...)のようになっている必要があります.質問のdataを正しく変更してX_train.shape = (None, 250, 29, 7)であるものとして話を進めます.train_test_split()の具合からして,最終的にX_train.shape = (3360, 250, 29, 7)になっているかなと思います.

TimeDistributedを使う場合

Conv2Dの箇所がConv1Dになります.

python:

1model = Sequential() 2model.add(Input(shape = (X_train.shape[1:]))) 3model.add(TimeDistributed(Conv1D(64, 3, padding = "same", activation = "relu", kernel_initializer = "he_normal", kernel_regularizer = 'l2'))) 4model.add(TimeDistributed(MaxPooling1D(2))) 5model.add(TimeDistributed(Conv1D(64, 3, padding = "same", activation = "relu", kernel_initializer = "he_normal", kernel_regularizer = 'l2'))) 6model.add(TimeDistributed(MaxPooling1D(2))) 7model.add(TimeDistributed(Flatten())) 8model.add(LSTM(128, return_sequences = False)) 9model.add(Dense(3, activation = "softmax"))

学習が進まない要因として,カーネルの初期値問題である説を考えた場合,Heの初期値を利用する解決策が挙げられます.kernel_initializer = "he_uniform"等で適用して解決を図ります.論文を読むとわかりますが,活性化関数がReLUである現状に特化した初期値です.また,パラメータ数が非常に多いので,kernel_regularizerを適用して過学習を防止します.

Conv2Dを使う場合

TimeDistributedを使用しないようにします.

Python

1model = Sequential() 2model.add(Input(shape = (X_train.shape[1:]))) 3model.add(Conv2D(64, 3, padding = "same", activation = "relu", kernel_initializer = "he_normal", kernel_regularizer = 'l2')) 4model.add(MaxPooling2D()) 5model.add(Conv2D(64, 3, padding = "same", activation = "relu", kernel_initializer = "he_normal", kernel_regularizer = 'l2')) 6model.add(MaxPooling2D()) 7model.add(TimeDistributed(Flatten())) 8model.add(LSTM(128, return_sequences = False)) 9model.add(Dense(3, activation = 'softmax'))

こちらでは,横軸時間,縦軸周波数のスペクトル画像(7チャンネル)を解析するイメージでモデルが実行されます.時系列処理としては少し微妙で,LSTMも畳み込まれたタイムスタンプ(長さ62)に対して解析を行うことになります.

精度

いずれも,次のジェネレータに対して100%の精度を出すことができました.

Python

1fs = 125 2T = 2 3t = np.linspace(0, 2, fs * 2) 4def gen_wave(v): # 適当な波形を生成する 5 ret = np.zeros_like(t) 6 if v == 0: 7 for i in range(1, 31): # HFLF両方 8 ret += np.random.uniform(0.5, 1) * np.sin((i + np.random.uniform(0, 0.9)) * t + np.random.randn(1)) 9 if v == 1: 10 for i in range(15, 31): # HF多め 11 ret += np.random.uniform(0.5, 1) * np.sin((i + np.random.uniform(0, 0.9)) * t + np.random.randn(1)) 12 ret -= np.abs(t - 1) / 2 13 if v == 2: 14 for i in range(1, 16): # LF多め 15 ret += np.random.uniform(0.5, 1) * np.sin((i + np.random.uniform(0, 0.9)) * t + np.random.randn(1)) 16 _t = t - 1.000001 17 ret += np.sin(15 * _t) / _t / 15 18 return 2 * (ret - ret.min()) / (ret.max() - ret.min()) - 1 19 20import librosa 21def mel_spectrogram(y): 22 mel_spect = np.abs(librosa.stft(y, n_fft = 128, window = "hamming", win_length = 128, hop_length = 1)) ** 2 23 mel_spect = librosa.feature.melspectrogram(S = mel_spect, sr = fs, n_mels = 30, fmax = 30) 24 return librosa.power_to_db(mel_spect, ref = np.max) 25 26def generator(batch): 27 while True: 28 x, y = list(), list() 29 for i in range(batch): 30 _y = np.random.randint(0, 2) 31 ch = list() 32 for _ in range(7): 33 ch.append(mel_spectrogram(gen_wave(_y))[:29, :250]) 34 x.append(ch) 35 y.append(_y) 36 x = np.swapaxes(np.array(x), 1, 3) 37 yield (x - x.mean()) / x.std(), np.array(y) 38 39hist = model.fit( 40 generator(32), 41 epochs = 32, 42 steps_per_epoch = 32, 43 callbacks = [es] 44)

投稿2022/12/18 16:23

PondVillege

総合スコア1579

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

colan

2022/12/18 17:26

丁寧にありがとうございます。 大変勉強になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.44%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問