{"cells":[{"metadata":{"trusted":false},"cell_type":"code","source":"from __future__ import division\nimport os\nimport sys\nimport pdb\nimport time\nimport h5py\n\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.autograd import Variable\nfrom torch.utils.data import Dataset\nfrom torchvision import transforms, utils\n\nimport cv2\nimport numpy as np\nimport pandas as pd\nfrom PIL import Image\nimport dask.dataframe as dd\nfrom sklearn import preprocessing\nfrom collections import OrderedDict\nfrom matplotlib import pyplot as plt","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Preprocessing"},{"metadata":{"trusted":false},"cell_type":"code","source":"df = dd.read_csv('/mnt/disks/open-images/metadata/bboxes/train-annotations-bbox.csv')\ndf.to_parquet('data/parquet', engine='fastparquet')","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"datasets = {}\ndatasets[\"training\"] = {\"path\":\"/mnt/disks/open-images/metadata/bboxes/train-annotations-bbox.csv\"}","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"# Check number of lines\ntrain_num_lines = !wc -l /mnt/disks/open-images/metadata/bboxes/train-annotations-bbox.csv | awk '{ print $1 }'\ntrain_num_lines = int(train_num_lines[0])\nprint(train_num_lines)","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"def write_output(output):\n    sys.stdout.write('\\r'+output)\n    sys.stdout.flush()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Groups work like dictionaries, and datasets work like NumPy arrays"},{"metadata":{"trusted":false},"cell_type":"code","source":"!ls data/parquet  ","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"df = dd.read_parquet('data/parquet', engine='fastparquet')","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"df.head(20)","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"counts = pd.DataFrame(df.groupby(df[\"ImageID\"]).size().compute())","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"counts.reset_index(level=0, inplace=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"counts.columns = [\"ImageID\", \"Count\"]","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"counts.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"counts.to_csv('data/index.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"# Check number of lines\nindex_num_lines = !wc -l data/index.csv | awk '{ print $1 }'\nindex_num_lines = int(index_num_lines[0])\nprint(index_num_lines)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### File conversion"},{"metadata":{"trusted":false},"cell_type":"code","source":"def create_hdf5(csv_path, chunksize, output, num_lines, num_features=4):\n\n    # this is your HDF5 database:\n    with h5py.File(output, 'w') as h5f:\n\n        string = h5py.special_dtype(vlen=str)\n        # use num_features-1 if the csv file has a column header\n        img_id_dataset = h5f.create_dataset('ids',\n                                   shape=(num_lines,),\n                                   compression=None,\n                                   dtype=string)\n        bbox_dataset = h5f.create_dataset('annotations',\n                                   shape=(num_lines, num_features),\n                                   compression=None,\n                                   dtype='float64')\n\n        # change range argument from 0 -> 1 if your csv file contains a column header\n        for i in range(1, num_lines, chunksize):  \n\n            df = pd.read_csv(csv_path,\n                         header=None,\n                         nrows=chunksize, # number of rows to read at each iteration\n                         skiprows=i)   # skip rows that were already read\n            \n            # use i-1 and i-1+10 if csv file has a column header\n            img_id_dataset[i:1+chunksize] = df.iloc[:, 0]\n            bbox_dataset[i:1+chunksize] = df.iloc[:, 4:8]\n            write_output(f\"Chunk: {i}/{num_lines}\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"def create_indexer_hdf5(csv_path, chunksize, output, num_lines, num_features=4):\n\n    # this is your HDF5 database:\n    with h5py.File(output, 'w') as h5f:\n\n        string = h5py.special_dtype(vlen=str)\n        # use num_features-1 if the csv file has a column header\n        img_id_dataset = h5f.create_dataset('ids',\n                                   shape=(num_lines,),\n                                   compression=None,\n                                   dtype=string)\n        counts_dataset = h5f.create_dataset('counts',\n                                   shape=(num_lines, num_features),\n                                   compression=None,\n                                   dtype=\"int32\")\n\n        # change range argument from 0 -> 1 if your csv file contains a column header\n        for i in range(1, num_lines, chunksize):  \n\n            df = pd.read_csv(csv_path,\n                         header=None,\n                         nrows=chunksize, # number of rows to read at each iteration\n                         skiprows=i)      # skip rows that were already read\n            # import pdb; pdb.set_trace()\n            # use i-1 and i-1+10 if csv file has a column header\n            img_id_dataset[i:1+chunksize] = df.iloc[:, 1]\n            counts_dataset[i:1+chunksize] = df.iloc[:, 2:3]\n            \n            write_output(f\"Chunk: {i}/{num_lines}\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"# Already run\n# create_hdf5(\"/mnt/disks/open-images/metadata/bboxes/train-annotations-bbox.csv\", 10**6, \"training.h5\", train_num_lines)","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"create_indexer_hdf5(\"data/index.csv\", 10**6, \"index.h5\", index_num_lines, num_features=2)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Initialize Dataset class"},{"metadata":{"trusted":false},"cell_type":"code","source":"class OpenImagesDataset(torch.utils.data.Dataset):\n    \n    def __init__(self, data_dir, data_path, index_path, transform=None):\n        \n        self.data_dir = data_dir\n        self.data = h5py.File(\"training.h5\", \"r\")\n        self.indexer = h5py.File(\"index.h5\", \"r\")\n        self.transform = transform\n        \n        self.current_index = 0\n        \n    def pad_to_square(self, img, pad_value=0):\n        x, y, _ = img.shape\n        dim_diff = np.abs(y - x)\n        # (upper / left) padding and (lower / right) padding\n        pad1, pad2 = dim_diff // 2, dim_diff - dim_diff // 2\n        # Determine padding\n        pad = (0, 0, pad1, pad2) if y <= x else (pad1, pad2, 0, 0)\n        # Add padding\n        img = F.pad(img, pad, \"constant\", value=pad_value)\n\n        return img, pad \n\n    def resize_and_pad(self, img):\n        # https://www.pyimagesearch.com/2018/11/12/yolo-object-detection-with-opencv/\n        desired_size = 416\n\n        old_size = img.shape[:2] # old_size is in (height, width) format\n\n        ratio = float(desired_size)/max(old_size)\n        new_size = tuple([int(x*ratio) for x in old_size])\n\n        # new_size should be in (width, height) format\n\n        img = cv2.resize(img, (new_size[1], new_size[0]))\n        before_padding = img.shape\n        delta_w = desired_size - new_size[1]\n        delta_h = desired_size - new_size[0]\n        top, bottom = delta_h//2, delta_h-(delta_h//2)\n        left, right = delta_w//2, delta_w-(delta_w//2)\n        color = [0, 0, 0]\n        new_img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT,\n            value=color)\n\n        return new_img, delta_w, delta_h, before_padding\n    \n    def convert_annotations(self, annotations):\n        x_min, x_max, y_min, y_max = annotations\n        width = x_max - x_min\n        height = y_max - y_min\n        x_center = (width / 2) + x_min\n        y_center = (height / 2) + y_min\n        return [width, height, x_center, y_center]       \n        \n    def preprocess(self, img, annotations, jitter=0):\n        \n         # Resize image and apply padding\n        img, padding_x, padding_y, without_padding = self.resize_and_pad(img)\n        unpad_h, unpad_w, _ = without_padding\n\n        # Convert annotations (bboxes)\n        mod_annotations = []\n        for a in annotations:\n            w, h, x_center, y_center = self.convert_annotations(a)\n            # Adjust x,y center for padding\n            x_center += (padding_x / 2) / unpad_w\n            y_center += (padding_y / 2) / unpad_h\n            mod_annotations.append([x_center, y_center, w, h])\n            \n        return img, mod_annotations\n    \n    def __getitem__(self, idx):\n        \n        idx += 1\n        \n        # Get image id and number of corresponding bboxes\n        bbox_count = self.indexer[\"counts\"][idx][0]\n        \n        \n        # Load image and bbox annotations\n        img_name = self.data[\"ids\"][idx] + \".jpg\"\n        \n        annotations = self.data[\"annotations\"][idx:idx + bbox_count]\n        \n        img_url = os.path.join(self.data_dir, \"images/train\", img_name)\n        img = cv2.imread(img_url)\n        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n        \n        # img = Image.open(img_url)\n        # img = Image.fromarray(np.uint8(img)).convert(\"RGB\")\n        # if img.getbands()[0] == 'L':\n        #     img = img.convert('RGB')\n        \n        # annotations_tensor = torch.from_numpy(annotations.reshape(-1, 4))\n        \n        assert img is not None\n                \n        img, targets = self.preprocess(img, annotations)\n        \n        if self.transform is not None:\n            img = self.transform(img)        \n    \n        return img, targets\n\n    def __len__(self):\n         return self.data[\"annotations\"].shape[0]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Training"},{"metadata":{"trusted":false},"cell_type":"code","source":"tfs = transforms.Compose([\n    # transforms.Resize((128, 128)),\n    transforms.ToTensor(),\n])\ntraining_data = OpenImagesDataset(\"/mnt/disks/open-images\", \"training.h5\", \"index.h5\", tfs)\ntraining_generator = torch.utils.data.DataLoader(\n    training_data,\n    batch_size=4,\n    shuffle=False,\n    num_workers=8\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"max_epochs = 1\nfor epoch in range(max_epochs):\n    # Training\n    for local_batch, local_labels in training_generator:\n        print(f\"\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Misc"},{"metadata":{"trusted":false},"cell_type":"code","source":"data_loader.dataset.image_data.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"img_path = cv2.imread(\"/mnt/disks/open-images/images/train/000002b66c9c498e.jpg\")\nimg = cv2.cvtColor(img_path, cv2.COLOR_BGR2RGB)\nplt.imshow(img)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.7.3"}},"nbformat":4,"nbformat_minor":1}