#-*- coding: utf-8 -*-
import numpy as np
def softmax_loss_naive(W, X, y, reg):
"""
使用显式循环版本计算Softmax损失函数
N表示:数据个数,D表示:数据维度,C:表示数据类别个数。
Inputs:
- W: 形状(D, C) numpy数组,表示分类器权重(参数).
- X: 形状(N, D) numpy数组,表示训练数据.
- y: 形状(N,) numpy数组,表示数据类标。
其中 y[i] = c 意味着X[i]为第c类数据,c取值为[0,c)
- reg: 正则化惩罚系数
Returns 二元组(tuple):
- loss,数据损失值
- dW,权重W所对应的梯度,其形状和W相同
"""
# 初始化损失值与梯度.
loss = 0.0
dW = np.zeros_like(W)
#############################################################################
# 任务:使用显式循环实现softmax损失值loss及相应的梯度dW 。 #
# 温馨提示: 如果不慎,将很容易造成数值上溢。别忘了正则化哟。 #
#############################################################################
# =============================================================================
# 第一种
# =============================================================================
# num_train = X.shape[0] # 获取训练样本数
# num_class = W.shape[1] # 获取分类总数
# for i in range(num_train):
# s = X[i].dot(W) # (1, C) 每类的可能性
# scores = s - max(s) # 关注最高分
# #使用指数函数,在不影响单调性的情况下,使相对得分更明显
# scores_E = np.exp(scores)
# # 计算总得分
# Z = np.sum(scores_E)
# # 找到目标值
# score_target = scores_E[y[i]]
# # 计算出损失值
# loss += -np.log(score_target/Z)
# # 计算梯度值
# for j in range(num_class):
# if j == y[i]:
# dW[:, j] += -(1-scores_E[j]/Z)*X[i]
# else:
# dW[:, j] += X[i]*scores_E[j]/Z
# # 使用平均损失,再引入正则化
# loss = loss/num_train+0.5*reg*np.sum(W*W)
# # 使用平均梯度,再引入正则化
# dW = dW/num_train+reg*W
# =============================================================================
# 第二种
# =============================================================================
N = X.shape[0] # 获取训练样本数
C = W.shape[1] # 获取分类总数
result = X.dot(W)
result -= np.max(result,axis=1,keepdims=True)#避免指数太大,导致计算太大,内存不够
for i in range(N):
# 计算函数值
soft_max = np.exp(result[i][y[i]])/np.sum(np.exp(result[i]))
# 计算出损失值
loss += -np.log(soft_max)
for j in range(C):
if j==y[i]:
dW[:,j] += -X[i].T
dW[:,j] += (X[i].T * np.exp(result[i][j])) / (np.sum(np.exp(result[i])))
loss/= N
loss += reg*np.sum(W*W)
dW /= N
dW += reg*2*W
#############################################################################
# 结束编码 #
#############################################################################
return loss, dW
def softmax_loss_vectorized(W, X, y, reg):
"""
Softmax损失函数,使用矢量计算版本.
输入,输出格式与softmax_loss_naive相同
"""
# 初始化损失值与梯度
loss = 0.0
dW = np.zeros_like(W)
#############################################################################
# 任务: 不使用显式循环计算softmax的损失值loss及其梯度dW. #
# 温馨提示: 如果不慎,将很容易造成数值上溢。别忘了正则化哟。 #
#############################################################################
# 训练样本数
num_train = X.shape[0]
# 计算函数值
s = np.dot(X, W)
# 关注最高分
scores = s-np.max(s, axis=1, keepdims=True)
# 使用指数函数来扩大相对比
scores_E = np.exp(scores)
# 求和得到总值
Z = np.sum(scores_E, axis=1, keepdims=True)
# 计算每一类的可能性
prob = scores_E/Z
# 真实标签标记
y_trueClass = np.zeros_like(prob)
y_trueClass[range(num_train), y] = 1.0
# 计算损失值
loss += -np.sum(y_trueClass*np.log(prob))/num_train+0.5*reg*np.sum(W*W)
# 计算梯度
dW += -np.dot(X.T, y_trueClass-prob)/num_train+reg*W
#############################################################################
# 结束编码 #
#############################################################################
return loss, dW
softmax.py
#-*- coding: utf-8 -*-
import numpy as np
from random import shuffle
from softmax_loss import *
class Softmax(object):
def __init__(self):
self.W = None
def train(self, X, y, learning_rate=1e-3, reg=1e-5, num_iters=100,
batch_size=200, verbose=False):
'''
使用最小批量梯度下降算法训练Softmax分类器
Parameters
----------
X : TYPE
数据
y : TYPE
数据类标
learning_rate : TYPE, optional
学习率. The default is 1e-3.
reg : TYPE, optional
权重衰减因子. The default is 1e-5.
num_iters : TYPE, optional
迭代次数. The default is 100.
batch_size : TYPE, optional
批大小. The default is 200.
verbose : TYPE, optional
是否显示中间过程. The default is False.
Returns
-------
loss_history : TYPE
DESCRIPTION.
'''
# 获得训练数据及维度
num_train, dim = X.shape
# 我们的计数是从0开始,因此10分类任务其y的最大值为9
num_classes = np.max(y) + 1
# 如果没有权重
if self.W is None:
# 随机初始化 W
self.W = 0.001 * np.random.randn(dim, num_classes)
# 储存每一轮的损失结果 W
loss_history = []
for it in range(num_iters):
X_batch = None
y_batch = None
#########################################################################
# 任务: #
# 从训练数据 X 中采样大小为batch_size的数据及其类标, #
# 并将采样数据及其类标分别存储在X_batch,y_batch中 #
# X_batch的形状为 (dim,batch_size) #
# y_batch的形状为 (batch_size) #
# 提示: 可以使用np.random.choice函数生成indices. #
# 重复采样要比非重复采样快许多 #
#########################################################################
# False表示不可以取相同数字
indices = np.random.choice(num_train, batch_size, False)
X_batch = X[indices, :]
y_batch = y[indices]
#########################################################################
# 结束编码 #
#########################################################################
# 计算损失及梯度
loss, grad = self.loss(X_batch, y_batch, reg)
loss_history.append(loss)
# 更新参数
#########################################################################
# 任务: #
# 使用梯度及学习率更新权重 #
#########################################################################
self.W = self.W - learning_rate*grad
#########################################################################
# 结束编码 #
#########################################################################
if verbose and it % 500 == 0:
print('迭代次数 %d / %d: loss %f' % (it, num_iters, loss))
return loss_history
def predict(self, X):
"""
使用已训练好的权重预测数据类标
Inputs:
- X:数据形状 (N,D) .表示N条数据,每条数据有D维
Returns:
- y_pred:形状为(N,) 数据X的预测类标,y_pred是一个长度维N的一维数组,
每一个元素是预测的类标整数
"""
y_pred = np.zeros(X.shape[0])
###########################################################################
# 任务: #
# 执行预测类标任务,将结果储存在y_pred #
###########################################################################
# 找到可能性最高的类别作为预测分类
y_pred = np.argmax(X.dot(self.W), axis=1)
###########################################################################
# 结束编码 #
###########################################################################
return y_pred
def loss(self, X_batch, y_batch, reg):
"""
Compute the loss function and its derivative.
Subclasses will override this.
Inputs:
- X_batch: A numpy array of shape (N, D) containing a minibatch of N
data points; each point has dimension D.
- y_batch: A numpy array of shape (N,) containing labels for the minibatch.
- reg: (float) regularization strength.
Returns: A tuple containing:
- loss as a single float
- gradient with respect to self.W; an array of the same shape as W
"""
return softmax_loss_vectorized(self.W, X_batch, y_batch, reg)