图像与机器学习-2-基础知识及cs231n/assignment1

part 1

机器学习基础知识:

包括线性回归,逻辑回归,交叉熵,softmax,KNN,神经网络中梯度的传递思想。关于线性回归和逻辑回归部分的知识,可以参考这个博客的内容,就不再累述:http://blog.csdn.net/viewcode/article/details/8794401

关于softmax的理解:

softmax是另一种误差函数的表现形式,可以叫做softmax-loss function.

loss的计算公式:



softmax梯度的求导(使用链式求导法,在two-layer-network中会使用到):



神经网络中的梯度的传递思想与上面softmax的链式求导法类似,逐级计算梯度然后一级一级传导。可以大大降低求梯度的难度。


part 2


cs231n/assignment1:

KNN:

原理:使用 k_nearest_neighbor分类器,实现对小型图像的识别,流程是:

1,载入数据:从cifar10数据库中随机抽取5000个样本作为训练集,500个样本作为测试集。

2,数据前处理:每个样本是一个32*32的彩色图片,一个像素由3个颜色组成,所以一张图片包含32×32×3=3072个数据,使用reshape函数,把每个样本的数据变成一个行向量(3072维),然后训练集就变成一个5000*3072的矩阵,测试集变成一个500*3072的矩阵。

3,计算距离矩阵:分别用三种方法(两层嵌套循环,一层循环,不使用循环)计算测试集中的样本与训练集中的样本在像素上的L2距离,存储在距离矩阵中(500*5000)。

     两层嵌套循环:
vector1=np.mat(X[i])
        vector2=np.mat(self.X_train[j])
        dists[i,j]=math.sqrt((vector1-vector2)*((vector1-vector2).T))

每次计算两个行向量的L2距离,存放在dists[i,j]中。

     一层循环:
p=np.mat(X[i])
      cT=self.X_train.T
      dists[i]=np.sqrt(np.square(p)*np.ones(cT.shape)+np.mat(np.ones(p.shape))*np.square(cT)-2*p*cT)

每次计算测试集一个样本(行向量)与训练集所有样本(矩阵)的L2距离,存放在dists[i]的行中。

     不使用循环:
a=np.mat(X)
    aT=np.mat(self.X_train.T)
    dists=np.sqrt(np.square(a)*np.ones(aT.shape)+np.ones(a.shape)*np.square(aT)-2*a*aT)

直接对测试集和训练集两个矩阵进行运算,不使用循环,dists[i,j]中存放的是第i个测试样本与第j个训练样本的L2距离。

4,类别预测:在这一步中,针对每个测试集中的样本,对其所对应的dists距离矩阵中的对应行向量中的距离排序(从小到大),然后选取前K(K是一个超参数)个最小的距离,然后返回对应的标签存放在closest_y中,然后对closest_y中元素进行统计分析,从中挑选出出现次数最多的标签,使用“多数赞成投票”法决定测试样本的标签的预测,最后返回到数组中:y_pred,其中存放所有测试样本的预测标签。

    代码段1:
order=np.argsort(dists[i]) #order is an array contains the index of array distance rank from mintomax
      for j in range(1,k+1):
        min=order[0,j-1] #order_k is the index of K-th value label
        closest_y.append(self.y_train[min]) #min is the min index of distance

实现功能:把dists[i]按从小到大排序,然后取前k个对应的标签存放到closest_y中。
  代码段2:
from collections import Counter
      c=Counter(closest_y).most_common(1)
      d=list(c[0])
      y_pred[i]=d[0] 

实现功能:统计closest_y中出现最多次数的标签给到y_pred[i]。
5,测试了K=1和等于K=5下识别的准确度:分别是

   k=1:Got 137 / 500 correct => accuracy: 0.274000

   k=5:Got 142 / 500 correct => accuracy: 0.284000
   可看出k=5的情况下准确度稍微高一点。
6,测试了计算dists矩阵的三种不同方式下耗费的计算时间:

   Two loop version took 57.856100 seconds
   One loop version took 25.614912 seconds
   No loop version took 0.358330 seconds
   可明显看出,向量和矩阵运算的使用明显加快了计算速度,特别是无循环下,直接用矩阵进行运算的速度超乎想象,可见矩阵的并行计算有很大的优势,的确是趋势。
7,交叉验证,最后一步,knn算法使用了交叉验证的方法来实现对超参数K的调谐,分别针对k_choices = [1, 3, 5, 8, 10, 12, 15, 20, 50, 100]这几个
超参数选项,分别使用交叉验证的方法反复计算多次,验证其所得到的预测准则度,然后找出效果最好的那个超参数k.
   代码段1:
X_train_folds=np.array_split(X_train,num_folds)
   y_train_folds=np.array_split(y_train,num_folds)

实现功能:把训练集均分为num_folds份。
   代码段2:
for k in k_choices:
      for i in range(num_folds):
        X_train_cross = np.array(X_train_folds[:i] + X_train_folds[i + 1:])
        y_train_cross = np.array(y_train_folds[:i] + y_train_folds[i + 1:])
        X_train_cross = X_train_cross.reshape(-1, X_train_cross.shape[2])
        y_train_cross = y_train_cross.reshape(-1)
        X_test_cross = np.array(X_train_folds[i])
        y_test_cross = np.array(y_train_folds[i])
        classifier = KNearestNeighbor()
        classifier.train(X_train_cross, y_train_cross)
        dists= classifier.compute_distances_no_loops(X_test_cross)
        y_test_pred = classifier.predict_labels(dists,k)
        num_correct = np.sum(y_test_pred == y_test_cross)   
        accuracy = float(num_correct) / y_test_cross.shape[0]
        if (k in k_to_accuracies.keys()):
            k_to_accuracies[k].append(accuracy)
        else:
            k_to_accuracies[k] = []
            k_to_accuracies[k].append(accuracy)

实现功能:循环数次,每次使用不同的K值,然后每个k值验证num_folds次,每次验证时,训练集的第i部分作为测试集,其余部分作为训练集,最后把结果存起来

  然后对结果(准确度)进行统计分析,可以绘制出一下的曲线:

SVM:

    这个算法的难点,主要是loss函数的计算和偏导数的计算,首先公式为:

L= (1/N)∑iLi + λR(W)

Li= ∑j≠yi max(0, (xiW)j−(xyiW)j+Δ)

其中:

λR(W):正则化惩罚,为什么要正则化,因为w不唯一,如果w正好能使得loss=0(最优权重),那么kw也能做到,为了得到唯一的W进行分类工作,我们可以添加一个正则化惩罚项。其最主要作用是防止过拟合,提高模型的泛化能力,因为如果产生了大数值的权重容易导致产生过大的loss,进而过拟合,所以正则化惩罚能有效地抑制大数组权重的产生。

(xiW)j:错误分类的得分,(xyiW)j:正确分类的得分,意味着对于每一张图像样本,正确分类的得分应该比错误分类的得分至少高ΔΔ的取值在实际中一般为1)。

梯度的公式:

WyiLi = - xiT(∑j≠yi1(xiWj- xiWyi +1>0)) + 2λWyi

WjLi = xiT 1(xiWj- xiWyi +1>0) + 2λWj , (j≠yi)

其中1()为逻辑函数,表达式为真为1,假为0.


代码段1

for i in xrange(num_train):
    scores = X[i].dot(W)
    correct_class_score = scores[y[i]]
    for j in xrange(num_classes):
      if j == y[i]:
        continue
      margin = scores[j] - correct_class_score + 1 # note delta = 1
      if margin > 0:
        loss += margin
        dW[:, y[i]] += -X[i, :]  
        dW[:, j] += X[i, :]     
  loss /= num_train
  dW /= num_train
  loss += 0.5 * reg * np.sum(W * W)
  dW += reg * W

实现功能:用循环的方式,求出lossdW

代码段2

scores = X.dot(W) 
  num_train = X.shape[0]
  num_classes = W.shape[1]
  scores_correct = scores[np.arange(num_train), y]   # 1 by N
  scores_correct = np.reshape(scores_correct, (num_train, 1))  # N by 1
  margins = scores - scores_correct + 1.0     # N by C
  margins[np.arange(num_train), y] = 0.0
  margins[margins <= 0] = 0.0
  loss += np.sum(margins) / num_train
  loss += 0.5 * reg * np.sum(W * W) 

实现功能:用对向量的操作,不适用循环语句,直接求出loss

代码段3

margins[margins > 0] = 1.0
  row_sum = np.sum(margins, axis=1)                  
  margins[np.arange(num_train), y] = -row_sum        
  dW += np.dot(X.T, margins)/num_train + reg * W  

实现功能:用对向量的操作,不适用循环语句,直接求出dW

代码段4

params = [(x,y) for x in learning_rates for y in regularization_strengths]
for lrate, regular in params:
    svm = LinearSVM()
    loss_hist = svm.train(X_train, y_train, learning_rate=lrate, reg=regular,num_iters=700, verbose=False)
    y_train_pred = svm.predict(X_train)
    accuracy_train = np.mean(y_train == y_train_pred)
    y_val_pred = svm.predict(X_val)
    accuracy_val = np.mean(y_val == y_val_pred)
    results[(lrate, regular)]=(accuracy_train, accuracy_val)
    if (best_val < accuracy_val):
        best_val = accuracy_val
        best_svm = svm

实现功能:svm算法中超参数的调谐,两个超参数:学习率和正则化惩罚系数:

learning_rates= [1.4e-7, 1.45e-7, 1.5e-7, 1.55e-7, 1.6e-7, 1.65e-7, 1.7e-7]

regularization_strengths= [3e4, 3.1e4, 3.2e4, 3.3e4, 3.4e4]

经过双重循环尝试遍所有可能的超参数组合,求出其对应的准确率,进行比较,可以找出准确率最高的一组超参数组合:

lr 1.400000e-07 reg 3.100000e+04 train accuracy: 0.375755 val accuracy: 0.401000

可见最好的超参数是学习率为 1.400000e-07,正则化惩罚系数为3.100000e+04,对应的准确率为40.1%.


Softmax:

softmaxsvm方法极其类似,唯一区别就是loss函数和梯度的计算方法不一样,svm中是Hingeloss,在softmax中替换成了交叉熵cross-entropyloss

Loss

L= -(1/N)∑ij1(k=yi)log(exp(fk-fmax)/∑jexp(fj-fmax))+ λR(W)

其中:-fmax是为了保证数值稳定性的问题,因为在计算过程中,exp(fyi)和 ∑jexp(fj)的值可能会变得非常大,大值数相除容易导致数值不稳定,所以要把这个大数值给剔除掉。λR(W)则是正则化惩罚,保证w的唯一性,抑制产生大数值的权重导致过拟合。

偏导:

WkL = -(1/N)∑i xiT(pi,m-Pm)+ 2λWk

其中:Pk= exp(fk-fmax/∑jexp(fj-fmax


因为和svm类似,所以softmaxsvm的代码段也很类似:

代码段1

dW_each = np.zeros_like(W)
  num_train, dim = X.shape
  num_class = W.shape[1]
  f = X.dot(W)   
  f_max = np.reshape(np.max(f, axis=1), (num_train, 1))   # N by 1
  prob = np.exp(f - f_max) / np.sum(np.exp(f - f_max), axis=1, keepdims=True) # N by C
  y_trueClass = np.zeros_like(prob)
  y_trueClass[np.arange(num_train), y] = 1.0
  for i in xrange(num_train):
      for j in xrange(num_class):    
          loss += -(y_trueClass[i, j] * np.log(prob[i, j]))    
          dW_each[:, j] = -(y_trueClass[i, j] - prob[i, j]) * X[i, :]
      dW += dW_each
  loss /= num_train
  loss += 0.5 * reg * np.sum(W * W)
  dW /= num_train
  dW += reg * W

实现功能:使用两层显示循环,计算lossdW

代码段2

num_train, dim = X.shape
  f = X.dot(W)
  f_max = np.reshape(np.max(f, axis=1), (num_train, 1)) 
  prob = np.exp(f - f_max) / np.sum(np.exp(f - f_max), axis=1, keepdims=True)
  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

实现功能:直接对向量进行计算,直接算出lossdW

代码段3

params = [(x,y) for x in learning_rates for y in regularization_strengths ]
for lrate, regular in params:
    softmax = Softmax()
    loss_hist = softmax.train(X_train, y_train, learning_rate=lrate, reg=regular,num_iters=700, verbose=True)
    y_train_pred = softmax.predict(X_train)
    accuracy_train = np.mean( y_train == y_train_pred)
    y_val_pred = softmax.predict(X_val)
    accuracy_val = np.mean(y_val == y_val_pred)
    results[(lrate, regular)] = (accuracy_train, accuracy_val)
    if(best_val < accuracy_val):
        best_val = accuracy_val
        best_softmax = softmax

实现功能:softmax算法中超参数的调谐,两个超参数:学习率和正则化惩罚系数:

learning_rates= [1.4e-7, 1.45e-7, 1.5e-7, 1.55e-7, 1.6e-7, 1.65e-7, 1.7e-7]

regularization_strengths= [3e4, 3.1e4, 3.2e4, 3.3e4, 3.4e4]

经过双重循环尝试遍所有可能的超参数组合,求出其对应的准确率,进行比较,可以找出准确率最高的一组超参数组合:

lr 1.400000e-07 reg 3.400000e+04 train accuracy: 0.340592 val accuracy: 0.367000

可见最好的超参数是学习率为 1.400000e-07,正则化惩罚系数为3.400000e+04,对应的准确率为36.7%.

二层神经网络:

神经网络基本结构示意:




        这个应用旨在学会搭建一个最小系统的神经网络:只包含一个输入层通过一个隐含层(一层神经元细胞)的神经网络,然后是输出层。

神经网络的具体训练过程如下:

1,参数设置:迭代次数N-iteration,Cifar-10中取出的样本库50000个,每次迭代抽样容量:batch-size

2,样本库预处理:把样本图片(32*32*3)正则化,即所有图片减去平均图像,可以控制图片矩阵的大小在一个范围内,矩阵reshape为行向量3072维。

3,初始化训练参数设置。

4,开始迭代过程:从样本中随机抽取batch-size个图片,输入神经网络,前向传导(hiddenlayer中神经元使用Relu作为激活函数),得到loss,然后反向传导,

反向逐级计算梯度,然后得到losssoftmaxloss)对W1W2的偏导数,并用其更新W1W2(随机梯度下降法)。

5,进行下一次迭代:从样本中随机抽取另外batch-size个图片,重复上面步骤,更新W1W2以使得loss趋于极小值点。

6,在迭代过程中,每间隔一个纪元epochepoch=50000/batch-size)次迭代,会进行一次训练准确度的检查,会计算并记录此时神经网络训练出的训练误差和验证误差,并且为了防止迭代到后期,学习率过大的问题,还会对学习率进行衰减。

对于迭代过程中的前向传导和反向传导:


    

上图中给出了迭代过程中数据在神经网络中前向传导和反向传导的公式。


neural-net.py中代码实现:

代码段1:

z1=X.dot(W1)+b1#(H)
    a1=np.zeros_like(z1)
    a1=np.maximum(z1,0)
    scores=a1.dot(W2)+b2
实现功能:计算出前向传导过程的中间值和最终输出。

代码段2:

scores = scores - np.reshape(np.max(scores,axis=1),(N,-1))
    p = np.exp(scores)/np.reshape(np.sum(np.exp(scores),axis=1),(N,-1))
    loss = -sum(np.log(p[np.arange(N),y]))/N
    loss += 0.5*reg*np.sum(W1*W1)+0.5*reg*np.sum(W2*W2)
实现功能:前向传导过程中的softmax-loss计算,并且对loss进行w1和w2正则化。
代码段3:

  dldf=p
    dldf[range(N),y]-=1.0
    dldf/=N
    dfdw2=a1
    dW2=np.dot(dfdw2.T,dldf)
    dh2 = np.sum(dldf,axis=0,keepdims=False)
    dfda1=W2 
    dlda1=np.dot(dldf,dfda1.T)
    dldz1=dlda1
    dldz1[a1<=0]=0
    dh1 = np.sum(dldz1,axis=0,keepdims=False)
    dz1dw1=X
    dW1=np.dot(dz1dw1.T,dldz1)
    dW2 += reg*W2
    dW1 += reg*W1
    
    grads['W1']=dW1
    grads['b1']=dh1
    grads['W2']=dW2
    grads['b2']=dh2
实现功能:反向传导,逐级计算梯度,计算出loss对w1,w2梯度(正则化)。

代码段4;

sample_index = np.random.choice(num_train, batch_size)
      X_batch = X[sample_index, :]   # select the batch sample
      y_batch = y[sample_index]      # select the batch label
实现功能:从50000个样本库中随机抽取batch-size个样本,作为训练集。

代码段5:

W1 = grads['W1']
      b1 = grads['b1']
      W2 = grads['W2']
      b2 = grads['b2']


      self.params['W1'] -= learning_rate*W1
      self.params['b1'] -= learning_rate*b1
      self.params['W2'] -= learning_rate*W2
      self.params['b2'] -= learning_rate*b2
实现功能:用梯度更新W1和W2,随机梯度下降法.

代码段6:

z1=X.dot(self.params['W1'])+self.params['b1']#(H)
    a1=np.zeros_like(z1)
    a1=np.maximum(z1,0)
    scores=a1.dot(self.params['W2'])+self.params['b2']
    y_pred = np.argmax(scores, axis=1)
实现功能:预测样本的类型。
two-layer-net.ipyn文件:

代码段1:

best_valacc=-1.0
input_size = 32 * 32 * 3
num_classes = 10
#hidden_size = 50
hidden_size = 32 * 32 * 3
learn_rate =[7.2e-4]
#learning_rate_decay=[0.94,0.95,0.93]
reg=[1e-3]
results = {}
params = [x1 for x1 in learn_rate ]
#          for x3 in learning_rate_decay for x4 in reg]
for learn_rate in params:
    net = TwoLayerNet(input_size, hidden_size, num_classes)

# Train the network
    stats = net.train(X_train, y_train, X_val, y_val,
            num_iters=6400, batch_size=128,
            learning_rate =7.2e-4, learning_rate_decay=0.95,
            reg=1e-3, verbose=True)

# Predict on the validation set
    val_acc = np.mean(net.predict(X_val) == y_val)
    results[learn_rate] =val_acc 
    if val_acc>best_valacc:
        best_valacc = val_acc
        best_net = net


for learn_rate in sorted(results):
    val_accuracy = results[(learn_rate)]
    print 'learn_rate %e val accuracy: %f' % (
                learn_rate,  val_accuracy)

print 'best validation accuracy achieved during cross-validation: %f' % best_valacc
实现功能:反复修改神经网络的初始化参数和超参数,调试出具有最高分类精度的超参数。
结果 :

按照上面代码中的参数设置最终实现的精度为54.7%.




猜你喜欢

转载自blog.csdn.net/lidawei0124/article/details/78664531