{"cells":[{"metadata":{},"cell_type":"markdown","source":"지금까지 올라온 커널들을 보면 배치마다 하드에서 이미지를 읽어와서 학습을 시켰습니다. 그러나 이번 대회는 데이터 용량이 크지 않기 때문에 메모리에 저장해두어서 배치마다 학습데이터를 더 빠르게 생성할 수 있습니다.\n\n또한 keras의 `fit_generator` 메서드에서 `use_multiprocessing=True`, `workers=n`으로 둬서 전처리 과정을 여러 cpu 코어에 나누어 처리할 수도 있습니다. (다만 이 기능을 윈도우의 주피터노트북 환경에서는 쓸 수 없습니다.)\n\n속도 테스트가 목적이므로 에폭은 2번만 돌렸습니다.\n\n---\n\n*참고*\n1. Cropped image dataset: 태명님의 https://www.kaggle.com/tmheo74/3rd-ml-month-car-image-cropping-dataset\n2. Augmentation: https://github.com/DeepVoltaire/AutoAugment 의 ImagenetPolicy\n3. Train-val-split: StratifiedKFold(5)의 첫 번째 fold\n4. Optimizer: 세원님이 https://www.kaggle.com/yangsaewon/ka-kr-sillim-pytorch-baseline-updated-7-01 에서 쓰신 SGD(momentum=0.9)"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import sys\nsys.path.append('../input/autoaugment')\nfrom autoaugment import ImageNetPolicy\n\nimport PIL\n\nimport pandas as pd\nimport numpy as np\n\nimport keras\nfrom keras.applications.mobilenet_v2 import MobileNetV2, preprocess_input\nfrom keras.models import Model\nfrom keras.layers import GlobalAveragePooling2D, Dense\nfrom keras.optimizers import SGD\n\nfrom sklearn.metrics import f1_score\nfrom sklearn.model_selection import StratifiedKFold\n\nfrom tqdm import tqdm","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"IMG_SIZE = 224\nBATCH_SIZE = 128","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train = pd.read_csv('../input/2019-3rd-ml-month-with-kakr/train.csv')\ntest = pd.read_csv('../input/2019-3rd-ml-month-with-kakr/test.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"folds = list(StratifiedKFold(5, random_state=0, shuffle=False).split(train, train['class']))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def make_dataset(df, augment=True, test=False):\n    x = []\n    for i, image_path in tqdm(enumerate(df['img_file'].values)):\n        if test:\n            image_path = '../input/3rd-ml-month-car-image-cropping-dataset/test_crop/' + image_path\n        else:\n            image_path = '../input/3rd-ml-month-car-image-cropping-dataset/train_crop/' + image_path\n        image = PIL.Image.open(image_path).convert(\"RGB\").resize((IMG_SIZE, IMG_SIZE))\n        x.append(image)\n    if test:\n        y = None\n    else:\n        y = keras.utils.to_categorical(df['class'].astype(int)-1, num_classes=196)\n    return x, y\n\nx_train, y_train = make_dataset(train.iloc[folds[0][0]])\nx_val, y_val = make_dataset(train.iloc[folds[0][1]])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(len(x_train))\nx_train[:5]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(y_train.shape)\ny_train","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class SlowGenerator(keras.utils.Sequence):\n    \n    def __init__(self, x, y=None, augment=True):\n        self.x = x\n        self.y = y\n        self.augment = augment\n        self.policy = ImageNetPolicy()\n        \n    def __len__(self):\n        return int(np.ceil(len(self.x)/BATCH_SIZE))\n    \n    def _transform(self, image):\n        image = self.policy(image)\n        image = preprocess_input(np.array(image))\n        return image\n    \n    def __getitem__(self, index):\n        if self.y is None:\n            images = [PIL.Image.open('../input/3rd-ml-month-car-image-cropping-dataset/test_crop/'+_x).convert('RGB').resize((IMG_SIZE, IMG_SIZE)) for _x in self.x[index*BATCH_SIZE:(index+1)*BATCH_SIZE]]\n            if self.augment:\n                x = list(map(self._transform, images))\n            else:\n                x = [preprocess_input(np.array(x_)) for x_ in images]\n            return np.array(x)\n        \n        images = [PIL.Image.open('../input/3rd-ml-month-car-image-cropping-dataset/train_crop/'+_x).convert('RGB').resize((IMG_SIZE, IMG_SIZE)) for _x in self.x[index*BATCH_SIZE:(index+1)*BATCH_SIZE]]\n        if self.augment:\n            x = np.array(list(map(self._transform, images)))\n            y = self.y[index*BATCH_SIZE:(index+1)*BATCH_SIZE]\n            y = keras.utils.to_categorical(y-1, num_classes=196)\n            return x, y\n        \n        x = np.array([preprocess_input(np.array(x_)) for x_ in images])\n        y = self.y[index*BATCH_SIZE:(index+1)*BATCH_SIZE]\n        y = keras.utils.to_categorical(y-1, num_classes=196)\n        return x, y\n\nclass FastGenerator(keras.utils.Sequence):\n    \n    def __init__(self, x, y=None, augment=True):\n        self.x = x\n        self.y = y\n        self.augment = augment\n        self.policy = ImageNetPolicy()\n        \n    def __len__(self):\n        return int(np.ceil(len(self.x)/BATCH_SIZE))\n    \n    def _transform(self, image):\n        image = self.policy(image)\n        image = preprocess_input(np.array(image))\n        return image\n    \n    def __getitem__(self, index):\n        \n        if self.y is None:\n            if self.augment:\n                x = list(map(self._transform, self.x[index*BATCH_SIZE:(index+1)*BATCH_SIZE]))\n            else:\n                x = [preprocess_input(np.array(x_)) for x_ in self.x[index*BATCH_SIZE:(index+1)*BATCH_SIZE]]\n            return np.array(x)\n        \n        if self.augment:\n            x = np.array([preprocess_input(np.array(x_)) for x_ in self.x[index*BATCH_SIZE:(index+1)*BATCH_SIZE]])\n            y = self.y[index*BATCH_SIZE:(index+1)*BATCH_SIZE]\n            return x, y\n        \n        x = np.array([preprocess_input(np.array(x_)) for x_ in self.x[index*BATCH_SIZE:(index+1)*BATCH_SIZE]])\n        y = self.y[index*BATCH_SIZE:(index+1)*BATCH_SIZE]\n        return x, y","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fast_train_generator = FastGenerator(x_train, y_train)\nfast_val_generator = FastGenerator(x_val, y_val, augment=False)\nslow_train_generator = SlowGenerator(train.iloc[folds[0][0]]['img_file'].values, train.iloc[folds[0][0]]['class'].values)\nslow_val_generator = SlowGenerator(train.iloc[folds[0][1]]['img_file'].values, train.iloc[folds[0][1]]['class'].values, augment=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_model():\n    \n    base_model = MobileNetV2(input_shape=(IMG_SIZE, IMG_SIZE, 3), include_top=False, weights='imagenet')\n    base_model.trainable = False\n    x = base_model.output\n    x = GlobalAveragePooling2D()(x)\n    output = Dense(196, activation='softmax')(x)\n    model = Model(inputs=base_model.input, outputs=output)\n    model.compile(loss='categorical_crossentropy', optimizer=SGD(momentum=0.9))\n\n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = get_model()\nhistory = model.fit_generator(\n    slow_train_generator,\n    validation_data=slow_val_generator,\n    epochs=2,\n    verbose=1\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = get_model()\nhistory = model.fit_generator(\n    fast_train_generator,\n    validation_data=fast_val_generator,\n    epochs=2,\n    verbose=1\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = get_model()\nhistory = model.fit_generator(\n    fast_train_generator,\n    validation_data=fast_val_generator,\n    epochs=2,\n    verbose=1,\n    use_multiprocessing=True,\n    workers=2\n)","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.4","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}