Kaggleの過去Featured問題「Home Credit Default Risk」を解いていきます。
このコンペは与えられた個人のクレジットの情報や以前の応募情報などから、各データが債務不履行になるかどうかを予測する問題です。
Kaggleで勝つには次の書籍がおすすめです。ディープラーニングを学ぶには違う書籍がよいでしょう。
[参考] 過去の機械学習関係の記事
ディープラーニングで解く
今回はディープラーニングのライブラリ「Keras」「Pytorch」を使って解いています。
さすがに本番コンペということもあり、正解率が低いと分かっているディープラーニングを使ったサンプルはネット上で見つかりませんでした。
ましてや「Keras」「Pytorch」の両方を試している人は、Kaggle以外でも多くないです。
なお、以前紹介した「Pytorch」のラッパーである「skorch」はエラーが出て動きませんでした。
ただえさえ情報が少ないライブラリでエラーが出てしまうと、不具合解析が面倒です。
なので、直接「Pytorch」を使うことにしました。さようなら「skorch」。
というより、「Pytorch」利用者達から、
「数十行のためにマイナーなラッパー使うのイミフ 笑ꉂꉂ(´ ∀`」
と、イジられたのが大きな要因の一つです。
Kerasで全結合モデルを構築する
Kerasでは過去に「全結合」「CNN」「LSTM」で作成した経験があるので、迷うことはありません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# 全結合モデル(Keras Functional API ver) def build_model(input_dim): inputs = Input(shape = (input_dim,)) # 全結合層(121層->20層)、活性化関数(ReLu関数) layer = Dense(20, activation = 'relu')(inputs) # 全結合層(20層->2層)、活性化関数(softmax関数) dense = Dense(2, activation = 'softmax')(layer) model = Model(inputs = inputs, outputs=dense) model.summary() # plot_model(model, to_file='model3.png', show_shapes=True) return model def keras_model(X_train, y_train): models = {} start = time.time() model = build_model(X_train.shape[1]) # モデルをコンパイル model.compile(loss = "categorical_crossentropy", optimizer = "adam", metrics = ["accuracy"]) # エポック、バッチサイズ model.fit(X_train, y_train, nb_epoch = 2, batch_size = 16) print(str(time.time() - start)) models["keras"] = model return models # Keras, sklearn用結果出力 def output_accuracy(models, X, y): best_model = None best_name = "" total = 0.0 for name, model in models.items(): y_pred = model.predict(X) cm = confusion_matrix(y.ravel(), y_pred.ravel()) print(cm) # extracting TN, FP, FN, TP TN, FP, FN, TP = cm.ravel() score = (TP + TN) / (TP + TN + FN + FP) print('Model[{}] Testing Accuracy = "{} !"'.format(name, score)) if total <= score: best_model = model best_name = name total = score print()# Print a new line print('%s was selected' % best_name) return best_model |
前回のサブミットで「どちらのラベルに分類されるか確率で出力する」必要があることが分かりました。
このため「categorical_crossentropy」「softmax」を使って実数出力を試みましたが、出力結果が「0」「1」の2値にしかなりません・・・。
うーん、理由分からず。。。。
結果の出力
結果は次のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
X_train:(246008, 121) y_train:(246008, 2) X_valid:(61503, 121) y_valid:(61503, 2) _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= input_1 (InputLayer) (None, 121) 0 _________________________________________________________________ dense_1 (Dense) (None, 20) 2440 _________________________________________________________________ dense_2 (Dense) (None, 2) 42 ================================================================= Total params: 2,482 Trainable params: 2,482 Non-trainable params: 0 _________________________________________________________________ Epoch 1/2 246008/246008 [==============================] - 42s 170us/step - loss: 1.5182 - acc: 0.9058 Epoch 2/2 246008/246008 [==============================] - ETA: 0s - loss: 1.2994 - acc: 0.919 - 46s 185us/step - loss: 1.2997 - acc: 0.9194 88.75368118286133 [[56515 4988] [ 4988 56515]] Model[keras] Testing Accuracy = "0.9188982651252784 !" keras was selected [[1. 0.] [1. 0.] [1. 0.] ... [1. 0.] [1. 0.] [1. 0.]] Finished. |
正確率は92%です。
サブミットしても「0」「1」の2値だと、Top95%程度だと思われるので確認していません。
Pytorchで全結合モデルを構築する
Pytorchはよく分かってませんが、前回の写経のおかげで理解が進み、なんとなく動作しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# Multi Layer Perceptron Network class MLPNet(nn.Module): def __init__(self, input_dim): super(MLPNet, self).__init__() self.fc1 = nn.Linear(input_dim,20) self.fc2 = nn.Linear(20,2) def forward(self, x): x = self.fc1(x) x = F.relu(x) x = self.fc2(x) return x # 学習モデル構築(Pytorch用) def pytorch_model(X_train, y_train): start = time.time() model = MLPNet(X_train.shape[1]) print(model) # PyTorchのテンソルに変換 X_train = torch.Tensor(X_train.values) y_train = torch.LongTensor(y_train.values) pytorch_train(model, X_train, y_train) print('Total Time = %s' % str(time.time() - start)) return model # 検証データを使った正解率(Pytorch用) def pytorch_output_accuracy(model, X_valid, y_valid): # PyTorchのテンソルに変換 X_valid = torch.Tensor(X_valid.values) y_valid = torch.LongTensor(y_valid.values) model.eval() #推論モード outputs = model(Variable(X_valid)) _, predicted = torch.max(outputs.data, 1) print('Accuracy: {:}'.format(predicted.eq(y_valid).sum().numpy() / len(predicted))) # テスト(Pytorch用) def pytorch_test(model, X_test): # PyTorchのテンソルに変換 X_test = torch.Tensor(X_test.values) model.eval() #推論モード outputs = model(Variable(X_test)) _, predicted = torch.max(outputs.data, 1) return predicted # 学習(Pytorch用) def pytorch_train(model, X_train, y_train): # GPUの設定(PyTorchでは明示的に指定する必要がある) device = 'cuda' if torch.cuda.is_available() else 'cpu' # Adamによる最適化 optimizer = optim.Adam(model.parameters(), lr = 0.02) criterion = nn.CrossEntropyLoss() # 損失関数の設定 train_loss = [] train_accu = [] i = 0 model.train() #学習モード for epoch in range(100): data, target = Variable(X_train), Variable(y_train) #微分可能な型 data = data.to(device) # GPUを使用するため,to()で明示的に指定 target = target.to(device) # 同上 optimizer.zero_grad() #勾配初期化 output = model(data) #データを流す loss = criterion(output, target) #loss計算 loss.backward() #バックプロパゲーション train_loss.append(loss.data.item()) optimizer.step() # 重み更新 prediction = output.data.max(1)[1] #予測結果 accuracy = prediction.eq(target.data).sum().numpy() / len(X_train) #正解率 train_accu.append(accuracy) if i % 10 == 0: print('Train Step: {}\tLoss: {}\tAccuracy: {}'.format(i, loss.data.item(), accuracy)) i += 1 print('Train Step: {}\tLoss: {}\tAccuracy: {}'.format(i, loss.data.item(), accuracy)) |
が、こちらも出力結果が「0」「1」の2値にしかなりません。
理由分からず。
そして、やっぱりKerasよりコードが長い。
結果の出力
結果は次のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
X_train:(246008, 121) y_train:(246008,) X_valid:(61503, 121) y_valid:(61503,) MLPNet( (fc1): Linear(in_features=121, out_features=20, bias=True) (fc2): Linear(in_features=20, out_features=2, bias=True) ) Train Step: 0 Loss: 3030.2880859375 Accuracy: 0.1508894019706676 Train Step: 10 Loss: 3560.700927734375 Accuracy: 0.9195148125264219 Train Step: 20 Loss: 5662.35693359375 Accuracy: 0.9195148125264219 Train Step: 30 Loss: 708.4314575195312 Accuracy: 0.8277982829826672 Train Step: 40 Loss: 651.2737426757812 Accuracy: 0.789868622158629 Train Step: 50 Loss: 227.5709686279297 Accuracy: 0.9157222529348639 Train Step: 60 Loss: 214.1273651123047 Accuracy: 0.6908596468407532 Train Step: 70 Loss: 251.84701538085938 Accuracy: 0.5907003024291893 Train Step: 80 Loss: 238.49000549316406 Accuracy: 0.3651751162563819 Train Step: 90 Loss: 556.5711669921875 Accuracy: 0.2411994731878638 Train Step: 100 Loss: 219.3664093017578 Accuracy: 0.9191977496666776 Total Time = 38.482603549957275 Accuracy: 0.9047688730631026 tensor([0, 0, 0, ..., 0, 0, 0]) Finished. |
正確率は90%です。
サブミットしても「0」「1」の2値だと、Top95%程度だと思われるので、こちらも確認していません。
まとめ
「Pytorch」と「Keras」で全結合モデルを構築して、問題を解いてみました。
少しずつライブラリの理解が深まり実装コストが下がっているので、今後も定期的に利用してみます。
ただ、Kaggle マスター曰く、Kaggleのスコアを本気で狙うのであればディープラーニングの知識は不要らしいです。
ディープラーニングの勉強目的でKaggleの問題を解いているのに・・・・・。
ソースコード
前回のsklearnの各種機械学習アルゴリズム版にKeras、Pytorchを継ぎ足したので、凄く長くなってしまいました。
ディープラーニングに必要な部分は半分もありません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 |
import warnings warnings.simplefilter('ignore') import time import pandas as pd import numpy as np import seaborn as sns import matplotlib.pyplot as plt from sklearn.preprocessing import LabelEncoder from sklearn.model_selection import train_test_split from xgboost import XGBClassifier from lightgbm import LGBMClassifier from catboost import CatBoostClassifier from sklearn.linear_model import LogisticRegression,Perceptron,PassiveAggressiveClassifier,RidgeClassifier,SGDClassifier from sklearn.svm import LinearSVC,NuSVC,SVC from sklearn.ensemble import AdaBoostClassifier,ExtraTreesClassifier,GradientBoostingClassifier,RandomForestClassifier,BaggingClassifier from sklearn.gaussian_process import GaussianProcessClassifier from sklearn.neighbors import KNeighborsClassifier,RadiusNeighborsClassifier from sklearn.tree import DecisionTreeClassifier,ExtraTreeClassifier from sklearn.neural_network import MLPClassifier from sklearn.naive_bayes import GaussianNB from sklearn.metrics import confusion_matrix from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score, precision_score from keras.models import Model from keras.utils import plot_model from keras.utils.np_utils import to_categorical from keras.layers import Input, Dense, Activation import torch import torch.nn.functional as F from torch import nn, optim from torch.utils.data import Dataset, DataLoader,TensorDataset from torch.autograd import Variable MODEL = "pytorch" # 外れ値の削除 def del_outlier(df): return df # 多重共線性の削除 def del_multicollinearity(df): return df # 欠損値補完 def do_imputation(df): for col in df: # check if it is a number if df[col].dtype != "object": df[col].fillna(0.0, inplace=True) else: df[col].fillna("NA", inplace=True) return df # 各変数の順序関係に従って、エンコーディング def do_encodiing(df, i, target): num = -1 mapping = {} for j in df.groupby(i)[target].mean().sort_values().index: num += 1 mapping[j] = num df[i] = df[i].map(mapping) return df # ラベルエンコーダー def encode_label(df, i): lbl = LabelEncoder() lbl.fit(list(df[i].values)) df[i] = lbl.transform(list(df[i].values)) return df # Data Cleansing def do_data_cleansing(df, target = ""): # 外れ値の削除 df = del_outlier(df) # 多重共線性の削除 df = del_multicollinearity(df) # 各変数の順序関係に従って、エンコーディング for i in df.loc[:, df.dtypes == "object"].columns: if (target != ""): df = do_encodiing(df, i, target) else: df = encode_label(df, i) # 欠損値補完 df = do_imputation(df) return df # ヒートマップによる相関の強い特徴量チェック def display_heatmap(df, k, target): corrmat = df.corr() cols = corrmat.nlargest(k, target)[target].index cm = np.corrcoef(df[cols].values.T) fig, ax = plt.subplots(figsize = (12, 10)) sns.set(font_scale = 1.2) hm = sns.heatmap(cm, cbar = True, annot = True, square = True, fmt = ".2f", annot_kws = {"size": 10}, yticklabels = cols.values, xticklabels = cols.values) plt.show() fig.savefig("figure4.png") # ヒストグラムによる分布の可視化 def display_chart(df): sns.set(font_scale = 0.8) df.hist(bins=50, figsize=(20,15)) # creates a figure with 10 (width) x 10 (height) inches plt.rcParams['figure.figsize'] = [10, 5] # グラフ同士が重ならないようにする関数 #plt.tight_layout() # グラフの表示 plt.show() # 概要出力 def display_overview(df_train, df_test): # それぞれのデータのサイズを確認 print("The size of train is : "+str(df_train.shape)) print("The size of test is : "+str(df_test.shape)) # 列名を表示 print(df_train.columns) # 表の一部分表示 display(df_train.head(10)) # 各列のデータの型を表示 print(df_train.dtypes.sort_values()) # 学習用データ、検証用データの割り当て def build_train_valid_data(df, target, train_size = 0.8): # 答えの削除 y_train = df[target] if MODEL == "keras": y_train = to_categorical(y_train) X_train = df.drop([target], axis = 1) # 80% を学習用データ X_train, X_valid, y_train, y_valid = train_test_split(X_train, y_train, train_size = train_size) # 作成した行列出力 print("X_train:{}".format(X_train.shape)) print("y_train:{}".format(y_train.shape)) print("X_valid:{}".format(X_valid.shape)) print("y_valid:{}".format(y_valid.shape)) return X_train, X_valid, y_train, y_valid # Keras, sklearn用結果出力 def output_accuracy(models, X, y): best_model = None best_name = "" total = 0.0 for name, model in models.items(): y_pred = model.predict(X) cm = confusion_matrix(y.ravel(), y_pred.ravel()) print(cm) # extracting TN, FP, FN, TP TN, FP, FN, TP = cm.ravel() score = (TP + TN) / (TP + TN + FN + FP) print('Model[{}] Testing Accuracy = "{} !"'.format(name, score)) if total <= score: best_model = model best_name = name total = score print()# Print a new line print('%s was selected' % best_name) return best_model clf_names = [["LogisticRegression",""], ["LinearSVC",""], #["NuSVC",""], # Nu-Support Vector Classification ["Perceptron",""], ["SVC",""], # Support Vector Machine Classification ["GaussianNB",""], # Gaussian 型 Naive Bayes ["AdaBoostClassifier",""], ["ExtraTreesClassifier",""], ["GradientBoostingClassifier",""], ["RandomForestClassifier",""], ["BaggingClassifier",""], ["PassiveAggressiveClassifier",""], ["RidgeClassifier",""], ["SGDClassifier",""], # Stochastic Gradient Descent(SGD:確率的勾配降下法) #["GaussianProcessClassifier",""], # Gaussian Naive Bayes ["KNeighborsClassifier",""], # kNN (K近傍法) ["DecisionTreeClassifier",""], ["MLPClassifier",""], # Multilayer perceptron(MLP:多層パーセプトロン ["LGBMClassifier",""], ["CatBoostClassifier","logging_level='Silent'"], ["XGBClassifier",""], ] # 全結合モデル(Keras Functional API ver) def keras_build_model(input_dim): inputs = Input(shape = (input_dim,)) # 全結合層(121層->20層)、活性化関数(ReLu関数) layer = Dense(20, activation = 'relu')(inputs) # 全結合層(20層->2層)、活性化関数(softmax関数) dense = Dense(2, activation = 'softmax')(layer) model = Model(inputs = inputs, outputs=dense) model.summary() # plot_model(model, to_file='model3.png', show_shapes=True) return model # 学習モデル構築(Keras) def keras_model(X_train, y_train): models = {} start = time.time() model = keras_build_model(X_train.shape[1]) # モデルをコンパイル model.compile(loss = "categorical_crossentropy", optimizer = "adam", metrics = ["accuracy"]) # エポック、バッチサイズ model.fit(X_train, y_train, nb_epoch = 2, batch_size = 16) print(str(time.time() - start)) models["keras"] = model return models # 学習モデル構築(sklearn) def sklearn_model(X_train, y_train): total_start = time.time() models = {} total = 0.0 name = "" for i in range(len(clf_names)): start = time.time() # インスタンス化 clf = eval("%s(%s)" % (clf_names[i][0], clf_names[i][1])) clf.fit(X_train, y_train) score = clf.score(X_train, y_train) print('%s Accuracy:' % clf_names[i][0], score) print(' Time = %s' % str(time.time() - start)) models[clf_names[i][0]] = clf if total <= score: total = score name = clf_names[i][0] print('Total Time = %s' % str(time.time() - total_start)) print('%s was selected' % name) return models # Multi Layer Perceptron Network class MLPNet(nn.Module): def __init__(self, input_dim): super(MLPNet, self).__init__() self.fc1 = nn.Linear(input_dim,20) self.fc2 = nn.Linear(20,2) def forward(self, x): x = self.fc1(x) x = F.relu(x) x = self.fc2(x) return x # 学習モデル構築(Pytorch用) def pytorch_model(X_train, y_train): start = time.time() model = MLPNet(X_train.shape[1]) print(model) # PyTorchのテンソルに変換 X_train = torch.Tensor(X_train.values) y_train = torch.LongTensor(y_train.values) pytorch_train(model, X_train, y_train) print('Total Time = %s' % str(time.time() - start)) return model # 検証データを使った正解率(Pytorch用) def pytorch_output_accuracy(model, X_valid, y_valid): # PyTorchのテンソルに変換 X_valid = torch.Tensor(X_valid.values) y_valid = torch.LongTensor(y_valid.values) model.eval() #推論モード outputs = model(Variable(X_valid)) _, predicted = torch.max(outputs.data, 1) print('Accuracy: {:}'.format(predicted.eq(y_valid).sum().numpy() / len(predicted))) # テスト(Pytorch用) def pytorch_test(model, X_test): # PyTorchのテンソルに変換 X_test = torch.Tensor(X_test.values) model.eval() #推論モード outputs = model(Variable(X_test)) _, predicted = torch.max(outputs.data, 1) return predicted # 学習(Pytorch用) def pytorch_train(model, X_train, y_train): # GPUの設定(PyTorchでは明示的に指定する必要がある) device = 'cuda' if torch.cuda.is_available() else 'cpu' # Adamによる最適化 optimizer = optim.Adam(model.parameters(), lr = 0.02) criterion = nn.CrossEntropyLoss() # 損失関数の設定 train_loss = [] train_accu = [] i = 0 model.train() #学習モード for epoch in range(100): data, target = Variable(X_train), Variable(y_train) #微分可能な型 data = data.to(device) # GPUを使用するため,to()で明示的に指定 target = target.to(device) # 同上 optimizer.zero_grad() #勾配初期化 output = model(data) #データを流す loss = criterion(output, target) #loss計算 loss.backward() #バックプロパゲーション train_loss.append(loss.data.item()) optimizer.step() # 重み更新 prediction = output.data.max(1)[1] #予測結果 accuracy = prediction.eq(target.data).sum().numpy() / len(X_train) #正解率 train_accu.append(accuracy) if i % 10 == 0: print('Train Step: {}\tLoss: {}\tAccuracy: {}'.format(i, loss.data.item(), accuracy)) i += 1 print('Train Step: {}\tLoss: {}\tAccuracy: {}'.format(i, loss.data.item(), accuracy)) def main(): # 分類するターゲット名 target = "TARGET" df_train = pd.read_csv("application_train.csv") df_test = pd.read_csv("application_test.csv") # 概要出力 #display_overview(df_train, df_test) df_train = do_data_cleansing(df_train, target) # ヒートマップによる相関の強い特徴量チェック #display_heatmap(df_train, 21, target) # ヒストグラムによる分布の可視化 #display_chart(df_train) X_train, X_valid, y_train, y_valid = build_train_valid_data(df_train, target, 0.8) # 学習モデル構築、学習 if MODEL == "keras": models = keras_model(X_train, y_train) model = output_accuracy(models, X_valid, y_valid) elif MODEL == "pytorch": model = pytorch_model(X_train, y_train) pytorch_output_accuracy(model, X_valid, y_valid) else: models = sklearn_model(X_train, y_train) model = output_accuracy(models, X_valid, y_valid) # 実際の出力/予測確率 if MODEL == "keras": predictions = model.predict(do_data_cleansing(df_test)) df_test[target] = predictions[:,1] elif MODEL == "pytorch": predictions = pytorch_test(model, do_data_cleansing(df_test)) df_test[target] = predictions else: # predictions = (model.predict_proba(do_data_cleansing(df_test))[:,0] < 0.5).astype(int) # df_test[target] = np.round(predictions).astype(np.int) predictions = model.predict_proba(do_data_cleansing(df_test)) df_test[target] = predictions[:,1] print(predictions) # CSVに出力する df_test[["SK_ID_CURR", target]].to_csv("submission.csv", index = False) print("Finished.") if __name__ == '__main__': main() |