Val_acc колеблется и не сходится при обучении с TPU по сравнению с GPU

Я реализовал архитектуру глубокого обучения MobileNets и обучил ее на Cifar-100. Для этого я использую Google Colab, и он правильно работал с их графическим процессором, хотя я не получил очень хорошей точности. Но когда я тренируюсь на их TPU, в течение первых 10 эпох точность проверки по существу остается на уровне 0, а затем, когда она повышается, она становится непоследовательной и не увеличивается постоянно, как в случае с графическим процессором.

Вы можете увидеть, что я имею в виду, на этих двух экранах: https://imgur.com/a/hmOFEcW

Я немного застрял, так как не совсем понимаю, как работает TPU, я знаю, что он должен разделить работу, но кроме этого ... Думаю, я мог бы попытаться изменить скорость обучения оптимизатора вручную? Чтобы его быстрее узнать. Но это не объясняет, почему точность падает в конце.

"""Cifar-100
"""

from google.colab import drive
drive.mount('/content/drive')

!pip install tensorflow==1.13.2

import os
os.listdir()
os.chdir("./drive/My Drive/Colab Notebooks/Cifar-100")

#IMPORTS FOR MODELS
from tensorflow.keras.layers import Input, Dense, DepthwiseConv2D, Flatten, Activation, Dropout, BatchNormalization, AveragePooling2D, Convolution2D
from tensorflow.keras import Model
import pdb

#DEFINITION OF MODELS

def depthwise_conv_1x1_conv(strides, n_filters, x):
    x = DepthwiseConv2D(kernel_size=3, strides=strides, padding='same')(x)
    x = BatchNormalization()(x)
    x = Activation(activation='relu')(x)
    x = Convolution2D(filters=n_filters, kernel_size=1, strides=1, padding='same')(x)
    x = BatchNormalization()(x)
    x = Activation(activation='relu')(x)
    return x

def make_mobile_net(args, input_shape, num_classes):
    inputs = Input(shape = input_shape, batch_size = args.batch_size)
    x = inputs
    x = Convolution2D(filters=32, kernel_size=3 , strides=1, padding='same')(x)
    x = BatchNormalization()(x)
    x = Activation(activation='relu')(x)

    for i in [(1, 64), (1, 128), (1, 128), (1, 256), (1, 256), (2, 512), (1, 512),(1, 512),(1, 512),(1, 512),(1, 512), (2, 1024), (1, 1024)] :
        x = depthwise_conv_1x1_conv(i[0], i[1], x)

    x = AveragePooling2D(pool_size=8, strides=1)(x)

    x = Flatten()(x)
    if args.add_dense :
        x = Dense(1000, activation='relu')(x)

    y = Dense(num_classes, activation='softmax')(x)
    model = Model(inputs=[inputs], outputs = [y])
    return model


builders = {'MobileNet': make_mobile_net }

def build_network(args, input_shape, num_classes):
    return builders[args.model](args, input_shape, num_classes)

#IMPORTS FOR TRAINING

import sys

from tensorflow.keras import backend as K
from tensorflow.keras.datasets import cifar100
from tensorflow.keras.layers import Lambda
from tensorflow.keras.models import load_model
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import argparse
import os
import h5py
import numpy as np
import tensorflow as tf

from tensorflow.keras.callbacks import TensorBoard, ModelCheckpoint

#TRAINING ARGUMENTS


class Arguments(object):
    def __init__(self, logdir= "./logs/", data_augment = False , normalize = False , add_dense = False , sgd = False , model = "MobileNet", batch_size = 128 ):
        self.logdir = logdir # The directory in which to store the logs (default: ./logs/)
        self.data_augment = data_augment # Whether to use data augmentation
        self.add_dense = add_dense # Should we add an additional dense layer before softmax
        self.sgd = sgd # Should we use sgd instead of adam for optimization
        self.model = model
        self.batch_size = batch_size


args = Arguments()

#Loading Cifar-100 Dataset, 60.000 32x32 color images
(x_train, y_train), (x_test, y_test) = cifar100.load_data(label_mode='fine') #or label_mode = 'coarse'

num_classes = 100
img_rows = x_train.shape[1]
img_cols = x_train.shape[2]
num_channels = 3
num_train = x_train.shape[0]
num_test = x_test.shape[0]
input_shape = (img_rows, img_cols, num_channels)

def split(X, y, test_size):
    idx = np.arange(X.shape[0])
    np.random.shuffle(idx)
    nb_test = int(test_size * X.shape[0])
    return X[nb_test:,:, :], y[nb_test:],\
           X[:nb_test, :, :], y[:nb_test]

x_train, y_train, x_val, y_val = split(x_train, y_train, test_size=0.1)

x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, num_channels)
y_train = to_categorical(y_train, num_classes)

x_val = x_val.reshape(x_val.shape[0], img_rows, img_cols, num_channels)
y_val = to_categorical(y_val, num_classes)

x_test = x_test.reshape(num_test, img_rows, img_cols, num_channels)
y_test = to_categorical(y_test, num_classes)

model = build_network(args, input_shape, num_classes)
model.summary()

# Callbacks

def generate_unique_logpath(logdir, raw_run_name):
    i = 0
    while(True):
        run_name = raw_run_name + "-" + str(i)
        log_path = os.path.join(logdir, run_name)
        if not os.path.isdir(log_path):
            return log_path
        i = i + 1

logpath = generate_unique_logpath(args.logdir, args.model)
tbcb = TensorBoard(log_dir=logpath)
print("=" * 20)
print("The logs will be saved in {}".format(logpath))
print("=" * 20)

checkpoint_filepath = os.path.join(logpath,  "best_model.h5")
checkpoint_cb = ModelCheckpoint(checkpoint_filepath, save_best_only=True)

# Compilation
if args.sgd :
    model.compile(loss='categorical_crossentropy',
                  optimizer='sgd',
                  metrics=['accuracy'])
else :
    model.compile(loss='categorical_crossentropy',
              optimizer='adam',
              metrics=['accuracy'])


TPU_WORKER = 'grpc://' + os.environ['COLAB_TPU_ADDR']
tf.logging.set_verbosity(tf.logging.INFO)

tpu_model = tf.contrib.tpu.keras_to_tpu_model(
    model,
    strategy=tf.contrib.tpu.TPUDistributionStrategy(
        tf.contrib.cluster_resolver.TPUClusterResolver(TPU_WORKER)))

# Training
if args.data_augment:
    datagen = ImageDataGenerator(shear_range=0.3,
                  zoom_range=0.1,
                  rotation_range=10.)

    train_flow = datagen.flow(x_train, y_train, batch_size=args.batch_size*8)
    history = model.fit_generator(train_flow,
            steps_per_epoch=x_train.shape[0]/128,
            epochs=50,
            verbose=1,
            validation_data = (x_val, y_val),
            callbacks=[tbcb, checkpoint_cb])

else:
    history = tpu_model.fit(x_train, y_train,
            batch_size=args.batch_size*8,
            epochs=40,
            verbose=1,
            validation_data = (x_val, y_val),
            callbacks=[tbcb, checkpoint_cb])


# Evaluation of the best model
model = load_model(checkpoint_filepath)
score = model.evaluate(x_test, y_test, verbose=1, batch_size = args.batch_size*8)
print('Test loss:', score[0])
print('Test accuracy:', score[1])

args.batch_size=None
inference_model = build_network(args, input_shape, num_classes)
checkpoint_filepath = './logs/MobileNet-3/best_model.h5'
inference_model.load_weights(checkpoint_filepath)

if args.sgd :
    inference_model.compile(loss='categorical_crossentropy',
                  optimizer='sgd',
                  metrics=['accuracy'])
else :
    inference_model.compile(loss='categorical_crossentropy',
              optimizer='adam',
              metrics=['accuracy'])
score = inference_model.evaluate(x_test, y_test, verbose=1)
print('Test loss:', score[0])
print('Test accuracy:', score[1])

# %load_ext tensorboard.notebook
# %tensorboard --logdir logs

checkpoint_filepath

person Flyfeuhhh    schedule 01.08.2019    source источник


Ответы (1)


Хорошо, я переобучил модель, но с большим количеством эпох (70), и, похоже, она достигла той же точности, что и с графическим процессором в конце.

Посередине все еще есть небольшое падение, я думаю, это отчасти связано с тем, как TPU обучает модель:

https://imgur.com/a/iiRBg2y

person Flyfeuhhh    schedule 01.08.2019