Как заменить функцию потерь при обучении tenorflow.keras - PullRequest
3 голосов
/ 02 апреля 2020

Я хочу заменить функцию потерь, связанную с моей нейронной сетью во время обучения, это сеть:

model = tensorflow.keras.models.Sequential()
        model.add(tensorflow.keras.layers.Conv2D(32, kernel_size=(3, 3), activation="relu", input_shape=input_shape))
        model.add(tensorflow.keras.layers.Conv2D(64, (3, 3), activation="relu"))
        model.add(tensorflow.keras.layers.MaxPooling2D(pool_size=(2, 2)))
        model.add(tensorflow.keras.layers.Dropout(0.25))
        model.add(tensorflow.keras.layers.Flatten())
        model.add(tensorflow.keras.layers.Dense(128, activation="relu"))
        model.add(tensorflow.keras.layers.Dropout(0.5))
        model.add(tensorflow.keras.layers.Dense(output_classes, activation="softmax"))
        model.compile(loss=tensorflow.keras.losses.categorical_crossentropy, optimizer=tensorflow.keras.optimizers.Adam(0.001), metrics=['accuracy'])
        history = model.fit(x_train, y_train, batch_size=128, epochs=5, validation_data=(x_test, y_test))

, поэтому теперь я хочу заменить tensorflow.keras.losses.categorical_crossentropy на другую, поэтому я сделал это:

model.compile(loss=tensorflow.keras.losses.mse, optimizer=tensorflow.keras.optimizers.Adam(0.001), metrics=['accuracy'])
    history = model.fit(x_improve, y_improve, epochs=1, validation_data=(x_test, y_test)) #FIXME bug during training

но у меня есть эта ошибка:

ValueError: No gradients provided for any variable: ['conv2d/kernel:0', 'conv2d/bias:0', 'conv2d_1/kernel:0', 'conv2d_1/bias:0', 'dense/kernel:0', 'dense/bias:0', 'dense_1/kernel:0', 'dense_1/bias:0'].

Почему? Как я могу это исправить? Есть еще один способ изменить функцию потерь?

Спасибо

1 Ответ

2 голосов
/ 03 апреля 2020

Итак, я бы дал простой ответ: переключитесь на pytorch, если вы хотите играть в подобные игры. Поскольку в pytorch вы определяете свои функции обучения и оценки, требуется всего лишь оператор if, чтобы переключиться с функции потерь на другую.

Кроме того, я вижу в вашем коде, что вы хотите переключиться с cross_entropy на mean_square_error, первый подходит для классификации последнего для регрессии, так что это не совсем то, что вы можете сделать, в коде, который следует за I перешел от среднеквадратичной ошибки к среднеквадратичной логарифмической ошибке c, которые обе являются потерями, пригодными для регрессии.

Несмотря на то, что другие ответы предлагают решения для вашего вопроса (см. изменение-функция-потери-динамически во время обучения ), неясно, можете ли вы доверять результатам или нет. Некоторые люди обнаружили, что даже с индивидуальной функцией иногда Keras продолжают тренироваться с первой потерей.

Решение:

Мое решение основано на train_on_batch, который позволяет нам обучать модель в течение l oop и поэтому прекращать ее обучение всякий раз, когда мы предпочитаем перекомпилировать модель с новым функция потери. Обратите внимание, что перекомпиляция модели не приводит к сбросу весов (см .: Повторная инициализация весов при перекомпиляции модели? ).

Набор данных можно найти здесь Бостонский набор данных жилья

# Regression Example With Boston Dataset: Standardized and Larger
from pandas import read_csv
from keras.models import Sequential
from keras.layers import Dense
from sklearn.model_selection import train_test_split
from keras.losses import mean_squared_error, mean_squared_logarithmic_error
from matplotlib import pyplot
import matplotlib.pyplot as plt

# load dataset
dataframe = read_csv("housing.csv", delim_whitespace=True, header=None)
dataset = dataframe.values

# split into input (X) and output (Y) variables
X = dataset[:,0:13]
y = dataset[:,13]

trainX, testX, trainy, testy = train_test_split(X, y, test_size=0.33, random_state=42)

# create model
model = Sequential()
model.add(Dense(13, input_dim=13, kernel_initializer='normal', activation='relu'))
model.add(Dense(6, kernel_initializer='normal', activation='relu'))
model.add(Dense(1, kernel_initializer='normal'))

batch_size = 25

# have to define manually a dict to store all epochs scores 
history = {}
history['history'] = {}
history['history']['loss'] = []
history['history']['mean_squared_error'] = []
history['history']['mean_squared_logarithmic_error'] = []
history['history']['val_loss'] = []
history['history']['val_mean_squared_error'] = []
history['history']['val_mean_squared_logarithmic_error'] = []

# first compiling with mse
model.compile(loss='mean_squared_error', optimizer='adam', metrics=[mean_squared_error, mean_squared_logarithmic_error])

# define number of iterations in training and test
train_iter = round(trainX.shape[0]/batch_size)
test_iter = round(testX.shape[0]/batch_size)

for epoch in range(2):

    # train iterations 
    loss, mse, msle = 0, 0, 0
    for i in range(train_iter):

        start = i*batch_size
        end = i*batch_size + batch_size
        batchX = trainX[start:end,]
        batchy = trainy[start:end,]

        loss_, mse_, msle_ = model.train_on_batch(batchX,batchy)

        loss += loss_
        mse += mse_
        msle += msle_

    history['history']['loss'].append(loss/train_iter)
    history['history']['mean_squared_error'].append(mse/train_iter)
    history['history']['mean_squared_logarithmic_error'].append(msle/train_iter)

    # test iterations 
    val_loss, val_mse, val_msle = 0, 0, 0
    for i in range(test_iter):

        start = i*batch_size
        end = i*batch_size + batch_size
        batchX = testX[start:end,]
        batchy = testy[start:end,]

        val_loss_, val_mse_, val_msle_ = model.test_on_batch(batchX,batchy)

        val_loss += val_loss_
        val_mse += val_mse_
        val_msle += msle_

    history['history']['val_loss'].append(val_loss/test_iter)
    history['history']['val_mean_squared_error'].append(val_mse/test_iter)
    history['history']['val_mean_squared_logarithmic_error'].append(val_msle/test_iter)

# recompiling the model with new loss
model.compile(loss='mean_squared_logarithmic_error', optimizer='adam', metrics=[mean_squared_error, mean_squared_logarithmic_error])

for epoch in range(2):

    # train iterations 
    loss, mse, msle = 0, 0, 0
    for i in range(train_iter):

        start = i*batch_size
        end = i*batch_size + batch_size
        batchX = trainX[start:end,]
        batchy = trainy[start:end,]

        loss_, mse_, msle_ = model.train_on_batch(batchX,batchy)

        loss += loss_
        mse += mse_
        msle += msle_

    history['history']['loss'].append(loss/train_iter)
    history['history']['mean_squared_error'].append(mse/train_iter)
    history['history']['mean_squared_logarithmic_error'].append(msle/train_iter)

    # test iterations 
    val_loss, val_mse, val_msle = 0, 0, 0
    for i in range(test_iter):

        start = i*batch_size
        end = i*batch_size + batch_size
        batchX = testX[start:end,]
        batchy = testy[start:end,]

        val_loss_, val_mse_, val_msle_ = model.test_on_batch(batchX,batchy)

        val_loss += val_loss_
        val_mse += val_mse_
        val_msle += msle_

    history['history']['val_loss'].append(val_loss/test_iter)
    history['history']['val_mean_squared_error'].append(val_mse/test_iter)
    history['history']['val_mean_squared_logarithmic_error'].append(val_msle/test_iter)

# Some plots to check what is going on   
# loss function 
pyplot.subplot(311)
pyplot.title('Loss')
pyplot.plot(history['history']['loss'], label='train')
pyplot.plot(history['history']['val_loss'], label='test')
pyplot.legend()

# Only mean squared error 
pyplot.subplot(312)
pyplot.title('Mean Squared Error')
pyplot.plot(history['history']['mean_squared_error'], label='train')
pyplot.plot(history['history']['val_mean_squared_error'], label='test')
pyplot.legend()

# Only mean squared logarithmic error 
pyplot.subplot(313)
pyplot.title('Mean Squared Logarithmic Error')
pyplot.plot(history['history']['mean_squared_logarithmic_error'], label='train')
pyplot.plot(history['history']['val_mean_squared_logarithmic_error'], label='test')
pyplot.legend()
plt.tight_layout()
pyplot.show()

Полученный график подтверждает, что функция потерь изменяется после второй эпохи:

enter image description here

Падение функции потерь связано с тем, что модель переключается с нормальной среднеквадратичной ошибки на логарифмическую c, которая имеет гораздо более низкие значения. Печать результатов также доказывает, что использованная потеря действительно изменилась:

print(history['history']['loss'])
[599.5209197998047, 570.4041115897043, 3.8622902120862688, 2.1578191178185597]
print(history['history']['mean_squared_error'])
[599.5209197998047, 570.4041115897043, 510.29034205845426, 425.32058388846264]
print(history['history']['mean_squared_logarithmic_error'])
[8.624503476279122, 6.346359729766846, 3.8622902120862688, 2.1578191178185597]

В первых двух эпохах значения потерь равны значениям mean_square_error, а в третьей и четвертой эпохах значения становятся равными of mean_square_logarithmic_error, который является новой потерей, которая была установлена. Таким образом, кажется, что с помощью train_on_batch можно изменить функцию потерь, тем не менее, я хочу еще раз подчеркнуть, что это в основном то, что нужно делать на pytoch, чтобы достичь тех же результатов, с той разницей, что поведение pytorch (в этом сценарии и в моем мнение) надежнее.

...