在現實任務中,原始樣本空間中可能不存在這樣可以將樣本正確分為兩類的超平面,但是我們知道如果原始空間的維數是有限的,也就是說屬性數是有限的,則一定存在一個高維特征空間能夠將樣本划分。
事實上,在做任務中,我們並不知道什么樣的核函數是合適的。但是核函數的選擇卻對支持向量機的性能有着至關重要的作用。如果核函數選擇不合適,則意味着樣本映射到一個不合適的特征空間,這樣就有可能導致性能不佳。故“核函數選擇”是非常重要的一項任務。
對於線性數據集的分類來說,我們當然會選擇線性核函數。但如果要分割非線性數據集,我們該如何做呢?答案是,我們可以改變損失函數中的核函數。我們今天就以高斯核函數來進行案例說明:
#導入庫 import matplotlib.pyplot as plt import numpy as np import tensorflow as tf from sklearn import datasets sess=tf.Session() #生成模擬數據:得到兩個同心圓數據,每個不同的環代表不同的類,分為類-1或者1 (x_vals,y_vals)=datasets.make_circles(n_samples=500,factor=.5,noise=.1) y_vals=np.array([1 if y==1 else -1 for y in y_vals]) class1_x=[x[0] for i,x in enumerate(x_vals) if y_vals[i]==1] class1_y=[x[1] for i,x in enumerate(x_vals) if y_vals[i]==1] class2_x=[x[0] for i,x in enumerate(x_vals) if y_vals[i]==-1] class2_y=[x[1] for i,x in enumerate(x_vals) if y_vals[i]==-1] #聲明批量大小、占位符以及變量b batch_size=250 x_data=tf.placeholder(shape=[None,2],dtype=tf.float32) y_target=tf.placeholder(shape=[None,1],dtype=tf.float32) prediction_grid=tf.placeholder(shape=[None,2],dtype=tf.float32) b=tf.Variable(tf.random_normal(shape=[1,batch_size])) #創建高斯函數 gamma=tf.constant(-50.0) dist=tf.reduce_sum(tf.square(x_data),1) dist=tf.reshape(dist,[-1,1]) sq_dists=tf.add(tf.subtract(dist,tf.multiply(2.,tf.matmul(x_data,tf.transpose(x_data)))),tf.transpose(dist)) my_kernel=tf.exp(tf.multiply(gamma,tf.abs(sq_dists))) #PS:線性核函數的表達式可以為:my_kernel=tf.matmul(x_data,tf.transpose(x_data)) #聲明對偶問題,為了最大化,這里采用最小損失函數的負數:tf.negative() model_output=tf.matmul(b,my_kernel) first_term=tf.reduce_sum(b) b_vec_cross=tf.matmul(tf.transpose(b),b) y_target_cross=tf.matmul(y_target,tf.transpose(y_target)) second_term=tf.reduce_sum(tf.multiply(my_kernel,tf.multiply(b_vec_cross,y_target_cross))) loss=tf.negative(tf.subtract(first_term,second_term))
#創建預測函數和准確度函數 rA=tf.reshape(tf.reduce_sum(tf.square(x_data),1),[-1,1]) rB=tf.reshape(tf.reduce_sum(tf.square(prediction_grid),1),[-1,1]) pred_sq_dist=tf.add(tf.subtract(rA,tf.multiply(2.,tf.matmul(x_data,tf.transpose(prediction_grid)))),tf.transpose(rB)) pred_kernel=tf.exp(tf.multiply(gamma,tf.abs(pred_sq_dist))) prediction_output=tf.matmul(tf.multiply(tf.transpose(y_target),b),pred_kernel) prediction=tf.sign(prediction_output-tf.reduce_mean(prediction_output)) accuracy=tf.reduce_mean(tf.cast(tf.equal(tf.squeeze(prediction),tf.squeeze(y_target)),tf.float32)) #創建優化器 my_opt=tf.train.GradientDescentOptimizer(0.001) train_step=my_opt.minimize(loss) #初始化變量 init=tf.global_variables_initializer() sess.run(init) #迭代訓練,記錄每次迭代的損失向量和准確度 loss_vec=[] batch_accuracy=[] for i in range(7500): rand_index=np.random.choice(len(x_vals),size=batch_size) rand_x=x_vals[rand_index] rand_y=np.transpose([y_vals[rand_index]]) sess.run(train_step,feed_dict={x_data:rand_x,y_target:rand_y}) temp_loss=sess.run(loss,feed_dict={x_data:rand_x,y_target:rand_y}) loss_vec.append(temp_loss) acc_temp=sess.run(accuracy,feed_dict={x_data:rand_x,y_target:rand_y,prediction_grid:rand_x}) batch_accuracy.append(acc_temp) if(i+1)%500==0: print('step#'+str(i+1)) print('loss='+str(temp_loss)) #創建數據點網格用於后續的數據空間可視化分類 x_min,x_max=x_vals[:,0].min()-1,x_vals[:,0].max()+1 y_min,y_max=x_vals[:,1].min()-1,x_vals[:,1].max()+1 xx,yy=np.meshgrid(np.arange(x_min,x_max,0.02), np.arange(y_min,y_max,0.02)) grid_points=np.c_[xx.ravel(),yy.ravel()] [grid_predictions]=sess.run(prediction,feed_dict={x_data:rand_x, y_target:rand_y, prediction_grid:grid_points}) grid_predictions=grid_predictions.reshape(xx.shape)
#繪制預測結果 plt.contourf(xx,yy,grid_predictions,cmap=plt.cm.Paired,alpha=0.8) plt.plot(class1_x,class1_y,'ro',label='得病') plt.plot(class2_x,class2_y,'kx',label='沒得病') plt.legend(loc='lower right') plt.ylim([-1.5,1.5]) plt.xlim([-1.5,1.5]) plt.show() #繪制批量結果准確度 plt.plot(batch_accuracy,'k-',label='精確度') plt.title('批量精確度') plt.xlabel('迭代次數') plt.ylabel('精確度') plt.legend(loc='lower right') plt.show() #繪制損失函數 plt.plot(loss_vec,'k-') plt.title('損失函數/迭代') plt.xlabel('迭代次數') plt.ylabel('損失誤差') plt.show()
訓練效果與分類結果:
更多技術干貨請關注: