text:
## Project: Building a Traffic Sign Recognition Classifier

In this project we make use of Convolutional Neural Network (CNN) to classify traffic signs. The CNN model was trained
and validated using the [German Traffic Sign dataset](http://benchmark.ini.rub.de/). The model was also tested on
images of German traffic signs downloaded from the Internet.

Following results were obtained with the trained CNN model.

  * Validation accuracy : 96.9%
  * Test accuracy : 94.8%

---
## Step 0: Load The Data

```python
# Load pickled data
import pickle
import numpy as np

# TODO: Fill this in based on where you saved the training and testing data
dataset_dir = './dataset'
sign_names_file = './signnames.csv'

training_file = dataset_dir + '/train.p'
validation_file = dataset_dir + '/valid.p'
testing_file = dataset_dir + '/test.p'

with open(training_file, mode='rb') as f:
    train = pickle.load(f)
with open(validation_file, mode='rb') as f:
    valid = pickle.load(f)
with open(testing_file, mode='rb') as f:
    test = pickle.load(f)

X_train, y_train = train['features'], train['labels']
X_valid, y_valid = valid['features'], valid['labels']
X_test, y_test = test['features'], test['labels']
sign_names = load_sign_names()

```

### Helper methods

```python
import matplotlib.pyplot as plt
import csv
import pandas as pd
import seaborn as sns
import numpy as np
import cv2
import pickle
from tqdm import tqdm
from time import sleep
import os
import glob

def load_sign_names(sign_names_file='./signnames.csv'):
    """
    Loads the CSV file containing traffic sign names.
    :param sign_names_file: Path to the sign-names CSV file.
    :return: A list containing sign-names, indexed by_set their label-class-number (known).
    """
    signs_list = []
    with open(sign_names_file, mode='r') as labels_file:
        reader = csv.reader(labels_file)
        next(reader, None)
        for sign in reader:
            signs_list.append(sign[1])
    return signs_list

def visualize_dataset(X, y, sign_names):
    """
    Displays 12 images randomly from the given dataset.
    """
    # Divide the display region by 4x3 cells for displaying 12 random images.
    rows = 4
    columns = 3
    fig = plt.figure(figsize=(20,15))
    fig.subplots_adjust(hspace = .75, wspace=.001)
    for i in range(1, rows * columns + 1):
        img_idx = np.random.randint(0, len(X))
        sign_image = X[img_idx]
        ax = fig.add_subplot(rows, columns, i)
        ax.title.set_text(sign_names[y[img_idx]])
        ax.title.set_fontsize(10)
        plt.axis('off')
        plt.imshow(sign_image)

def describe_labels(y, sign_names, count_plot_name=None):
    """
    Provides insight on the count of each sign-label in the labels-set.
    """
    sign_dict = dict(zip([idx for idx in range(len(sign_names))], sign_names))
    y_labels = list(map(lambda sign_num : sign_names[sign_num], y))
    y_df = pd.DataFrame(y_labels, dtype=str, columns=['sign_name'])
    cnt_plot = sns.factorplot(x=y, data=y_df, kind='count', size=8, aspect=1.2, color=".4")
    cnt_plot.set_xlabels('Traffic sign class')
    cnt_plot.fig.suptitle(count_plot_name, size=20)
    # print('### Label index (vs) Sign name map ###')
    # print(pd.DataFrame(list(sign_dict.values()), columns=['Sign Name']))
    # print('\n')
    print('### Sign counts ###')
    print(y_df['sign_name'].value_counts())

def convert_to_grayscale(X):
    """
    Converts an RGB image having 3 channels to grayscale.
    :param X: RGB image set, each image represented as an ndarray.
    :return: Grayscale images.
    """
    return np.sum(X / 3, axis=3, keepdims=True)

def min_max_scale_grayscale_images(X, scale_min=0.1, scale_max=0.9):
    """
    Applies min-max scaling to make the pixel values fall in the range [scale_min, scale_max]
    :param X: Set of images, type ndarray.
    :return: Min-max scaled images.
    """
    grayscale_min = 0
    grayscale_max = 255
    return scale_min + ((X - grayscale_min) / (grayscale_max - grayscale_min)) * (scale_max - scale_min)

def normalize_images(X):
    return (X - np.mean(X)) / np.std(X)

def quick_normalize_images(X):
    return (X - 128) / 128

def preprocess_images(X):
    """
    Applies preprocessing pipeline on the images.
    :param X: Input image dataset.
    :return: Preprocessed image dataset.
    """
    X_gray = convert_to_grayscale(X)
    return normalize_images(X_gray)

def random_translate(img, trans_range=3):
    """
    Translates the image in both x and y directions.
    Range for pixel-translation is set to -2 to 2.
    :param img: Input image.
    :param trans_range: Range, in pixels, to translate the image by.
    :return: Translated image.
    """
    height,width = img.shape[:2]
    dx = dy = np.random.uniform(trans_range) - trans_range / 2
    translation_mat = np.float32([[1,0,dx],[0,1,dy]])
    return cv2.warpAffine(img, translation_mat, (height,width))

def random_shear(img, shear_range=10):
    """
    Shears the image (stretch or shrink) by defining a pair of three points.
    :param img: Input image.
    :param shear_range: Amount of shearing, in pixels, to be applied on the image.
    :return: Sheared image.
    """
    height,width = img.shape[:2]
    # Defining shear limits with a pair of 3-points.
    px = 5 + shear_range * np.random.uniform() - shear_range / 2
    py = 20 + shear_range * np.random.uniform() - shear_range / 2
    shear_src = np.float32([[5,5],[20,5],[5,20]])
    shear_dst = np.float32([[px,5],[py,px],[5,py]])
    shear_mat = cv2.getAffineTransform(shear_src, shear_dst)
    return cv2.warpAffine(img, shear_mat, (height,width))

def random_rotate(img, angle_range=20):
    """
    Rotates the image by a certain angle.
    :param img: Input image.
    :param angle_range: Range of the angle of rotation, in pixels.
    :return: Rotated image.
    """
    height,width = img.shape[:2]
    rot_angle = np.random.uniform(angle_range) - angle_range / 2
    rot_mat = cv2.getRotationMatrix2D((height/2,width/2), rot_angle, 1)
    return cv2.warpAffine(img, rot_mat, (height,width))

def random_brightness(img):
    r_brightness = 0.3 + np.random.uniform()
    img_hsv = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)
    img_hsv[:,:,2] = r_brightness * img_hsv[:,:,2]
    return cv2.cvtColor(img_hsv, cv2.COLOR_HSV2RGB)

def augment_jitter_data(X, y, min_num_samples=750):
    num_classes = len(np.unique(y))
    print('Augmenting data for classes which have < {} samples ..'.format(min_num_samples))
    augmented_train_set = {}
    for sample_class in range(num_classes):
        sample_indices = np.where(sample_class == y)
        num_samples = len(sample_indices[0])
        if num_samples < min_num_samples:
            print('\nClass {}: {} samples, {} samples to augment'.format(sample_class, num_samples, min_num_samples-num_samples))
            sleep(0.1)
            # Augment samples for this class by applying geometric transformation on existing images
            # having the same class.
            for i in range(min_num_samples - num_samples):
                img = X[sample_indices[0][i % num_samples]]
                transformed_img = random_shear(random_translate(random_rotate(random_brightness(img))))
                X = np.concatenate((X, [transformed_img]), axis=0)
                y = np.concatenate((y, [sample_class]), axis=0)
            sleep(0.5)
    augmented_train_set['features'] = X
    augmented_train_set['labels'] = y
    pickle.dump(augmented_train_set, open('augmented_train.p', 'wb'))
    return X, y

```

---

## Step 1: Dataset Summary & Exploration

### Basic Summary of the Data Set

  * There are 34799, 4410 and 12630 samples in train, validation and test sets respectively.
  * Image dimension inside this dataset is 32x32x3.
  * Number of classes is 43.

```python
### Replace each question mark with the appropriate value.
### Use python, pandas or numpy methods rather than hard coding the results

# TODO: Number of training examples
n_train = X_train.shape[0]

# TODO: Number of validation examples
n_validation = X_valid.shape[0]

# TODO: Number of testing examples.
n_test = X_test.shape[0]

# TODO: What's the shape of an traffic sign image?
image_shape = X_train[0].shape

# TODO: How many unique classes/labels there are in the dataset.
n_classes = len(np.unique(y_train))

print("Image dimensions: {}".format(X_train[0].shape))
print("Training Set:   {} samples".format(len(X_train)))
print("Validation Set: {} samples".format(len(X_valid)))
print("Test Set:       {} samples".format(len(X_test)))

print("Number of training examples =", n_train)
print("Number of testing examples =", n_test)
print("Image data shape =", image_shape)
print("Number of classes =", n_classes)
```

    Image dimensions: (32, 32, 3)
    Training Set:   47780 samples
    Validation Set: 4410 samples
    Test Set:       12630 samples
    Number of training examples = 47780
    Number of testing examples = 12630
    Image data shape = (32, 32, 3)
    Number of classes = 43

### Exploratory visualization of the dataset

### Displaying random images from the dataset

Note: Few images' brightness tend to be poor which can be hard to distinguish to naked eyes.

```python
import matplotlib.pyplot as plt
%matplotlib inline
visualize_dataset(X_train, y_train, sign_names)

```

![png](output_10_0.png)

### Dataset description

Below provided is the histogram of sign counts, along with a table containing their actual values,
for each of train, validation and test sets.

#### Training set labels

```python
describe_labels(y_train, sign_names, 'Training set labels')
```

    ### Sign counts ###
    Speed limit (50km/h)                                  2010
    Speed limit (30km/h)                                  1980
    Yield                                                 1920
    Priority road                                         1890
    Keep right                                            1860
    No passing for vehicles over 3.5 metric tons          1800
    Speed limit (70km/h)                                  1770
    Speed limit (80km/h)                                  1650
    Road work                                             1350
    No passing                                            1320
    Speed limit (100km/h)                                 1290
    Speed limit (60km/h)                                  1260
    Speed limit (120km/h)                                 1260
    Right-of-way at the next intersection                 1170
    General caution                                       1080
    Ahead only                                            1080
    No entry                                               990
    Stop                                                   690
    Wild animals crossing                                  690
    Turn right ahead                                       599
    Traffic signals                                        540
    No vehicles                                            540
    Children crossing                                      480
    Slippery road                                          450
    Beware of ice/snow                                     390
    Vehicles over 3.5 metric tons prohibited               360
    Turn left ahead                                        360
    End of speed limit (80km/h)                            360
    Go straight or right                                   330
    Bumpy road                                             330
    Roundabout mandatory                                   300
    Dangerous curve to the right                           300
    Keep left                                              270
    Double curve                                           270
    Bicycles crossing                                      240
    Road narrows on the right                              240
    Pedestrians                                            210
    End of no passing                                      210
    End of no passing by vehicles over 3.5 metric tons     210
    End of all speed and passing limits                    210
    Go straight or left                                    180
    Dangerous curve to the left                            180
    Speed limit (20km/h)                                   180
    Name: sign_name, dtype: int64

![png](output_13_1.png)

#### Validation set labels

```python
describe_labels(y_valid, sign_names, 'Validation set labels')
```

    ### Sign counts ###
    Yield                                                 240
    Speed limit (30km/h)                                  240
    Speed limit (50km/h)                                  240
    No passing for vehicles over 3.5 metric tons          210
    Keep right                                            210
    Speed limit (70km/h)                                  210
    Speed limit (80km/h)                                  210
    Priority road                                         210
    Right-of-way at the next intersection                 150
    Speed limit (120km/h)                                 150
    No passing                                            150
    Road work                                             150
    Speed limit (100km/h)                                 150
    Speed limit (60km/h)                                  150
    General caution                                       120
    Ahead only                                            120
    No entry                                              120
    Wild animals crossing                                  90
    Stop                                                   90
    No vehicles                                            90
    Turn right ahead                                       90
    Traffic signals                                        60
    Vehicles over 3.5 metric tons prohibited               60
    Go straight or right                                   60
    Beware of ice/snow                                     60
    Roundabout mandatory                                   60
    Turn left ahead                                        60
    Children crossing                                      60
    Dangerous curve to the right                           60
    Double curve                                           60
    Slippery road                                          60
    Bumpy road                                             60
    End of speed limit (80km/h)                            60
    End of all speed and passing limits                    30
    Speed limit (20km/h)                                   30
    Dangerous curve to the left                            30
    Bicycles crossing                                      30
    Pedestrians                                            30
    Keep left                                              30
    End of no passing by vehicles over 3.5 metric tons     30
    Road narrows on the right                              30
    Go straight or left                                    30
    End of no passing                                      30
    Name: sign_name, dtype: int64

![png](output_15_1.png)

#### Test set labels

```python
describe_labels(y_test, sign_names, 'Test set labels')
```

    ### Sign counts ###
    Speed limit (50km/h)                                  750
    Yield                                                 720
    Speed limit (30km/h)                                  720
    Priority road                                         690
    Keep right                                            690
    No passing for vehicles over 3.5 metric tons          660
    Speed limit (70km/h)                                  660
    Speed limit (80km/h)                                  630
    Road work                                             480
    No passing                                            480
    Speed limit (120km/h)                                 450
    Speed limit (60km/h)                                  450
    Speed limit (100km/h)                                 450
    Right-of-way at the next intersection                 420
    General caution                                       390
    Ahead only                                            390
    No entry                                              360
    Wild animals crossing                                 270
    Stop                                                  270
    No vehicles                                           210
    Turn right ahead                                      210
    Traffic signals                                       180
    Beware of ice/snow                                    150
    Vehicles over 3.5 metric tons prohibited              150
    Children crossing                                     150
    Slippery road                                         150
    End of speed limit (80km/h)                           150
    Go straight or right                                  120
    Bumpy road                                            120
    Turn left ahead                                       120
    Roundabout mandatory                                   90
    End of no passing by vehicles over 3.5 metric tons     90
    Dangerous curve to the right                           90
    Double curve                                           90
    Bicycles crossing                                      90
    Road narrows on the right                              90
    Keep left                                              90
    End of no passing                                      60
    Pedestrians                                            60
    Dangerous curve to the left                            60
    End of all speed and passing limits                    60
    Speed limit (20km/h)                                   60
    Go straight or left                                    60
    Name: sign_name, dtype: int64

![png](output_17_1.png)

----

## Step 2: Designing and Testing a Model Architecture

### Pre-processing the Data Set

  * Above description of the distribution of labels show that not all classes have equal number of samples.
  This is a potential issue where the model could underfit on classes having high number of samples.

  * A *jitter-pipeline* is used to overcome this (to an extent) where each class is augmented with samples from its
  own class if it has less than a given number of samples (set to 850). This ensures that each class at least holds
  850 samples during the training stage.

  * Augmented data is picked from existing images (having the same label) and is obtained by
  performing geometric-transformations on those images, as CNNs are invariant to such transformations i.e. rotation,
  translation, shearing, etc.

Please note that this *augmented-train* set was pickled to be used for future usage. This part is commented
out below and took ~10 minutes to finish.

```python
# Augmenting jitter data to classes/labels which have less than 850 samples.
# X_train, y_train = augment_jitter_data(X_train, y_train, 850)
with open('augmented_train.p', mode='rb') as f:
    train = pickle.load(f)
X_train, y_train = train['features'], train['labels']
print(X_train.shape)
```

    (47780, 32, 32, 3)

#### Sample augmented images

Following is a set of images of **No vehicles** and **Beware of ice/snow** signs which were augmented to the
existing set of train samples to their respective class' samples.

```python
nvehicle_indices = np.where(15 == y_train)[0]  # Class label of No vehicles sign is 15.
icesnow_indices = np.where(30 == y_train)[0]  # Class label of Beware of ice/snow sign is 30.
# Fetching last 10 image index values.
nv_idx = nvehicle_indices[-10:]
isnow_idx = icesnow_indices[-10:]
fig,ax = plt.subplots(2, 10, figsize=(15,6))
fig.subplots_adjust(hspace=.0001, wspace=.1)
ax = ax.ravel()
for i in range(10):
    ax[i].axis('off')
    ax[i].imshow(cv2.cvtColor(X_train[nv_idx[i]], cv2.COLOR_BGR2RGB))
for i in range(10):
    ax[i+10].axis('off')
    ax[i+10].imshow(cv2.cvtColor(X_train[isnow_idx[i]], cv2.COLOR_BGR2RGB))
```

![png](output_22_0.png)

#### Pre-processing steps

Apart from data augmentation, following preprocessing steps were carried out on all of the images of the dataset
(train, validation and test sets).

  1. Conversion to grayscale : RGB images were converted to grayscale, utilizes less processing power with respect
    to the network parameters.
  2. Normalizing the images : Two variants of normalization were performed on each of the train, validation and test
    sets.
    * One which does (lazy/quick) normalization on the images which is (X-128) / 128.
    * The other which tries to center (globally) the mean of the image pixel values to 0, with uniform
    standard deviation of 1 : (X - mean(X)) / stddev(X).

Among the two normalization techniques, the latter one showed better performance on validation accuracies and
was chosen. It is noted that a better normalization could be the one where each image (locally) is centered at
0 mean with uniform standard-deviation but this would be quite an expensive process.

#### Images before pre-processing

```python
rimg_indices = np.where(25 == y_train)[0]  ## Picking class 25's indices for display.
rimg_idx = rimg_indices[-5:]
fig,ax = plt.subplots(1, 5, figsize=(15,6))
fig.subplots_adjust(hspace=.0001, wspace=.1)
ax = ax.ravel()
for i in range(5):
    ax[i].axis('off')
    ax[i].imshow(cv2.cvtColor(X_train[rimg_idx[i]], cv2.COLOR_BGR2RGB))

```

![png](output_25_0.png)

```python
X_train = preprocess_images(X_train)
X_valid = preprocess_images(X_valid)
X_test = preprocess_images(X_test)
```

#### Images after pre-processing

```python
fig,ax = plt.subplots(1, 5, figsize=(15,6))
fig.subplots_adjust(hspace=.0001, wspace=.1)
ax = ax.ravel()
for i in range(5):
    ax[i].axis('off')
    ax[i].imshow(X_train[rimg_idx[i]].squeeze(), cmap='gray')
```

![png](output_28_0.png)

#### Augmented training set labels' description

```python
describe_labels(y_train, sign_names, 'Augmented Training set labels')
```

    ### Sign counts ###
    Speed limit (50km/h)                                  2010
    Speed limit (30km/h)                                  1980
    Yield                                                 1920
    Priority road                                         1890
    Keep right                                            1860
    No passing for vehicles over 3.5 metric tons          1800
    Speed limit (70km/h)                                  1770
    Speed limit (80km/h)                                  1650
    Road work                                             1350
    No passing                                            1320
    Speed limit (100km/h)                                 1290
    Speed limit (120km/h)                                 1260
    Speed limit (60km/h)                                  1260
    Right-of-way at the next intersection                 1170
    Ahead only                                            1080
    General caution                                       1080
    No entry                                               990
    Turn left ahead                                        850
    Roundabout mandatory                                   850
    Beware of ice/snow                                     850
    End of no passing                                      850
    Double curve                                           850
    Dangerous curve to the left                            850
    Stop                                                   850
    Go straight or left                                    850
    End of all speed and passing limits                    850
    Dangerous curve to the right                           850
    End of no passing by vehicles over 3.5 metric tons     850
    Wild animals crossing                                  850
    End of speed limit (80km/h)                            850
    Traffic signals                                        850
    No vehicles                                            850
    Road narrows on the right                              850
    Speed limit (20km/h)                                   850
    Turn right ahead                                       850
    Pedestrians                                            850
    Bicycles crossing                                      850
    Vehicles over 3.5 metric tons prohibited               850
    Bumpy road                                             850
    Children crossing                                      850
    Keep left                                              850
    Go straight or right                                   850
    Slippery road                                          850
    Name: sign_name, dtype: int64

![png](output_30_1.png)

### Model Architecture

#### CNN architectures

Three variants of LeNet architecture were experimented with.

  1. One having dropout applied on the units of fully-connected layers (two in number).

  2. Variant of the architecture as described in Sermanet '11 paper on Traffic sign classification.
    In this version, activations from layer 2 (flattened) were passed to the classifier
    (a fully-connected layer) along with activations from layer 3 (convolved and flattened).
    According to the paper, doing so provides "different scales of receptive fields to the classifier"
    i.e. both global and invariant features from the penultimate layer (with respect to the fully-connected layer)
    as well as the local features from the layer before the penultimate one are extracted and hence passed
    to the classifier for better classification.

  3. Variant of LeNet with one additional fully-connected layer, making it a total of three fully-connected layers.

My final model architecture consisted of the following.

| Layer          | Description                                           |
|----------------|------------------------------------------------------:|
| Input          | 32x32x1 grayscale image                               |
| Convolutional (Layer 1)  | 1x1 stride, valid padding. Output = 28x28x6           |
| ReLu           |   |
| Max-pooling    | 2x2 stride, valid padding. Output = 14x14x6           |
| Convolutional (Layer 2)  | 1x1 stride, valid padding. Output = 10x10x16          |
| ReLu           |   |
| Max-pooling    | 2x2 stride, valid padding. Output = 5x5x16 |
| Fully connected 1 (Layer 3) | Input = 400. Output = 120
| ReLu           |   |
| Dropout        | Dropout on activations, with keep-probability of 0.5 |
| Fully connected 2 (Layer 4) | Input = 120. Output = 84 |
| ReLu           |   |
| Dropout        | Dropout on activations, with keep-probability of 0.5 |
| Classifer  (Layer 5) | Input = 84. Output = 43 |
| Softmax        |   |

```python
import tensorflow as tf
from tensorflow.contrib.layers import flatten

def conv2d(x, W, b, strides=1):
    x = tf.nn.conv2d(x, W, strides=[1, strides, strides, 1], padding='VALID')
    return tf.nn.bias_add(x, b)

def maxpool2d(x, k=2):
    return tf.nn.max_pool(x, ksize=[1, k, k, 1], strides=[1, k, k, 1], padding='VALID')

def build_lenet(x, keep_prob=0.5):
    '''
    LeNet architecture with dropout applied for the activations of fully-connected layers.
    '''
    mu = 0
    sigma = 0.1

    weights = {
        'fw1': tf.Variable(tf.truncated_normal(shape=(5, 5, 1, 6), mean=mu, stddev=sigma)),
        'fw2': tf.Variable(tf.truncated_normal(shape=(5, 5, 6, 16), mean=mu, stddev=sigma)),
        'fcw1': tf.Variable(tf.truncated_normal(shape=(400, 120), mean=mu, stddev=sigma)),
        'fcw2': tf.Variable(tf.truncated_normal(shape=(120, 84), mean=mu, stddev=sigma)),
        'fcw3': tf.Variable(tf.truncated_normal(shape=(84, 43), mean=mu, stddev=sigma))
    }

    biases = {
        'b1': tf.Variable(tf.zeros(6)),
        'b2': tf.Variable(tf.zeros(16)),
        'fcb1': tf.Variable(tf.zeros(120)),
        'fcb2': tf.Variable(tf.zeros(84)),
        'fcb3': tf.Variable(tf.zeros(43))
    }

    # Layer 1: Convolutional. Input = 32x32x1. Output = 28x28x6.
    conv1 = conv2d(x, weights['fw1'], biases['b1'])

    # Activation.
    conv1 = tf.nn.relu(conv1)

    # Pooling. Input = 28x28x6. Output = 14x14x6.
    conv1 = maxpool2d(conv1)

    # Layer 2: Convolutional. Output = 10x10x16.
    conv2 = conv2d(conv1, weights['fw2'], biases['b2'])

    # Activation.
    conv2 = tf.nn.relu(conv2)

    # Pooling. Input = 10x10x16. Output = 5x5x16.
    conv2 = maxpool2d(conv2)

    # Flatten. Input = 5x5x16. Output = 400.
    conv2 = flatten(conv2)

    # Layer 3: Fully Connected. Input = 400. Output = 120.
    conv3 = tf.add(tf.matmul(conv2, weights['fcw1']), biases['fcb1'])

    # Activation.
    conv3 = tf.nn.relu(conv3)

    # Dropout.
    conv3 = tf.nn.dropout(conv3, keep_prob)

    # Layer 4: Fully Connected. Input = 120. Output = 84.
    conv4 = tf.add(tf.matmul(conv3, weights['fcw2']), biases['fcb2'])

    # Activation.
    conv4 = tf.nn.relu(conv4)

    # Dropout.
    conv4 = tf.nn.dropout(conv4, keep_prob)

    # Layer 5: Fully Connected. Input = 84. Output = 43.
    logits = tf.add(tf.matmul(conv4, weights['fcw3']), biases['fcb3'])
    return logits

def build_lenet2(x, keep_prob=0.5):
    '''
    LeNet architecture with a trial on passing activations of a non-penultimate layer
    (with respect to classification-layer)to the classifier. Inspired by Sermanet '11 paper.
    '''
    mu = 0
    sigma = 0.1

    weights = {
        'fw1': tf.Variable(tf.truncated_normal(shape=(5, 5, 1, 6), mean=mu, stddev=sigma)),
        'fw2': tf.Variable(tf.truncated_normal(shape=(5, 5, 6, 16), mean=mu, stddev=sigma)),
        'fw3': tf.Variable(tf.truncated_normal(shape=(5, 5, 16, 400), mean=mu, stddev=sigma)),
        'fcw1': tf.Variable(tf.truncated_normal(shape=(800, 43), mean=mu, stddev=sigma))
    }

    biases = {
        'b1': tf.Variable(tf.zeros(6)),
        'b2': tf.Variable(tf.zeros(16)),
        'b3': tf.Variable(tf.zeros(400)),
        'fcb1': tf.Variable(tf.zeros(43))
    }

    ### Stage 0.
    # Layer 1: Convolutional. Input = 32x32x1. Output = 28x28x6.
    conv1 = conv2d(x, weights['fw1'], biases['b1'])

    # Activation.
    conv1 = tf.nn.relu(conv1)

    # Pooling. Input = 28x28x6. Output = 14x14x6.
    conv1 = maxpool2d(conv1)

    ### Stage 1. Outputs from this stage are also passed to the (first) fully-connected layer.
    # Layer 2: Convolutional. Output = 10x10x16.
    conv2 = conv2d(conv1, weights['fw2'], biases['b2'])

    # Activation.
    conv2 = tf.nn.relu(conv2)

    # Pooling. Input = 10x10x16. Output = 5x5x16.
    conv2 = maxpool2d(conv2)
    layer2 = conv2  # To be used in the classifier.

    # Layer 3: Convolutional. Input = 5x5x16. Output = 1x1x400
    conv3 = conv2d(conv2, weights['fw3'], biases['b3'])

    # Activation.
    conv3 = tf.nn.relu(conv3)

    # Flatten layer2 and output from layer 3 and concat them.
    layer2_flat = flatten(layer2)
    layer3_flat = flatten(conv3)
    conv3 = tf.concat_v2([layer2_flat, layer3_flat], 1)

    # Dropout.
    conv3 = tf.nn.dropout(conv3, keep_prob)

    # Layer 4: Fully Connected. Input = 800. Output = 43.
    logits = tf.add(tf.matmul(conv3, weights['fcw1']), biases['fcb1'])
    return logits

def build_lenet3(x, keep_prob=0.5):
    '''
    LeNet architecture with dropout applied for the activations of fully-connected layers.
    '''
    mu = 0
    sigma = 0.1

    weights = {
        'fw1': tf.Variable(tf.truncated_normal(shape=(5, 5, 1, 6), mean=mu, stddev=sigma)),
        'fw2': tf.Variable(tf.truncated_normal(shape=(5, 5, 6, 16), mean=mu, stddev=sigma)),
        'fcw1': tf.Variable(tf.truncated_normal(shape=(400, 120), mean=mu, stddev=sigma)),
        'fcw2': tf.Variable(tf.truncated_normal(shape=(120, 84), mean=mu, stddev=sigma)),
        'fcw3': tf.Variable(tf.truncated_normal(shape=(84, 60), mean=mu, stddev=sigma)),
        'fcw4': tf.Variable(tf.truncated_normal(shape=(60, 43), mean=mu, stddev=sigma))
    }

    biases = {
        'b1': tf.Variable(tf.zeros(6)),
        'b2': tf.Variable(tf.zeros(16)),
        'fcb1': tf.Variable(tf.zeros(120)),
        'fcb2': tf.Variable(tf.zeros(84)),
        'fcb3': tf.Variable(tf.zeros(60)),
        'fcb4': tf.Variable(tf.zeros(43))
    }

    # Layer 1: Convolutional. Input = 32x32x1. Output = 28x28x6.
    conv1 = conv2d(x, weights['fw1'], biases['b1'])

    # Activation.
    conv1 = tf.nn.relu(conv1)

    # Pooling. Input = 28x28x6. Output = 14x14x6.
    conv1 = maxpool2d(conv1)

    # Layer 2: Convolutional. Output = 10x10x16.
    conv2 = conv2d(conv1, weights['fw2'], biases['b2'])

    # Activation.
    conv2 = tf.nn.relu(conv2)

    # Pooling. Input = 10x10x16. Output = 5x5x16.
    conv2 = maxpool2d(conv2)

    # Flatten. Input = 5x5x16. Output = 400.
    conv2 = flatten(conv2)

    # Layer 3: Fully Connected. Input = 400. Output = 120.
    conv3 = tf.add(tf.matmul(conv2, weights['fcw1']), biases['fcb1'])

    # Activation.
    conv3 = tf.nn.relu(conv3)

    # Dropout.
    conv3 = tf.nn.dropout(conv3, keep_prob)

    # Layer 4: Fully Connected. Input = 120. Output = 84.
    conv4 = tf.add(tf.matmul(conv3, weights['fcw2']), biases['fcb2'])

    # Activation.
    conv4 = tf.nn.relu(conv4)

    # Dropout.
    conv4 = tf.nn.dropout(conv4, keep_prob)

    # Layer 5: Fully Connected. Input = 84. Output = 60.
    conv5 = tf.add(tf.matmul(conv4, weights['fcw3']), biases['fcb3'])

    # Activation.
    conv5 = tf.nn.relu(conv5)

    # Dropout.
    conv5 = tf.nn.dropout(conv5, keep_prob)

    # Layer 6: Fully Connected. Input = 60. Output = 43.
    logits = tf.add(tf.matmul(conv5, weights['fcw4']), biases['fcb4'])
    return logits
```

### Training operations

**Notes on training operations**

  * Cross entropy is used as the cost-function for the classifications made by the model.

  * Adam optimizer was used to optimize the cost-function. Details on why it is used instead of traditional
    Stochastic Gradient Descent is bit hazy, something to read-up in the next few days.

  * It took good amount of time to fine-tune the hyperparameters, not with respect to their range of values
    but with the amount of time it takes to tune them back and forth after observing the validation accuracies.
    With Adam optimizer, the range of values to be tuned tends to be minimal. Related comment on potential
    improvement is given in *Reflections* section below.

  * Traditional LeNet architecture with dropouts applied on fully-connected layers is used as the model.
    The other two variants didn't perform well compared to this model.

```python
import tensorflow as tf
from sklearn.utils import shuffle

# Hyper parameters.
learning_rate = 0.0009
EPOCHS = 75
BATCH_SIZE = 128

tf.reset_default_graph()

# Placeholders for input features and labels.
x = tf.placeholder(tf.float32, (None, image_shape[0], image_shape[1], 1))
y = tf.placeholder(tf.int32, (None))
keep_prob = tf.placeholder(tf.float32)  # Probability with which units' will be dropped out.
one_hot_y = tf.one_hot(y, n_classes)

logits = build_lenet(x, keep_prob)
cross_entropy = tf.nn.softmax_cross_entropy_with_logits(labels=one_hot_y, logits=logits)
loss_operation = tf.reduce_mean(cross_entropy)
optimizer = tf.train.AdamOptimizer(learning_rate = learning_rate)
training_operation = optimizer.minimize(loss_operation)
```

### Model evaluation

```python
correct_prediction = tf.equal(tf.argmax(logits, 1), tf.argmax(one_hot_y, 1))
accuracy_operation = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
saver = tf.train.Saver()

def evaluate(X_data, y_data):
    num_examples = len(X_data)
    total_accuracy = 0
    sess = tf.get_default_session()
    for offset in range(0, num_examples, BATCH_SIZE):
        batch_x, batch_y = X_data[offset:offset+BATCH_SIZE], y_data[offset:offset+BATCH_SIZE]
        accuracy = sess.run(accuracy_operation, feed_dict={x: batch_x, y: batch_y, keep_prob:1.0})
        total_accuracy += (accuracy * len(batch_x))
    return total_accuracy / num_examples
```

### Train, Validate and Test the Model

### Training routine.

```python
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    num_examples = len(X_train)
    epochs = []
    v_accuracy = []
    print("Training...")
    print()
    for i in range(EPOCHS):
        X_train, y_train = shuffle(X_train, y_train)
        for offset in range(0, num_examples, BATCH_SIZE):
            end = offset + BATCH_SIZE
            batch_x, batch_y = X_train[offset:end], y_train[offset:end]
            sess.run(training_operation, feed_dict={x: batch_x, y: batch_y, keep_prob:0.5})

        validation_accuracy = evaluate(X_valid, y_valid)
        epochs.append(i)
        v_accuracy.append(validation_accuracy)
        print("EPOCH {} ...".format(i + 1))
        print("Validation Accuracy = {:.3f}".format(validation_accuracy))
        print()

    plt.plot(epochs, v_accuracy)
    plt.show()
    saver.save(sess, './lenet')
    print("Model saved")
```

    Training...

    EPOCH 1 ...
    Validation Accuracy = 0.701

    EPOCH 2 ...
    Validation Accuracy = 0.820

    EPOCH 3 ...
    Validation Accuracy = 0.873

    EPOCH 4 ...
    Validation Accuracy = 0.899

    EPOCH 5 ...
    Validation Accuracy = 0.903

    EPOCH 6 ...
    Validation Accuracy = 0.907

    EPOCH 7 ...
    Validation Accuracy = 0.919

    EPOCH 8 ...
    Validation Accuracy = 0.921

    EPOCH 9 ...
    Validation Accuracy = 0.928

    EPOCH 10 ...
    Validation Accuracy = 0.922

    EPOCH 11 ...
    Validation Accuracy = 0.937

    EPOCH 12 ...
    Validation Accuracy = 0.938

    EPOCH 13 ...
    Validation Accuracy = 0.939

    EPOCH 14 ...
    Validation Accuracy = 0.943

    EPOCH 15 ...
    Validation Accuracy = 0.951

    EPOCH 16 ...
    Validation Accuracy = 0.949

    EPOCH 17 ...
    Validation Accuracy = 0.949

    EPOCH 18 ...
    Validation Accuracy = 0.944

    EPOCH 19 ...
    Validation Accuracy = 0.949

    EPOCH 20 ...
    Validation Accuracy = 0.952

    EPOCH 21 ...
    Validation Accuracy = 0.947

    EPOCH 22 ...
    Validation Accuracy = 0.954

    EPOCH 23 ...
    Validation Accuracy = 0.957

    EPOCH 24 ...
    Validation Accuracy = 0.956

    EPOCH 25 ...
    Validation Accuracy = 0.955

    EPOCH 26 ...
    Validation Accuracy = 0.960

    EPOCH 27 ...
    Validation Accuracy = 0.962

    EPOCH 28 ...
    Validation Accuracy = 0.956

    EPOCH 29 ...
    Validation Accuracy = 0.958

    EPOCH 30 ...
    Validation Accuracy = 0.961

    EPOCH 31 ...
    Validation Accuracy = 0.961

    EPOCH 32 ...
    Validation Accuracy = 0.960

    EPOCH 33 ...
    Validation Accuracy = 0.960

    EPOCH 34 ...
    Validation Accuracy = 0.959

    EPOCH 35 ...
    Validation Accuracy = 0.962

    EPOCH 36 ...
    Validation Accuracy = 0.962

    EPOCH 37 ...
    Validation Accuracy = 0.960

    EPOCH 38 ...
    Validation Accuracy = 0.958

    EPOCH 39 ...
    Validation Accuracy = 0.965

    EPOCH 40 ...
    Validation Accuracy = 0.960

    EPOCH 41 ...
    Validation Accuracy = 0.967

    EPOCH 42 ...
    Validation Accuracy = 0.964

    EPOCH 43 ...
    Validation Accuracy = 0.964

    EPOCH 44 ...
    Validation Accuracy = 0.963

    EPOCH 45 ...
    Validation Accuracy = 0.964

    EPOCH 46 ...
    Validation Accuracy = 0.967

    EPOCH 47 ...
    Validation Accuracy = 0.965

    EPOCH 48 ...
    Validation Accuracy = 0.961

    EPOCH 49 ...
    Validation Accuracy = 0.965

    EPOCH 50 ...
    Validation Accuracy = 0.963

    EPOCH 51 ...
    Validation Accuracy = 0.965

    EPOCH 52 ...
    Validation Accuracy = 0.966

    EPOCH 53 ...
    Validation Accuracy = 0.960

    EPOCH 54 ...
    Validation Accuracy = 0.965

    EPOCH 55 ...
    Validation Accuracy = 0.963

    EPOCH 56 ...
    Validation Accuracy = 0.962

    EPOCH 57 ...
    Validation Accuracy = 0.965

    EPOCH 58 ...
    Validation Accuracy = 0.969

    EPOCH 59 ...
    Validation Accuracy = 0.963

    EPOCH 60 ...
    Validation Accuracy = 0.969

    EPOCH 61 ...
    Validation Accuracy = 0.968

    EPOCH 62 ...
    Validation Accuracy = 0.970

    EPOCH 63 ...
    Validation Accuracy = 0.964

    EPOCH 64 ...
    Validation Accuracy = 0.960

    EPOCH 65 ...
    Validation Accuracy = 0.966

    EPOCH 66 ...
    Validation Accuracy = 0.967

    EPOCH 67 ...
    Validation Accuracy = 0.965

    EPOCH 68 ...
    Validation Accuracy = 0.966

    EPOCH 69 ...
    Validation Accuracy = 0.958

    EPOCH 70 ...
    Validation Accuracy = 0.966

    EPOCH 71 ...
    Validation Accuracy = 0.966

    EPOCH 72 ...
    Validation Accuracy = 0.970

    EPOCH 73 ...
    Validation Accuracy = 0.970

    EPOCH 74 ...
    Validation Accuracy = 0.962

    EPOCH 75 ...
    Validation Accuracy = 0.969

![png](output_41_1.png)

    Model saved

### Validation accuracy results

* **Validation accuracy achieved** : **0.969**
* **Best validation accuracy during training** : **0.97**

### Validation accuracy log

- Vanilla LeNet

|Batch Size|Epochs | Learning Rate | Preprocessing steps                  | Dropout present | Validation accuracy | Comments            |
|----------|:-----:|:-------------:|:------------------------------------:|:---------------:|:-------------------:|--------------------:|
|128       |30     | 0.001         | Grayscale, min-max scaling [0.1,0.9] | no              | ~ 0.91              |                     |
|128       |30     | 0.001         | Grayscale, quick normalization       | no              | ~ 0.92              |                     |
|128       |50     | 0.001         | Grayscale, quick normalization       | no              | ~ 0.92              |                     |
|128       |75     | 0.001         | Grayscale, standard normalization    | no              | > 0.93, < 0.95      | high accuracy jumps |
|128       |100    | 0.001         | Grayscale, standard normalization    | no              | > 0.93, < 0.95      | high accuracy jumps |
|128       |75     | 0.0009        | Grayscale, standard normalization    | no              | ~ 0.94              | low accuracy jumps  |
|128       |75     | 0.0009        | Grayscale, standard normalization    | 0.5             | <= 0.964            | regularization!     |
|128       |75     | 0.0009        | same as above + Augmented train (750)| 0.5             | ~ 0.964, 0.965      | Jitter pipeline!    |
|128       |75     | 0.0009        | same as above + Augmented train (750)| 0.25            | ~ 0.917             |Activations did not generalize well|
|256       |75     | 0.0009        | same as above + Augmented train (750)| 0.5             | ~ 0.962             |Higher batch size, no improvement|
|128       |75     | 0.0009        | same as above + Augmented train (850)| 0.5             | ~ 0.969, 0.97       |extra 100 samples augmented!|

- LeNet with few modifications inspired from Sermanet '11 paper on Traffic Sign classification.

|Batch Size|Epochs | Learning Rate | Preprocessing steps                  | Dropout present | Validation accuracy | Comments            |
|----------|:-----:|:-------------:|:------------------------------------:|:---------------:|:-------------------:|--------------------:|
|128       |75     | 0.0009        | graysclale,normalized,augmented (850)| 0.5             | ~ 0.957             |bit jumpy, no performance improvement with hacky implementation of Sermanet|

- LeNet with one additional fully-connected layer, making it a total of 3 fully-connected layers.

|Batch Size|Epochs | Learning Rate | Preprocessing steps                  | Dropout present | Validation accuracy | Comments            |
|----------|:-----:|:-------------:|:------------------------------------:|:---------------:|:-------------------:|--------------------:|
|128       |75     | 0.0009        | graysclale,normalized,augmented (850)| 0.5             | ~ 0.955             |bit jumpy near highs, no performance improvement|

#### Thoughts on CNN architectures

  1. To start out simple, classical LeNet was put into place with the following major components completely or
    partially missing.
    * **Dropout** : Helps a lot as a regularization technique to remove dependency of the overall network
    to a subset of neuron activations.
    * **Data augmentation** : Number of samples spread across the class-labels is disproportionate. We know that
    deep-neural-nets perform really well majorly because of their ability to identify patterns/features in the data.
    Having non-uniform number of samples distributed across the class-labels would definitely underfit or overfit
    the model. This became a **crucial pipeline** to apply to improve the model's performance. Also this pipeline
    took quite a while (~ 10 minutes) for maintaining a minimum of 850 samples per class-label. I believe
    the performance could definitely be increased by having at least 3000 samples per class-label.
    * **Normalization technique** : Min-max scaling was used and didn't seem to perform well. Coming to think of it, it
    applies a global-threshold-bound on the pixel values which is good for the training-routine to converge faster
    but doing so might cost on the *convolutional* model to miss out on certain features.

  2. Once a basic LeNet was found to be working well with regards to validation accuracy,
    architecture from Sermanet '11 paper on Traffic Sign Classification was tried. To compare the approaches, two major differences are seen :
      1. They had used images in YUV spectrum, whereas this model used grayscale.
      2. In their work, convolutions from 2nd stage/layer were being passed to the classifier as well as the
      flattened outputs from layer 1 and layer 2 were included. In my model, convolutions from 2nd layer, flattened,
      and outputs from 1st layer were together passed to the classifier.

    This architecture didn't perform better than the previous version though.

### Testing routine

```python
model_path = './lenet'
with tf.Session() as sess:
    saver = tf.train.import_meta_graph(model_path + '.meta')
    saver.restore(sess, model_path)
    test_accuracy = evaluate(X_test, y_test)
print('Test accuracy {:.3f}'.format(test_accuracy))
```

    Test accuracy 0.948

### Test accuracy result

**Accuracy achieved in the test-set** : **0.948**

---

## Step 3: Testing the Model on New Images

### Load and Output the Images

Eight images on German traffic signs were downloaded from the Internet and
the model from above was run on classifying these images. Below given are the results of this classification.

```python
### Load the images and plot them here.
def load_test_images(path='dataset/test_images/*.jpg'):
    test_images = []
    test_images_scaled = []
    fig, ax = plt.subplots(2, 4, figsize=(12,5))
    ax = ax.ravel()
    for i, img in enumerate(glob.glob(os.getcwd()+'/'+path)):
        image = cv2.imread(img)
        ax[i].axis('off')
        ax[i].imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
        test_images.append(image)
        test_images_scaled.append(cv2.resize(image, (32,32)))
    return np.asarray(test_images), np.asarray(test_images_scaled)

test_images, test_images_scaled = load_test_images()
test_labels = [25, 17, 13, 33, 28, 27, 23, 12]
```

![png](output_51_0.png)

```python
# Display test images with their label names.
fig, ax = plt.subplots(2, 4, figsize=(12,5))
fig.subplots_adjust(hspace=.75, wspace=.5)
ax = ax.ravel()
for i in range(len(test_images)):
    ax[i].axis('off')
    ax[i].set_title(sign_names[test_labels[i]])
    ax[i].imshow(cv2.cvtColor(test_images[i], cv2.COLOR_BGR2RGB))
```

![png](output_52_0.png)

### Predicting the Sign Type for Each Image

```python
def predict(image, model):
    with tf.Session() as sess:
        saver = tf.train.import_meta_graph(model + '.meta')
        saver.restore(sess, model)
        prediction = tf.argmax(logits, 1)
        return prediction.eval(feed_dict={x: image[np.newaxis,:,:,:], keep_prob: 1.0})

test_images_normalized = preprocess_images(test_images_scaled)

# Display predictions.
fig, ax = plt.subplots(2, 4, figsize=(12,5))
fig.subplots_adjust(hspace=.75, wspace=.5)
ax = ax.ravel()
for i in range(len(test_images)):
    prediction = predict(test_images_normalized[i], model_path)
    prediction = np.asscalar(prediction)
    ax[i].axis('off')
    ax[i].set_title("Prediction: " + sign_names[prediction])
    ax[i].imshow(cv2.cvtColor(test_images[i], cv2.COLOR_BGR2RGB))
```

![png](output_54_0.png)

### Analyzing Performance of Prediction

Above prediction on eight road signs show the following:

  * There is an accuracy of 0.875 i.e. 87.5%, for a (fairly) random set of eight images. This is far lower
  than the accuracies achieved on test and validation sets. Further probing on the types of (top-k) class-labels
  returned by the classifier is covered in the next section.

  * **Road work** sign (class number 25) is misclassified as **Double curve**.

  * **No entry** sign (class number 17) is misclassified as **Keep left**.

### Output Top 5 Softmax Probabilities For Each Image Found on the Web

```python
def print_top_k_softmax(test_image, model, k=5):
    '''
    Returns the top-k class-labels predicted on a test-image with a given model.
    '''
    with tf.Session() as sess:
        saver = tf.train.import_meta_graph(model + '.meta')
        saver.restore(sess, model)
        # Softmax predictions on this test-image.
        softmax = sess.run(tf.nn.softmax(logits), feed_dict={x: test_image[np.newaxis,:,:,:], keep_prob: 1.0})
        # Return top-k softmax probabilities predicted on this test-image.
        return sess.run(tf.nn.top_k(softmax, k))

def print_softmax_predictions(pred):
    '''
    Prints softmax-predictions in ascending order, with the class-label having the highest (softmax)
    probability on top.
    '''
    # Index 0 has tuple of probabilities.
    # Index 1 has tuple of class-label indices.
    for i in range(len(pred[0][0])):
        print('{} : {:.3f}%'.format(sign_names[pred[1][0][i]], pred[0][0][i] * 100))
```

### Softmax prediction on Road work sign

Below softmax probabilities have **Road work** sign on number 3 with 11.633% confidence of classifying it correctly.
The model believes it to be a **Double curve** sign with a higher probability, and hence the top one, with 70.8%
confidence.

Following shows a **Double curve** and **Dangerous curve to the left** signs which the classifier predicts
with greater confidence than its correct class **Road work**.

```python
dcurve_indices = np.where(21 == y_test)  # Class number of a Double curve road-sign is 21.
dcurve_idx = dcurve_indices[0][0]
dang_left_indices = np.where(19 == y_test)  # Class number of Dangerous curve to the left sign is 19.
dang_left_idx = dang_left_indices[0][0]
fig,ax = plt.subplots(1,2)
plt.subplots_adjust(hspace=0.25, wspace=0.75)
ax[0].axis('off')
ax[0].set_title('Double curve (processed)')
ax[0].imshow(X_test[dcurve_idx].squeeze(), cmap='gray')
ax[1].axis('off')
ax[1].set_title('Dangerous curve to the left (processed)')
ax[1].imshow(X_test[dang_left_idx].squeeze(), cmap='gray')
```

    <matplotlib.image.AxesImage at 0x7f9943f9f198>

![png](output_60_1.png)

```python
# Predictions for Road-work sign.
softmax_predictions = print_top_k_softmax(test_images_normalized[0], model_path)
print('Softmax predictions for Road Work sign..')
print_softmax_predictions(softmax_predictions)
```

    Softmax predictions for Road Work sign..
    Double curve : 70.843%
    Dangerous curve to the left : 12.046%
    Road work : 11.633%
    Wild animals crossing : 3.238%
    Slippery road : 1.756%

**Notes**: Above misclassified images look close to the **Road work** sign, something that the classifier could
become better at.

### Softmax prediction on No entry sign

Following softmax probabilities show no sign of classifying **No entry** sign correctly. Thoughts on this prediction
are as follows.

  * One intuitive case for this to happen is when the classifier didn't train well enough on **No entry** sign's features. The number of train-samples belonging to this class is 990, well below the maximum number of samples for any given class at around 2100. Adding the jitter-pipeline where images are augmented to the training set did improove the validation accuracy. For the classifier to predict well on classes of this type having less samples, augmenting more images (~4000 samples per class) could be a potential improvement.

  * The other top-4 classes predicted for this sign all share about equal softmax probabilities. Hence we can tell that the classifier is very poor in identifying images belonging to this class.

```python
# Predictions for No entry sign.
softmax_predictions = print_top_k_softmax(test_images_normalized[1], model_path)
print('Softmax predictions for Stop sign..')
print_softmax_predictions(softmax_predictions)
```

    Softmax predictions for Stop sign..
    Keep left : 20.843%
    Turn left ahead : 16.696%
    Roundabout mandatory : 16.644%
    Go straight or left : 11.567%
    Turn right ahead : 6.615%

### Softmax prediction on Yield sign

Below prediction shows that the classifier is very confident in identifying images of **Yield** traffic-sign.

```python
softmax_predictions = print_top_k_softmax(test_images_normalized[2], model_path)
print('Softmax predictions for Yield sign..')
print_softmax_predictions(softmax_predictions)
```

    Softmax predictions for Yield sign..
    Yield : 100.000%
    No vehicles : 0.000%
    Priority road : 0.000%
    Speed limit (60km/h) : 0.000%
    Speed limit (50km/h) : 0.000%

### Softmax predictions on rest of the images

From the predictions below, we see that the classifier performs well on classes of certain type (Children crossing,
Slippery road, Priority road) and just manages to predict correctly the other classes (Turn Right Ahead, Pedestrians).
This is good news since we have lots of room for improvement as addressed in the *Reflections* sections below.

```python
softmax_predictions = print_top_k_softmax(test_images_normalized[3], model_path)
print('Softmax predictions for Turn Right Ahead sign..')
print_softmax_predictions(softmax_predictions)
```

    Softmax predictions for Turn Right Ahead sign..
    Turn right ahead : 54.138%
    Turn left ahead : 13.802%
    Roundabout mandatory : 9.673%
    Stop : 5.354%
    Vehicles over 3.5 metric tons prohibited : 4.706%

```python
softmax_predictions = print_top_k_softmax(test_images_normalized[4], model_path)
print('Softmax predictions for Children Crossing sign..')
print_softmax_predictions(softmax_predictions)
```

    Softmax predictions for Children Crossing sign..
    Children crossing : 99.153%
    Traffic signals : 0.412%
    Pedestrians : 0.301%
    Bumpy road : 0.098%
    Dangerous curve to the right : 0.030%

```python
softmax_predictions = print_top_k_softmax(test_images_normalized[5], model_path)
print('Softmax predictions for Pedestrians sign..')
print_softmax_predictions(softmax_predictions)
```

    Softmax predictions for Pedestrians sign..
    Pedestrians : 51.652%
    Traffic signals : 25.533%
    Road narrows on the right : 20.355%
    General caution : 1.440%
    Double curve : 0.988%

```python
softmax_predictions = print_top_k_softmax(test_images_normalized[6],  model_path)
print('Softmax predictions for Slippery Road sign..')
print_softmax_predictions(softmax_predictions)
```

    Softmax predictions for Slippery Road sign..
    Slippery road : 99.971%
    Dangerous curve to the left : 0.029%
    Bumpy road : 0.000%
    Beware of ice/snow : 0.000%
    Double curve : 0.000%

```python
softmax_predictions = print_top_k_softmax(test_images_normalized[7], model_path)
print('Softmax predictions for Priority Road sign..')
print_softmax_predictions(softmax_predictions)
```

    Softmax predictions for Priority Road sign..
    Priority road : 100.000%
    Roundabout mandatory : 0.000%
    Speed limit (100km/h) : 0.000%
    No vehicles : 0.000%
    No passing : 0.000%

## Reflections

### Potential improvements

  1. **Data augmentation** : Adding more data for the training routine will definitely help improving the model.
    This routine could be handed down to existing frameworks like Keras which provides ImageDataGenerator. A good
    number for the minimum number of samples could be 4000, making it a total of 172000 training samples for all
    the classes combined, compared to existing number of ~ 47000.

  2. **Image pre-processing** : Current approach uses plain grayscale images and normalizes them.
    * Better approach would be to endure that images have zero-mean and uniform standard-deviation for the model
    to converge faster.
    * Also other pre-processing techniques like blurring the images could be helpful since that'd replicate
    real-world data taken from a camera mounted on a moving vehicle.
    * Using the images in a space other than grayscale e.g. YUV color-space could be a potential improvement.
    In this case the Y channel could be normalized as it holds the brightness-knob of the image, leaving the other
    two channels, U and V related to the color components, unchanged.
    * Increasing the contrast in the images could help the convolutions to pick up features which are significant.
    This could be done with [Adaptive Historgram Equalization](https://en.wikipedia.org/wiki/Adaptive_histogram_equalization).

  3. **Regularization** : Dropout is the only regularization mechanism currently being used. Adding L2 regularization
    would add penalties on the weights if they're grow too large, directly leading the model to keep their values
    bounded and hence avoiding overfitting as much as possible.

  4. **Hyperparameter tuning** : Instead of tuning hyperparameters by hand e.g. making the *learning-rate* go up or
  down, **grid-search** could be used where we the model would be automated to look for the best values falling in
  a given range.

repository: ashishraste/CarND-TrafficSignClassifier

repo_name: ashishraste/CarND-TrafficSignClassifier


text:
# ReThink Technical Challenge

Sarah Park

**Using an `express`/`sequelize` backend and a `react`/`redux` front end boilerplate**

**Problem 2: 60 minutes
You have over a million rows of data. You need to display this data on a web page along with a search field. Update search results with each character entered by the user. Make sure to call out any assumptions and / or limitations in your solution.**

Implementation

* `npm install`
* Create our postgres database (only need to do this once! it works for question 3 too)
```
export searchdata
createdb searchdata
```
* `npm run seed` to get our dummy data
* using node version 12.11.1
* `npm run start-dev`
**open localhost:8080/searchData**

Review

* Should cache results that have been searched before

Main Searching Algorithm:

* Upon page load, we get all the animals in the data base and sort them alphabetically once
* Then, every time the user enters the letter, we use a binary search to search the sorted names in logarithmic time

Limitations

* Small sample test size (1000) with dummy data
* Algorithm still requires the data to be sorted once
* Must call for all data every initial page load because we want to display all results to the user in the prompt

Assumptions

* All data is formatted the same way
* Data only includes first name

**Problem 3: 60 minutes
Given any URL, shorten it and return a globally unique URL back to the user. Make sure to call out any assumptions and / or limitations in your solution.**

Implementation

* `npm install`
* `npm run start-dev`
**open localhost:8080/shortenUrl**

Review

* valid url library checks if the entered url is safe
* prompts user to enter url if they leave the form empty
* returns unique shortened urls

Limitations

* have to use localhost to redirect at the moment

Thank you for your consideration :-)

license: MIT

repository: sarahyaepark/rethinkTechnical

branch_name: refs/heads/main

extension: md

gha_language: JavaScript

gha_license_id: MIT

license_type: permissive

repo_name: sarahyaepark/rethinkTechnical


text:
# Autossh

## Introduce
Encapsulation ssh tunnel with autologin, `public_key` and `google_authenticator` authentization are supported.

找不到支持用google验证码自动登录的版本，只好自己写了一个，将通过TOTP_SECRET_KEY环境变量将SECRET传进去，我会用python计算出当前的TOKEN，然后用expect自动输入，从而通过ssh验证。ssh tunnel是把瑞士军刀，必须要封装一下以便随时使用。

SSH port forwarding is a mechanism in SSH for tunneling application ports from the client machine to the server machine, or vice versa. It can be used for adding encryption to legacy applications, going through firewalls, and some system administrators and IT professionals use it for opening backdoors into the internal network from their home machines. It can also be abused by hackers and malware to open access from the Internet to the internal network.

## SSH Tunnel Mode
- L

    Local Forwarding

- R

    Remote Forwarding (Reverse Proxy)

## Quick Start
- Local Forwarding

    Local forwarding is used to forward a port from the client machine to the server machine. Basically, the SSH client listens for connections on a configured port, and when it receives a connection, it tunnels the connection to an SSH server. The server connects to a configurated destination port, possibly on a different machine than the SSH server.

     The connection will then be tunneled back to the client host, and the client then makes a TCP connection to port 80 on localhost. Any other host name or IP address could be used instead of localhost to specify the host to connect to.

repository: jamesqin-cn/autossh

branch_name: refs/heads/master

repo_name: jamesqin-cn/autossh


text:
If we are given two lines P and Q, meeting at A, and a fixed point X, we
may try to draw a line segment through X which joins P and Q and is as
short as possible. It is in fact not possible to solve this problem
using the rules of traditional geometry (it is equivalent to trying to
double the volume of a give cube).

But we can show that the solution has the following property:

Let the line segment, l, through X meet P and Q at points Y and Z. Draw
a line perpendicular to l, through A, meeting l at F. Then distance
FY=XZ.


text:
# Diagnostics

## About This Module

This notebook produces a modified version of the diagnostics visualisation on the MALLET website. A single model will be viewable as a web page called `index.html`. The notebook also produces a comparative visualisation file for multiple models called `comparison.html`. The main notebook for this module is `visualize_diagnostics.ipynb`.

## User Guide

This module assembles the MALLET diagnostics xml filse together with assets for a web-based visualization of the contents. Because it does not generate any information itself, it simply outputs a link to the visualization index file.

### Create Diagnostics Visualizations

This cell copies all of the diagnostics xml files from the diagnostics module directory and generates two web pages called `index.html` and `comparison.html`. Opening `index.html` on the public visualization port (a link is created by the notebook) launches the visualizations. Instructions for using the visualizations can be viewed by clicking "About This Tool" in the menu. The "Model Comparison Tool" menu item switches to the comparison view, from which the "Individual Model Tool" will take you back to the single-model visualization.

!!! important
    In the Model Comparison Tool, one or two scatterplots may sometimes fail to load due to other browser activity. Usually doing a hard refresh of the page will allow them to load.

### Zip Diagnostics

This optional cell The second cell optionally creates a zip archive of the visualization, which is suitable for export, in the module directory.

gha_language: Jupyter Notebook


text:
# Using the Dynatrace SDK to Connect Invocations

A typical use case for Lambda functions is to use them to create evented,
asynchronous applications.

This is a challenge for end-to-end-tracing as the tracing information often gets
lost when traversing components like queues.

In this lab we will deploy and application that uses SNS to queue a message and
which is then consumed and analyzed by another Lambda function.

![Lambda SNS Comprehend](/assets/lambda-sns-comprehend.png)

Additionally, we will use the [Dynatrace SDK](https://github.com/Dynatrace/OneAgent-SDK-for-NodeJs),
to connect the lambda functions as we would lose context when we go througfh SNS.

## Stype by step
1. In your terminal, change into `projects/message-filter`

2. Rename `env-sample.yml` to `env.yml` and copy the dynatrace crendentials from
   our previous example into the env.yml file.

3. We now have to change one configuration option to tell our agent where it
   will find the Dynatrace tag: `"dynatraceTagPropertyPath":"Records.0.Sns.MessageAttributes.x-dynatrace.Value"`
   > **Explanation:** In `queueNote`, we propagate the Dynatrace tag via SNS
   metadata. This metadata is then sent with the event received by the second Lambda
   function.

   ```js
    try {
      await tracer.start(() => {
        const dtTag = tracer.getDynatraceStringTag();
        const params = {
          Message: JSON.stringify({ payload: { note: data.note } }),
          MessageAttributes: {
            'x-dynatrace': {
              DataType: 'String',
              StringValue: dtTag,
            },
          },
          TopicArn: `arn:aws:sns:us-east-2:${event.requestContext.accountId}:analyzeNote`,
        };
        return sns.publish(params).promise();
    });
   ```

4. Use `npx serverless deploy` to deploy the app

5. In Postman, call the provided endpoint with a POST request:
   ```js
   {
     "note": "Today is a wonderful day!",
   }
   ```

7. Run `npx serverless logs -f queueNote -t` and hit the endpoint with different
   messages and see if it was positive enough

8. Review the results in Dynatrace
   ![SNS Stitched](/assets/sns-stitched.png)

:arrow_up: [Back to TOC](/README.md)


text:
# sheet-JSON

## Overview

This is a proof of concept that accepts a spreadsheet file
and converts it into readable JSON.

### Spreadsheet requirements
* File must have extension: `.ods | .xml | .xls | .xlsx`
* Choir name will be based off of the sheet name
* File name and sheet name should be the same
* Row 1 contains singer attribute labels
* Following rows contain singer specific attributes, correlating to row 1

### Running the app
1. Install [Node.js](https://nodejs.org/en/) \(or `sudo pip3 install node`\) latest version
2. Open sheet-JSON directory in bash
3. Run `node sheet-json.js`
4. Open browser [sheet-JSON](http://localhost:8675/)
5. Upload spreadsheet
  * Make sure spreadsheet has an accepted extension
  * Spreadsheet contents should be displayed in bash after upload

#### Notice
* Currently does not store values into db
* Currently does not handle errors elegantly

#### Planned changes
* Make downloadable default template
* Integrate with Choirmaster project
* Handle errors elegantly

repository: CovenantCollege/ChoirMasterServer

repo_name: CovenantCollege/ChoirMasterServer


text:
---
weight: 202
toc: true
title: Compatibility
menu:
    docs:
        parent: operator
lead: The Prometheus Operator supports a number of Kubernetes and Prometheus releases.
images: []
draft: false
description: The Prometheus Operator supports a number of Kubernetes and Prometheus releases.
---

It is recommended to use versions of the components identical or close to the versions used by the operator's end-to-end test suite (the specific version numbers are listed below).

## Kubernetes

Due to the use of apiextensions.k8s.io/v1 CustomResourceDefinitions, prometheus-operator requires Kubernetes >= v1.16.0.

The Prometheus Operator uses the official [Go client](https://github.com/kubernetes/client-go) for Kubernetes to communicate with the Kubernetes API. The compatibility matrix for client-go and Kubernetes clusters can be found [here](https://github.com/kubernetes/client-go#compatibility-matrix). All additional compatibility is only best effort, or happens to be still/already supported.

The current version of the Prometheus operator uses the following Go client version:

```$ mdox-exec="go list -m  -f '{{ .Version }}' k8s.io/client-go"
v0.28.0
```

## Prometheus

Prometheus Operator supports all Prometheus versions >= v2.0.0. The operator's end-to-end tests verify that the operator can deploy the following Prometheus versions:

```$ mdox-exec="go run ./cmd/po-docgen/. compatibility"
* v2.37.0
* v2.37.1
* v2.37.2
* v2.37.3
* v2.37.4
* v2.37.5
* v2.37.6
* v2.37.7
* v2.37.8
* v2.38.0
* v2.39.0
* v2.39.1
* v2.39.2
* v2.40.0
* v2.40.1
* v2.40.2
* v2.40.3
* v2.40.4
* v2.40.5
* v2.40.6
* v2.40.7
* v2.41.0
* v2.42.0
* v2.43.0
* v2.43.1
* v2.44.0
* v2.45.0
```

The end-to-end tests are mostly tested against

```$ mdox-exec="go run ./cmd/po-docgen/. compatibility defaultPrometheusVersion"
* v2.45.0
```

## Alertmanager

The Prometheus Operator is compatible with Alertmanager v0.15 and above.

The end-to-end tests are mostly tested against

```$ mdox-exec="go run ./cmd/po-docgen/. compatibility defaultAlertmanagerVersion"
* v0.26.0
```

## Thanos

The Prometheus Operator is compatible with Thanos v0.10 and above.

The end-to-end tests are mostly tested against

```$ mdox-exec="go run ./cmd/po-docgen/. compatibility defaultThanosVersion"
* v0.32.0
```

repository: prometheus-operator/prometheus-operator

gha_language: Go

repo_name: prometheus-operator/prometheus-operator


text:
---
title: PWA with Typescript
desc: (@quasar/app-webpack) How to use Typescript with Quasar PWA
---

In order to support PWA with Typescript, you will need to:

1. Make sure that your project is [configured with Typescript](/quasar-cli-webpack/supporting-ts).
1. Then rename the extension for your files in /src-pwa from `.js` to `.ts` and make the necessary TS code changes.

More info: [Supporting TS](/quasar-cli-webpack/supporting-ts)

repository: quasarframework/quasar

branch_name: refs/heads/dev

repo_name: quasarframework/quasar


text:
---
template: overrides/main.html
title: Insiders
---

# Insiders

Material for MkDocs follows the _sponsorware_ release strategy, which means
that _new features are first exclusively released to sponsors_ as part of
__Insiders__. Read on to learn [how sponsorship works][1], and how easy it is
to [get access to Insiders][2].

A demo is worth a thousand words — check it out at
[squidfunk.github.io/mkdocs-material-insiders][3]

  [1]: #how-sponsorship-works
  [2]: #how-to-become-a-sponsor
  [3]: https://squidfunk.github.io/mkdocs-material-insiders/

## How sponsorship works

New features first land in Insiders, which means that _sponsors will have access
immediately_. Every feature is tied to a funding goal in monthly subscriptions.
When a funding goal is hit, the features that are tied to it are merged back
into Material for MkDocs and released for general availability. Bugfixes are
always released simultaneously in both editions.[^1]

  [^1]:
    You may ask yourself why you should pay for something that is Open Source.
    Doesn't that contradict the ethos of Open Source software? Yes and no. Yes,
    some features are locked behind a monthly subscription, which means they are
    only accessible when paying a small amount of money. No, the features are
    only exclusive for a short time until specific funding goals are hit. Making
    an Open Source project sustainable is exceptionally hard: maintainers burn
    out, projects are abandoned. That's not great and very unpredictable. The
    sponsorware model ensures that if you decide to use Material for MkDocs,
    you can be sure that bugs are fixed quickly and new features are added
    regularly.

_Don't want to sponsor? No problem, Material for MkDocs already has tons of
features available, so chances are that most of your requirements are already
satisfied. See the [list of exclusive features][4] to learn which features are
currently only available to sponsors._

  [4]: #exclusive-features

## How to become a sponsor

You can become a sponsor using your individual or organization's GitHub account.
Just visit __[squidfunk's sponsor profile][5]__, pick any tier __from
$10/month__, and complete the checkout. Then, after a few hours, @squidfunk will
add you as a collaborator to the super-secret private GitHub repositority
containing the Insiders edition, which contains all [brand new and exclusive
features][4].

__Important__: If you're sponsoring @squidfunk through a GitHub organization,
please send a short email to<EMAIL_ADDRESS>with the name of your
organization and the account that should be added as a collaborator.[^2]

  [^2]:
    It's currently not possible to grant access to each member of an
    organization, as GitHub only allows for adding users. Thus, after
    sponsoring, please send an email to<EMAIL_ADDRESS>stating which
    account should become a collaborator of the Insiders repository. We're
    working on a solution which will make access to organizations much simpler.
    To ensure that access is not tied to a particular individual GitHub account,
    create a bot account (i.e. a GitHub account that is not tied to a specific
    individual), and use this account for the sponsoring. After being added to
    the list of collaborators, the bot account can create a private fork of the
    private Insiders GitHub repository, and grant access to all members of the
    organizations.

You can cancel your sponsorship anytime.[^3]

  [^3]:
    If you cancel your sponsorship, GitHub schedules a cancellation request
    which will become effective at the end of the billing cycle, which ends at
    the 22nd of a month for monthly sponsorships.  All charges are processed by GitHub
    through Stripe. As we don't receive any information regarding your payment,
    and GitHub doesn't offer refunds, sponsorships are non-refundable.

[:octicons-heart-fill-24:{ .mdx-heart }   Join our  awesome sponsors][5]{ .md-button .md-button--primary .mdx-sponsorship-button }

    If you sponsor publicly, you're automatically added here with a link to
    your profile and avatar to show your support for Material for MkDocs.
    Alternatively, if you wish to keep your sponsorship private, you'll be a
    silent +1. You can select visibility during checkout and change it
    afterwards.

  [5]: https://github.com/sponsors/squidfunk

## Exclusive features

The following features are currently exclusively available to sponsors:

- [x] [Boosting pages in search :material-new-box:][30]
- [x] [Tags (with search integration) :material-new-box:][29]
- [x] [Stay on page when switching versions][28]
- [x] [Version warning][26]
- [x] [Custom admonition icons][28]
- [x] [Code block annotations][25]
- [x] [Anchor tracking ][24]
- [x] [Section index pages][22]
- [x] [Sticky navigation tabs][21]
- [x] [Mermaid.js integration][27]
- [x] [Search suggestions][18]
- [x] [Search highlighting][19]
- [x] [Search sharing][20]
- [x] [Remove generator notice][23]

_New features are added to this list every few weeks, so be sure to come back
from time to time to learn about what's new, or follow [@squidfunk on
:fontawesome-brands-twitter:{ .twitter } Twitter][6] to stay updated._

  [6]: https://twitter.com/squidfunk

## Funding

### Goals

Following is a list of funding goals. When a funding goal is hit, the features
that are tied to it are merged back into Material for MkDocs and released to
the public for general availability.

#### $ 2,500 – Biquinho Vermelho

- [x] [Search suggestions][18]
- [x] [Search highlighting][19]
- [x] [Search sharing][20]

  [18]: ../setup/setting-up-site-search.md#search-suggestions
  [19]: ../setup/setting-up-site-search.md#search-highlighting
  [20]: ../setup/setting-up-site-search.md#search-sharing

#### $ 3,000 – Caribbean Red

- [x] [Sticky navigation tabs][21]
- [x] [Section index pages][22]
- [x] [Remove generator notice][23]

  [21]: ../setup/setting-up-navigation.md#sticky-navigation-tabs
  [22]: ../setup/setting-up-navigation.md#section-index-pages
  [23]: ../setup/setting-up-the-footer.md#remove-generator

#### $ 4,000 – Ghost Pepper

- [x] [Anchor tracking][24]
- [x] [Code block annotations][25]
- [x] [Version warning][26]

[24]: ../setup/setting-up-navigation.md#anchor-tracking
[25]: ../reference/code-blocks.md#adding-annotations
[26]: ../setup/setting-up-versioning.md#version-warning

#### $ 5,000 – Aji Panca

- [x] [Mermaid.js integration][27]
- [x] [Stay on page when switching versions][28]
- [x] [Tags (with search integration)][29]

  [27]: ../reference/diagrams.md
  [28]: ../setup/setting-up-versioning.md#stay-on-page
  [29]: ../setup/setting-up-tags.md

#### $ 6,000 – Trinidad Scorpion

- [x] [Boosting pages in search][30]
- [ ] Improved search result summaries
- [ ] Stay on page when switching languages

  [30]: ../setup/setting-up-site-search.md#boosting-a-page

#### $ 7,000 – Royal Gold

- [ ] Table of contents auto-collapse
- [ ] Table of contents follows active anchor
- [ ] Native lightbox integration

#### $ 8,000 – Scotch Bonnet

- [x] [Custom admonition icons][31]
- [ ] Table of contents shows which sections have search results
- [ ] List of last searches

  [31]: ../reference/admonitions.md#changing-the-icons

#### Future

- [ ] [Material for MkDocs Live Edit][32]
- [ ] New layouts and styles
- [ ] Code block palette toggle

  [32]: https://twitter.com/squidfunk/status/1338252230265360391

### Goals completed

#### $ 2,000 – Black Pearl

- [x] Latest release tag
- [x] [Color palette toggle][16]
- [x] [Back-to-top button][17]

  [16]: ../setup/changing-the-colors.md#color-palette-toggle
  [17]: ../setup/setting-up-navigation.md#back-to-top-button

#### $ 1,500 – Bhut Jolokia

- [x] [Admonition inline blocks][12]
- [x] [Site language selection][13]
- [x] [Versioning][14]

  [12]: ../reference/admonitions.md#inline-blocks
  [13]: ../setup/changing-the-language.md#site-language-selector
  [14]: ../setup/setting-up-versioning.md#versioning

#### $ 1,000 – Prairie Fire

- [x] [Navigation sections][7]
- [x] [Navigation expansion][8]
- [x] [Hiding the sidebars][9]
- [x] [Table of contents in navigation][10]
- [x] [Header hides on scroll][11]

  [7]: ../setup/setting-up-navigation.md#navigation-sections
  [8]: ../setup/setting-up-navigation.md#navigation-expansion
  [9]: ../setup/setting-up-navigation.md#hiding-the-sidebars
  [10]: ../setup/setting-up-navigation.md#navigation-integration
  [11]: ../setup/setting-up-the-header.md#automatic-hiding

#### $ 500 – Madame Jeanette

- [x] Improved search result grouping
- [x] Improved search result relevance and scoring
- [x] Missing query terms in search results

## Frequently asked questions

### Compatibility

_We're running an open source project and want to make sure that users can build
the documentation without having access to Insiders. Is this still possible?_

Yes. Insiders is compatible with Material for MkDocs. All new features are
implemented behind feature flags; all configuration changes are
backward-compatible. This means that your users will be able to build the
documentation locally with Material for MkDocs and when they push their changes,
it can be built with Insiders (e.g. as part of GitHub Actions). Thus, it's
recommended to [install Insiders][33] only in CI, as you don't want to expose
your `GH_TOKEN` to users.

  [33]: ../publishing-your-site.md#github-pages

### Terms

_We're using Material for MkDocs to build the developer documentation of a
commercial project. Can we use Insiders under the same terms and conditions?_

Yes. Whether you're an individual or a company, you may use _Material for MkDocs
Insiders_ precisely under the same terms as Material for MkDocs, which are given
by the [MIT license][34]. However, we kindly ask you to respect the following
guidelines:

- Please __don't distribute the source code__ of Insiders. You may freely use
  it for public, private or commercial projects, fork it, mirror it, do whatever
  you want with it, but please don't release the source code, as it would
  counteract the sponsorware strategy.

- If you cancel your subscription, you're removed as a collaborator and will
  miss out on future updates of Insiders. However, you may __use the latest
  version__ that's available to you __as long as you like__. Just remember that
  [GitHub deletes private forks][35].

  [34]: ../license.md
  [35]: https://docs.github.com/en/github/setting-up-and-managing-your-github-user-account/removing-a-collaborator-from-a-personal-repository


text:
## Outline for Sublime Text 3

### Overview

Inspired by [FileBrowser](https://github.com/aziz/SublimeFileBrowser), this package shows the outline of your file, class/function name list of your code, or table of content/toc of your markdown/LaTeX document in a sidebar-style tab.

![Screenshot](screenshot.png?raw=true "Screenshot")

### Installation

#### Install via Package Control

This package is available on [Package Control](https://packagecontrol.io/). Search for `Outline`.

#### Manual installation

1. Clone or download this repository to your hard drive using the green `Clone or download` button
2. Rename the cloned or extracted folder to `Outline`. Make sure `outline.py` is at the root of the `Outline` folder.
3. Move the `Outline` folder to your Sublime Text's `Packages` folder. To find the `Packages` folder, click menu `Preferences` > `Browse Packages`.
4. Restart Sublime Text, and press `Ctrl + Shift + P` to select your preferred layout (`Browse Mode`)

### Default layout

The outline tab can be set as a sidebar on the left or right. Press `Ctrl + Shift + P` and select either `Browse Mode: Outline (Left)` or `Browse Mode: Outline (Right)` to set your preferred layout.

If you also use [FileBrowser](https://github.com/aziz/SublimeFileBrowser), you can use both in three different layouts:

* `FileBrowser` left, `Outline` right
* `FileBrowser` top left, `Outline` bottom left
* `FileBrowser` top right, `Outline` bottom right

To use `FileBrowser` and `Outline` together, please close the `FileBrowser` sidebar first and then use the correponding `Browse Mode` command to set the layout, otherwise the `Outline` view may not work as intended.

### Color theme

`Outline` can be configured to use the current editor color scheme. To do so, change the setting below:

```json
"outline_inherit_color_scheme": true
```

`Outline` has two built-in color themes: Bright (default theme) and Dark. To switch to the Dark theme, add the following to your user settings file. Open the user settings file by "Preferences > Package Settings > Outline > Settings" (Sublime Text version 3124 or later), or "Settings - User":

```json
"outline_inherit_color_scheme": false
"color_scheme": "Packages/Outline/outline-Dark.hidden-tmTheme"
```

Remove `-Dark` or remove the entire line to return to the bright theme. To customize your own color theme, see [this issue](https://github.com/warmdev/SublimeOutline/issues/1).

### Outline content and indentation

Outline is updated when you save a file or switch between files.

Content and indentation in the `Outline` tab is controlled by the `Symbol List.tmPreferences` file (file name may differ) corresponding to the syntax of your file.

### Known issue

* This package may not work if you use a multi-column/row layout.

### License

This plugin is licensed under the MIT license.

repository: warmdev/SublimeOutline

gha_language: Python

repo_name: warmdev/SublimeOutline


text:
---
contentKey: blog
title: Trello, now 10, offers up an ambitious platform overhaul
date: 2021-03-19T10:21:06.550Z
---
<!--StartFragment-->

Productivity app Trello [announced a major redesign this week](https://blog.trello.com/a-whole-new-trello), adding features to help businesses better manage third-party integrations, new customizable cards and the ability to access workloads beyond the core whiteboard view.

The changes come after a year in which Trello said it saw a spike in users because of the rush to remote work caused by the COVID-19 pandemic; the company now boasts more than 50 million signups.

“During the pandemic, Trello became many people’s new offices in a remote-first world," Trello co-founder Michael Pryor wrote in a company blog post. Sign-ups rose 73% in March 2020, he said, compared to the same month a year earlier.

<!--EndFragment-->

repository: alami/gatsby-coffee-shop

repo_name: alami/gatsby-coffee-shop


text:
---
title: What Are Impredicative Types?
tags: haskell, types
---

So the results from Stephen's [poll][poll] are in! Surprisingly,
impredicative types topped out the list of type system extensions
people want to talk about so I figured I can get the ball rolling.

First things first, all the Haskell code will need the magical
incantation

``` haskell
    {-# LANGUAGE ImpredicativeTypes #-}
```

## What Is Impredicative Polymorphism

We have a lot of extensions that make polymorphism more flexible in
Haskell, `RankNTypes` and `Rank2Types` spring to mind. However, one
important feature lacking is "first class polymorphism".

With impredicative polymorphism `forall`'s become a normal type like
any other. We can embed them in structures, toss them into polymorphic
functions, and generally treat them like any other type.

Readers with a mathematical background will wonder why these are
called "impredicative" types then. The idea is that since we can have
polymorphic types embedded in other structures, we could have
something like

``` haskell
    type T = (Int, forall a. a -> Int)
```

That `a` could assume any time *including `T`*. So each type
definition can quantify over itself which nicely corresponds to the
mathematical notion of impredicativity.

One simple example where this might come up is when dealing with
lenses. Remember lenses have the type

``` haskell
    type Lens {- viciously -} s t a b = forall f. (a -> f b) -> s -> f t
```

If we were to embed lenses in let's say a tuple,

``` haskell
    type TLens a b = (Lens a a (a, b) (a, b), Lens b b (a, b) (a, b))

    foo :: TLens Int Bool
    foo = (_1, _2)
```

We'd need impredicative types because suddenly a polymorphic type has
appeared within a structure.

## Why No One Uses It

Now that we've seen how amazing impredicative polymorphism, let's talk
about how no one uses it. There are two main reasons

 1. GHC's support for impredicative types is fragile at best and
    broken at worst
 2. Avoiding the need for impredicative types is very straightforward

Reason 1 isn't exactly a secret. In fact, SPJ has stated a number of
times that he'd like to deprecate the extension since it's very hard
to maintain with everything else going on.

As it stands right now, our only choice is more or less to type check
a program and add type signatures when GHC decides to instantiate our
beautiful polymorphic type with fresh monomorphic type variables.

For this reason alone, impredicative types aren't really the most
useful thing. The final nail in the coffin is that we can easily make
things more reliable by using newtypes. In lens for example we avoid
impredicativity with

``` haskell
    newtype ScopedLens s t a b =
      ScopedLens {getScopedLens :: Lens s t a b}
```

This means that instead of impredicative types we just need rank N
types, which are much more polished.

## Wrap Up

Well, I'm sorry to be the bearer of bad news for those who filled out
`-XImpredicativeTypes` on the poll, but there you are.

To end on a positive note however, I do know of two example of where
impredicative types did save the day. I've used impredicative type
[exactly once][gist] to handle church lists properly. Lennart
Augustson's [Python DSL][dsl] makes heavy use of them to present a
unified face for variables.

[poll]: http://www.stephendiehl.com/posts/poll.html
[gist]: https://gist.github.com/jozefg/d790c0cd09714cc55a5c
[dsl]: http://augustss.blogspot.com/2011/07/impredicative-polymorphism-use-case-in.html

repository: jozefg/blog

repo_name: jozefg/blog


text:
---
layout: post
title: "Large-scale Simple Question Answering with Memory Networks"
date: 2015-06-05 21:48:39
categories: arXiv_CV
tags: arXiv_CV Transfer_Learning Memory_Networks
author: Antoine Bordes, Nicolas Usunier, Sumit Chopra, Jason Weston
mathjax: true
---

* content
{:toc}

##### Abstract
Training large-scale question answering systems is complicated because training sources usually cover a small portion of the range of possible questions. This paper studies the impact of multitask and transfer learning for simple question answering; a setting for which the reasoning required to answer is quite easy, as long as one can retrieve the correct evidence given a question, which can be difficult in large-scale conditions. To this end, we introduce a new dataset of 100k questions that we use in conjunction with existing benchmarks. We conduct our study within the framework of Memory Networks (Weston et al., 2015) because this perspective allows us to eventually scale up to more complex reasoning, and show that Memory Networks can be successfully trained to achieve excellent performance.

##### Abstract (translated by Google)

##### URL
[https://arxiv.org/abs/1506.02075](https://arxiv.org/abs/1506.02075)

##### PDF
[https://arxiv.org/pdf/1506.02075](https://arxiv.org/pdf/1506.02075)


text:
# How to Contribute to Pipetest

## Did you find a bug?

**Ensure the bug was not already reported** by searching on GitHub under
[Issues](https://github.com/javanile/pipetest/issues).

If you are unable to find an open issue addressing the problem please [open
a new one](https://github.com/javanile/pipetest/issues/new). Please be as specific
as possible when reporting the issue. Include the observed behavior as well as
what you thought should have happened. Please also provide environmental
details like Pipetest version, shell, OS, etc...

## Did you write a patch that fixes a bug?

Open a new GitHub pull request with the patch. Refer to the [Development
section of the README](https://github.com/javanile/pipetest#development) for the
details on how to run the unit tests. Please make sure that unit tests pass on
Travis CI.

Pull request must contain changes that add new features, fix bugs, or fix
incorrect documentation. Unsolicited pull requests that only contain formatting
changes like indentation, or line length, or letter case will be rejected.

## Do you want to contribute the Pipetest documentation?

Documentation can always be improved! Right now there is just the
[README](README.md) use as single point of documentation.

Thanks for contributing!

repository: javanile/pipetest

repo_name: javanile/pipetest


text:
When user call some Remote Procedure,
before perform operation we should:
- Balance load.
- Resolve repo location.
- Discover complementary nodes.

 Praefect cares about last lo steps.

 ### Praefect

 Praefect is a router and transaction manager for Gitaly, and a required component for running a Gitaly Cluster.

 > The high level design takes a reverse proxy approach to fanning out write requests to the appropriate nodes:
>
 ![praefect](https://user-content.gitlab-static.net/42d614c076d253d6497e96b4f5b5c51571f7d263/68747470733a2f2f646f63732e676f6f676c652e636f6d2f64726177696e67732f642f652f32504143582d3176526c3757532d3652424f5778794c5342624242416f56394d75706d5468357654714d4f775f41583961786c626f716b796254624671477145784c7979594f696c7145573753396575586442487a582f7075623f773d39363026683d373230)

 Datastore contains:
 - Primary location for a project.
 - Redundant locations for a project.
 - Available storage locations.

 Storage Coordinator serves for:
 - Resolving repo location to modify primary node.
 - Discovering complementary nodes to replicate.

 See entire workflow [here](https://gitlab.com/gitlab-org/gitaly/-/blob/master/doc/design_ha.md).

 ### Load Balancer

 ![load balancer](https://docs.gitlab.com/13.3/ee/administration/gitaly/img/praefect_architecture_v12_10.png)

 The minimum recommended configuration for a Gitaly Cluster requires:

- 1 load balancer
- 1 PostgreSQL server (PostgreSQL 11 or newer)
- 3 Praefect nodes
- 3 Gitaly nodes (1 primary, 2 secondary)

Gitaly Cluster docs is [here](https://docs.gitlab.com/13.3/ee/administration/gitaly/praefect.html).

**Load Balancers for RPC:**
- [grpclb](https://github.com/bsm/grpclb) - External Load Balancing Service solution for gRPC written in Go.
- [nRPC](https://github.com/nats-rpc/nrpc) - Load balancing without load balancers: Stateless microservices can be hosted redundantly and connected to the same NATS cluster. The incoming requests can then be random-routed among these using NATS queueing. There is no need to setup a (high availability) load balancer per microservice.

repository: valerybugakov/degitx

repo_name: valerybugakov/degitx


text:
# ImageCLEF 2015

Deployment of model to classify images from the ImageCLEF 2015 dataset

## Implementation

Install the Requirements:

```bash
 pip install -r requirements.txt
```

Start the streamlit server using:

```bash
 streamlit run main.py
```

## Built With

* [Streamlit](https://streamlit.io/) - The web framework
* [Tensorflow](https://www.tensorflow.org/) - end-to-end open source platform for machine learning

## Contributing

Please read [CONTRIBUTING.md](https://github.com/Atharva-Gundawar/ImageCLEF) for details on our code of conduct, and the process for submitting pull requests.

## Authors

* **Atharva Gundawar** - *Initial work* - [Github handle](https://github.com/Atharva-Gundawar)

See also the list of [contributors](https://github.com/Atharva-Gundawar/ImageCLEF/contributors) who participated in this project.

## License

This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details

repository: Atharva-Gundawar/ImageCLEF

repo_name: Atharva-Gundawar/ImageCLEF


text:
When proposing changes/additions to the Ruby style guide:

* Consider the best practices and rules recommended by the
  [Ruby Community Style Guide](https://github.com/bbatsov/ruby-style-guide).

* Style guide rules should always lead to better readability, consistency and
  code quality. Avoid enforcing personal preferences that don't contribute with
  any of these.

* If you have any questions or need feedback, feel free to hit up
  \#ruby-style-guide on Slack.

repository: Shopify/ruby-style-guide

gha_language: Ruby

repo_name: Shopify/ruby-style-guide


text:
# FRIENDS-Smart-List
SmartList Plug-In - Part of FRIENDS SmartConcepts
(c) 2011 Florian Eck, FRIENDS Financial Coaching

## About

This is my SmartList plugin, kinda raw, not yet test-covered or anything, but works good as hell.
Its kinda similar to acts_as_list, but it does the following things (better in my opinion, thats why i wrote it;-):

## Example:

    Class UserStuff < ActiveRecord::Base

      smart_list :group => :user_id, :base_class => 'UserStuff' # => shiity thing which needs to be fixed - always must pass the model name !
      # default value for ordering stuff is 'order_bit', could be anything else, like 'created_at' or what ever
      # u can ignore ':group' if u just want a whole table as one list

    end

You have the following data in your user stuff table:

      id
      user_id
      some_date
      order_bit

1	1	'bli'       	  100

2	2	'bla'       	  100

3	3	'blubb'     	  100

4	1	'blibla'    	  101

5	1	'blubbblubb'	  102

6	1	'abc'       	  103

7	2	'blubbbla'  	  101

8	3	'def'       	  101

Now u can do:

    stuff = UserStuff.find_by_user_id(1) # stuff is <UserStuff #1>

### Get all items in group
    stuff.group_list_items #=> returns [<UserStuff #1>, <UserStuff #4>, <UserStuff #5>, <UserStuff #6>]

### Or u do
    UserStuff.grouped_list(1) # Get all items with user_id 1

### if u have an item of a list, you can do:

    item.move_up!     # Move item up in oder position
    item.move_down!   # Move item down in oder position

    item.pre          # Get previous item in list, returns self when no other item is available
    item.post         # Get next item in list, returns self when no other item is available

    item.followers    # check which items are next in list
    item.group_list_items # show all items in group

### Includes Helpers, Partials and Controllers to do:

    <%= smart_list_links(item, options = {:uplink => {:text => "<", :class => nil}, :downlink => {:text => ">", :class => nil}}) %>

will render a button box for controlling the list items (movin up and down).
You can add custom text and/or css classes for up- and down-links (By default it displays ↑ and ↓)

## Notes
No test coverage yet, hope u like it anyway

## License

Copyright (c) 2013 Florian Eck

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.