PythonとGridDBによる予知保全

すべての資産にはライフサイクルがあり、したがって頻繁なメンテナンスが必要です。しかし、あまり早く資源を使うのはもったいないし、遅すぎるのもリスクが高いので困ります。このように、「いつ」修理するかは重要な問題です。

固定資産の故障の確率を予測・予想するのが予知保全です。大企業ではモーターの故障を予測し、中小企業ではプリンターの故障を予測するなど、あらゆるビジネスにおいて予知保全は重要です。また、工場の機械の故障やガス漏れの可能性を予測するなど、人命救助にも活用できます。

従来、予測モデリングは特徴量エンジニアリングと単純な回帰モデルで行われてきましたが、これらの方法は再利用が困難です。そこで、より高度なLSTMモデルを使用します。LSTMは、データのシーケンスを使用して、ローリングベースで予測を行う機能を持っています。データの列は5個から100個まで可能です。データのバックエンドには、拡張性が高く、高い信頼性を確保できるGridDBを使用する予定です。GridDBのインストールは簡単で、こちらにはドキュメントも充実しています。Python-GridDBクライアントについてはこちらのビデオを参照してください。

セットアップ

まずはGridDBをセットアップしましょう。

Ubuntu 20.04でGridDB Python Clientの簡単なセットアップを行います。

  • GridDBのインストール

こちらからdebをダウンロードし、インストールします。

  • C言語のクライアントをインストールする

こちらからUbuntuをダウンロードし、インストールします。

  • 必要なものをインストールする

1) Swig

wget https://github.com/swig/swig/archive/refs/tags/v4.0.2.tar.gz 
tar xvfz v4.0.2.tar.gz 
cd swig-4.0.2 
./autogen.sh 
./configure 
make 

2) pythonクライアントのインストール


wget \ 
https://github.com/griddb/python_client/archive/refs/tags/0.8.4.zip 
unzip . 0.8.4.zip 

対応するpythonのバージョンに対応するpython-devがインストールされていることを確認してください。この記事では、python 3.8を使用する予定です。

3) 正しい場所を指し示すことも必要です

export CPATH=$CPATH:<python header file directory path> 
export LIBRARY_PATH=$LIBRARY_PATH:<c client library file directory path> 

</c></python>

また、こちらのように、DockerでGridDBを利用することも可能です。

Python ライブラリ

次に、Pythonのライブラリをインストールします。numpy、keras、tensorflow、sklearn、pandasのインストールは、pip installで簡単にできます。

pip install keras 
pip install numpy 
pip install tensorflow 
pip install pandas 
pip install sklearn

プレディクティブ・モデリング

ステップ1:データセットのダウンロード

ここでは、このKaggleプロジェクトからダウンロードできるNASA turbofan datasetのサブセットを使用します。このデータには、ユニット番号、サイクルの回数、3つの運転設定、21のセンサー測定値が含まれています。train/testファイルにはこれまでのサイクルが、truthファイルには実行可能な総サイクル数が記載されています。

ステップ2:ライブラリのインポート

 
import pandas as pd
import numpy as np
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import confusion_matrix, recall_score, precision_score

from keras.models import Sequential
from keras.layers import Dense, Dropout, LSTM, Activation
from keras.callbacks import EarlyStopping

ステップ3:データの読み込みと処理

データの読み込み

 
dataset_train = pd.read_csv('/content/PM_train.txt',sep=' ',header=None).dropna(axis=1)
dataset_test  = pd.read_csv('/content/PM_test.txt',sep=' ',header=None).dropna(axis= 1)
dataset_truth = pd.read_csv('/content/PM_truth.txt',sep=' ',header=None).dropna(axis=1)

また、このデータフレームを取得するためにGridDBを使用することも可能です。

 import griddb_python as griddb

# Initialize container
gridstore = factory.get_store(host= host, port=port, 
            cluster_name=cluster_name, username=uname, 
            password=pwd)

conInfo = griddb.ContainerInfo("attrition",
                    [["id", griddb.Type.LONG],
                    ["cycle",griddb.Type.LONG],
              .... #for all 23 variables      
                    griddb.ContainerType.COLLECTION, True)
                    
cont = gridstore.put_container(conInfo) 
cont.create_index("id", griddb.IndexType.DEFAULT)

ここで、簡単に識別できるようにカラムの名前を変更します。

 
features_col_name = ['os1','os2','os3','s1','s2','s3','s4','s5','s6','s7','s8','s9','s10','s11','s12','s13','s14','s15','s16','s17','s18','s19','s20','s21']
col_names = ['id','cycletime'] + features_col_name
dataset_train.columns = col_names

#renaming columns
dataset_test.columns=col_names
dataset_train.columns=col_names

正解のファイルにも同じことをします。

dataset_truth.columns=['rul']
dataset_truth['id']=dataset_truth.index+1

次に、ラベルを生成します。我々は、今後15日間の故障を予測したいと思っています。データは、最後のサイクルの実行が故障のポイントになるように構成されています。しかし、テストセットでは最後のデータポイントは存在せず、正解のデータセットでのみ利用可能です。そこで、まず、これまでに実行されたサイクルの合計を取り、正解のデータセットから残りのサイクルを追加して、故障の合計時間を得ます。最後に、残り時間から現在時間を差し引き、故障までの時間を求めます。

#get cycles left for train
dataset_train['ttf'] = dataset_train.groupby(['id'])['cycletime'].transform(max) - dataset_train['cycletime']

# generate column max for test data
rul = dataset_test.groupby('id')['cycletime'].max().reset_index()
dataset_test['ttf'] = dataset_train.groupby(['id'])['cycletime'].transform(max) - dataset_train['cycletime']
dataset_truth['rtf'] = dataset_truth['rul'] + rul['cycletime']
dataset_test = dataset_test.merge(pm_truth , on=['id'],how='left')
dataset_test['ttf'] = dataset_test['rtf'] - dataset_test['cycletime']
dataset_test.drop('rtf', axis=1, inplace=True)

次に、予測期間に基づいてラベルを付与します。

period=15

dataset_train['label'] = dataset_train['ttf'].apply(lambda x: 1 if x <= period else 0)
dataset_test['label'] = dataset_test['ttf'].apply(lambda x: 1 if x <= period else 0)
dataset_train.head()

次に、LSTMではデータをスケーリングする必要があるため、データをスケーリングします。

sc=MinMaxScaler()
dataset_train[features_col_name]=sc.fit_transform(dataset_train[features_col_name])
dataset_test[features_col_name]=sc.transform(dataset_test[features_col_name])

次に、LSTMに使用するデータポイントの数を選択します。50個の予測値を使用することができるため、学習データを50個ずつにグループ化します。

def gen_sequence(id_df, seq_length, seq_cols):
    df_zeros=pd.DataFrame(np.zeros((seq_length-1, id_df.shape[1])),columns=id_df.columns)
    id_df=df_zeros.append(id_df,ignore_index=True)
    data_array = id_df[seq_cols].values
    num_elements = data_array.shape[0]
    la=[]
    for start, stop in zip(range(0, num_elements-seq_length), range(seq_length, num_elements)):
        la.append(data_array[start:stop, :])
    return np.array(la)


#generate train data
X_train=np.concatenate(list(list(gen_sequence(dataset_train[dataset_train['id']==id], seq_length, seq_cols))
                         for id in dataset_train['id'].unique()))
y_train=np.concatenate(list(list(gen_sequence(dataset_train[dataset_train['id']==id], seq_length,['label'])) 
                         for id in dataset_train['id'].unique())).max(axis =1)

# generate test data
X_test=np.concatenate(list(list(gen_sequence(dataset_test[dataset_test['id']==id], seq_length, seq_cols)) 
                         for id in dataset_test['id'].unique()))
print(X_test.shape)

y_test=np.concatenate(list(list(gen_sequence(dataset_test[dataset_test['id']==id], seq_length, ['label'])) 
                        for id in dataset_test['id'].unique())).max(axis =1)
print(y_test.shape)

ステップ4: 予測

次に、予測処理を開始します。

初期化

まずKerasでLSTMモデルを作成します。そのためにLSTMレイヤーを使用します。

 
nb_features =X_train.shape[2]

timestamp=seq_length

model = Sequential()

model.add(LSTM(
         input_shape=(timestamp, nb_features),
         units=100,
         return_sequences=True))
model.add(Dropout(0.2))

model.add(LSTM(
          units=seq_length,
          return_sequences=False))
model.add(Dropout(0.2))

model.add(Dense(units=1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

model.summary()

トレーニング

次に、モデルをコンパイルします。損失としてmean_squared_errorを使用し、精度で評価します。

 # fit the network
model.fit(X_train, y_train, epochs=10, batch_size=200, validation_split=0.05, verbose=1,
          callbacks = [EarlyStopping(monitor='val_loss', min_delta=0, patience=0, verbose=0, mode='auto')])
 

次に、100エポック分のモデルの学習を行います。

 
history=model.fit(X_train, y_train, epochs=100, batch_size=1, verbose=1, shuffle=False) 
Epoch 1/10
98/98 [==============================] - 28s 250ms/step - loss: 0.1596 - accuracy: 0.9394 - val_loss: 0.0611 - val_accuracy: 0.9679

評価と予測

最後に、テストセットを評価し、予測値を再スケールして、グランドトゥルースとともにプロットします。

y_prob=model.predict(X_test)
y_classes = y_prob.argmax(axis=-1)
print('Accuracy of model on test data: ',accuracy_score(y_test,y_classes))

Accuracy of model on test data:  0.9744536780547861
 

また、各マシンの故障確率は次のように計算することができます。

machine_id = 1
machine_df=df_test[df_test.id==machine_id]
machine_test=gen_sequence(machine_df,seq_length,seq_cols)
m_pred=model.predict(machine_test)
failure_prob=list(m_pred[-1]*100)[0]

失敗確率は0.15824139です。

予測期間、LSTMの間隔、可変個数を変更することで、さらに良い結果を得ることができます。

まとめ

この投稿では、Keras、python、GridDBを使用してLSTM予測メンテナンスモデルを学習する方法を学びました。数行のコードで ~97% の予測精度を得ることができます。

ブログの内容について疑問や質問がある場合は Q&A サイトである Stack Overflow に質問を投稿しましょう。 GridDB 開発者やエンジニアから速やかな回答が得られるようにするためにも "griddb" タグをつけることをお忘れなく。 https://stackoverflow.com/questions/ask?tags=griddb

Leave a Reply

Your email address will not be published. Required fields are marked *