{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"! pip uninstall -y tensorflow_datasets\n! pip install tensorflow_datasets==4.4.0","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-03-26T05:08:15.520750Z","iopub.execute_input":"2022-03-26T05:08:15.521061Z","iopub.status.idle":"2022-03-26T05:08:31.080902Z","shell.execute_reply.started":"2022-03-26T05:08:15.520988Z","shell.execute_reply":"2022-03-26T05:08:31.080359Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport os\nfrom sklearn.preprocessing import LabelEncoder\nimport dill\nimport tensorflow as tf\nimport matplotlib.pyplot as plt\nfrom kaggle_datasets import KaggleDatasets\nimport tensorflow as tf\nfrom tensorflow import keras \nfrom tensorflow.keras import backend as K \nimport seaborn as sns\nimport random\nimport gc\nfrom tqdm.notebook import tqdm\nimport tensorflow_addons as tfa\nimport sys\nsys.path.append(\"../input/sorghum100cultivarjpgtfrecords512x512\")\nfrom fgvc_dataset import FGVCDataset","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-03-26T05:08:31.082450Z","iopub.execute_input":"2022-03-26T05:08:31.082702Z","iopub.status.idle":"2022-03-26T05:08:39.541334Z","shell.execute_reply.started":"2022-03-26T05:08:31.082664Z","shell.execute_reply":"2022-03-26T05:08:39.539978Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# NEW on TPU in TensorFlow 24: shorter cross-compatible TPU/GPU/multi-GPU/cluster-GPU detection code\ntpu = None\ntry: # detect TPUs\n    tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect() # TPU detection\n    strategy = tf.distribute.TPUStrategy(tpu)\nexcept ValueError: # detect GPUs\n    #strategy = tf.distribute.MirroredStrategy() # for GPU or multi-GPU machines\n    strategy = tf.distribute.get_strategy() # default strategy that works on CPU and single GPU\n    #strategy = tf.distribute.experimental.MultiWorkerMirroredStrategy() # for clusters of multi-GPU machines\n\n    \n#strategy,tpu = tf.distribute.MirroredStrategy(devices=[\"TPU:0\", \"TPU:1\",\"TPU:2\"]),True\n\nprint(\"Number of accelerators: \", strategy.num_replicas_in_sync)\n\n\nAUTO = tf.data.experimental.AUTOTUNE\nREPLICAS = strategy.num_replicas_in_sync\nprint(f'REPLICAS: {REPLICAS}')","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-03-26T05:08:39.542465Z","iopub.execute_input":"2022-03-26T05:08:39.542662Z","iopub.status.idle":"2022-03-26T05:08:39.559729Z","shell.execute_reply.started":"2022-03-26T05:08:39.542640Z","shell.execute_reply":"2022-03-26T05:08:39.558346Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# We prepared the dataset in the following notebooks:\n\nhttps://www.kaggle.com/tchaye59/images-to-jpeg-512x512\n\nhttps://www.kaggle.com/tchaye59/512x512-images-to-tfrecords","metadata":{}},{"cell_type":"code","source":"train_df = pd.read_csv(\"../input/sorghum-id-fgvc-9/train_cultivar_mapping.csv\")\ntest_df = pd.read_csv(\"../input/sorghum-id-fgvc-9/sample_submission.csv\")\nGCS_PATH = KaggleDatasets().get_gcs_path('sorghum100cultivarjpgtfrecords512x512')","metadata":{"execution":{"iopub.status.busy":"2022-03-26T05:08:39.562165Z","iopub.execute_input":"2022-03-26T05:08:39.562377Z","iopub.status.idle":"2022-03-26T05:08:40.104225Z","shell.execute_reply.started":"2022-03-26T05:08:39.562349Z","shell.execute_reply":"2022-03-26T05:08:40.103231Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"USE_SAVED_MODEL = False","metadata":{"execution":{"iopub.status.busy":"2022-03-26T05:08:40.106118Z","iopub.execute_input":"2022-03-26T05:08:40.106339Z","iopub.status.idle":"2022-03-26T05:08:40.110741Z","shell.execute_reply.started":"2022-03-26T05:08:40.106313Z","shell.execute_reply":"2022-03-26T05:08:40.109897Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Filter entries with no image associated","metadata":{}},{"cell_type":"code","source":"def image_exists(path):\n    return os.path.exists(path)\ntrain_df = train_df[[image_exists(f\"../input/sorghum-id-fgvc-9/train_images/{img}\") for img in train_df.image]]","metadata":{"execution":{"iopub.status.busy":"2022-03-26T05:08:40.111741Z","iopub.execute_input":"2022-03-26T05:08:40.111944Z","iopub.status.idle":"2022-03-26T05:09:09.003724Z","shell.execute_reply.started":"2022-03-26T05:08:40.111917Z","shell.execute_reply":"2022-03-26T05:09:09.002831Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Load dataset","metadata":{}},{"cell_type":"code","source":"%%time\ndata_dir= GCS_PATH+\"/fgvc_dataset\"\nbuilder = FGVCDataset(data_dir=data_dir)\nbuilder.download_and_prepare()\ntrain_ds = builder.as_dataset()['train']\ntest_ds = builder.as_dataset()['test']","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-03-26T05:09:09.004908Z","iopub.execute_input":"2022-03-26T05:09:09.005107Z","iopub.status.idle":"2022-03-26T05:09:10.555362Z","shell.execute_reply.started":"2022-03-26T05:09:09.005082Z","shell.execute_reply":"2022-03-26T05:09:10.554604Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def show_image_batch(images: list):\n    \"\"\"\n    Displays a batch of image present in images\n    \"\"\"\n    fig = plt.figure(figsize=(10,5))\n    for idx in range(6):\n        ax = plt.subplot(2, 3, idx+1)\n        plt.imshow(images[idx])\n        plt.axis(\"off\")\n\ndef show_dataset(dataset):\n    batch = next(iter(dataset))\n    images, labels = batch\n    \n    plt.figure(figsize=(10, 10))\n    for idx in range(9):\n        ax = plt.subplot(3, 3, idx + 1)\n        plt.imshow(images[idx].numpy().astype(\"uint8\"))\n        plt.title(\"Class: {}\".format(labels[idx].numpy().decode()))\n        plt.axis(\"off\")","metadata":{"_kg_hide-input":true,"jupyter":{"source_hidden":true},"execution":{"iopub.status.busy":"2022-03-26T05:09:10.556651Z","iopub.execute_input":"2022-03-26T05:09:10.556857Z","iopub.status.idle":"2022-03-26T05:09:10.566614Z","shell.execute_reply.started":"2022-03-26T05:09:10.556830Z","shell.execute_reply":"2022-03-26T05:09:10.565630Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"show_dataset(train_ds.map(lambda data:(data['img'],data['cultivar'])).batch(9))","metadata":{"execution":{"iopub.status.busy":"2022-03-26T05:09:10.567962Z","iopub.execute_input":"2022-03-26T05:09:10.568694Z","iopub.status.idle":"2022-03-26T05:09:15.422955Z","shell.execute_reply.started":"2022-03-26T05:09:10.568663Z","shell.execute_reply":"2022-03-26T05:09:15.422349Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"le = dill.load(open(\"../input/sorghum100cultivarjpgtfrecords512x512/le.dill\",\"rb\"))\ntrain_df[\"target\"] = le.transform(train_df.cultivar)","metadata":{"execution":{"iopub.status.busy":"2022-03-26T05:09:15.425182Z","iopub.execute_input":"2022-03-26T05:09:15.425494Z","iopub.status.idle":"2022-03-26T05:09:15.451501Z","shell.execute_reply.started":"2022-03-26T05:09:15.425465Z","shell.execute_reply":"2022-03-26T05:09:15.450183Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"SEED = 987456\nHEIGHT = 512\nWIDTH = 512\nN_CLASSES = len(train_df.cultivar.unique())\nBATCH_SIZE = 32 if tpu else 4\nIMG_DIR = \"../input/sorghum-id-fgvc-9\" if not tpu else GCS_PATH","metadata":{"execution":{"iopub.status.busy":"2022-03-26T05:09:15.452626Z","iopub.execute_input":"2022-03-26T05:09:15.453044Z","iopub.status.idle":"2022-03-26T05:09:15.462057Z","shell.execute_reply.started":"2022-03-26T05:09:15.452947Z","shell.execute_reply":"2022-03-26T05:09:15.460655Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# TF functions","metadata":{}},{"cell_type":"code","source":"def data_augmentation():\n    return keras.Sequential([\n        keras.layers.experimental.preprocessing.RandomZoom(0.2,seed=SEED),\n        #keras.layers.experimental.preprocessing.RandomCrop(HEIGHT//2, WIDTH//2,seed=SEED),\n        keras.layers.experimental.preprocessing.RandomContrast(0.2,seed=SEED),\n        keras.layers.experimental.preprocessing.RandomFlip(),\n        keras.layers.experimental.preprocessing.RandomRotation(0.4,seed=SEED),\n        tf.keras.layers.GaussianNoise(0.2),\n        #keras.layers.experimental.preprocessing.Resizing(HEIGHT, WIDTH),\n    ])\ndaug = data_augmentation()","metadata":{"execution":{"iopub.status.busy":"2022-03-26T05:09:15.463314Z","iopub.execute_input":"2022-03-26T05:09:15.464984Z","iopub.status.idle":"2022-03-26T05:09:15.522709Z","shell.execute_reply.started":"2022-03-26T05:09:15.464916Z","shell.execute_reply":"2022-03-26T05:09:15.521392Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_train_image(data):\n    img = data['img']\n    cultivar = data['cultivar']\n    name = data['name']\n    target = data['target']\n    # Resize image\n    img = tf.image.resize(img,(WIDTH, HEIGHT),)\n    return img,target\n\ndef load_test_image(data):\n    img = data['img']\n    name = data['name']\n    # Resize image\n    img = tf.image.resize(img,(WIDTH, HEIGHT),)\n    img = tf.keras.applications.efficientnet.preprocess_input(img)\n    return img,name\n\ndef prepare_train_dataset(train_ds):\n    steps = len(train_ds)//BATCH_SIZE\n    train_ds = train_ds.repeat().shuffle(5000).map(load_train_image,num_parallel_calls=AUTO)\n    train_ds = train_ds.batch(BATCH_SIZE).map(lambda x,y:(daug(x),y),num_parallel_calls=AUTO).prefetch(100)\n    return steps,train_ds\n\ndef prepare_submission_dataset(ds):\n    ds = ds.map(load_test_image,num_parallel_calls=AUTO)\n    ds = ds.batch(BATCH_SIZE*2).prefetch(100)\n    return ds","metadata":{"execution":{"iopub.status.busy":"2022-03-26T05:09:15.523915Z","iopub.execute_input":"2022-03-26T05:09:15.524136Z","iopub.status.idle":"2022-03-26T05:09:15.533040Z","shell.execute_reply.started":"2022-03-26T05:09:15.524109Z","shell.execute_reply":"2022-03-26T05:09:15.532003Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Show augmented images","metadata":{}},{"cell_type":"code","source":"show_dataset(train_ds.map(lambda data:(data['img'],data['cultivar'])).batch(9).map(lambda x,y:(daug(x),y)))","metadata":{"execution":{"iopub.status.busy":"2022-03-26T05:09:15.534195Z","iopub.execute_input":"2022-03-26T05:09:15.534526Z","iopub.status.idle":"2022-03-26T05:09:20.599382Z","shell.execute_reply.started":"2022-03-26T05:09:15.534492Z","shell.execute_reply":"2022-03-26T05:09:20.594955Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model ","metadata":{}},{"cell_type":"code","source":"with strategy.scope():\n    image_input = tf.keras.layers.Input(shape=(WIDTH,HEIGHT,3))\n    \n    backbone = tf.keras.applications.EfficientNetB4(include_top=False,weights=\"imagenet\",input_shape=(WIDTH,HEIGHT,3))\n    out = backbone(image_input)\n    out = tf.keras.layers.GlobalMaxPooling2D()(out)\n    out = tf.keras.layers.Dropout(0.2)(out)\n    out = tf.keras.layers.Dense(N_CLASSES,activation=\"softmax\")(out)\n    \n    model = tf.keras.Model(image_input,out)\n    model.compile()\n    model.summary()","metadata":{"execution":{"iopub.status.busy":"2022-03-26T05:09:20.600547Z","iopub.execute_input":"2022-03-26T05:09:20.601120Z","iopub.status.idle":"2022-03-26T05:09:26.210673Z","shell.execute_reply.started":"2022-03-26T05:09:20.601092Z","shell.execute_reply":"2022-03-26T05:09:26.209678Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train","metadata":{}},{"cell_type":"code","source":"with strategy.scope():\n    if not USE_SAVED_MODEL:\n        steps_per_epoch,ds =  prepare_train_dataset(train_ds)\n        callback = tf.keras.callbacks.EarlyStopping(monitor='acc',mode='max', patience=20)\n        ckp_callback = tf.keras.callbacks.ModelCheckpoint(\n                                                    filepath=f'model.h5',\n                                                    save_weights_only=True,\n                                                    monitor='acc',\n                                                    mode='max',\n                                                    options=tf.train.CheckpointOptions(experimental_io_device='/job:localhost'),\n                                                    save_best_only=True)\n        reduce_lr = tf.keras.callbacks.ReduceLROnPlateau(monitor='acc',mode='max',factor=0.2,patience=3, min_lr=1e-5)\n        callbacks=[callback,ckp_callback,reduce_lr]\n        # Compile the model\n        model.compile(optimizer=tf.keras.optimizers.Adam(1e-3),\n                      loss=tf.keras.losses.sparse_categorical_crossentropy,\n                      metrics=['acc',])\n\n        history = model.fit(ds,\n                            steps_per_epoch=steps_per_epoch,\n                            epochs=30,\n                            callbacks=callbacks)","metadata":{"execution":{"iopub.status.busy":"2022-03-26T05:09:26.211939Z","iopub.execute_input":"2022-03-26T05:09:26.212219Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Submit","metadata":{}},{"cell_type":"code","source":"if not USE_SAVED_MODEL:\n    model.load_weights('model.h5')\nelse:\n    model.load_weights('../input/sorghum100efficientnetbaselinemodel/model.h5')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def predict(x):\n    return model(x,training=False)\n@tf.function\ndef dist_predict(dist_inputs):\n    res = strategy.run(predict, args=(dist_inputs,))\n    return res","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\nwith strategy.scope():\n    ds = prepare_submission_dataset(test_ds)\n    dist_ds = strategy.experimental_distribute_dataset(ds)\n    \n    all_names = []\n    all_targets = []\n    for img,names in tqdm(dist_ds):\n        preds = dist_predict(img)\n        if tpu:\n            preds = tf.concat(preds.values,axis=0)\n            names = tf.concat(names.values,axis=0)\n        preds = preds.numpy()\n        names = names.numpy()\n        preds = np.argmax(preds,axis=-1)\n        all_targets.extend(list(preds))\n        all_names.extend([s.decode('ascii') for s in names])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub_df = pd.DataFrame({\n    \"filename\":all_names,\n    \"cultivar\":le.inverse_transform(all_targets)\n})\nsub_df.head(5)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub_df.to_csv(\"submission.csv\",index=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}