为什么CNN的损失会长时间减少然后突然增加?

时间:2018-09-07 10:07:05

标签: python tensorflow keras

我建立了一个简单的网络来查找虚线,并且进行了非常奇怪的训练。损失keras.losses.binary_crossentropy在大约1500个时期稳定下降,然后突然上升并达到平稳状态。

graph of loss function vs epoch

发生这种情况有哪些原因?优化器,损失函数,网络结构?

我检查了砝码,所有砝码都没有NaN值。输入数据是250,000+张32x32的图像,上面有线条,并且同一行图像的线条被去除了几像素,因此它们被“破坏了”。

sample solid lines and broken lines

这是模型创建代码:

input_shape = (1, 32, 32)
kernel_shape = (16, 16)
keras.backend.set_image_data_format("channels_first")
n_filters = 64
input_layer = engine.Input(input_shape)
active_1 = layers.Activation("relu")(input_layer)
conv_1 = layers.Conv2D(n_filters, kernel_shape)(active_1)
conv_2 = layers.Conv2D(2*n_filters, kernel_shape)(conv_1)
pool_1 = layers.MaxPooling2D()(conv_2)

s = tupleFromShape(pool_1.shape)
p = 1
for d in s:
    p *= d

shaped_1 = layers.Reshape((p,))(pool_1)
dense_1 = layers.Dense(2)(shaped_1)
out = layers.Activation("softmax")(dense_1)
model = engine.Model(input_layer, out)
model.save("broken-lines-start.h5")

培训代码:

full = #numpy array (c, slices, 32, 32)
broken = #numpy array(c, slices, 32, 32)
full = full[0]
broken = broken[0]

n = len(full) - 1024
n2 = len(broken) - 1024

random.shuffle(full)
random.shuffle(broken)

optimizer = keras.optimizers.Adam(0.00001)
loss_function = keras.losses.binary_crossentropy
model.compile(
        model, 
        optimizer, 
        loss_function=loss_function)
batch_size = 256
steps = n//batch_size + n2//batch_size
model.fit_generator(generator=getDataGenerator(full[:n], broken[:n2], batch_size),
                steps_per_epoch=steps,
                epochs=4680,
                validation_data=getDataGenerator(full[n:], broken[n2:], batch_size),
                validation_steps=2048//batch_size,
                callbacks=[saves_last_epoch_and_best_epoch]
                    )
model.save("broken-lines-trained.h5")

生成器代码:

def getDataGenerator(solid, broken, batch_size=128):
    zed = [([chunk], [1, 0]) for chunk in solid] + [([chunk], [0, 1]) for chunk in broken]
    random.shuffle(zed)
    xbatch = []
    ybatch = []
    while True:
        for i in range(len(zed)):
            x,y = zed[i]
            xbatch.append(x)
            ybatch.append(y)
            if len(xbatch)==batch_size:
                yield numpy.array(xbatch),numpy.array(ybatch)
                xbatch = []
                ybatch = []

我已经对该模型进行了很大的改进,但是它还没有表现出这种行为,但是我想了解为什么会这样。

后来我尝试过的事情:

将损失功能更改为logcosh->有效

更改adam优化器的epsilon值->仍然爆炸。

将优化程序更改为SGD->爆炸速度更快,没有初始下降。

1 个答案:

答案 0 :(得分:2)

亚当优化器可能是一个问题-长时间训练它会“爆炸”。

让我们看看 Adam 的公式(很抱歉,我们的演示很丑,以后可能会更改为漂亮的LaTeX):

t <- t + 1
lr_t <- learning_rate * sqrt(1 - beta2^t) / (1 - beta1^t)

m_t <- beta1 * m_{t-1} + (1 - beta1) * g
v_t <- beta2 * v_{t-1} + (1 - beta2) * g * g
variable <- variable - lr_t * m_t / (sqrt(v_t) + epsilon)

其中mv分别是梯度的第一矩(均值)和第二矩(无中心方差)的估计。长时间训练模型后,v可能会变得很小。

默认情况下,根据tensorflow docsbeta1=0.9beta2=0.999。因此mv的更改速度更快。因此,m可以再次变大,而v不能追赶。这将导致大量数字除以非常小的值并爆炸。

尝试增加epsilon参数,默认情况下为1e-08。根据模型,尝试使用0.010.001之类的值。