ai-starthon / AI_Starthon2019

60 stars 44 forks source link

1번 문제 TF 2.0으로 가능한거 맞나요? 뭘 해도 점수 1400대길래봤더니 #209

Closed alanpurple closed 5 years ago

alanpurple commented 5 years ago

뭔짓을 해도 1400대길래, 심지어 틀린 코드 많아서 중간에 베이스 코드 및 채점 코드 변경도 하셨고 게다가 트레인할때 로스도 이게 값을 못보니 잘 나오는건지 안나오는건지 알 수도 없고

5일 고생하고 (심지어 썹밋도 1시간에 한번밖에 안되니까요. 값도 못 보는 게 원칙이고)

올려놓으신 파이토치 그냥 다 넣고 dense 돌린걸 썹밋 해봤는데 4백이 나오네요.

열받기도 해서 똑같이 TF 2.0 keras Model로 fit해서 썹밋했더니 1550이 나옵니다.

inference 부분 잘못 짰나 수백번봤지만 그냥 tf 2.0 keras model.predict해서 2개짜리를 뽑던 각각 뽑던 인덱스 붙여서 넘겨주라고 되어 있고 그게 다이고, 어짜피 숫자 안 맞으면 썹밋할때 에러가 날테고

애초에 제가 모델 잘못 짜서 별 걸 다 시도해봤지만 그게 아니었던거죠

지금 리더보드에 4백근처 3팀 1400대 3팀 있는데 다 TF 2.0이던 다른 플랫폼이던 다 이런 이유로 안되는 것인데요.

NSML 팀에선 TF 2.0 간단한 모델에 model.fit, predict로 4백대 submit 점수 가능한가요?

여기서 누가 1번 안되면 다른거 하지라 할 수 있는데 간단한 모델 기본 점수 ( 1등의 2배라던가 ) 도 안나오는데 다른 문제 할 엄두가 안나죠. 애초에 지금 플랫폼 사용도 할 줄 모르는 상황이라 봐도 되는데

jungwoo-ha commented 5 years ago
  1. training loss는 웹 UI를 통해 확인 가능하십니다. 웹에서 태스크 클릭하시면 세션들이 나오는데요. 거기에 loss 상황이 출력됩니다.
  2. TF 2.0 keras는 써보지 않았지만 keras API 가 동일하다는 전제하에 기존 keras로 돌리면

    
    def bind_model(model):
    def save(path, *args, **kwargs):
        # save the model with 'checkpoint' dictionary.        
        model.model.save_weights(os.path.join(path, 'model.h5'))    
    
    def load(path, *args, **kwargs):
        model.model.load_weights(os.path.join(path, 'model.h5'))
    
    def infer(path, **kwargs):
        return inference(path, model, config)
    
    nsml.bind(save, load, infer)

class Model(): def init(self, lr): self.model = Sequential([Dense(32, input_shape=(FEATURE_DIM,)), Activation('relu'), Dense(OUTPUT_DIM), Activation('relu')]) rms_pr = RMSprop(lr=lr) self.model.compile(optimizer=rms_pr, loss='mse') return

model = Model(LR)



이렇게 정의해주면 정상적인 weight가 저장/로딩되고 제가 테스트 했을 때 대략 simple linear regression with ReLU로도 37정도의 score가 나옵니다. TF, Pytorch, keras 모두가 각각 모델을 저장/로딩하는 방법들이 다소 다르긴 하지만 각각이 API Document가 잘되어 있기 때문에 충분히 응용가능할 것이라 생각합니다. 
alanpurple commented 5 years ago

@jungwoo-ha

지금 저렇게 돌렸을때 TF 2.0으로 1500 나온다는 건데요 train 할때 loss는 잘 줄고 있고요

저말고도 저 포함 6팀이 그렇게 나오고 있어요

잘하고 못하고 기본을 모르고 문제가 아니라 아예 엉뚱한 값이 나오고 있는겁니다. 최악으로 못해도 파이토치처럼 4백점이 나와야하는데 1400이 나오고 있으니까요

대충 봤을때 다 넣고 그냥 덴스 돌린게 4백이니까 단순 실력이 떨어진다고 가정해도 2~3백은 나와야 정상일 거 같아요.

alanpurple commented 5 years ago

@jungwoo-ha

위에 말씀하신거 그대로 돌려서 1430점 나옵니다.

jungwoo-ha commented 5 years ago

@alanpurple

해당 점수는 높은 확률로 TF 2.0 keras의 모델 저장/로딩의 이슈로 보입니다. 1400점이 최초 keras 모델 저장/로딩이 잘못될 때 나오는 점수거든요. 2.0에서 save_weights // load_weights 에서 문제가 있다면 다른 save / loading 함수(구버전에서는 save, load가 weight only와 전체 아키텍처 포함을 구분)를 시도 해보시거나 이전 버전의 TF Keras를 해보실 것을 권장드립니다. 말씀드린바와 같이 모든 버전의 라이브러리에 대해 저희가 정상동작 여부를 체크하는 것에는 한계가 있음을 양해부탁드립니다.

참고로 제 코드는

import torch
from torch.autograd import Variable
import numpy as np

from nsml import DATASET_PATH
import nsml
import h5py

from keras.models import Sequential
from keras.layers import Dense, Activation
from keras.optimizers import RMSprop
import keras.models
from sklearn.metrics import f1_score, accuracy_score, mean_squared_error

#import glob
import os
import argparse

FEATURE_DIM = 14 #지역(0~9), 연(2016~2019), 월, 일, t-5 ~ t-1의 미세 & 초미세
OUTPUT_DIM = 2 # t-time의 (미세, 초미세)

def bind_model(model):
    def save(path, *args, **kwargs):
        # save the model with 'checkpoint' dictionary.

        model.model.save_weights(os.path.join(path, 'model.h5'))    

    def load(path, *args, **kwargs):
        model.model.load_weights(os.path.join(path, 'model.h5'))

    def infer(path, **kwargs):
        return inference(path, model, config)

    nsml.bind(save, load, infer)

def inference(path, model, config, **kwargs):

    #model.eval()

    test_path = path+'/test_data'
    data = convData(np.load(test_path))
    mean10_val = np.mean(data[:,4::2])
    print (len(data))
    pred_val = model.model.predict(data/mean10_val).tolist()
    print (len(pred_val))
    pred_results = [[step, val] for step, val in enumerate(pred_val)]
    return pred_results

def convData(data_arr):
    v = np.zeros(FEATURE_DIM, dtype=np.float32)
    v[1] = 2016
    new_d = np.asarray([d - v for d in data_arr])
    return new_d

class Model():
    def __init__(self, lr):
        self.model = Sequential([Dense(32, input_shape=(FEATURE_DIM,)), Activation('relu'), Dense(OUTPUT_DIM), Activation('relu')])
        rms_pr = RMSprop(lr=lr)
        self.model.compile(optimizer=rms_pr, loss='mse')
        return    

if __name__ == '__main__':

    args = argparse.ArgumentParser()

    # DONOTCHANGE: They are reserved for nsml
    args.add_argument('--mode', type=str, default='train', help='submit일때 해당값이 test로 설정됩니다.')
    args.add_argument('--iteration', type=str, default='0',
                      help='fork 명령어를 입력할때의 체크포인트로 설정됩니다. 체크포인트 옵션을 안주면 마지막 wall time 의 model 을 가져옵니다.')
    args.add_argument('--pause', type=int, default=0, help='model 을 load 할때 1로 설정됩니다.')

    config = args.parse_args()

    EP, LR = 100, 0.0001    
    # Bind model
    model = Model(LR)
    bind_model(model)

    # DONOTCHANGE: They are reserved for nsml
    # Warning: Do not load data before the following code!
    if config.pause:
        nsml.paused(scope=locals())

    if config.mode == "train":

        train_dataset_path = DATASET_PATH + '/train/train_data'
        #train_data_files = sorted(glob.glob(train_dataset_path + '/*.npy')) 
        tr_X = convData(np.load(train_dataset_path))
        mean10_val = np.mean(tr_X[:,4::2])
        train_label_file = DATASET_PATH + '/train/train_label'
        tr_Y = np.load(train_label_file)

        for epp in range(EP):
            model.model.fit(tr_X/mean10_val, tr_Y, epochs=2, batch_size=1024)
            if epp % 20 == 0:
                print (epp)
                nsml.save(epp)              

        nsml.save(EP)

이것이 전부입니다. 이 버전이 37점 score가 나옵니다.

alanpurple commented 5 years ago

@jungwoo-ha

토치코드는 점수 정상적으로 나오는 거 확인해서 애초에 이슈 올린거고요

그리고 모델 로딩 잘 안되는 게 제 잘못은 아닐텐데요

그리고 전체 저장/로딩 웨이트만 저장/로딩 둘다 안됩니다.

그리고 애초에 네이버 측에 tf 2.0 되냐고 질문도 올렸었는데 쓸 수 있다 하셨고요 아닌말로 제가 nsml.bind를 디버깅 할 수 있는거고 아니고 데이터 볼 수 있는 거도 아니고

설사 지금 수정해서 잘 나오게 하는 방법이 있다해도 이런 환경에서 제가 알아내긴 힘들거 같네요.

전 애초에 제 잘못도 아닌데 엉뚱한 점수를 기본적인 부분이 모델에서 문제가 있을거라 생각하며 3일 이상을 날렸네요.

jungwoo-ha commented 5 years ago

@alanpurple

위의 코드는 pytorch 코드가 아니고 keras 코드입니다. 다만 import 부분을 수정을 하지 않은 것이고요. 그래서 구버전의 keras 코드로 정상동작을 확인 했다고 공유를 드린 부분입니다. 말씀 주신 대로 TF 2.0 에 대한 저장/로딩 까지 새심하게 체크하지 못한 점 사과말씀드립니다. 다만 말씀 드린대로 모든 Library의 정상동작을 제대로 체크하기는 현실적으로 어려워서 가장 많이 쓰이는 Pytorch 와 TF 1점대 그리고 추후 keras (버그 수정은 다른 참가자분께서) 정도까지 공유 드렸습니다. Keras에 익숙하시다면 구버전의 keras를 위의 방법을 이용해 사용하실 것을 권장드립니다.

alanpurple commented 5 years ago

@jungwoo-ha

애초에 제가 TF 2.0 되느냐 했을때 (물론 정우님이 답변하신 건 아니었지만)

주최측에서 권유하지 않는다고 답변을 했어야 하는게 맞았을 거 같네요. 또한 에러가 안나도 문제가 있을 가능성에 대한 건 시스템 개발자가 체크를 못한 부분이고요. 어느 프레임워크나 사용가능하다고 미리 알린것도 결국 문제로 볼 수 있겠습니다.

덕분에 전 3일을 통으로 날리고 스트레스도 엄청 받았습니다.

제가 뭐라 해서 무슨 소용이 있겠습니까만, 준비가 제대로 된 것은 아닌것으로 보입니다. 유료 컴페티션도 아니고 네이버측에서는 나름 선의로 제공을 한다햇던거지만, 이렇게 피해만 줬으면 무슨 소용이 있겠습니까

덧붙이자면 TF 2.0 beta.1도 지금 굉장히 많이 쓰는 프레임웤입니다(한국에서는 아닐지 몰라도) 저 혼자 특이한 걸 썼다가 본인 탓으로 고생했다고 볼 수는 없겠죠

jungwoo-ha commented 5 years ago

정상적 동작 코드 확인을 위해 서밋하신 코드 기준으로 수정했고 TF 2.0 Keras 기준 정상 저장/로딩 되는 것을 확인했습니다. 2 epoch 기준 35.11 이 출력됩니다.

def bind_model(model):
    def save(path,*args,**kwargs):
        model.save_weights(os.path.join(path, 'model_alan.tf'))

    def load(path,*args, **kwargs):
        model.load_weights(os.path.join(path,'model_alan.tf'))

    def infer(path,**kwargs):
        return inference(path,model, config)

    nsml.bind(save,load,infer)

def inference(path, model, config, **kwargs):

image

이번 챌린지는 연구 챌린지가 아닌 사업화 지원 챌린지의 성격이 강하니 다양한 환경에서 실제 프러덕트 만드는 역량을 검증하는 것이 중요하다고 생각합니다. 그리고 말씀드린대로 모든 경우에 대해서 완전히 테스트 하는 것은 현실적으로 어렵다는 점도 다시한번 말씀 드립니다.