Which is Better? Leaky ReLU or ReLU

使用 ReLU 激活函数与 LReLU 激活函数时模型性能是否存在明显差异?

介绍

作为数据科学家,我们不断寻求改进并为我们的机器学习 (ML) 模型找到最佳参数。我们将研究人们可能希望将两种不同的激活函数应用到他们的 ML 模型中,在今天的例子中是神经网络。选择正确的激活函数可以使模型在训练过程中具有更高的准确性、更低的损失并且更稳定。

什么是激活函数?

激活函数允许 ML 模型解决非线性问题。今天的模型可以采用许多不同的激活函数(即 Sigmoid、Swish、Mish、tanh),我强烈建议您可以多进行尝试,看下哪种函数最适合您的下一个模型。

Rectified Linear Unit (ReLU) 激活函数

ReLU 激活函数显示在克服使用 Sigmoid 激活函数时发生饱和具有很好的效果。

什么是饱和?它与训练神经网络时出现的梯度爆炸和消失问题一致。当梯度“爆炸”时,激活被发送到非常大的数字并且模型权重的更新太大,导致模型无法学习解决给定任务。当梯度“消失”时,模型权重的更新变得非常小,以至于无法更改它们以符合和解决给定的问题。

ReLU 激活函数分两种情况解决了这个问题:

  • 它不像 S 形激活函数(沿 y 轴)那样受 0 和 1 的约束。

  • 任何负值都将被设定为零。

    144d42f977b9046f83e34c2e4975e761.png

ReLU 激活函数在每个实例中取 x 的最大值。此外,ReLU 激活函数往往收敛得更快,因为它在计算中没有除法或指数计算。

Leaky Rectified Linear Unit (LReLU) 激活函数

Leaky ReLU 激活函数 (LReLU) 与 ReLU 激活函数非常相似,只有一个变化。不是将负值直接设为 0,而是使用一个非常小的斜率参数 ,该参数包含来自负值的一些信息。

af04b543aaddfa152939d671ddbe911a.png

该激活函数首先由 Maas 等人引入,使用 0.01 的斜率参数。

实验

本实验使用的数据集是手写数字的MNIST数据集。要使用此数据集,我们需要使用 Python 将其正确加载到我们的代码中,并将每个图像 reshpe 至 (28,28,1)。之后,我们可以通过将每个图像除以 255(像素数)来对其进行归一化。

# Model / data parameters
num_classes = 10
input_shape = (28, 28, 1)


# Load the data and split it between train and test sets
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()


# Scale images to the [0, 1] range
x_train = x_train.astype("float32") / 255
x_test = x_test.astype("float32") / 255
# Make sure images have shape (28, 28, 1)
x_train = np.expand_dims(x_train, -1)
x_test = np.expand_dims(x_test, -1)

在实验中,比较激活函数在 1、10、100 和 1,000 个epoch内的性能。这是我为我的实验调整的主要参数,但是可以调整其他各种参数以查看不同的激活函数如何影响性能(例如调整模型中的层数)。除了它们采用不同的激活函数外,这些模型是相同的。

model_1 = keras.Sequential(
    [
        keras.Input(shape=input_shape),
        layers.Conv2D(32, kernel_size=(3, 3)),
        layers.LeakyReLU(),
        layers.MaxPooling2D(pool_size=(2, 2)),
        layers.Conv2D(64, kernel_size=(3, 3)),
        layers.LeakyReLU(),
        layers.MaxPooling2D(pool_size=(2, 2)),
        layers.Flatten(),
        layers.Dropout(0.5),
        layers.Dense(num_classes, activation="softmax"),
    ]
)




model_2 = keras.Sequential(
    [
        keras.Input(shape=input_shape),
        layers.Conv2D(32, kernel_size=(3, 3)),
        layers.ReLU(),
        layers.MaxPooling2D(pool_size=(2, 2)),
        layers.Conv2D(64, kernel_size=(3, 3)),
        layers.ReLU(),
        layers.MaxPooling2D(pool_size=(2, 2)),
        layers.Flatten(),
        layers.Dropout(0.5),
        layers.Dense(num_classes, activation="softmax"),
    ]
)

如上面的模型所示,我创建了一个卷积神经网络 (CNN) 来对 MNIST 图像进行分类。这两个模型将采用相同的架构,即两个卷积层后跟最大池化层,但激活函数不同。

epoch_values = [1, 10, 100,1000]


def model_comparison(first_model, second_model, x_train, y_train, x_test, y_test, num_epochs):


  batch_size = 128
  model_1.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"])


  model_2.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"])


  model_1_train_acc = []
  model_1_train_loss = []
  model_1_test_acc = []
  model_1_test_loss = []


  model_2_train_acc = []
  model_2_train_loss = []
  model_2_test_acc = []
  model_2_test_loss = []




  for epoch in num_epochs:
    print('************ EPOCHS: {} ************'.format(epoch))
    history_1 = model_1.fit(x_train, y_train, batch_size=batch_size, epochs=epoch, validation_split=0.1)
    history_2 = model_2.fit(x_train, y_train, batch_size=batch_size, epochs=epoch, validation_split=0.1)


    print('Model 1 Train Accuracy | Loss After {0} Epochs: {1}% | {2}%'.format(epoch, history_1.history['accuracy'][-1], 
    history_1.history['loss'][-1]))
    print('Model 2 Train Accuracy | Loss After {0} Epochs: {1}% | {2}%'.format(epoch, history_2.history['accuracy'][-1], 
    history_2.history['loss'][-1]))


    model_1_train_acc.append(history_1.history['accuracy'][-1])
    model_1_train_loss.append(history_1.history['loss'][-1])


    model_2_train_acc.append(history_2.history['accuracy'][-1])
    model_2_train_loss.append(history_2.history['loss'][-1])


    test_loss_1, test_acc_1 = model_1.evaluate(x_test,  y_test, verbose=2)
    test_loss_2, test_acc_2 = model_2.evaluate(x_test,  y_test, verbose=2)


    print('Model 1 Test Accuracy | Loss cy After {0} Epochs: {1}% | {2}%'.format(epoch, test_acc_1, test_loss_1))
    print('Model 2 Test Accuracy | Loss After {0} Epochs: {1}% | {2}%'.format(epoch, test_acc_2, test_loss_2))


    model_1_test_acc.append(test_acc_1)
    model_1_test_loss.append(test_loss_1)


    model_2_test_acc.append(test_acc_2)
    model_2_test_loss.append(test_loss_2)




  print('Creating DataFrame...')
  results_dict = {'Epochs' : num_epochs, 'Model 1 Train Accuracy' : model_1_train_acc, 
  'Model 2 Train Accuracy' : model_2_train_acc,
                  'Model 1 Train Loss' : model_1_train_loss, 'Model 2 Train Loss' : model_2_train_loss,
                  'Model 1 Test Accuracy' : model_1_test_acc, 'Model 2 Test Accuracy' : model_2_test_acc,
                  'Model 1 Test Loss' : model_1_test_loss, 'Model 2 Test Loss' : model_2_test_loss}
  df = pd.DataFrame.from_dict(results_dict, orient='index')
  results = df.transpose()
  
  return results

上面的代码是为这个实验设计的。如果您改变训练实验的e poch,这将非常有用。如果您计划采用更高级的方法并改变其他超参数(模型层、神经元数量等),您可能需要使用更复杂的训练函数(如 Gridsearch)。

结果

76b8bdb505bb28a89c8b5b7d6fa1618c.png

对于 1 个 epoch,ReLU 模型在训练集上表现更好,而 LReLU 模型在测试集上表现更好。但模型训练的 1 个 epoch 的结果并不能最清楚地表明哪个激活函数最终表现更好,但有助于分析模型性能随着 epoch 数量的增加而受到的影响。对于训练集,ReLU 模型的准确率比 LReLU 模型高 0.2789%,损失值低 0.9952%。对于 1 个 epoch 的训练集,ReLU 模型表现更好。对于测试集,ReLU 模型的准确率比 LReLU 模型低 0.5230%,损失值高 1.0000%。对于 1 个 epoch 的测试集,LReLU 模型表现更好。

经过 10 个 epoch 的模型训练,LReLU 模型在所有评估标准中都表现更好。在训练集上,ReLU模型的准确率比LReLU模型低0.1166%,损失值高0.4811%。对于 10 个 epoch 的训练集,LReLU 模型表现更好。使用测试集,ReLU 模型的准确率比 LReLU 模型低 0.0190%,损失值高 1.8700%%。10 个 epoch 的测试集结果概述了 LReLU 模型如何表现更好。在这一点上,LReLU 模型在所有指标上都比 ReLU 模型表现更好。

在模型训练的 100 个 epoch 中,LReLU 激活函数在所有类别中再次获胜。对于训练集,ReLU 模型的准确率比 LReLU 模型低 0.0574%,损失值高 0.1367%。对于 100 个 epoch 的训练集,LReLU 模型表现更好。使用测试集,ReLU 模型的精度比 LReLU 模型低 0.1600%,损失值高 1.7030%。如前所述,在对测试集进行预测时,LReLU 模型的表现优于 ReLU 模型。

最后,使用 1,000 个 epoch,LReLU 激活函数在所有类别中的表现再次都优于 ReLU。对于训练集,ReLU 模型的准确率比 LReLU 模型低 0.0888%,损失值高 0.3474%。LReLU 模型在 1,000 个 ReLU 的训练集上表现更好。用测试集评估模型,ReLU 模型的精度比 LReLU 模型低 0.0900%,损失值高 2.1124%。这遵循与之前相同的模式:LReLU 模型比 ReLU 模型表现更好。

最终结论:在该模型下,LReLU 激活函数优于 ReLU 激活函数。

讨论

如结果所示,虽然差异很小(但确实说明了很多,因为两个模型的性能都非常高),LReLU 模型显示随着 epoch 数量的增加表现更好。考虑这个指标很重要,因为采用整个训练集的平均准确度,ReLU 模型的表现要好 0.003275%。ReLU 模型在不同级别的 epoch 中确实有更高的损失,平均损失为 0.0075%。

对于测试集,LReLU 模型具有更好的精度,在所有试验中比 ReLU 模型高 0.2424%。此外,LReLU 模型的损失值平均比 ReLU 模型低 0.85%。虽然 ReLU 模型在一次试验中具有更高的准确性(在 1 个时期!),但结果表明采用 LReLU 激活函数的模型总体上具有更佳的性能。

结论

虽然结果微乎其微,但在改变训练时期的数量(对于今天的给定任务)时,LReLU 激活函数实际上确实比 ReLU 激活函数表现更好。这项研究有几点需要注意。首先,这项研究是使用 MNIST 数据集进行的,该数据集并不难用于实现高模型性能。另一个需要注意的是,实验唯一改变的参数是 epoch。今天的目标是看看在训练神经网络时使用 LReLU 激活函数是否比 ReLU 激活函数有优势,并且如结果所示,在网络中采用 LReLU 激活函数可能会表现更好。

Code

model_1_train_acc =[0.890833,  
0.986815,  
0.996463,  
0.998130]  


model_2_train_acc =[0.888074,
0.987981,  
0.997037,  
0.999018]


model_1_train_loss = [0.363096,  
0.043024,  
0.009764,  
  0.007270]
  
model_2_train_loss = [0.373048,  
0.038213,  
0.008396,  
0.003796]


model_1_test_acc = [0.9687,  
  0.9897,  
  0.9914,  
0.9921]


model_2_test_acc= [.9740,  
  0.9916,  
  0.9930,  
  0.9930]


model_1_test_loss =[0.097081,  
  0.029695,  
  0.031368,  
  0.069522]


model_2_test_loss = [0.087532,
  0.024234,
  0.029281,
  0.052542,]
for i in range(4):
  print(i)
  print('-'*50 + 'Train Results' +  '-'*50)
  print('-'*50 + 'Train Acc. Results' + '-'*50)
  model_1_train_avg_acc = model_1_train_acc[i]
  model_2_train_avg_acc = model_2_train_acc[i]
  print(model_1_train_avg_acc)
  print(model_2_train_avg_acc)
  print((model_1_train_avg_acc-model_2_train_avg_acc)*100)


  print('-'*50 + 'Train Loss Results' + '-'*50)
  model_1_train_avg_loss = model_1_train_loss[i]
  model_2_train_avg_loss = model_2_train_loss[i]


  print(model_1_train_avg_loss)
  print(model_2_train_avg_loss)
  print((model_1_train_avg_loss-model_2_train_avg_loss)*100)


  print('-'*50 + 'Test Results' + '-'*50)
  print('-'*50 + 'Test Acc. Results' + '-'*50)
  model_1_test_avg_acc = model_1_test_acc[i]
  model_2_test_avg_acc = model_2_test_acc[i]
  print(model_1_test_avg_acc)
  print(model_2_test_avg_acc)
  print((model_1_test_avg_acc-model_2_test_avg_acc)*100)
  print('-'*50 + 'Test Loss Results' + '-'*50)


  model_1_test_avg_loss = model_1_test_loss[i]


  model_2_test_avg_ss = model_2_test_loss[i]


  print(model_1_test_avg_loss)
  print(model_2_test_avg_loss)
  print((model_1_test_avg_loss-model_2_test_avg_loss)*100)
model_1_train_acc =[0.890833,  
0.986815,  
0.996463,  
0.998130]  


model_2_train_acc =[0.888074,
0.987981,  
0.997037,  
0.999018]


model_1_train_loss = [0.363096,  
0.043024,  
0.009764,  
  0.007270]
  
model_2_train_loss = [0.373048,  
0.038213,  
0.008396,  
0.003796]


model_1_test_acc = [0.9687,  
  0.9897,  
  0.9914,  
0.9921]


model_2_test_acc= [.9740,  
  0.9916,  
  0.9930,  
  0.9930]


model_1_test_loss =[0.097081,  
  0.029695,  
  0.031368,  
  0.069522]


model_2_test_loss = [0.087532,
  0.024234,
  0.029281,
  0.052542,]


print('-'*50 + 'Train Results' + '-'*50)
print('-'*50 + 'Train Acc. Results' + '-'*50)
model_1_train_avg_acc = np.mean(model_1_train_acc)
model_2_train_avg_acc = np.mean(model_2_train_acc)
print(model_1_train_avg_acc)
print(model_2_train_avg_acc)
print((model_1_train_avg_acc-model_2_train_avg_acc)*100)
print('-'*50 + 'Train Loss Results' + '-'*50)
model_1_train_avg_loss = np.mean(model_1_train_loss)


model_2_train_avg_loss = np.mean(model_2_train_loss)


print(model_1_train_avg_loss)
print(model_2_train_avg_loss)
print((model_1_train_avg_loss-model_2_train_avg_loss)*100)


print('-'*50 + 'Test Results' + '-'*50)
print('-'*50 + 'Test Acc. Results' + '-'*50)
model_1_test_avg_acc = np.mean(model_1_test_acc)


model_2_test_avg_acc = np.mean(model_2_test_acc)
print(model_1_test_avg_acc)
print(model_2_test_avg_acc)
print((model_1_test_avg_acc-model_2_test_avg_acc)*100)
print('-'*50 + 'Test Loss Results' + '-'*50)


model_1_test_avg_loss = np.mean(model_1_test_loss)


model_2_test_avg_loss = np.mean(model_2_test_loss)


print(model_1_test_avg_loss)
print(model_2_test_avg_loss)
print((model_1_test_avg_loss-model_2_test_avg_loss)*100)

·  END  ·

HAPPY LIFE

e49be5480b43ae9511c086cadf3afc22.png

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值