내 풀이 링크: https://github.com/lionkingchuchu/cs231n.git
이번 과제는 주된 목표는 softmax 함수의 forward, backward를 구현하는 것, 그리고 Stochastic Gradient Descent를 구현하는 것이다. Softmax함수란 Loss function의 일종으로 cross entropy 함수와 같이 사용하여 Li = -log (정답 클래스의 점수 / 모든 클래스의 점수의 합) 으로 표현된다. 정답 / 전체 를 다르게 생각하면 확률로 생각 할 수 있기에 각 클래스의 예측 확률로 생각 할 수도 있는 것이 특징이다. 여기서 각 클래스의 점수는 e에 해당 클래스의 출력값을 곱하여 계산한다.
이 과제에서의 softmax()함수는 단지 softmax함수 만이 아니라, 실제 모델 예측을 하기 위해 1개의 Affine layer와 연결되어 있는 softmax함수 형태이다.
def softmax_loss_naive(W, X, y, reg):
loss = 0.0
dW = np.zeros_like(W)
# *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
num_train = X.shape[0]
num_class = W.shape[1]
for i in range(num_train):
scores = np.dot(X[i],W)
y_score = scores[y[i]]
result = np.log(np.exp(y_score) / np.sum(np.exp(scores)))
dW[:,y[i]] -= X[i]
dW += (np.dot(np.reshape(X[i],[-1,1]),
np.reshape(np.exp(scores),[1,-1]))) / np.sum(np.exp(scores))
loss -= result
loss /= num_train
dW /= num_train
loss += reg * np.sum(W * W)
dW += 2 * reg * W
# *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
return loss, dW
루프를 사용하여 naive한 방법으로는 위와 같이 구할 수 있다. 공식 그대로 np.exp(y_score) / np.sum(np.exp(scores)) 으로 (정답 클래스의 점수 / 모든 클래스의 점수의 합) 를 구현하고 로그를 취해주어 loss를 구할 수 있다. dW는 backpropagation을 이용하여 각 correct_class에서는 -Xi 만큼 빼주고, 모든 클래스에는 (Xi) X (각 클래스의 점수 / 모든 클래스의 점수의 합) 을 더해주어 구할 수 있다. num_train 나눠주기 regularization을 잊지 말자.
Inline Question 1
Why do we expect our loss to be close to -log(0.1)? Explain briefly.**
YourAnswer: softmax function's inner part of logarithm can be interpreted as a probability of correct class. Since there are 10 class, and W are in totally random state, probability of getting the correct class would be (1/10) for each X[i] data. we added up all, and divided with num_train which will make total loss near -log(1/10). Small difference between actual loss and sanity check would be due to either randomness of initial W, and regularization.
여기서 첫번째 문제가 나오는데 기초의 softmax함수에 CIFAR-10 데이터를 입력하면 왜 loss가 -log(0.1)에 맞게 나와야 하는지 물어보는 문제이다. softmax는 위에 말한 것처럼 확률로도 표현 할 수 있다. 가장 random한 상태에서 10개의 클래스중 정답의 클래스를 맞출 확률은 1/10 이기에, -log(1/10) 인 -log(0.1)과 같아야 한다. 작은 차이가 있을 것인데, 그것은 regularization 때문이거나, 아니면 초기의 랜덤으로 배정한 W 들이 정답인 클래스의 맞출 확률이 정확히 1/10 은 아닐 것이기에 차이가 있다.
다음으로 numerical gradient와 위에서 구한 함수를 이용한 analytic gradient를 비교한다.
def softmax_loss_vectorized(W, X, y, reg):
loss = 0.0
dW = np.zeros_like(W)
# *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
num_train = X.shape[0]
num_class = W.shape[1]
scores = np.dot(X,W)
y_mask = np.zeros_like(scores,dtype = 'bool')
y_mask[np.arange(num_train),y]=1
y_scores = scores[y_mask]
sum_score = np.log(np.sum(np.exp(scores),axis = 1))
loss -= np.sum(y_scores)
loss += np.sum(sum_score)
loss /= num_train
loss += reg * np.sum(W*W)
dLdWj = np.exp(scores) / np.reshape(np.sum(np.exp(scores), axis=1),[-1,1])
dW += np.dot(X.T, dLdWj)
dW -= np.dot(X.T, y_mask)
dW /= num_train
dW += 2 * reg * W
# *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
return loss, dW
다음으로 루프를 사용하지 않고 vectorized 형태로 구하는 것이다. 위에서 루프를 돌며 구한 과정을 행렬 곱셈을 통해 + broadcast를 이용해 잘 구현해 주면 된다.
from cs231n.classifiers import Softmax
results = {}
best_val = -1
best_softmax = None
# Provided as a reference. You may or may not want to change these hyperparameters
learning_rates = [1e-7, 5e-7, 5e-8]
regularization_strengths = [2.5e4, 1e4]
# *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
for lr in learning_rates:
for reg in regularization_strengths:
softmax = Softmax()
softmax.train(X_train,y_train,learning_rate=lr,reg=reg,num_iters=2000)
y_train_pred = softmax.predict(X_train)
y_val_pred = softmax.predict(X_val)
y_train_acc = np.mean(y_train == y_train_pred)
y_val_acc = np.mean(y_val == y_val_pred)
results[(lr,reg)] = (y_train_acc,y_val_acc)
if y_val_acc>best_val:
best_val = y_val_acc
best_softmax = softmax
# *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
# Print out results.
for lr, reg in sorted(results):
train_accuracy, val_accuracy = results[(lr, reg)]
print('lr %e reg %e train accuracy: %f val accuracy: %f' % (
lr, reg, train_accuracy, val_accuracy))
print('best validation accuracy achieved during cross-validation: %f' % best_val)
위에서 구현한 softmax함수를 통해 실제로 예측 모델을 만들어 보고, learning rate와 regularization strength를 cross validation 해 가며 최고의 정확도를 보이는 최적의 모델을 찾아낸다.
Inline Question 2 - True or False
Suppose the overall training loss is defined as the sum of the per-datapoint loss over all training examples. It is possible to add a new datapoint to a training set that would leave the SVM loss unchanged, but this is not the case with the Softmax classifier loss.
YourAnswer: Yes
YourExplanation: Remember for the SVM loss function there was a max(0, s(j) - s(yi) + delta). If new data's every s(j) - s(yi) + delta is below zero, loss function would not be added at all wich will leave the SVM loss unchanged, but it will affect the Softmax classifier loss since remeber the softmax can be interpreted as probabilty of correct class, and probabilty of correct class cannot be (1) when newly added.
다음 문제는 만약 새로운 training data 1개를 추가할 때, SVM loss는 변형시키지 않고 softmax loss만 변형시키는 결과를 내는 데이터를 추가할 수 있는지 에 관한 문제이다. SVM loss function을 다시 기억해 보면 max(0, s(j) - s(yi) + delta) 였다. 만약 새로운 데이터의 s(j) - s(yi) + delta가 0보다 작다면, max(0)에 의해 사라져 loss에는 변화가 없을 것이다. 하지만 softmax에서는 각 클래스의 점수를 e의 제곱으로 계산하기에, 어떤 데이터를 넣더라도 변화가 일어날 수 밖에 없다.
시각화를 해도 저번 결과처럼 비슷한 그림이 나오는 것을 볼 수 있다.
'cs231n' 카테고리의 다른 글
cs231n Assignment 2: Q1 (Fully Connected Network 구현) (0) | 2023.02.14 |
---|---|
cs231n Assignment 1: Q5 (HOG, HSV 추출 사용) (0) | 2023.02.06 |
cs231n Assignment 1: Q4 (Two Layer Network 구현) (0) | 2023.02.01 |
cs231n Assignment 1: Q2 (Support Vector Machine 모델 구현) (0) | 2023.01.29 |
cs231n Assignment 1: Q1 (K Nearest Neighbor 모델 구현) (0) | 2023.01.27 |