Эта записная книжка использует простую CNN с несколькими головками для задачи классификации нескольких классов в динамически создаваемом наборе данных. Модель построена с использованием функционального API Keras

Неисчерпывающий список преимуществ нейронных сетей с несколькими головками (или несколькими выходами):
— «НС может изучать скрытые представления, которые полезны для прогнозирования всех выходных данных сети. NN» https://goo.gl/xQQJ74
— Если выходные данные NN используют общие шаблоны для прогнозирования, общие представления — это способ снизить стоимость вычислений (полезно для ускорения времени вывода и прогнозирования в реальном времени). )
- …

Реализация ноутбука может быть не лучшим примером, чтобы подчеркнуть эти преимущества, поскольку он используется для определения цветов и форм. Эти две категории не имеют общих шаблонов, поэтому, возможно, стоит использовать меньшую и более оптимизированную сеть для каждой задачи. Тем не менее, это остался хороший пример для понимания концепции и того, как построить такую ​​модель.

Если вы хотите получить больше информации, я предлагаю вам прочитать этот пост

Набор данных

Для удобства искусственный набор данных создается путем рисования случайных форм и цветов с помощью OpenCV. Таким образом, мы можем расширить набор данных по мере необходимости. Как только модель будет обучена, мы также можем легко создавать новые образцы, чтобы увидеть, насколько хорошо наша сеть способна обобщать.

def random_shape(img, r_shapes,r_colors,colors, i):
    '''Draw a rectangle or a circle with random coordinates
    and a random color
    '''
    if(r_shapes[i] == 0):
        coord = np.random.randint(config.IMG_SIZE, size=(1, 2))
        size = np.random.randint(40, size=1)
        
        cv2.circle(img,(
            coord[0][0],coord[0][1]), 
                   size[0] +10, 
                   colors[r_colors[i]], -1)
        
    elif(r_shapes[i] == 1):
        center = np.random.randint(config.IMG_SIZE//2, size=2)+30
        coord = np.random.randint(config.IMG_SIZE//3, size=4)
        
        cv2.rectangle(img,
                      (center[0] - coord[0],center[1] - coord[1]),
                      (center[0] + coord[2],center[1] + coord[3]),
                      colors[r_colors[i]], 
                      thickness  = 3)
def create_data(nbr = 60):
    '''Build toy dataset
    '''
    r_shapes = np.random.randint(2, size=nbr) 
    r_colors = np.random.randint(3, size=nbr) 
    colors = [(255,0,0),(0,255,0),(0,0,255)]
    data = np.empty((0,config.IMG_SIZE,config.IMG_SIZE,3))
    
    for i in range(nbr):
        img = np.zeros((config.IMG_SIZE,config.IMG_SIZE,3), np.uint8)
        random_shape(img, r_shapes,r_colors, colors, i)
        img = np.expand_dims(img, 0)
        data = np.append(data, img, axis=0)
    
    return data, r_shapes, r_colors
data, r_shapes, r_colors =  create_data(2500)

Модель

def build_head(x, label_nbr, last_layer_name):
    '''Build the head for each output
    '''
    x = KL.Flatten()(x)
    x = KL.Dense(64, activation='relu')(x)
    x = KL.Dense(label_nbr)(x)
    x = KL.Activation('softmax', name=last_layer_name)(x)
    return x;
def build_model(num_shape, num_color):
    '''Build model
    '''
    inputs = KL.Input(shape=(config.IMG_SIZE, config.IMG_SIZE, 3))
    x = KL.ZeroPadding2D((3, 3))(inputs)
    x = KL.Conv2D(32, (3, 3), strides = (1, 1))(inputs)
    x = KL.BatchNormalization(axis = 3)(x)
    x = KL.Activation('relu')(x)
    x = KL.MaxPooling2D((2, 2))(x)
    x = KL.Dropout(0.25)(x)
shapeBranch = build_head(x, num_shape, 'shape')
    colorBranch = build_head(x, num_color, 'color')
return Model(
        inputs=inputs,
        outputs= [shapeBranch, colorBranch],
        name="shape_color_cls")
def prepare_model(model):
    '''Compile model
    '''
    losses = {
        "shape": "categorical_crossentropy",
        "color": "categorical_crossentropy",
        }
lossWeights = {"shape": 1.0, "color": 1.0}
model.compile(optimizer=Adam(lr=0.0001, decay=0.00001),
                      loss=losses,
                      loss_weights=lossWeights,
                      metrics=[metrics.categorical_accuracy])
def train_model(model, data, y_shape, y_color):
    '''
    Train model
    Compile the model
Return:
    H -- history of training
    '''
    H = model.fit(
        data,
        {"shape": y_shape, "color": y_color},
        epochs=config.EPOCHS,
        batch_size=16)
return H

Обобщение

Как было сказано ранее, искусственные наборы данных позволяют нам легко создавать новые данные. Затем мы можем использовать нашу сеть, чтобы делать прогнозы для этих новых выборок и смотреть, насколько хорошо она обобщается.

def display_random_data(model, data, rows):
    '''Predict samples from training data 
    to see if the network was able to classify them accurately
    '''
    idx = np.random.randint(data.shape[0], size=rows*4)
    fig, axarr = plt.subplots(2, rows, figsize=(rows*10, rows*4))
    
    for i in range(1,rows*2+1):
        img = data[idx[i]]
        to_pred = np.expand_dims(img, axis=0)
        pred = model.predict(to_pred, True)
        
        title = config.SHAPES[np.argmax(pred[0])] +' - '+ config.COLORS[np.argmax(pred[1])]
        
        img = data[idx[i]]/255
        axarr[i//(rows+1),i%rows].imshow(img)
        axarr[i//(rows+1),i%rows].set_title(title, fontsize=35)
        axarr[i//(rows+1),i%rows].axis('off')
        
new_data, _, _ =  create_data(60)
display_random_data(model,new_data, 5)

Примечание: этот материал в основном направлен на то, чтобы кристаллизовать мои знания. Мы с радостью примем любые предложения или исправления