diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..56b52c1e8a076839cfd155613b04a95ffaa19541
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,49 @@
+# Compiled source #
+###################
+*.pyc
+*.com
+*.class
+*.dll
+*.exe
+*.o
+*.so
+
+# Packages #
+############
+# it's better to unpack these files and commit the raw source
+# git has its own built in compression methods
+*.7z
+*.dmg
+*.gz
+*.iso
+*.jar
+*.rar
+*.tar
+*.zip
+
+# Logs and databases #
+######################
+*.log
+*.sql
+*.sqlite
+*.sqlite3
+
+# OS generated files #
+######################
+.DS_Store
+.DS_Store?
+._*
+.Spotlight-V100
+.Trashes
+ehthumbs.db
+Thumbs.db
+.idea/
+/venv/
+
+# check plot folder #
+#####################
+/plots/
+
+# tmp folder #
+##############
+/tmp/
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..753c6e7f74687102959923303c80a8090bba8907
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,3 @@
+Keras==2.2.4
+numpy==1.15.4
+tensorflow==1.12.0
diff --git a/src/inception_model.py b/src/inception_model.py
new file mode 100644
index 0000000000000000000000000000000000000000..8ffbb3d5109bbc723804e42f6a34d0e222b3ceb4
--- /dev/null
+++ b/src/inception_model.py
@@ -0,0 +1,195 @@
+__author__ = 'Felix Kleinert, Lukas Leufen'
+
+import keras
+from keras.layers import Input, Dense, Conv2D, MaxPooling2D, AveragePooling2D, ZeroPadding2D, Dropout, Flatten, \
+    Concatenate, Reshape, Activation
+from keras.models import Model
+from keras.regularizers import l2
+from keras.optimizers import SGD
+
+
+class InceptionModelBase:
+    """
+    This class contains all necessary construction blocks
+    """
+
+    def __init__(self):
+        self.number_of_blocks = 0
+        self.part_of_block = 0
+        # conversion between chr and ord:
+        # >>> chr(97)
+        # 'a'
+        # >>> ord('a')
+        # 97
+        # set to 96 as always add +1 for new part of block
+        self.ord_base = 96
+
+    def block_part_name(self):
+        """
+        Use unicode due to some issues of keras with normal strings
+        :return:
+        """
+        return chr(self.ord_base + self.part_of_block)
+
+    def create_conv_tower(self,
+                          input_X,
+                          reduction_filter,
+                          tower_filter,
+                          tower_kernel,
+                          activation='relu',
+                          regularizer=l2(0.01)):
+        """
+        This function creates a "convolution tower block" containing a 1x1 convolution to reduce filter size followed by convolution
+        with given filter and kernel size
+        :param input_X: Input to network part
+        :param reduction_filter: Number of filters used in 1x1 convolution to reduce overall filter size before conv.
+        :param tower_filter: Number of filters for n x m convolution
+        :param tower_kernel: kernel size for convolution (n,m)
+        :param activation: activation function for convolution
+        :return:
+        """
+        self.part_of_block += 1
+
+        if tower_kernel == (1, 1):
+            tower = Conv2D(tower_filter,
+                           tower_kernel,
+                           activation=activation,
+                           padding='same',
+                           kernel_regularizer=regularizer,
+                           name='Block_{}{}_{}x{}'.format(self.number_of_blocks,
+                                                          self.block_part_name(),
+                                                          tower_kernel[0],
+                                                          tower_kernel[1]))(input_X)
+        else:
+            tower = Conv2D(reduction_filter,
+                           (1, 1),
+                           activation=activation,
+                           padding='same',
+                           kernel_regularizer=regularizer,
+                           name='Block_{}{}_1x1'.format(self.number_of_blocks, self.block_part_name()))(input_X)
+
+            tower = Conv2D(tower_filter,
+                           tower_kernel,
+                           activation=activation,
+                           padding='same',
+                           kernel_regularizer=regularizer,
+                           name='Block_{}{}_{}x{}'.format(self.number_of_blocks,
+                                                          self.block_part_name(),
+                                                          tower_kernel[0],
+                                                          tower_kernel[1]))(tower)
+        return tower
+
+    @staticmethod
+    def create_pool_tower(input_X, pool_kernel, tower_filter):
+        """
+        This function creates a "MaxPooling tower block"
+        :param input_X: Input to network part
+        :param pool_kernel: size of pooling kernel
+        :param tower_filter: Number of filters used in 1x1 convolution to reduce filter size
+        :return:
+        """
+        tower = MaxPooling2D(pool_kernel, strides=(1, 1), padding='same')(input_X)
+        tower = Conv2D(tower_filter, (1, 1), padding='same', activation='relu')(tower)
+        return tower
+
+    def inception_block(self, input_X, tower_conv_parts, tower_pool_parts):
+        """
+        Crate a inception block
+        :param input_X: Input to block
+        :param tower_conv_parts: dict containing settings for parts of inception block; Example:
+                                 tower_conv_parts = {'tower_1': {'reduction_filter': 32,
+                                                                 'tower_filter': 64,
+                                                                 'tower_kernel': (3, 1)},
+                                                     'tower_2': {'reduction_filter': 32,
+                                                                 'tower_filter': 64,
+                                                                 'tower_kernel': (5, 1)},
+                                                     'tower_3': {'reduction_filter': 32,
+                                                                 'tower_filter': 64,
+                                                                 'tower_kernel': (1, 1)},
+                                                    }
+        :param tower_pool_parts: dict containing settings for pool part of inception block; Example:
+                                 tower_pool_parts = {'pool_kernel': (3, 1), 'tower_filter': 64}
+        :return:
+        """
+        self.number_of_blocks += 1
+        self.part_of_block = 0
+        tower_build = {}
+        for part, part_settings in tower_conv_parts.items():
+            tower_build[part] = self.create_conv_tower(input_X,
+                                                       part_settings['reduction_filter'],
+                                                       part_settings['tower_filter'],
+                                                       part_settings['tower_kernel']
+                                                       )
+        tower_build['pool'] = self.create_pool_tower(input_X,
+                                                     tower_pool_parts['pool_kernel'],
+                                                     tower_pool_parts['tower_filter']
+                                                     )
+        block = keras.layers.concatenate(list(tower_build.values()), axis=3)
+        return block
+
+    @staticmethod
+    def flatten_tail(input_X, tail_block):
+        input_X = Flatten()(input_X)
+        tail = tail_block(input_X)
+        return tail
+
+
+if __name__ == '__main__':
+    print(__name__)
+    from keras.datasets import cifar10
+    from keras.utils import np_utils
+    from keras.layers import Input
+    conv_settings_dict = {'tower_1': {'reduction_filter': 64,
+                                      'tower_filter': 64,
+                                      'tower_kernel': (3, 3)},
+                          'tower_2': {'reduction_filter': 64,
+                                      'tower_filter': 64,
+                                      'tower_kernel': (5, 5)},
+                          }
+    pool_settings_dict = {'pool_kernel': (3, 3),
+                          'tower_filter': 64}
+    myclass = True
+
+    (X_train, y_train), (X_test, y_test) = cifar10.load_data()
+    X_train = X_train.astype('float32')
+    X_test = X_test.astype('float32')
+    X_train = X_train / 255.0
+    X_test = X_test / 255.0
+    y_train = np_utils.to_categorical(y_train)
+    y_test = np_utils.to_categorical(y_test)
+    input_img = Input(shape=(32, 32, 3))
+
+    if myclass:
+        googLeNet = InceptionModelBase()
+        output = googLeNet.inception_block(input_img, conv_settings_dict, pool_settings_dict)
+    else:
+        tower_1 = Conv2D(64, (1, 1), padding='same', activation='relu')(input_img)
+        tower_1 = Conv2D(64, (3, 3), padding='same', activation='relu')(tower_1)
+
+        tower_2 = Conv2D(64, (1, 1), padding='same', activation='relu')(input_img)
+        tower_2 = Conv2D(64, (5, 5), padding='same', activation='relu')(tower_2)
+
+        tower_3 = MaxPooling2D((3, 3), strides=(1, 1), padding='same')(input_img)
+        tower_3 = Conv2D(64, (1, 1), padding='same', activation='relu')(tower_3)
+
+        output = keras.layers.concatenate([tower_1, tower_2, tower_3], axis=3)
+
+    output = Flatten()(output)
+    out = Dense(10, activation='softmax')(output)
+    model = Model(inputs=input_img, outputs=out)
+    print(model.summary())
+
+    epochs = 10
+    lrate = 0.01
+    decay = lrate/epochs
+    sgd = SGD(lr=lrate, momentum=0.9, decay=decay, nesterov=False)
+
+    model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy'])
+
+    print(X_train.shape)
+    # model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=epochs, batch_size=32)
+    #
+    # scores = model.evaluate(X_test, y_test, verbose=0)
+    # print("Accuracy: %.2f%%" % (scores[1]*100))
+
+