{"cells":[{"metadata":{"_cell_guid":"187ee82d-6607-403e-a386-df8908af9345","_uuid":"f99f42879c4d807d0b2f03d619482e090acaeee0"},"cell_type":"markdown","source":"**Identifying Ships in Satellite Images**\n\nThe dataset consists of image chips extracted from Planet satellite imagery collected over the San Franciso Bay area. It includes 2800 80x80 RGB images labeled with either a \"ship\" or \"no-ship\" classification. Image chips were derived from PlanetScope full-frame visual scene products, which are orthorectified to a 3 meter pixel size.  The pixel value data for each 80x80 RGB image is stored as a list of 19200 integers within of the data list. The first 6400 entries contain the red channel values, the next 6400 the green, and the final 6400 the blue. The image is stored in row-major order, so that the first 80 entries of the array are the red channel values of the first row of the image.\n\nThe \"ship\" class includes 700 images. Images in this class are near-centered on the body of a single ship. Ships of different ship sizes, orientations, and atmospheric collection conditions are included.  The \"no-ship\" class includes 2100 images. A third of these are a random sampling of different landcover features - water, vegetion, bare earth, buildings, etc. - that do not include any portion of an ship. The next third are \"partial ships\" that contain only a portion of an ship, but not enough to meet the full definition of the \"ship\" class. The last third are images that have previously been mislabeled by machine learning models, typically caused by bright pixels or string linear features. Example images from this class are shown below."},{"metadata":{"_cell_guid":"d3b63159-2473-4352-82c7-e732a1f25505","_uuid":"8baf513c988724c25fac48ba0332809a4437fbfc"},"cell_type":"markdown","source":"*Step 1: Import Modules*"},{"metadata":{"_cell_guid":"93e6ec92-525b-4b3c-8c9e-6ea5d2cbd57e","_kg_hide-input":true,"_uuid":"f83e9373a00ef1109c299a8197067517f967da74","trusted":true,"collapsed":true},"cell_type":"code","source":"import random\nimport numpy as np \nimport pandas as pd \nimport matplotlib.pyplot as plt \nfrom PIL import Image \nimport json  \nfrom mpl_toolkits.basemap import Basemap\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport os\nimport itertools\nfrom PIL import Image\nimport sklearn as sklearn\nfrom sklearn.metrics import confusion_matrix\nfrom keras.callbacks import Callback, EarlyStopping, ReduceLROnPlateau, ModelCheckpoint\nfrom sklearn import model_selection\nfrom sklearn.model_selection import train_test_split, learning_curve\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.tree import DecisionTreeClassifier\nfrom sklearn.neighbors import KNeighborsClassifier\nfrom sklearn.naive_bayes import GaussianNB\nfrom sklearn.svm import SVC, LinearSVC\nfrom sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier\nfrom sklearn.neural_network import MLPClassifier as MLPC\nfrom sklearn.ensemble import GradientBoostingClassifier\nimport xgboost as xgb\nfrom xgboost import XGBClassifier\nfrom sklearn import model_selection\nimport tensorflow as tf\nimport keras\nfrom keras import backend as K\nfrom keras.models import Sequential\nfrom keras.layers import Dense, Dropout, Activation, Flatten, Conv2D, MaxPooling2D\nfrom keras import initializers, layers, models\nfrom keras.utils import to_categorical\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.callbacks import Callback, EarlyStopping, ReduceLROnPlateau, ModelCheckpoint\nfrom keras import callbacks\nfrom keras.utils.vis_utils import plot_model\n%matplotlib inline","execution_count":9,"outputs":[]},{"metadata":{"_cell_guid":"b6855a51-4de5-4d88-a7a5-58fa1265fb22","_uuid":"23bfad1a175b473f69ed4f1b2465fc35837aed86"},"cell_type":"markdown","source":"*Step 2: Load Data*"},{"metadata":{"_cell_guid":"f5770111-56d8-4c07-82bf-905f5d63dd8c","_uuid":"9238c73592789d4dce948cb38b66dd65bd7dcc87","trusted":true,"collapsed":true},"cell_type":"code","source":"with open('../input/shipsnet.json') as data_file:\n    dataset = json.load(data_file)\nShipsnet= pd.DataFrame(dataset)\nprint(Shipsnet.head())\nprint('')    \nx = np.array(dataset['data']).astype('uint8')\ny = np.array(dataset['labels']).astype('uint8')\ndef describeData(a,b):\n    print('Total number of images: {}'.format(len(a)))\n    print('Number of NoShip Images: {}'.format(np.sum(b==0)))\n    print('Number of Ship Images: {}'.format(np.sum(b==1)))\n    print('Percentage of positive images: {:.2f}%'.format(100*np.mean(b)))\n    print('Image shape (Width, Height, Channels): {}'.format(a[0].shape))\ndescribeData(x,y)","execution_count":10,"outputs":[]},{"metadata":{"_cell_guid":"91fc6de4-74a4-48e5-9166-b9e98cb6e6a8","_uuid":"d4a994086834722998c8df98d16ff08347827afa"},"cell_type":"markdown","source":"*Step 3: Reshape Data*"},{"metadata":{"_cell_guid":"bf6328d1-9aa4-4316-b873-b696db17edb3","_uuid":"8933c23fb51f799570f19af01f5f7d76f9a53976","trusted":true,"collapsed":true},"cell_type":"code","source":"xReshaped = x.reshape([-1, 3, 80, 80]).transpose([0,2,3,1])\nyReshaped = to_categorical(y, num_classes=2)\nprint(\"Data Shape\",x.shape)\nprint('Labels Shape',y.shape)\nprint('Reshaped Data Shape',xReshaped.shape)\nprint('Reshaped Labels Shape',yReshaped.shape)\ndef describeDataset(features,labels):\n    print(\"\\n'X' shape: %s.\"%(features.shape,))\n    print(\"\\n'y' shape: %s.\"%(labels.shape,))\n    print(\"\\nUnique elements in y: %s\"%(np.unique(y)))\ndescribeDataset(xReshaped,yReshaped)","execution_count":11,"outputs":[]},{"metadata":{"_cell_guid":"a22d4e17-b043-4476-95b7-8f2e2d2f1c5b","_uuid":"b8c930309b9501b3602db6d497baf60fbc8a9c2e"},"cell_type":"markdown","source":"*Step 4: Plot Data*"},{"metadata":{"_cell_guid":"305a183a-752f-4d46-9d2a-464d1563932a","_uuid":"1df7b4d5547bbb94ae96630aad50cab8a06682f5","trusted":true,"collapsed":true},"cell_type":"code","source":"imgs0 = xReshaped[y==0] \nimgs1 = xReshaped[y==1] \n\ndef plotOne(a,b):\n    \"\"\"\n    Plot one numpy array\n    \"\"\"\n    plt.subplot(1,2,1)\n    plt.title('Not A Ship')\n    plt.imshow(a[100])\n    plt.subplot(1,2,2)\n    plt.title('Ship')\n    plt.imshow(b[100])\nplotOne(imgs0, imgs1) ","execution_count":12,"outputs":[]},{"metadata":{"_cell_guid":"0504b4d1-aee6-4a8a-bba6-95cfb5ee6f95","_uuid":"6c0ebfc67868aa947d594d702250047173e9f02c","trusted":true,"collapsed":true},"cell_type":"code","source":"def plotTwo(a,b): \n    \"\"\"\n    Plot a bunch of numpy arrays sorted by label\n    \"\"\"\n    for row in range(3):\n        plt.figure(figsize=(20, 10))\n        for col in range(3):\n            plt.subplot(1,8,col+1)\n            plt.title('Not A Ship')\n            plt.imshow(a[row+col])\n            plt.axis('off')       \n            plt.subplot(1,8,col+4)\n            plt.title('Ship')\n            plt.imshow(b[row+col])\n            plt.axis('off')\nplotTwo(imgs0, imgs1) ","execution_count":13,"outputs":[]},{"metadata":{"_cell_guid":"67a66920-11e2-4db7-9c86-7db1659ffd06","_uuid":"748e473ed792b03484ec8e9c43b3aba310515a8a","trusted":true,"collapsed":true},"cell_type":"code","source":"def plotHistogram(a):\n    \"\"\"\n    Plot histogram of RGB Pixel Intensities\n    \"\"\"\n    plt.figure(figsize=(10,5))\n    plt.subplot(1,2,1)\n    plt.imshow(a)\n    plt.axis('off')\n    plt.title('Ship' if y[1] else 'Not A Ship')\n    histo = plt.subplot(1,2,2)\n    histo.set_ylabel('Count')\n    histo.set_xlabel('Pixel Intensity')\n    n_bins = 30\n    plt.hist(a[:,:,0].flatten(), bins= n_bins, lw = 0, color='r', alpha=0.5);\n    plt.hist(a[:,:,1].flatten(), bins= n_bins, lw = 0, color='g', alpha=0.5);\n    plt.hist(a[:,:,2].flatten(), bins= n_bins, lw = 0, color='b', alpha=0.5);\nplotHistogram(xReshaped[100])","execution_count":14,"outputs":[]},{"metadata":{"_cell_guid":"9bdd557f-29c2-4ee7-b117-cd90df79fad1","_uuid":"3418297dd2447869beeca0f42943ed7bf8037083"},"cell_type":"markdown","source":"*Step 5: Preprocess Data*"},{"metadata":{"_cell_guid":"d77b2790-7633-4ded-9973-899fd26bf125","_uuid":"9cc25e87465b008902cea1212fb3998dd6409787","trusted":true,"collapsed":true},"cell_type":"code","source":"xReshaped = xReshaped/255\nplotHistogram(xReshaped[100])\n\n#from sklearn.cross_validation import train_test_split\nx_train,x_test,y_train,y_test = train_test_split(x,y,test_size = 0.2 ,random_state = 123)\n# Reduce Sample Size for DeBugging\nx_train = x_train[0:300000] \ny_train = y_train[0:300000]\nx_test = x_test[0:300000] \ny_test = y_test[0:300000]\n\nx_trainReshaped,x_testReshaped,y_trainReshaped,y_testReshaped = train_test_split(xReshaped,yReshaped,test_size = 0.2 ,random_state = 123)\n# Reduce Sample Size for DeBugging\nx_trainReshaped = x_trainReshaped[0:300000] \ny_trainReshaped = y_trainReshaped[0:300000]\nx_testReshaped = x_testReshaped[0:300000] \ny_testReshaped = y_testReshaped[0:300000]","execution_count":15,"outputs":[]},{"metadata":{"_cell_guid":"e81f3321-69b7-4a7c-bead-e78ea34ba214","_uuid":"5a4316c351e884e869b4e0c277692091981afe1d"},"cell_type":"markdown","source":"*Step 6: Compare Standard Classifiers*"},{"metadata":{"_cell_guid":"7de98893-fabf-4b43-ad0b-dd24170a02fb","_uuid":"fb9b65c64392f025050be61e2fcffe6946b0d41b","trusted":true,"collapsed":true},"cell_type":"code","source":"def compareABunchOfDifferentModelsAccuracy(a,b,c,d):   \n    print('\\nCompare Multiple Classifiers:')\n    print('\\nK-Fold Cross-Validation Accuracy:\\n')\n    models = []\n    models.append(('LR', LogisticRegression()))\n    models.append(('RF', RandomForestClassifier()))\n    models.append(('KNN', KNeighborsClassifier()))\n    models.append(('SVM', SVC()))\n    models.append(('LSVM', LinearSVC()))\n    models.append(('GNB', GaussianNB()))\n    models.append(('DTC', DecisionTreeClassifier()))\n    models.append(('XGB', XGBClassifier()))\n#    models.append(('GBC', GradientBoostingClassifier()))\n#    models.append(('LDA', LinearDiscriminantAnalysis()))  \n    resultsAccuracy = []\n    names = []\n    for name, model in models:\n        model.fit(a,b)\n        kfold = model_selection.KFold(n_splits=10, random_state=7)\n        accuracy_results = model_selection.cross_val_score(model, a,b, cv=kfold, scoring='accuracy')\n        resultsAccuracy.append(accuracy_results)\n        names.append(name)\n        accuracyMessage = \"%s: %f (%f)\" % (name, accuracy_results.mean(), accuracy_results.std())\n        print(accuracyMessage)\n   \n    # boxplot algorithm comparison\n    fig = plt.figure()\n    fig.suptitle('Algorithm Comparison: Accuracy')\n    ax = fig.add_subplot(111)\n    plt.boxplot(resultsAccuracy)\n    ax.set_xticklabels(names)\n    ax.set_ylabel('Cross-Validation: Accuracy Score')\n    plt.show()\n    return\n\ncompareABunchOfDifferentModelsAccuracy(x_train,y_train,x_test,y_test)\n\ndef defineModels():\n    print('LR = LogisticRegression')\n    print('RF = RandomForestClassifier')\n    print('KNN = KNeighborsClassifier')\n    print('SVM = Support Vector Machine SVC')\n    print('LSVM = LinearSVC')\n    print('GNB = GaussianNB')\n    print('DTC = DecisionTreeClassifier')\n    print('XGB = XGBClassifier')\n#    print('GBC = GradientBoostingClassifier')\n#    print('LDA = LinearDiscriminantAnalysis')\n    return\ndefineModels()","execution_count":16,"outputs":[]},{"metadata":{"_cell_guid":"4b0cb271-71c9-4b32-9885-e5112bc98b2a","_kg_hide-input":true,"_uuid":"0c916a7d137dec155cce9ffba3d457c891bd26b3"},"cell_type":"markdown","source":"*Step 7: Define Helper Functions*"},{"metadata":{"_cell_guid":"27c5b337-04ef-48e8-ad88-9de49c23ec76","_uuid":"c4493e1e74871e4424116afdb5a56aa149186e68","collapsed":true,"trusted":true},"cell_type":"code","source":"# Plot confusion matrix\ndef plot_confusion_matrix(cm, classes,\n                          normalize=False,\n                          title='Confusion matrix',\n                          cmap=plt.cm.Blues):\n    \"\"\"\n    This function prints and plots the confusion matrix.\n    Normalization can be applied by setting `normalize=True`.\n    \"\"\"\n    plt.figure(figsize = (5,5))\n    plt.imshow(cm, interpolation='nearest', cmap=cmap)\n    plt.title(title)\n    plt.colorbar()\n    tick_marks = np.arange(len(classes))\n    plt.xticks(tick_marks, classes, rotation=90)\n    plt.yticks(tick_marks, classes)\n    if normalize:\n        cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]\n\n    thresh = cm.max() / 2.\n    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):\n        plt.text(j, i, cm[i, j],\n                 horizontalalignment=\"center\",\n                 color=\"white\" if cm[i, j] > thresh else \"black\")\n    plt.tight_layout()\n    plt.ylabel('True label')\n    plt.xlabel('Predicted label')\n\n# Special callback to see learning curves\nclass MetricsCheckpoint(Callback):\n    \"\"\"Callback that saves metrics after each epoch\"\"\"\n    def __init__(self, savepath):\n        super(MetricsCheckpoint, self).__init__()\n        self.savepath = savepath\n        self.history = {}\n    def on_epoch_end(self, epoch, logs=None):\n        for k, v in logs.items():\n            self.history.setdefault(k, []).append(v)\n        np.save(self.savepath, self.history)\n\ndef plotKerasLearningCurve():\n    plt.figure(figsize=(10,5))\n    metrics = np.load('logs.npy')[()]\n    filt = ['acc'] # try to add 'loss' to see the loss learning curve\n    for k in filter(lambda x : np.any([kk in x for kk in filt]), metrics.keys()):\n        l = np.array(metrics[k])\n        plt.plot(l, c= 'r' if 'val' not in k else 'b', label='val' if 'val' in k else 'train')\n        x = np.argmin(l) if 'loss' in k else np.argmax(l)\n        y = l[x]\n        plt.scatter(x,y, lw=0, alpha=0.25, s=100, c='r' if 'val' not in k else 'b')\n        plt.text(x, y, '{} = {:.4f}'.format(x,y), size='15', color= 'r' if 'val' not in k else 'b')   \n    plt.legend(loc=4)\n    plt.axis([0, None, None, None]);\n    plt.grid()\n    plt.xlabel('Number of epochs')\n\ndef plot_learning_curve(history):\n    plt.figure(figsize=(8,8))\n    plt.subplot(1,2,1)\n    plt.plot(history.history['acc'])\n    plt.plot(history.history['val_acc'])\n    plt.title('model accuracy')\n    plt.ylabel('accuracy')\n    plt.xlabel('epoch')\n    plt.legend(['train', 'test'], loc='upper left')\n    plt.savefig('./accuracy_curve.png')\n    #plt.clf()\n    # summarize history for loss\n    plt.subplot(1,2,2)\n    plt.plot(history.history['loss'])\n    plt.plot(history.history['val_loss'])\n    plt.title('model loss')\n    plt.ylabel('loss')\n    plt.xlabel('epoch')\n    plt.legend(['train', 'test'], loc='upper left')\n    plt.savefig('./loss_curve.png')\n    \ndict_characters = {0: 'No Ship', 1: 'Ship'}","execution_count":19,"outputs":[]},{"metadata":{"_cell_guid":"2d223b39-6dac-4a4a-88e4-9ed9f48c4e0d","_uuid":"800989af9852060e144994402ba29b062bbc60d4"},"cell_type":"markdown","source":"*Step 8: Evaluate Convolutional Network*"},{"metadata":{"_cell_guid":"58367c2d-36b0-4629-93c8-328ff305f5f8","_uuid":"5b6877cf49846a5f4a20c0c50cfc64dc27b0abc9","trusted":true,"collapsed":true},"cell_type":"code","source":"def runKerasCNNAugment(a,b,c,d):\n    batch_size = 128\n    num_classes = 2\n    epochs = 12\n    #img_rows, img_cols = X_train.shape[1],X_train.shape[2]\n    #input_shape = (img_rows, img_cols, 3)\n    input_shape = (80,80,3)\n    model = Sequential()\n    model.add(Conv2D(32, kernel_size=(3, 3),\n                     activation='relu',\n                     input_shape=input_shape))\n    model.add(Conv2D(64, (3, 3), activation='relu'))\n    model.add(MaxPooling2D(pool_size=(2, 2)))\n    model.add(Dropout(0.25))\n    model.add(Flatten())\n    model.add(Dense(128, activation='relu'))\n    model.add(Dropout(0.5))\n    model.add(Dense(num_classes, activation='softmax'))\n    model.compile(loss=keras.losses.categorical_crossentropy,\n                  optimizer=keras.optimizers.Adadelta(),\n                  metrics=['accuracy'])\n    datagen = ImageDataGenerator(\n        featurewise_center=False,  # set input mean to 0 over the dataset\n        samplewise_center=False,  # set each sample mean to 0\n        featurewise_std_normalization=False,  # divide inputs by std of the dataset\n        samplewise_std_normalization=False,  # divide each input by its std\n        zca_whitening=False,  # apply ZCA whitening\n        rotation_range=10,  # randomly rotate images in the range (degrees, 0 to 180)\n        width_shift_range=0.1,  # randomly shift images horizontally (fraction of total width)\n        height_shift_range=0.1,  # randomly shift images vertically (fraction of total height)\n        horizontal_flip=True,  # randomly flip images\n        vertical_flip=False)  # randomly flip images\n    history = model.fit_generator(datagen.flow(a,b, batch_size=32),\n                        steps_per_epoch=len(a) / 32, epochs=epochs, validation_data = [c, d],callbacks = [MetricsCheckpoint('logs')])\n    score = model.evaluate(c,d, verbose=0)\n    print('\\nKeras CNN #1C - accuracy:', score[1],'\\n')\n    y_pred = model.predict(c)\n    map_characters = {0: 'No Ship', 1: 'Ship'}\n    print('\\n', sklearn.metrics.classification_report(np.where(d > 0)[1], np.argmax(y_pred, axis=1), target_names=list(map_characters.values())), sep='')    \n    score = model.evaluate(c,d, verbose=0)\n    Y_pred_classes = np.argmax(y_pred,axis = 1) \n    Y_true = np.argmax(d,axis = 1) \n    plotKerasLearningCurve()\n    plt.show()  \n    plot_learning_curve(history)\n    plt.show()\n    confusion_mtx = confusion_matrix(Y_true, Y_pred_classes) \n    plot_confusion_matrix(confusion_mtx, classes = list(dict_characters.values())) \n    plt.show()    \nrunKerasCNNAugment(x_trainReshaped, y_trainReshaped,  x_testReshaped, y_testReshaped)","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"4672838d-fc36-4c0c-8739-75233945357f","_uuid":"d160aa30725f3bf6d3f5b5a9a500a6c75ad1d53d","collapsed":true},"cell_type":"markdown","source":"With this convolutional network we were able to predict with >90% accuracy whether or not a given \"image chip\" contained an image of a ship.  Interestingly, we had a similar results with both XGBoost and convolutional networks."}],"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}