実現したいこと
作成した二値分類予測モデルを使用して,新規(未知)のデータを正常か異常できるかを確認したいです。単純にそのままcsvファイルを読み込めば良いわけではないことを確認し,手探りで色々と試したところ,解決に至らない状況です。エラーに対する解決策をご教示いただけますと幸いです。
学習の際に使用した及び新規データのcsvファイルの形式は,下記のような30行・119列からなるデータになります。(1行目にunnamedという解析に関係のない列が入ってしまっています)
| unnamed | idx | pelvis.x | pelvis.y | pelvis.z | left_hip.x | left_hip.y | left_hip | … | hip_angle | knee_angle |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | -1437.3 | -1.9 | 1591. | -1357.5 | 81.1 | 1592.4 | … | -359.8 | 1133.0 |
| 0 | 1 | -1429.4 | -9.1 | 1590.7 | -1357.5 | 77.4 | 1592.1 | … | -300.3 | 1128.2 |
| 0 | 2 | -1420.2 | -68.3 | 1575.7 | -1348.4 | 19.0 | 1578.6 | … | -347.0 | 1102.4 |
| 0 | … | … | … | … | … | … | … | … | … | … |
| 0 | 29 | -1464.9 | -210.8 | 1552.9 | -100.1 | 1566.6 | -1495.7 | … | -393.1 | 1043.5 |
前提
下記のコードで予測モデルを作成し,"model.h5"として保存しました。
python
1import csv 2import math 3import numpy as np 4from glob import glob 5import pandas as pd 6import seaborn as sns 7import matplotlib.pyplot as plt 8import os 9from sklearn.preprocessing import StandardScaler 10from sklearn.model_selection import StratifiedKFold 11from google.colab import drive 12drive.mount('/content/drive') 13 14class DataLoader: 15 def __init__(self, split: int, batch_size: int, epochs: int, roll: int): 16 self.batch_size = batch_size 17 self.epochs = epochs 18 self.roll = roll 19 self.file, self.y, self.l = list(), list(), list() 20 self.category = {"normal": 0, "abnormal": 1} 21 for name in self.category.keys(): 22 for i, file in enumerate(glob(f"/content/drive/MyDrive/data/{name}/*.csv")): 23 self.file.append(file) 24 self.y.append(self.category[name]) 25 self.l.append(len(open(file).readlines()) - 1) 26 assert self.l[-1] > roll, f"Missing roll size: (roll, file length): ({roll}, {self.l[-1]}) on {file}" 27 self.skf = StratifiedKFold(split, shuffle = True) 28 29 def generator(self, idx, epochs): 30 X1, X2, X3, y = list(), list(), list(), list() 31 for e in range(epochs): 32 np.random.shuffle(idx) 33 for i in idx: 34 start = np.random.randint(0, self.l[i] - self.roll - 1) 35 data = pd.read_csv(self.file[i]).values[start: start + self.roll] 36 data = StandardScaler().fit_transform(data.reshape(-1, 1)).reshape(data.shape) 37 X1.append(np.concatenate([data[:, 8:26], data[:, 71:83]], axis = -1)) 38 X2.append(data[:, 107:113]) 39 X3.append(data[:, 117:120]) 40 y.append(self.y[i]) 41 if len(X1) == self.batch_size: 42 yield list(map(np.array, [X1, X2, X3])), np.array(y) 43 X1, X2, X3, y = list(), list(), list(), list() 44 if len(X1): 45 yield list(map(np.array, [X1, X2, X3])), np.array(y) 46 47 def split(self): 48 for train, test in self.skf.split(self.file, self.y): 49 self.test_idx = test 50 yield ( 51 self.generator(train, self.epochs), 52 self.generator(test, self.epochs), 53 math.ceil(len(train) / self.batch_size), 54 math.ceil(len(test) / self.batch_size) 55 ) 56 57import tensorflow as tf 58from tensorflow.python import keras 59from keras.models import Sequential, Model 60from keras.layers import Input, Dense, Concatenate, Flatten, Dropout 61from keras.layers import Conv1D, AveragePooling1D, GlobalAveragePooling1D 62from keras.layers import LSTM 63from keras.optimizers import Adam 64from keras.callbacks import EarlyStopping, ReduceLROnPlateau 65 66def build_model(time_stamp): 67 inputs1 = Input(shape = (time_stamp, 30)) 68 inputs2 = Input(shape = (time_stamp, 6)) 69 inputs3 = Input(shape = (time_stamp, 3)) 70 71 x1 = Conv1D(32, 7, activation = "swish", kernel_initializer = "he_uniform")(inputs1) 72 x1 = AveragePooling1D()(x1) 73 x2 = Conv1D(32, 7, activation = "swish", kernel_initializer = "he_uniform")(inputs2) 74 x2 = AveragePooling1D()(x2) 75 x3 = Conv1D(32, 7, activation = "swish", kernel_initializer = "he_uniform")(inputs3) 76 x3 = AveragePooling1D()(x3) 77 78 combined = Concatenate(axis = -1)([x1, x2, x3]) 79 x = LSTM(32, dropout = 0.2)(combined) 80 x = Dense(1, activation = "sigmoid")(x) 81 return Model(inputs = [inputs1, inputs2, inputs3], outputs = x) 82 83from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay 84from sklearn.metrics import balanced_accuracy_score, accuracy_score, precision_score, recall_score, f1_score 85 86epochs = 128 87batch_size = 8 88time_stamp = 15 89generator = DataLoader(split = 3, roll = time_stamp, batch_size = batch_size, epochs = epochs) 90 91for train_gen, valid_gen, steps_per_epoch, validation_steps in generator.split(): 92 model = build_model(time_stamp) # Be sure to rebuild the model with each fold. 93 model.summary() 94 model.compile( 95 loss = "binary_crossentropy", 96 optimizer = Adam(), 97 metrics = ["acc"] 98 ) 99 es = EarlyStopping( 100 monitor = "val_loss", # val_lossが 101 patience = 10, # 10epoch間で 102 mode = "min", # 最小値を更新しなかったら 103 restore_best_weights = True, # ベストのweightsを採用して終了 104 verbose = 1, 105 ) 106 107 model.fit( 108 train_gen, 109 epochs = epochs, 110 steps_per_epoch = steps_per_epoch, 111 class_weight = {0: 4, 1: 1}, 112 validation_data = valid_gen, 113 validation_steps = validation_steps, 114 callbacks = [es], 115 ) 116 117 y_valid, y_pred = list(), list() 118 test_generator = generator.generator(generator.test_idx, 1) 119 for (X1, X2, X3), y in test_generator: 120 y_pred.extend(round(model.predict([X1, X2, X3], batch_size = batch_size))) 121 y_valid.extend(y) 122 123model.save("/content/drive/MyDrive/model.h5")
発生している問題・エラーメッセージ
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-90-3ff49088c926> in <cell line: 15>() 13 X3 = data[:, 117:120] 14 ---> 15 model.predict([X1, X2, X3]) 1 frames /usr/local/lib/python3.9/dist-packages/keras/engine/training.py in tf__predict_function(iterator) 13 try: 14 do_return = True ---> 15 retval_ = ag__.converted_call(ag__.ld(step_function), (ag__.ld(self), ag__.ld(iterator)), None, fscope) 16 except: 17 do_return = False ValueError: in user code: File "/usr/local/lib/python3.9/dist-packages/keras/engine/training.py", line 2169, in predict_function * return step_function(self, iterator) File "/usr/local/lib/python3.9/dist-packages/keras/engine/training.py", line 2155, in step_function ** outputs = model.distribute_strategy.run(run_step, args=(data,)) File "/usr/local/lib/python3.9/dist-packages/keras/engine/training.py", line 2143, in run_step ** outputs = model.predict_step(data) File "/usr/local/lib/python3.9/dist-packages/keras/engine/training.py", line 2111, in predict_step return self(x, training=False) File "/usr/local/lib/python3.9/dist-packages/keras/utils/traceback_utils.py", line 70, in error_handler raise e.with_traceback(filtered_tb) from None File "/usr/local/lib/python3.9/dist-packages/keras/engine/input_spec.py", line 298, in assert_input_compatibility raise ValueError( ValueError: Input 0 of layer "model_2" is incompatible with the layer: expected shape=(None, 15, 30), found shape=(None, 30)
該当のソースコード
python
1import pandas as pd 2from tensorflow.keras.models import load_model 3import numpy as np 4 5model = load_model("/content/drive/MyDrive/model.h5") 6 7data = pd.read_csv("/content/drive/MyDrive/data/new/ID001.csv").values 8 9X1 = np.concatenate([data[:, 8:26], data[:, 71:83]], axis = -1) 10X2 = data[:, 107:113] 11X3 = data[:, 117:120] 12 13model.predict([X1, X2, X3])
試したこと
dataをmodel.predict(data)としてもエラーメッセージ(ValueError: Layer model_2 expects 3 input(s), but it received 1 input tensors.)が出て,3つの変数を入れてもエラーメッセージが出ている状況です。
> 下記のコードで予測モデルを作成し,"model.h5"として保存しました。
「model.save('model.h5')」みたいな、保存するところも質問のコードに追記してください
そのコードをそのまま実行したら、「NameError: name 'build_model2' is not defined」というエラーが出ます
下記のように変更すればいいのですかね
model = build_model2(time_stamp) # Be sure to rebuild the model with each fold.
↓ 修正
model = build_model(time_stamp) # Be sure to rebuild the model with each fold.
あと、csvファイルの形式も質問に追記してください
https://teratail.com/questions/8z6i2xtgzx2vvd
に書かれてるのと同じ形式でしょうか?
jbpb0様,いつもご丁寧に方向性を確認いただきありがとうございます。
モデルの保存方法及びcsvファイルの詳細を追記致しました。また,jbpb0様のおっしゃる通り,model = build_model2(time_stamp) は間違いで,model = build_model(time_stamp) が正確な情報です。ご迷惑おかけして申し訳ございません。
> 下記のような30行・119列からなるデータになります。(1行目にunnamedという解析に関係のない列が入ってしまっています)
「unnamed」を含めて119列ですか?
それとも、「unnamed」以外が119列で、「unnamed」を含めた実際の全部は120列ですか?
もし前者なら、119列なら0〜118なので、推論コードの
X3 = data[:, 117:120]
の「117:120」では、117, 118の二つの列しかありませんので、学習コードの
> inputs3 = Input(shape = (time_stamp, 3))
の「3」と矛盾するような
(もし実際にそうだとしても、それはこの質問のエラーの原因ではありませんが)
あと、30行はヘッダー(列名)を含めてですか?
それとも、ヘッダー以外の数値の行が30行で、ヘッダーを含めたら31行ですか?
【追記】
ヘッダー行と、「unnamed」列を含めて、31行120列のcsvだと仮定して、その形式で内容は適当なものをでっち上げて、google colabで学習コードを実行したら、下記のエラーが出ました
> --> 121 y_pred.extend(round(model.predict([X1, X2, X3], batch_size = batch_size)))
122 y_valid.extend(y)
123
TypeError: type numpy.ndarray doesn't define __round__ method
実際に使ったコードと、まだ何か相違点がありませんか?
学習コードの
> model.summary()
の実行で、
> Layer (type) Output Shape Param # Connected to
==================================================================================================
input_1 (InputLayer) [(None, 15, 30)] 0 []
input_2 (InputLayer) [(None, 15, 6)] 0 []
input_3 (InputLayer) [(None, 15, 3)] 0 []
みたいに表示されてたはずで、入力するデータの形式が上記の「Output Shape」に合わないといけません
(「None」は何でもいいが、それ以外は一致しないといけない)
学習コードの
> for (X1, X2, X3), y in test_generator:
のすぐ下に(インデントを合わせて)
print(X1.shape)
print(X2.shape)
print(X3.shape)
を追加して実行したら、
(数字, 15, 30)
(数字, 15, 6)
(数字, 15, 3)
のように表示されるはずで、上記は「model.summary()」の結果と合ってます
(「model.summary()」の結果の「None」は何でもいい)
一方、推論コードのエラーが出る
> model.predict([X1, X2, X3])
のすぐ上に
print(X1.shape)
print(X2.shape)
print(X3.shape)
を追加して実行したら、結果表示は「model.summary()」の結果と合ってないはずで、それがこの質問のエラーの原因です
(数字, 15, 30)
(数字, 15, 6)
(数字, 15, 3)
のように表示されないといけませんが、おそらく
(30, 30)
(30, 6)
(30, 3)
のようになってると思います
・「unnamed」を含めて119列ですので,117:120は間違いです…細部に至るまでご確認いただきありがとうございます。修正いたします。
・ヘッダーを含めて31行です。
・y_pred.extend(np.round(model.predict([X1, X2, X3], batch_size = batch_size)))が正しい表記です。お手数おかけして申し訳ございません。
(数字, 15, 30)
(数字, 15, 6)
(数字, 15, 3)
上記の形式に推論コードを変換する場合はどのように記述すればよろしいでしょうか(丸投げのような質問で申し訳ございません…)
X1 = np.concatenate([data[0:15, 8:26], data[0:15, 71:83]], axis = -1)
X1 = np.stack([X1], 0)
X2 = data[np.newaxis, 0:15, 107:113]
X3 = data[np.newaxis, 0:15, 117:120]
上記に変更したところ,エラーメッセージが出なかったのですが,修正内容に問題ないでしょうか。
csvファイルの30行のデータの内の、上から15行で推論すればいいのなら、それで大丈夫だと思います
ちなみに、X2, X3と同じ「np.newaxis」を使って、
X1 = np.concatenate([data[np.newaxis, 0:15, 8:26], data[np.newaxis, 0:15, 71:83]], axis = -1)
としても、同じ結果になるはずです
jbpb0様,無事に実現したいことを解決できました!ご丁寧にご指南いただき心より感謝申し上げます。
> 「unnamed」を含めて119列
そうなら、
print(X3.shape)
の結果が
(1, 15, 2)
となって、その「2」と、学習コードの
> inputs3 = Input(shape = (time_stamp, 3))
の「3」が矛盾するので、エラーになると思うのですが
推論コードに
print(data.shape)
を追加して、確認してみてください
120列ありませんか?
細部に至るまでご確認いただきありがとうございます。
(15, 120)と出力されたため,120列であることを確認いたしました。間違った情報を提示してしまい,申し訳ございません…
> (15, 120)と出力された
csvファイルはヘッダーを除いて30行だから「(30, 120)」となるはずですが、推論用に15行のcsvファイルを作ったのでしょうか?
行がいくつでも列は120なのだから、質問の
「学習の際に使用した及び新規データのcsvファイルの形式は,下記のような30行・119列からなるデータになります。」
は間違いなので、質問を編集して「119」を「120」に修正してください
回答2件
あなたの回答
tips
プレビュー