LinearClassification,线性分类中分值函数的代码实现。
import numpy as np
D = 784 #数据维度 28*28*1
K = 10 #类型数 10个数字
N = 128 #样本数量
X = np.random.randn(N,D) #数据矩阵,每一行一个样本
# print(X)
W = 0.01*np.random.randn(D,K)
# print(W)
b = np.zeros((1,K))
# print(b)
scores = np.dot(X,W) + b
#dot是矩阵乘法
#广播机制,numpy自动识别意图,不必将b转成N*K大小的矩阵。
使用上文代码,继续编写。
构造指数化分值矩阵,样本归一化,负对数损失函数。
y = np.random.randint(K,size= N)# y为样本标签
# np.random.randint和random.randint有不同,前者区间为前闭后开,后者区间为前闭后闭
# np.random.randint(K,size = K)第一个参数为区间[0,K),第二个参数为矩阵列数,即大小为N的向量
#指数化分治矩阵:使用以e为底的指数函数,将分值由实数映射为正实数。
exp_scores = np.exp(scores)
#样本归一化系数
exp_scores_sum = np.sum(exp_scores, axis=1)
# axis=1表示,对于N*K的矩阵,每一列不变,将每一行的数相加。
#样本真实类别的归一化分值
corect_probs = exp_scores[range(N),y]/exp_scores_sum
#负对数损失函数
corect_logprobs = -np.log(corect_probs)
以f(x)= x^2/2 为例
alpha = 1 #二次项系数
epslon = 0.5 #学习率
iter_num = 100 #循环次数
x0 =1 #输入值
def f(x):
return alpha*x**2/2
def df(x):
return alpha*x
def GD_update(x):
return x-epslon*df(x)
x = x0
for k in range(iter_num):
x = GD_update(x)
print(k,x,f(x),df(x))
正则化也是重要的概念,他能够控制模型额学习容量,减弱过拟合的风险。
这里采用ReLU激活函数,原因如下:
1、sigmoid激活函数在输入比较大和负数的时候,函数值接近于1或者0,处于饱和状态,梯度为0。梯度为0是很危险的,不能够继续进行有效的学习。而现在也很少使用sigmoid作为激活函数了。
2、tanh激活函数是sigmoid函数的放大平移,虽然也存在饱和区域,但是效果更好些。
代码中,dim1与dim2为超参数。这里我们就要考虑到,参数数量越多,模型学习容量越大,越容易导致过拟合,这就需要正则化。通常正则化是权重参数的L2范数。
import numpy as np
D = 784 #28*28*1数据维度
K = 10 #类别数
N = 128 #样本数量
dim1 = 128 #隐含层宽度
dim2 = 36
W1 = 0.01 * np.random.randn(D,dim1)
b1 = np.zeros((1,dim1))
W2 = 0.01*np.random.randn(dim1,dim2)
b2 = np.zeros((1,dim2))
W3 = 0.01*np.random.randn(dim2,K)
b3 = np.zeros((1,K))
X = np.random.randn(N,D)# 数据矩阵,每行一个样本
hidden_layer1 = np.maximum(0,np.dot(X,W1)+b1)
#ReLU激活函数激活
hidden_layer2 = np.maximum(0,np.dot(hidden_layer1,W2)+b2)
#ReLU激活函数激活
scores = np.dot(hidden_layer2,W3)+b3
#输出层不需要激活函数