俺人〜OREGIN〜俺、バカだから人工知能に代わりに頑張ってもらうまでのお話

俺って、おバカさんなので、とっても優秀な人工知能を作って代わりに頑張ってもらうことにしました。世界の端っこでおバカな俺が夢の達成に向けてチマチマ頑張る、そんな小さなお話です。現在はG検定、E資格に合格し、KaggleやProbSpaceのコンペに参画しながら、Pythonや機械学習、統計学、Dockerなどの勉強中です。学習したことをブログにアウトプットすることで、自分の身に着けていきたいと思います。まだまだ道半ばですが、お時間がありましたら見て行ってください。

E資格対策振り返り(応用数学-確率統計-オッズ比)

E資格(JDLA Deep Learning for ENGINEER 2019 #2)対策として学習した応用数学の分野のうち、確率統計用語のオッズ比を振り返ります。

オッズ比

1.オッズ比とは何か

オッズ比とは、ある事象の起こりやすさを比較するための統計学的な指標になります。

例えば、「喫煙ありの人」と「喫煙なしの人」との肺がんになりやすさを比較する時などに使われます。

「喫煙ありの人」のうち肺がんになった人の割合が、「喫煙なしの人」が肺がんになった割合がqのとき、それぞれのオッズは、以下の通りとなります。

オッズ1

オッズ2

この「オッズ」の比がオッズ比となり、「喫煙ありの人」の肺がんになったオッズ比は以下の通りとなります。

オッズ比

この値が、1より大きい場合、分子のオッズの事象(例の場合は「喫煙ありの人」が肺がんになった)が、より起こりやすい事象であるということになります。逆に1より小さい場合、分子のオッズの事象が、より起こりにくい事象であることになります。

ただし、起こりやすいかどうかだけの指標なので、オッズ比が2(=オッズが2倍)という場合でも、起こりやすさが2倍というわけではないことに注意が必要です。

2.オッズ比の具体例

では、以下の例を用いて、実際にオッズ比を求めてみます。(※計算例なので現実の数値とは関係ありません。)

冬に風邪をひくオッズは、

(60/110)/(1-60/110)=1.2

夏に風邪をひくオッズは、

(40/240)/(1-40/240)=0.2

となるので、オッズ比は、

1.2/0.2= 6

となります。

オッズ比が、1より大きいので、この表の数値上は、冬に風邪をひく事象は、夏に風邪をひく事象より起きやすいと言えます。

(※あくまでも計算例の数字なので、現実の数値とは全く関係ありません。)

 

以上が、オッズ比の振り返りになります。

概念的に少しわかりづらい値なのですが、求め方と単にある事象とある事象の起こりやすさを比較するための値と理解しました。

厳密に理解するには、もっと意味的なところも理解していく必要があると思いますが、まずは、使えるようになりたいと思います。

 

2019年8月31日(土)にE資格を受験して、合格しました!

E資格対策として勉強の進め方や、参考書などをまとめました。

これから受験される方がいらっしゃいましたらご参考まで。

oregin-ai.hatenablog.com 

 

 2019年3月9日(土)にG検定を受験し、見事合格できました!

受験の体験記や勉強法などを別のブログにまとめました。

これから受験される方がいらっしゃいましたらご参考まで。

g-kentei.hatenablog.com

 【E資格対策に使った参考書】

 

 

E資格対策振り返り(深層学習-ゲート付きRNN-GRU)

E資格(JDLA Deep Learning for ENGINEER 2019 #2)対策として学習した深層学習の分野のうち、ゲート付きRNNのひとつGRU(Gated Reccurent Unit)を振り返ります。

GRU(Gated Reccurent Unit)

1.GRUとは何か

LSTMと同様にシンプルなRNNの勾配爆発や、勾配消失の欠点を補うために開発されたゲート付きRNNです。

LSTMよりゲート数が少ない構成となっており、その分パラメータ数も少なく計算量が少なくて済みます。

では、今回も全体像から構成要素まで、順に振り返っていきたいと思います。

2.GRU全体像

GRUの全体像は以下の図のような構成となっており、LSTMと違い、記憶セルもなく、ゲートも2つになっています。

GRU
では、構成要素を順に見ていきたいと思います。

3.リセットゲート(R

過去の出力の要素を弱める程度を決めるゲートになります。
以下の式で程度が決まります。

リセットゲート
入力(f:id:kanriyou_h004:20200131000154p:plain)と、一つ前の出力(f:id:kanriyou_h004:20200131000249p:plain)に、それぞれ重みをかけたものにバイアスを足して、最後にシグモイド関数で、0~1に閉じ込めます。

このことによって、過去の出力の要素を何割減にするかが決まります。

4.仮の出力(

入力(f:id:kanriyou_h004:20200131000154p:plain)と一つ前の出力(f:id:kanriyou_h004:20200131000249p:plain)にリセットゲートの値(R)をかけたものに重みをかけて、バイアスを足したものになります。

出力を求める前に一旦、仮の出力を求めます。
双曲線正接関数(tanh)を使い、正負に広がりを持った分布になります。

 5.更新ゲート(Z

出力する際に、一つ前の出力(f:id:kanriyou_h004:20200131000249p:plain)と仮の出力()の混合の割合を決めるゲートになります。

以下の式で割合が決まります。

リセットゲートと同様、入力(f:id:kanriyou_h004:20200131000154p:plain)と、一つ前の出力(f:id:kanriyou_h004:20200131000249p:plain)に、それぞれ重みをかけたものにバイアスを足して、最後にシグモイド関数で、0~1に閉じ込めます。

6.出力する要素(ℎ𝑡)

最後に、 一つ前の出力(f:id:kanriyou_h004:20200131000249p:plain)に更新ゲートの値(Z)をかけた値に、仮の出力()に1から更新ゲートを引いた値(1-Z)をかけた値を足して、出力を計算します。

 

以上が、GRUの振り返りになります。

つながりは、少し複雑ですが、LSTMよりパラメータも少なく計算量も少ないので、LSTMが理解した後では、比較的簡単に把握できました。

前回のLSTMとGRUは、E資格にもよく出題されるので、しっかり理解したうえで、試験に臨み、何とか攻略することができました。

今後、Kaggle等でも実際に試していきたいと思います。

 

2019年8月31日(土)にE資格を受験して、合格しました!

E資格対策として勉強の進め方や、参考書などをまとめました。

これから受験される方がいらっしゃいましたらご参考まで。

oregin-ai.hatenablog.com 

 

 2019年3月9日(土)にG検定を受験し、見事合格できました!

受験の体験記や勉強法などを別のブログにまとめました。

これから受験される方がいらっしゃいましたらご参考まで。

g-kentei.hatenablog.com

 【E資格対策に使った参考書】

 

 

E資格対策振り返り(深層学習-ゲート付きRNN-LSTM)

E資格(JDLA Deep Learning for ENGINEER 2019 #2)対策として学習した深層学習の分野のうち、ゲート付きRNNのひとつLSTM(長短期記憶- Long short-term memory)を振り返ります。

LSTM(長短期記憶- Long short-term memory)

1.LSTMとは何か

系列を扱うシンプルなRNNでは、入力に同じ処理を繰り返すために、伝播する勾配が1より大きい場合は発散(勾配爆発)してしまい、1より小さい場合は0(勾配消失)してしまう欠点があります。

LSTMは、その欠点を補うための手法になります。

ゲートという、データを通過させる程度を決めるノードがあり、水道の蛇口のような役割を果たし、過去の情報をどこまで影響させるかを調整します。

調整には、シグモイド関数が使われます。

といっても、なかなかわかりづらいので、順を追って振り返っていきたいと、思います。 

2.LSTM全体像

LSTMの全体像は以下の図のような構成となっており、過去の情報を記憶しておく記憶セル(C)とデータを通過させる程度を決める三つのゲートで構成されます。

f:id:kanriyou_h004:20200130235054p:plain

では、構成要素を順に見ていきたいと思います。

3.入力ゲート(𝒊)

記憶セルに入力する要素を弱める程度を決めるゲートになります。
以下の式で程度が決まります。

f:id:kanriyou_h004:20200131000109p:plain

入力(f:id:kanriyou_h004:20200131000154p:plain)と、一つ前の出力(f:id:kanriyou_h004:20200131000249p:plain)に、それぞれ重みをかけたものにバイアスを足して、最後にシグモイド関数で、0~1に閉じ込めます。

このことによって、入力する要素を何割減にするかが決まります。

4.入力する要素(𝒈)

入力する要素は、入力(f:id:kanriyou_h004:20200131000154p:plain)と一つ前の出力(f:id:kanriyou_h004:20200131000249p:plain)に重みをかけて、バイアスを足したものになります。

f:id:kanriyou_h004:20200201001258p:plain
入力ゲートとは違い、活性化関数にシグモイド関数ではなく双曲線正接関数(tanh)を使い、正負に広がりを持った分布になります。

 5.忘却ゲート(𝒇)

記憶セル(𝐶𝑡)に入力する記憶セル過去の記憶(𝐶𝑡−1)を忘れる程度を決めるゲートになります。 
以下の式で程度が決まります。

f:id:kanriyou_h004:20200201001455p:plain

入力ゲートと同様、入力(f:id:kanriyou_h004:20200131000154p:plain)と、一つ前の出力(f:id:kanriyou_h004:20200131000249p:plain)に、それぞれ重みをかけたものにバイアスを足して、最後にシグモイド関数で、0~1に閉じ込めます。

6.記憶セル(𝐶𝑡)

過去の記憶を蓄積する値となります。入力ゲートで弱められた入力(g・i)と、忘却ゲートで忘れられた過去の記憶(𝐶𝑡1・f)を足し算することで求められます。

f:id:kanriyou_h004:20200201001835p:plain

この記憶セルの内容が出力に伝わることで過去の情報を引き継いでいきます。

7.出力ゲート(𝒐)

記憶セル(𝐶𝑡)の内容を出力(ℎ𝑡)に反映する程度を決めるゲートになります。 
以下の式で程度が決まります。

f:id:kanriyou_h004:20200201095424p:plain
入力ゲート、忘却ゲートと同様に、入力(f:id:kanriyou_h004:20200131000154p:plain)と、一つ前の出力(f:id:kanriyou_h004:20200131000249p:plain)に、それぞれ重みをかけたものにバイアスを足して、最後にシグモイド関数で、0~1に閉じ込めます。

8.出力する要素(ℎ𝑡)

最後に、 記憶セルの内容を双曲線正接関数(tanh)で変換した後、出力ゲートの値(出力する程度)をかけて出力を計算します。

f:id:kanriyou_h004:20200201095137p:plain

 

以上が、LSTMの振り返りになります。

全体像を一度に把握しようとすると、なかなかに難解なのですが、一つ一つの構成要素はそんなに難しくはないので、順に追いかけて理解を進めました。

これからE資格を受験される方の参考になれば幸いです。

 

2019年8月31日(土)にE資格を受験して、合格しました!

E資格対策として勉強の進め方や、参考書などをまとめました。

これから受験される方がいらっしゃいましたらご参考まで。

oregin-ai.hatenablog.com 

 

 2019年3月9日(土)にG検定を受験し、見事合格できました!

受験の体験記や勉強法などを別のブログにまとめました。

これから受験される方がいらっしゃいましたらご参考まで。

g-kentei.hatenablog.com

 【E資格対策に使った参考書】

 

 

ProbSpace浮世絵作者予測コンペ振り返り(10位にランクイン!)

先日、「ProbSpace」というプラットフォームで開催された「浮世絵作者予測」コンペに参戦したので、振り返っていきたいと思います。

私にとって、画像分類のコンペは初めてでしたが、E資格の課題が画像分類でしたので、その時に得た知識をフル動員して取り組みました。

最終順位は参加232チーム中、10位でした。トップ10入りができてとてもうれしいです!!

f:id:kanriyou_h004:20200118191959p:plain

まだまだ、改善の余地はたくさんあると思いますが、これまでの取り組みで結果を残せたので、素直に喜びたいと思います!!

全体像

上位の方の見よう見まねで全体像の図を作ってみました。

描き方とかも理解できていないので、わかりにくかったら申し訳ございません。

f:id:kanriyou_h004:20200118213140p:plain

では、振り返ってまいります。

1.データ拡張

データを読み込んで、E資格の課題のときに大活躍したデータ拡張をいろんなモデルに、それぞれの割合をハイパーパラメータとして最大になる値を探索しました。

データ拡張は、HorizontalFlip,RandomContrast,RandomBrightness,Blur,Cutoutの6種類を使いました。

また、モデルはResNet18,34,101,WideResNet50,DenseNet121,VGG11,13,16の8種類を使いました。

以下は、ResNet18でのデータ拡張の割合を探索する例です。 

import optuna

def objective(trial):
    model = models.resnet18(num_classes=10)
    model.cuda()

    #最適化するパラメータの設定
    lr_par = trial.suggest_loguniform('learning_rate'1e-51e-2)
    HoriFlip_p = trial.suggest_uniform('H_Flip'0.00.5)
    RandCont_p = trial.suggest_uniform('R_Cont'0.00.5)
    RandBrig_p = trial.suggest_uniform('R_Brig'0.00.5)
    Blur_p = trial.suggest_uniform('Bluer'0.00.5)
    Cut_p = trial.suggest_uniform('Cut_out'0.00.5)
    optim_flg = trial.suggest_categorical('optimizer', ['SGD''Adam'])
    
    #データを訓練用とテスト用に分ける
    train_x, valid_x, train_y, valid_y = train_test_split(train_images, train_labels, test_size=0.2, random_state=RANDOM_SEED)
  
    #データをローダーに格納する。
    train_loader = dataset.DataLoader(
      Dataset(train_x, train_y, HoriFlip_p, RandCont_p, RandBrig_p, Blur_p,Cut_p, train=True), batch_size=64, shuffle=True)
    valid_loader = dataset.DataLoader(
      Dataset(valid_x, valid_y, HoriFlip_p, RandCont_p, RandBrig_p, Blur_p, Cut_p,train=False), batch_size=64, shuffle=False)

    if optim_flg == 'Adam':
      optimizer = optim.Adam(model.parameters(), lr=lr_par)
    else:
      optimizer = optim.SGD(model.parameters(), lr=lr_par, weight_decay=0.01, momentum=0.9)

    log = []

    for epoch in range(20):
      model.train()

      with autograd.detect_anomaly():
        train_loss, train_accuracy = perform(model, train_loader, optimizer)

      model.eval()

      with torch.no_grad():
        valid_loss, valid_accuracy = perform(model, valid_loader, None)

      print('[{}] train(loss/accuracy)={:.2f}/{:.2f}, valid(loss/accuracy)={:.2f}/{:.2f}'.format(epoch + 1, train_loss, train_accuracy, valid_loss, valid_accuracy))

      log.append( (epoch + 1, train_loss, train_accuracy, valid_loss, valid_accuracy) )

    return valid_loss

#最適化の実行
study = optuna.create_study()
study.optimize(objective, n_trials=500)
 

 

2.1層目の学習

先ほど探索した割合のデータ拡張を施した入力を使って1層目の学習を実施します。

1層目の学習はStratifiedKFoldを使って、5Foldのクロスバリデーションを行いました。

今回は、各Fold毎に最も精度が良くなるモデルを保存するように工夫してみました。

def Exe_oof(model,origin_statetrain_images,train_labels,test_imagesoptim_flg,epoch_num,str_name,num_acc,num_fold):
  cv = StratifiedKFold(n_splits=Nsplits, shuffle=True, random_state=42)
  oof_pred = np.zeros( (len(train_images),10 ) )
  y_pred_max = np.zeros( (len(test_images),10 ) )
  str_model = str_name +'_0_0000'
  y_pred_flg=0 

  for fold, (train_idx, val_idx) in enumerate(cv.split(train_images, train_labels)):
    print(fold)
    print(num_fold)
    if fold==num_fold:
      print('True')
      max_acc = num_acc
      model.load_state_dict(origin_state)
      #データを訓練用と検証用に分ける
      train_x, valid_x = train_images[train_idx], train_images[val_idx]
      train_y, valid_y = train_labels[train_idx], train_labels[val_idx]
    
      #データをローダーに格納する。
      train_loader = dataset.DataLoader(
          Dataset(train_x, train_y, HoriFlip_p, RandCont_p, RandBrig_p, Blur_p,Cut_p, train=True), batch_size=64, shuffle=True)
      valid_loader = dataset.DataLoader(
          Dataset(valid_x, valid_y, HoriFlip_p, RandCont_p, RandBrig_p, Blur_p, Cut_p,train=False), batch_size=64, shuffle=False)

      if optim_flg == 'Adam':
        optimizer = optim.Adam(model.parameters(), lr=lr_par)
      else:
        optimizer = optim.SGD(model.parameters(), lr=lr_par, weight_decay=0.01, momentum=0.9)

      log = []
      import datetime

      print(datetime.datetime.now())

      for epoch in range(epoch_num):

        model.train()
        with autograd.detect_anomaly():
          train_loss, train_accuracy = perform(model, train_loader, optimizer)
  
        model.eval()
        with torch.no_grad():
          valid_loss, valid_accuracy = perform(model, valid_loader, None)

        print('[{}] train(loss/accuracy)={:.2f}/{:.2f}, valid(loss/accuracy)={:.2f}/{:.2f}'.format(epoch + 1, train_loss, train_accuracy, valid_loss, valid_accuracy))

        if valid_accuracy > max_acc:
          int_model = int(valid_accuracy*10000)
          str_model = str_name +'_'str(fold) +'_'str(int_model)
          DATA_DIR = 'drive/My Drive/ProbSpace/Ukiyoe/'+ str_name + '/' + str_model
          torch.save(model.state_dict(), DATA_DIR)
          #################################
          # 検証用データの予測
          #################################
          model.eval 
          hogehoge_i = 1
          for images, _ in valid_loader:
            images = images.cuda()
            with torch.no_grad():
              if hogehoge_i>=1 :
                preds = model(images)
                hogehoge_i=0
              else:
                preds = torch.cat([preds,model(images)],dim=0)
          dvs=torch.device('cpu'
          preds_cpu = preds.to(dvs)
          preds_np = preds_cpu.clone().numpy()
          oof_pred[val_idx] = preds_np

          #################################
          # テスト用データの予測
          #################################
          dummy_labels = np.zeros( (test_images.shape[0], 1), dtype=np.int64)
          test_loader = dataset.DataLoader(Dataset(test_images, dummy_labels,0.,0.,0.,0.,0.), batch_size=64, shuffle=False)
          model.eval()
          hogehoge_i = 1
          for images, _ in test_loader:
            images = images.cuda()
            with torch.no_grad():
              if hogehoge_i>=1 :
                preds = model(images)
                hogehoge_i=0
              else:
                preds = torch.cat([preds,model(images)],dim=0)
          y_pred_max = preds
          #################################
          max_acc = valid_accuracy

        print(datetime.datetime.now())

        log.append( (epoch + 1, train_loss, train_accuracy, valid_loss, valid_accuracy) )

      if y_pred_flg==0 :
        y_pred = y_pred_max
        y_pred_flg=1
      else:
        y_pred = torch.cat([y_pred,y_pred_max],dim=1)     
      print('Partial score of fold {} is: {}'.format(fold, max_acc))
   

 

3.1層目の出力(2層目の入力を作成)

先ほど学習させた精度の良い各モデルの出力を2層目への入力として作成しました。

def make_input_for_layer2(model,train_images,train_labels,test_images,str_name,num_fold):
  cv = StratifiedKFold(n_splits=Nsplits, shuffle=True, random_state=42)
  for fold, (train_idx, val_idx) in enumerate(cv.split(train_images, train_labels)):
    print(fold)
    if fold==num_fold:
      print(True)
      #データを訓練用と検証用に分ける
      train_x, valid_x = train_images[train_idx], train_images[val_idx]
      train_y, valid_y = train_labels[train_idx], train_labels[val_idx]
    
      #データをローダーに格納する。
      valid_loader = dataset.DataLoader(
          Dataset(valid_x, valid_y, 0.00.00.00.00.0,train=False), batch_size=64, shuffle=False)

      import datetime
      print(datetime.datetime.now())

      if True:
          str_model = str_name +'_'str(fold)
          DATA_DIR = 'drive/My Drive/ProbSpace/Ukiyoe/'+ str_name + '/' + str_model
          #################################
          # 検証用データの予測
          #################################
          model.eval 
          hogehoge_i = 1
          for images, _ in valid_loader:
            images = images.cuda()
            with torch.no_grad():
              if hogehoge_i>=1 :
                preds = model(images)
                hogehoge_i=0
              else:
                preds = torch.cat([preds,model(images)],dim=0)
          dvs=torch.device('cpu'
          preds_cpu = preds.to(dvs)
          preds_np = preds_cpu.clone().numpy()
          print(preds_np.shape)
          #################################
          # テスト用データの予測
          #################################
          dummy_labels = np.zeros( (test_images.shape[0], 1), dtype=np.int64)
          test_loader = dataset.DataLoader(Dataset(test_images, dummy_labels,0.,0.,0.,0.,0.), batch_size=64, shuffle=False)
          model.eval()
          hogehoge_i = 1
          for images, _ in test_loader:
            images = images.cuda()
            with torch.no_grad():
              if hogehoge_i>=1 :
                preds = model(images)
                hogehoge_i=0
              else:
                preds = torch.cat([preds,model(images)],dim=0)
          preds_sub  = torch.max(preds, dim=1)[1]
          preds_cpu = preds.to(dvs)
          preds_y = preds_cpu.clone().numpy()
          print(preds_y.shape)
          print(preds.shape)
          #################################
          
          print(datetime.datetime.now())

          with open('drive/My Drive/ProbSpace/Ukiyoe/'+ str_name + '/'+ str_model + '_preds_np.pkl','wb'as f1:
            pickle.dump(preds_np,f1)
          with open('drive/My Drive/ProbSpace/Ukiyoe/'+ str_name + '/'+ str_model + '_val_idx.pkl','wb'as f2:
            pickle.dump(val_idx,f2)
          with open('drive/My Drive/ProbSpace/Ukiyoe/'+ str_name + '/'+ str_model + '_pred_y_torch.pkl','wb'as f3:
            pickle.dump(preds,f3)
          with open('drive/My Drive/ProbSpace/Ukiyoe/'+ str_name + '/'+ str_model + '_pred_y.pkl','wb'as f4:
            pickle.dump(preds_y,f4)
          with open('drive/My Drive/ProbSpace/Ukiyoe/'+ str_name + '/'+ str_model + '_pred_sub.pkl','wb'as f5:
            pickle.dump(preds_sub,f5)
          with open('drive/My Drive/ProbSpace/Ukiyoe/Layer1/_'+ str_model + '_valid_y.pkl','wb'as f6:

            pickle.dump(valid_y,f6)

4.1層目の出力に係数をかけてLightGBMに入力

2層目は、LightGBMを使ってみました。

入力は、1層目の出力に対して、0.0~1.0の係数をかけて、精度が最大となる係数をOptunaにて探索しました。

5.上記までのモデルを3パターン作って平均をとる

最終的には、上記までのモデルを3パターン作って、平均したものを提出しました。

結果

 最終結果としては、提出回数98回、ベストスコア:0.899、順位:10位でフィニッシュできました。

f:id:kanriyou_h004:20200118231350p:plain
E資格の課題で、画像分類を実施していたので、その時の経験をフルに活用でき、ベスト10に入れたので、非常に満足のいく結果でした。

ただ、逆にいうとE資格の課題に取り組んだ際に学んだ知識しかなかったので、上位の方々の解法を参考にして、もっと精進していきたいと思います。

今後もいろいろなコンペに参加して、技術を磨いていきたいと思います。

 

[商品価格に関しましては、リンクが作成された時点と現時点で情報が変更されている場合がございます。]

Kaggleで勝つデータ分析の技術 [ 門脇大輔 ]
価格:3608円(税込、送料無料) (2019/12/30時点)

 【参考記事】E資格、G検定 合格記

2019年8月31日(土)にE資格を受験して、合格しました!

E資格対策として勉強の進め方や、参考書などをまとめました。

これから受験される方がいらっしゃいましたらご参考まで。

oregin-ai.hatenablog.com 

 

 2019年3月9日(土)にG検定を受験し、見事合格できました!

受験の体験記や勉強法などを別のブログにまとめました。

これから受験される方がいらっしゃいましたらご参考まで。

g-kentei.hatenablog.com

 【E資格対策に使った参考書】

 

 

E資格 復習のつぶやきまとめ

昨年合格した、JDLA E資格の復習のつぶやきをまとめました。

来月のE資格を受験される方の参考にしていただければと思います。

f:id:kanriyou_h004:20200111093416j:image

 

ProbSpace給与推定コンペ振り返り

先日、「ProbSpace」というプラットフォームで開催された「給与推定」コンペに参戦したので、振り返っていきたいと思います。

私にとって、初めて公式の結果が確定したコンペとなり、最終順位は参加310チーム中、46位でした。全体の15%以内に入れたので、まずまずの出来だったと思います。

f:id:kanriyou_h004:20191230142705p:plain

ただ、上位陣の解法を拝見すると、自分のコードは、まだまだ、全然できていないなぁと感じました。

では、さっそく時系列に取り組みを振り返っていきます。

(あえて、時系列にしたのは、計画的にとりくめなかった自分の反省を込めて・・。)

特徴量(その1)

1.欠損値を確認

データを読み込んで、とりあえず欠損値の有無を確認しました。

# Read Data
train_df = pd.read_csv('train_data.csv', index_col=0)
test_df = pd.read_csv('test_data.csv', index_col=0)

#Check Null
print(train_df.isnull().sum())
print('='*20)
print(test_df.isnull().sum())

position 0
age 0
area 0
sex 0
partner 0
num_child 0
education 0
service_length 0
study_time 0
commute 0
overtime 0
salary 0
dtype: int64
====================
position 0
age 0
area 0
sex 0
partner 0
num_child 0
education 0
service_length 0
study_time 0
commute 0
overtime 0
dtype: int64

確認したところ、欠損値がなく、補完の処理も不要であったので、ここは楽でした。

2.ラベルエンコーディング

「Area」の列が、「東京都」、「大阪」など文字列の情報になっているので、数値データに置き換えました。

# Area
from sklearn import preprocessing
le = preprocessing.LabelEncoder()
df['area'] = le.fit_transform(df['area'])

 

アンサンブル学習(スタッキング)のモデルを作成(その1)

1.1層目の作成

1層目は、まず、RandomForet,AdaBoost,GradientBoosting,ExtraTree,Baggingの5つをつかってみました。

 from sklearn.ensemble import (RandomForestRegressor, AdaBoostRegressor, 
GradientBoostingRegressor, ExtraTreesRegressor,BaggingRegressor)

2.2層目の作成

2層目は、LightGBMを使ってみました。

import lightgbm as lgb 

3.全体構成その1

 全体としては、以下のような感じです。 

f:id:kanriyou_h004:20191230150437p:plain

 

特徴量(その2)

特徴量(その2)では、いくつかの特徴量を新たに追加したのですが、効果を発することなく終わってしまいました。

1.Areaカウントを追加

「Area」について、単純にコード化するのではなく、エリアごとのレコード数をコードの代わりにする列を作ってみました。

# 'area'
train_df['area_count_enc'] = train_df.groupby('area')['overtime'].transform('count')
test_df['area_count_enc'] = test_df.groupby('area')['overtime'].transform('count')

 

2.Educationを分割

また、「Education」が、2以下と3以上でSalaryの傾向が異なっていたので、2分割にしてみました。

#education を 2以下と3以上の区分に分ける。
train_df['education_2under_3over']=[3 if i >=3 else 1 for i in train_df['education']]
test_df['education_2under_3over']=[3 if i >=3 else 1 for i in test_df['education']]

 

 

3.Service_length,commute,study_timeをビンニング

「Service_length」,「commute」,「study_time」については、それぞれ、5、5、4にビンニング処理を実施。

train_df['Categorical_length']=pd.qcut(train_df['service_length'],5)
test_df['Categorical_length']=pd.qcut(test_df['service_length'],5)
train_df['Categorical_length'] = le.fit_transform(train_df['Categorical_length'])
test_df['Categorical_length'] = le.fit_transform(test_df['Categorical_length'])

#以下同様にcommute,study_time

特徴量(その3)

特徴量(その3)では、複数の特徴量を組み合わせたり、対数をとったりしてみました。

これによって、MAEが24を切ることができました。

1.交差項追加

いろいろな列の掛け算をとって、モデルに投入して、精度が上がる組み合わせをOptuna等をつかって探索しました。

 #cros_Feature
df['commute_x_partner'] = df['commute'] * df['partner']
df['commute_x_num_child'] = df['commute'] * df['num_child']
df['position_x_age'] = df['position'] * df['age']
#などなどいろいろ追加して試す

 

2.対数変換

数値の列については、対数をとってみました。

def to_Log(df):
continuas_col=['age','service_length','study_time','commute','overtime']
for i,col in enumerate(continuas_col):
df['Log_'+col]=np.log1p(df[col]+1)

to_Log(train_df)
to_Log(test_df)

 

 ついでに、Salaryも対数変換しました。

うっかり、提出用のデータも対数のまま提出してしまい、提出データの精度がガタ落ちして、何が起こったかわからず、プチパニックになりました。

# 入力データの作成
y_train = np.log1p(train_df['salary'].ravel())

train = train_df.drop(['salary'], axis=1)
x_train = train.values # 学習データ
x_test = test_df.values # テストデータ

 提出時は以下を忘れてはいけない。

predicts = np.expm1(model.predict(input_test_df))

3.「東京」、「大阪」は特別扱い

トピックに「東京」、「大阪」を特別扱いするとよいとの記事があったので、さっそく参考にさせていただきました。

  df["Live_in_Tokyo_or_Osaka"] = [1 if (i ==9) | (i==26) else 0 for i in df['area']]

  

4.Target Encording

Kaggleで勝つデータ分析の技術 [ 門脇大輔 ]」を拝見して、Target Encordingにも挑戦してみました。

リークとならないように、平均につかったレコード以外を置き換えていくのがポイントですね。

from sklearn.cross_validation import KFold

kf = KFold(ntrain, n_folds=7, random_state=42)
#=========================================================#
cat_col=['position','area','sex','partner','education']

for c in cat_col:
  # 学習データ全体で各カテゴリにおける給料の平均を計算
  data_tmp = pd.DataFrame({c: train_df[c],'target':train_df['salary']})
  target_mean = data_tmp.groupby(c)['target'].mean()
  #テストデータのカテゴリを置換
  test_df[c] = test_df[c].map(target_mean)

  # 変換後の値を格納する配列を準備
  tmp = np.repeat(np.nan, train_df.shape[0])

  for i, (train_index, test_index) in enumerate(kf): # NFOLDS回まわる
      #学習データについて、各カテゴリにおける目的変数の平均を計算
      target_mean = data_tmp.iloc[train_index].groupby(c)['target'].mean()
      #バリデーションデータについて、変換後の値を一時配列に格納
      tmp[test_index] = train_df[c].iloc[test_index].map(target_mean)

  #変換後のデータで元の変数を置換
  train_df[c] = tmp

#========================================================#

 

 

アンサンブル学習(スタッキング)のモデルを作成(その2)

1.1層目の予測パターンを作成

1層目について、 特徴量として「①対数変換を行う前」「➁対数変換を行った後」「➁にTargetEncording実施」の3つそれぞれに、予測モデルとしてRandomForet、AdaBoost、GradientBoosting、ExtraTree、Baggingの5つを使った、合計

15個の予測パターンを作成しました。

2.2層目の作成

2層目は、LightGBMで、1層目の15個の予測パターンのうち、どのパターンを使うと最も精度が高くなるかをOptunaを使って探索しました。 

3.全体構成その2

 探索した結果、以下のような構成となりました。 

f:id:kanriyou_h004:20191230161600p:plain

アンサンブル学習(スタッキング)のモデルを作成(その3) 

1.3層目を作ってみる

モデルを作成(その2)で行き詰まってしまったので、その2のOptunaで、精度が良かった組み合わせをいくつかピックアップして、2層目の出力の平均をとる3層目をつくってみました。

ここからは、いろんなパターンを作成して、少しでも精度が良かったモデルができたら出力ファイルをためておいて毎日提出するという力技になってしまいました。

f:id:kanriyou_h004:20191230162419p:plain

結果

 最終結果としては、提出回数109回、ベストスコア:22.539、順位:46位でフィニッシュできました。

f:id:kanriyou_h004:20191230163029p:plain

最後までやり切った初めてのコンペでした。

充実感もありましたが、やはり、全体的な計画ができていなかったので、特徴量を検討するのか、モデルを検討するのか、どっちつかずで、おろおろしている間に終わってしまったのが反省点でした。

また、今回は木モデルを中心に構成しましたが、上位陣の方々の解法を拝見するとニューラルネットワークを使いこなしていらっしゃったので、もっと勉強して手札を増やしていく必要があると感じました。

 次のコンペはもっと、計画的にいろいろなパターンを試して、さらに順位アップを狙っていきたいと思います。

 

[商品価格に関しましては、リンクが作成された時点と現時点で情報が変更されている場合がございます。]

Kaggleで勝つデータ分析の技術 [ 門脇大輔 ]
価格:3608円(税込、送料無料) (2019/12/30時点)

 【参考記事】E資格、G検定 合格記

2019年8月31日(土)にE資格を受験して、合格しました!

E資格対策として勉強の進め方や、参考書などをまとめました。

これから受験される方がいらっしゃいましたらご参考まで。

oregin-ai.hatenablog.com 

 

 2019年3月9日(土)にG検定を受験し、見事合格できました!

受験の体験記や勉強法などを別のブログにまとめました。

これから受験される方がいらっしゃいましたらご参考まで。

g-kentei.hatenablog.com

 【E資格対策に使った参考書】

 

 

E資格対策振り返り(応用数学-情報理論-クロスエントロピー)

E資格(JDLA Deep Learning for ENGINEER 2019 #2)対策として学習した応用数学の分野のうち、今回は、情報理論-クロスエントロピーを振り返ります。

深層学習では、以下の4つが既知のものとして登場してきます。

  1. 自己情報量
  2. エントロピー
  3. カルバック・ライブラー情報量(KLダイバージェンス)
  4. クロスエントロピー

今回はこれらのうち、4つ目のクロスエントロピーについて、振り返っていきます。

クロスエントロピー

1.クロスエントロピーとは何か

クロスエントロピーとは、ある分布p(x)を調整してq(x)にしたい場合に、誤差を最小化する時に利用する関数となります。

実際のp(x)とq(x)の誤差は、前回振り返ったカルバック・ライブラー情報量(KLダイバージェンス)となるのですが、誤差を最小化するという観点では、p(x)を調整する事で変動する部分だけを最小化すれば良く、p(x)を調整しても変動しない部分は、考慮しなくて良い事になります。

この カルバック・ライブラー情報量(KLダイバージェンス)から、p(x)を調整しても、変動しない部分を除いたものが、クロスエントロピーとなります。

言葉だけでは伝わらない部分が多いかと思いますので、順を追って説明していきたいと思います。 

2.カルバック・ライブラー情報量(KLダイバージェンス)を変形する

カルバック・ライブラー情報量(KLダイバージェンス)は以下の式となることは、前回の記事で振り返りました。

f:id:kanriyou_h004:20191201153957p:plain


この式を、対数関数の減算の処理(減算<=>除算の変換)などを使って変換すると以下の通り変換できます。

f:id:kanriyou_h004:20191201154701p:plain

上記の第1項は、p(x)を含まないので、p(x)を調整しても変動しない部分になります。ということは、第2項が、p(x)を調整することで変動させることができる部分となります。(なお、第1項は、q(x)のエントロピー(の符号を反転したもの)となります。)

よって、p(x)を調整して、p(x)とq(x)の誤差(カルバックライブラー情報量)を最小化するためには、第2項を最小化する事になります。

この第2項がクロスエントロピー(H(q,p))となり、以下の式となります。

f:id:kanriyou_h004:20191201155752p:plain

このクロスエントロピーは、ニューラルネットワークの誤差関数として必須な関数となりますので、しっかり理解するように心がけました。

3.2値クロスエントロピー(binary cross entropy)

先ほど、振り返ったクロスエントロピーのうち、特に、2値で分類(例えばコインの裏表試行など)する際のクロスエントロピーとして片方の値が出る確率p、q(0<=p<=1、0<=q<=1)(例えばコインの表が出る実際の確率と、予測モデルでの表が出る確率)について、クロスエントロピーの式に当てはめると以下となります。

f:id:kanriyou_h004:20191201161032p:plain

こちらも、頻出の式となるので、しっかり理解できるよう頑張りました。

 

以上で、E資格の情報理論で頻出の数式の4つを振り返ることができました。

途中、Kaggleなどのコンペにも参戦していたので、全部投稿し終えるのに期間がかかってしまいましたが、今後E資格を受験されるかたの参考にしていただければ幸いです。

今後も、E資格の振り返りや、Kaggleへの参戦記など、投稿していきたいと思います。

引き続き、宜しくお願い致します。 

2019年8月31日(土)にE資格を受験して、合格しました!

E資格対策として勉強の進め方や、参考書などをまとめました。

これから受験される方がいらっしゃいましたらご参考まで。

oregin-ai.hatenablog.com 

 

 2019年3月9日(土)にG検定を受験し、見事合格できました!

受験の体験記や勉強法などを別のブログにまとめました。

これから受験される方がいらっしゃいましたらご参考まで。

g-kentei.hatenablog.com

 【E資格対策に使った参考書】