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

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

ただいまの
回答率

89.99%

kerasによる機械学習において損失係数が低下しない問題、中間層の設定について

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 7,762

yohehe

score 44

加速度・ジャイロを回転行列で計算し、xyzの3次元で出力したデータを、ravel()で時間軸なしで1次元にしたデータで分類器を作成したく、機械学習を行なっています。
特徴量Xとしてkerasで機械学習を行いました。xyzデータを累積和としてdfデータに入れています。

import keras
from keras.models import Sequential
from keras.layers import Dense,Activation,Dropout
from sklearn import datasets
import numpy as np
import matplotlib.pyplot as plt

df=[]
#測定データをnpyデータで呼び出し、dfに格納
for i in range(40):
    acgydata=np.load(f"acgydata{i}.npy")
    onedata=[]
    x=[d[0] for d in acgydata]
    x=np.array(x).ravel()
    x=np.cumsum(x)
    y=[d[1] for d in acgydata]
    y=np.array(y).ravel()
    y=np.cumsum(y)
    z=[d[2] for d in acgydata]
    z=np.array(z).ravel()
    z=np.cumsum(z)
    onedata.append(x)
    onedata.append(y)
    onedata.append(z)
    onedata=np.ravel(onedata)
    df.append(onedata)
#特徴量とターゲットデータを設定
X=np.array(df)
(n_samples,n_features)=X.shape
y=np.array([0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3])
n_classes=len(np.unique(y))
y_keras=keras.utils.to_categorical(y,n_classes)
model=Sequential()
model.add(Dense(units=200,activation="relu",input_shape=(n_features,)))
model.add(Dropout(0.1))
model.add(Dense(units=100,activation="relu"))
model.add(Dropout(0.1))
model.add(Dense(units=n_classes,activation="softmax"))
model.compile(loss="categorical_crossentropy",optimizer="adam",metrics=["accuracy"])

history=model.fit(X,y_keras,epochs=4000,validation_split=0.1,batch_size=n_samples,verbose=2)
result=model.predict_classes(X,verbose=0)


#以下で損失関数のグラフを描画
val_loss,=plt.plot(history.history["val_loss"],c="orange")
loss,=plt.plot(history.history["loss"],c="blue")
plt.legend([loss,val_loss],["loss","val_loss"])
plt.show()
#accuracyをグラフ化
val_acc,=plt.plot(history.history["val_acc"],c="yellowgreen")
acc,=plt.plot(history.history["acc"],c="red")
plt.legend([loss,val_acc],["acc","val_acc"])
plt.show()

イメージ説明イメージ説明
損失係数のグラフを作成したのですが、lossは低下しているのですが、val_lossが一度も変動していないような直線を描くグラフになってしまっています。
accuracyにおいてもaccは0.7前後まで上昇するときもあるのですが,val_accは0の部分で直線を描いてしまっています。
これはプログラムの記載ミスから起こっているのか、サンプル数が少ないために起こる問題なのか、それとも中間層の設定の問題なのか、アドバイスをいただけますと幸いです。
svmなども色々試したのですが、ランダムフォレストにおける分類を行うとpredictは100%近くでるテストデータを用いています。

追記
アドバイスをいただきまして中間層のunits、batchsize=1などに変更した結果を追記いたします。
様々なアドバイスでval_loss,accに振幅がみられるようになってきました。やはりサンプルが少なすぎるのが問題の根本なのかもしれません。

model=Sequential()
#設定値は適当
model.add(Dense(units=20,activation="relu",input_shape=(n_features,)))
model.add(Dropout(0.1))
model.add(Dense(units=10,activation="relu"))
model.add(Dropout(0.1))
model.add(Dense(units=n_classes,activation="softmax"))
model.compile(loss="categorical_crossentropy",optimizer="adam",metrics=["accuracy"])
#学習を行う
history=model.fit(X,y_keras,epochs=4000,validation_split=0.5,batch_size=1,verbose=2)
コード


イメージ説明
イメージ説明

6/17 Dropoutをの代わりにregurlarizationを導入

#neuralnetworkの以下に変更定義を変更 Dropoutを中止し、l2による正則化をを中間層に設定
from keras import regularizers
model=Sequential()
model.add(Dense(units=20,activation="relu",input_shape=(n_features,)))
model.add(Dense(10, input_dim=20,
                kernel_regularizer=regularizers.l2(0.01),
                activity_regularizer=regularizers.l2(0.01)))
model.add(Dense(units=10,activation="relu"))
model.add(Dense(units=n_classes,activation="softmax"))
model.compile(loss="categorical_crossentropy",optimizer="adam",metrics=["accuracy"])
history=model.fit(X,y_keras,epochs=6000,validation_split=0.5,batch_size=20,verbose=2)

コード


イメージ説明
イメージ説明

いただいたアドバイスをもとに中間層の設定にDropoutをなくし、l2によるregularlizationを導入した結果を追記しました。regularizationとactivity_regularizerの引数については調べているものの数値の理解がまだ曖昧ですので適切かどうか不明瞭です。正しいかどうかはわかりませんがloss,val_loss共に低下し、accracyについても変動はみられています。ありがとうございます。

#l2_lossを定義
def l2_loss(w):
return 0.5 * np.sum(w ** 2)

w1 = np.array([1.0, 2.0, 3.0])
w2 = np.array([4.0, 5.0, 6.0])
#aを欠損値とする
a=3.0
loss = a + l2_loss(w1) + l2_loss(w2)
を設定しまして,中間層の正則化に自己で導入したパラメータを導入
kernel_regularizer=l2_loss
コード


で中間層を変更するとエラーがでてきてしまうため、解決致しましたら追記いたします。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • yohehe

    2018/06/15 23:38 編集

    何度か加筆修正しております。修正しまして使用している全プログラムデータを記載いたしました。

    キャンセル

  • hayataka2049

    2018/06/16 00:00 編集

    fitの処理が抜けていませんか

    キャンセル

  • yohehe

    2018/06/16 00:04 編集

    なんどもすみません。fitの処理の項目がペーストできていなかったため、修正しました。

    キャンセル

回答 2

checkベストアンサー

+2

40件のデータでvalidation_split=0.1って、4件でバリデーションすることになります。各動作1つずつ。これは各ラベルごとに均等に振られる保障とかもないらしいので、なんだか怪しいです。
他のミスとか見落としているかもしれませんが、とりあえず最初に気になったのはそこです。0.5くらいにしたら平然と動いたりしませんか。

 追記

y_keras=keras.utils.to_categorical(y,n_classes)


以下を消してこのコードを挿入。交差検証した正解率が出てきます。

from sklearn.ensemble import RandomForestClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import cross_validate

# 以下4行は消す。消さないでこのコードだけ1つのファイルにまとめて書くと、digitsで動く
from sklearn.datasets import load_digits
digits = load_digits()
X = digits.data  # X=np.array(df)で作ったXになるように
y = digits.target  # y=np.array([0,1,1,1,1,...で作ったyになるように

rfc = RandomForestClassifier(n_estimators=1000, n_jobs=-1)
gnb = GaussianNB()

for name, clf in zip(["RandomForest", "GaussianNB"], [rfc, gnb]):
    d = cross_validate(clf, X, y, cv=4, scoring="accuracy", n_jobs=-1)
    print(name)
    print("accuracy:{:.5f}".format(d["test_score"].mean()))
""" => こんな感じ
RandomForest
accuracy:0.94273
GaussianNB
accuracy:0.80866
"""

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/17 23:52

    L2正則化が効きましたか。もうちょっと正則化の効きを強くして(0.01を上げる)、学習に回すデータを増やして(validation_splitを下げる)、バッチサイズを小さめにするともうちょっと上の方まで持っていけるかもしれません

    キャンセル

  • 2018/06/18 13:31 編集

    効果が出てよかったです。
    後私の書いた関数は忘れてもらっても構いません。
    あれは、l2ノルムがどういうものか?中でどういう処理をしているのか?というのを理解してもらえればいいなと思い書いただけで
    kerasの方で同じものが用意されていますし、
    既に実装に成功しているようなので、私のコードをあえて使う必要はないです。

    後L2とドロップアウトは併用可能ですので、一緒に入れておいてもいいと思います。
    効果があるかどうかはわかりませんが、今回の場合とりあえず入れておいて損はないと思います

    キャンセル

  • 2018/06/18 14:49

    hayataka2049様、ありがとうございます。validiationspilitを下げるとval_accuracyがやや直線になってしまいましたが、predictの正答率は上がったという結果でした。それでも50%に届かないくらいでしたが。サンプルを増やすことが根本的な点でありそうなので増やしながらアドバイスを活かしてみます。

    puroko3様、ありがとうございます。
    l2ノルムによる正則化によるパラメータに条件を課すこととdropoutは併用可能なんですね。勉強になります。
    組み合わせを試しながら最適な部分を探していってみようと思います。

    キャンセル

+2

変数600個に対して条件式が40個だったら560個の未知変数が残るので…

それとも、書き間違いで40変数に対する600サンプルでしょうか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/15 22:46 編集

    すみません間違っておりました。ご指摘ありがとうございます。n_samples:40,n_features:600の設定で、サンプル1つにつきxyzデータを並べた600のデータを特徴量としております。
    修正いたしました。

    キャンセル

  • 2018/06/18 00:11

    val_lossがうまく行っていそうなのに、val_accが0に沈んでいるのが若干気持ち悪いですね。
    epoch数が多すぎるのもあるのですが…

    差し支えなければデータの方を公開できませんか?

    キャンセル

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

  • ただいまの回答率 89.99%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる