欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【CS231n】Spring 2020 Assignments - Assignment1 - Softmax

程序员文章站 2024-03-25 10:23:24
...


前言

我的作业是在 Google Colaboratory 上完成的,还是挺方便的。


一、Implement softmax_loss_naive(W, X, y, reg)

逻辑回归分类器(Softmax Classifier):希望正确类别得到的概率分数接近 1

Softmax 损失函数(常用,也叫多项式逻辑回归):我们用 softmax 对分数进行转化处理(即不直接使用),并得到正确类别的损失函数是 − l o g P -logP logP ;公式如下

L i = −   l o g ( e s y i ∑ j e s j ) L_i = -\ log(\frac{e^{s_{y_i}}}{\sum_{j}{e^{s_j}}}) Li= log(jesjesyi)

综上,损失的计算还是比较简单。先求出分数 Scores,将 Scores 正数化( e S e^S eS),再将 Scores 归一化,即除以每个数据样本在每个类的得分总和,这样就可以得出概率 P 了。那对于每个数据样本 X i X_i Xi L i = −   l o g ( e s y i ∑ j e s j ) L_i = -\ log(\frac{e^{s_{y_i}}}{\sum_{j}{e^{s_j}}}) Li= log(jesjesyi)

可是计算梯度 dW 就比较复杂了,因为这个损失函数比较复杂,可以参考下面这篇文章:

多分类器softmax——绝对简单易懂的梯度推导 by 月下花弄影

里面讲得很详细。

下面是代码:

    num_train = X.shape[0]
    num_classes = W.shape[1]
    scores = X.dot(W)
    positive_scores = np.e ** scores
    softmax = positive_scores / np.sum(positive_scores, axis=1).reshape((num_train, 1))

    for i in range(num_train):
      for j in range(num_classes):
        if j == y[i]:
          loss += -np.log(softmax[i][j])
          dW[:, j] += (softmax[i][j] - 1) * X[i]
        else:
          dW[:, j] += softmax[i][j] * X[i]

    loss /= num_train
    loss += reg * np.sum(W*W)

    dW /= num_train
    dW += 2 * reg * W

二、Implement softmax_loss_vectorized(W, X, y, reg)

这题和 SVM 的第二题差不多。损失是比较好求的,比较难的仍然是梯度矩阵。

总体思路是构造出一个矩阵,让它和 X 点乘能够得到 dW 。从上一题中我们可以看到 dW[:, j] 都需要加上 X[i] ,只不过当 j = y[i] 时的系数需要减 1 ,那么很自然的我们先将 softmax 相应的项减去1,再与 X.T 点乘即可得到 dW。当然最后别忘了除以 num_train 以及 进行正则化惩罚。

    num_train = X.shape[0]
    num_classes = W.shape[1]
    dim = X.shape[1]
    scores = X.dot(W)
    positive_scores = np.e ** scores
    softmax = positive_scores / np.sum(positive_scores, axis=1).reshape((num_train, 1))

    loss = np.sum((-np.log(softmax))[range(num_train), y])
    softmax[range(num_train), y] -= 1
    dW = X.T.dot(softmax)

    loss /= num_train
    loss += reg * np.sum(W*W)

    dW /= num_train
    dW += 2 * reg * W

三、Write code that chooses the best hyperparameters

这一题的思路跟 SVM 里面的完全一样,想看思路的同学可以看我的上一篇博客。

需要注意的是,我选用的参数都是经过对比、选择最后得出来的,并不是一开始就将 learning_rate_step_size, regularization_strength_step_size, num_iters 这些参数设成这个值的。

其实研究了一下其他同学的代码之后,我尝试了一下,发现不怕耗费时间的同学真的可以将 num_iters 固定成一个比较大的值,这样训练出来的结果会准确很多,对于区间的选择也更精准。

learning_rate_step_size = (1.288000e-06 - 0.5e-7) / 15
regularization_strength_step_size = (4.200000e+04 - 1e4) / 15

lr = 1e-7 - learning_rate_step_size
regularization_strength = 1e4 - regularization_strength_step_size

best_lr = 0.
best_regularization_strength = 0.

for i in range(15):
  lr += learning_rate_step_size
  regularization_strength = 1e4
  for j in range(15):
    regularization_strength += regularization_strength_step_size
    new_softmax = Softmax()
    new_softmax.train(X_train, y_train, learning_rate=lr, reg=regularization_strength, num_iters=700, verbose=False)
    y_train_pred = new_softmax.predict(X_train)
    training_accuracy = np.mean(y_train == y_train_pred)
    y_val_pred = new_softmax.predict(X_val)
    validation_accuracy = np.mean(y_val == y_val_pred)
    if validation_accuracy > best_val:
      best_val = validation_accuracy
      best_softmax = new_softmax
      best_lr = lr
      best_regularization_strength = regularization_strength
    results[(lr, regularization_strength)] = (training_accuracy, validation_accuracy)

# Train best_softmax and update bast_value
best_softmax.train(X_train, y_train, best_lr, best_regularization_strength, num_iters=800, verbose=True)
y_val_pred = best_softmax.predict(X_val)
best_val = np.mean(y_val == y_val_pred)
print('best_lr:', best_lr, 'best_regularization_strength:', best_regularization_strength)

总结

学习CS231n对数学的要求真的蛮高的。