4 แบบฝึกหัด

“Try not to become a man of success,
but rather try to become a man of value.”

—Albert Einstein

“อย่าพยายามเป็นคนประสบความสำเร็จ
แต่ให้พยายามเป็นคนที่มีคุณค่า.”

—อัลเบิร์ต ไอน์สไตน์

4.0.0.0.1 แบบฝึกหัด

จงสร้างข้อมูลหนึ่งมิติขึ้นมา (อาจใช้คำสั่ง เช่น np.random.normal) และใช้วิธีการประมาณความหนาแน่นแก่น (สมการ \(\eqref{eq: KDE shell}\) และ \(\eqref{eq: KDE kernel}\)) เพื่อประมาณความหนาแน่นความน่าจะเป็น จากข้อมูลนั้น โดยทดลองค่า \(\sigma\) หลาย ๆ ค่า. สังเกตผล อภิปราย และสรุป.

รายการ [code: kde] แสดงโปรแกรมวิธีการประมาณความหนาแน่นแก่น. ตัวอย่างการเรียกใช้ เช่น

datax = np.random.normal(3, 2, 100).reshape((1,-1))
xs = np.linspace(-2, 8, 50).reshape((1,-1))
pdx = kde(xs, datax, sigma=1)
plt.plot(xs[0,:], pdx[0,:], 'k')

บรรทัดแรกเป็นคำสั่งเพื่อสร้างข้อมูล datax ขึ้นมา จากการแจกแจงแบบเกาส์เซียน จำนวน \(100\) จุดข้อมูล โดยมีค่าเฉลี่ยเป็น \(3\) และค่าเบี่ยงเบนมาตราฐานเป็น \(2\). บรรทัดที่สอง สร้างค่า \(x\) ที่ต้องการถาม และบรรทัดที่สาม คือการเรียกโปรแกรม kde เพื่อประมาณความหนาแน่นความน่าจะเป็นของข้อมูล datax. บรรทัดสุดท้ายเป็นการวาดกราฟแสดงความหนาแน่นที่ค่าอินพุตต่าง ๆ. ดูตัวอย่างจากรูป [fig: kde sigma's].

def kde(x, kx, sigma=1):
    '''
    x: D x Nx
    kx: D x Nk; D - # dimensions, Nk - # datapoints
    '''
    N = x.shape[1]
    px = np.zeros((1, N))
    norm = 1/N * 1/np.sqrt(2*np.pi*sigma**2)
    
    for n in range(N):
        distn = np.sum((x[:,[n]] - kx)**2, axis=0) # (Nk, )
        texn = np.exp(-distn/(2*sigma**2)) # (Nk,)
        px[0,n] = norm * np.sum(texn)
        
    return px
4.0.0.0.2 แบบฝึกหัด

จงสร้างข้อมูลสองมิติขึ้นมา โดยอาจใช้คำสั่ง เช่น

mu = [6, 9]
cov = [[8, -5], [-5, 9]]
x = np.random.multivariate_normal(mu, cov, 500).reshape((2,-1))

เมื่อ mu และ cov แทนค่าเฉลี่ยและค่าความแปรปรวนร่วมเกี่ยว ตามลำดับ และสร้างเป็นข้อมูลสองมิติจำนวน \(500\) จุดข้อมูล. และใช้วิธีการประมาณความหนาแน่นแก่น (สมการ \(\eqref{eq: KDE shell}\) และ \(\eqref{eq: KDE kernel}\)) เพื่อประมาณความหนาแน่นความน่าจะเป็น จากข้อมูลนั้น โดยทดลองค่า \(\sigma\) หลาย ๆ ค่า. สังเกตผล อภิปราย และสรุป.

รูป 2 แสดงตัวอย่างข้อมูลสองมิติที่สร้างขึ้น และค่าความหนาแน่นที่ประมาณออกมา.

ตัวอย่างการประมาณค่าความหนาแน่นความน่าจะเป็นสำหรับข้อมูลสองมิติ. ภาพซ้าย แสดงจุดข้อมูลตัวอย่าง. ภาพขวา แสดงค่าประมาณความหนาแน่นความน่าจะเป็นของข้อมูล. ระดับสีแทนค่าความหนาแน่นความน่าจะเป็น ซึ่งค่าแสดงด้วยแถบสีด้านข้าง. ตัวอย่างการประมาณค่าความหนาแน่นความน่าจะเป็นสำหรับข้อมูลสองมิติ. ภาพซ้าย แสดงจุดข้อมูลตัวอย่าง. ภาพขวา แสดงค่าประมาณความหนาแน่นความน่าจะเป็นของข้อมูล. ระดับสีแทนค่าความหนาแน่นความน่าจะเป็น ซึ่งค่าแสดงด้วยแถบสีด้านข้าง.
4.0.0.0.3 แบบฝึกหัด

แบบฝึกหัดนี้ เราจะศึกษารูปปฐมของซัพพอร์ตเวกเตอร์แมชชีน. จงสร้างข้อมูลขึ้นมาจำนวน \(200\) จุดข้อมูล โดยเป็นกลุ่มบวกและกลุ่มลบอย่างละครึ่ง จุดข้อมูลอยู่ในปริภูมิสองมิติ และข้อมูลสามารถแบ่งแยกได้อย่างสมบูรณ์เชิงเส้น เช่น ข้อมูลที่แสดงในรูป 3. แล้วแก้ปัญหาในรูปปฐมของซัพพอร์ตเวกเตอร์แมชชีน เพื่อหาอภิระนาบแบ่งแยก นั่นคือ หาค่าพารามิเตอร์ \(\boldsymbol{w}\) และ \(b\) ดังแสดงในรูป 4.

ทบทวนปัญหาปฐม สำหรับข้อมูลที่สามารถแบ่งแยกได้โดยสมบูรณ์เชิงเส้น คือ \[\begin{eqnarray} \underset{\boldsymbol{w}, b}{\mathrm{minimize}} & \frac{1}{2} \boldsymbol{w}^T \boldsymbol{w} & \nonumber \\ \mbox{s.t.} & y_i (\boldsymbol{w}^T \boldsymbol{x}_i + b) \geq 1 & \mbox{ for } i =1, \ldots, N. \nonumber \end{eqnarray}\]

หมายเหตุ ปัญหานี้ เราจะใช้ฟังก์ชันเอกลักษณ์เป็นลักษณะสำคัญ นั่นคือ \(\boldsymbol{z} = \phi(\boldsymbol{x}) = \boldsymbol{x}\) (ซึ่งเทียบเท่าการใช้เคอร์เนลเชิงเส้น \(k(\boldsymbol{x}, \boldsymbol{x}') = \boldsymbol{x}^T \boldsymbol{x}'\)).

เราอาจสามารถแก้ปัญหาได้ด้วยวิธีการลงโทษ เช่นอาจกำหนดฟังก์ชันลงโทษ เป็น \[P(\boldsymbol{w}, b) = \sum_i \mathrm{relu}\left(1 - y_i \cdot (\boldsymbol{w}^T \boldsymbol{x}_i + b)\right)\] เมื่อ \[\begin{eqnarray} \mathrm{relu}(a) = \left\{ \begin{array}{ll} a & \mbox{ เมื่อ } a \geq 0, \\ 0 & \mbox{ หากเป็นกรณีอื่น} . \end{array} \right. \nonumber \end{eqnarray}\]

จากปัญหาปฐมของซัพพอร์ตเวกเตอร์แมชชีน ตัวอย่างคำสั่งข้างล่าง

la = 100
loss_adaptor = lambda wb: loss(wb[:2], wb[2], la)[0,0]
dloss_adaptor = lambda wb: dloss(wb[:2], wb[2], la)
wb0 = np.zeros((3,1))
wbo, gd_losses, wbs = gd(dloss_adaptor, wb0, loss_adaptor, 
    step_size = 0.0001, Nmax = 5000)

ใช้ค้นหาอภิระนาบ (ระบุด้วย \(\boldsymbol{w}\) และ \(b\) ซึ่งคือ wbo[:2] และ wbo[2] ตามลำดับ). โปรแกรม loss และ dloss รวมถึงโปรแกรมอื่นที่เกี่ยวข้องกำหนดดังแสดงในรายการ [code: svm primal gd]. โปรแกรม gd (แสดงในรายการ [code: gd as function]) คำนวณวิธีลงเกรเดียนต์.

relu = lambda a: (a >= 0)*a
drelu = lambda a: (a >= 0)*1

def loss(w, b, la):
    term1 = 0.5 * np.dot(w.transpose(), w)
    term2 = relu(1 - datay * (np.dot(w.transpose(), datax) + b))
    return  term1 + la * np.sum(term2)

def dloss(w, b, la):
    N = datax.shape[1]
    term1 = np.vstack((w,0))
    dc = - datay * np.vstack((datax, np.ones( (1, N))))
    term2 = drelu(1 - datay*(np.dot(w.transpose(),datax) + b))*dc
    sum_dpenalty = np.sum(term2, axis=1).reshape((-1,1))
    
    return  term1 + la * sum_dpenalty
def gd(grad, v0, g, step_size=0.01, Nmax=100, tol=1e-6):
    '''
    grad: gradient function
    v0: initial value
    g: objective function
    '''    
    losses = []
    vs = np.zeros(v0.shape)
    v = v0
    gradv = grad(v)
    
    for i in range(Nmax):
        v = v - step_size * gradv
        gradv = grad(v)
        
        loss = g(v)
        losses.append(loss)
        vs = np.hstack((vs, v))

        eps = np.linalg.norm(gradv)
        if  eps <= tol:
            print('Reach termination criteria')
            break

    return v, losses, vs
ตัวอย่างข้อมูลที่สามารถแบ่งแยกได้โดยสมบูรณ์เชิงเส้น.
ตัวอย่างอภิระนาบที่หาได้จากรูปปฐม สำหรับข้อมูลที่สามารถแบ่งแยกได้โดยสมบูรณ์เชิงเส้น. เส้นทึบสีน้ำเงิน แสดงอภิระนาบที่หาได้.

4.0.0.1 มอดูลไซไพ.

หัวข้อนี้ แนะนำมอดูลไซไพ (Scipy) ซึ่งมีเครื่องมือหลายอย่างสำหรับงานคำนวณทางวิทยาศาสตร์ รวมถึงมอดูล optimize. มอดูล optimize มีเครื่องมือการหาค่าดีที่สุดอยู่หลายวิธี. แม้วิธีลงเกรเดียนต์ (หัวข้อ [sec: opt grad desc]) เป็นวิธีการที่ใช้งานได้ แต่ในทางปฏิบัติ มีวิธีที่มีประสิทธิภาพมากกว่าวิธีลงเกรเดียนต์อยู่มากมาย และด้วยแบบจำลอง optimize เราสามารถไปใช้วิธีเหล่านั้นได้ โดยไม่ต้องใช้เวลาในการศึกษารายละเอียดของวิธีเหล่านั้นมากนั้น. มอดูล optimize สามารถนำเข้าได้ด้วยคำสั่ง

from scipy import optimize

แบบฝึกหัด 1.0.0.1.1 จะแก้ปัญหาเดียวกับแบบฝึกหัด 1.0.0.0.3 เพียงแต่จะใช้เครื่องมือจากแบบจำลอง optimize แทนวิธีลงเกรเดียนต์.

4.0.0.1.1 แบบฝึกหัด

เช่นเดียวกับแบบฝึกหัด 1.0.0.0.3 จงสร้างข้อมูลขึ้นมาจำนวน \(200\) จุดข้อมูล โดยเป็นกลุ่มบวกและกลุ่มลบอย่างละครึ่ง จุดข้อมูลอยู่ในปริภูมิสองมิติ และข้อมูลสามารถแบ่งแยกได้อย่างสมบูรณ์เชิงเส้น แล้วแก้ปัญหาในรูปปฐมของซัพพอร์ตเวกเตอร์แมชชีน เพื่อหาอภิระนาบแบ่งแยก.

ศึกษาการเขียนโปรแกรมด้วยการใช้มอดูล optimize (ดังแสดงในตัวอย่างของแบบฝึกหัดนี้) เปรียบเทียบกับด้วยวิธีลงเกรเดียนต์ (แบบฝึกหัด 1.0.0.0.3) ทดลองใช้งาน สังเกตผล อภิปราย และสรุป.

ตัวอย่างคำสั่งข้างล่าง ฝึกแบบจำลอง และรายงานผลอภิระนาบที่พบ

svm = primal_SVM()
svm.phi = lambda xq: xq # identity projection
res = svm.train(datax, datay)
print('w=', svm.wopt.T)
print('b=', svm.bopt)

โดย บรรทัดแรก เป็นการสร้างตัวแปรวัตถุ svm จากคลาส primal_SVM ซึ่งแสดงในรายการ [code: gd as function]. บรรทัดที่สอง กำหนดฟังก์ชันลักษณะสำคัญเป็นฟังก์ชันเอกลักษณ์. บรรทัดที่สาม เป็นการฝึกซัพพอร์ตเวกเตอร์แมชชีน ด้วยข้อมูล datax และ datay. ผลลัพธ์ที่ได้จากการฝึกจะสรุปออกมาเป็นค่าของพารามิเตอร์ svm.wopt และ svm.bopt ที่ใช้บรรยายอภิระนาบ. สังเกตว่า เมท็อด train มีการเรียกใช้

res = optimize.minimize(minf, wb0, method='SLSQP', jac=gradf,
          constraints=ineq_cons, options=options)

ซึ่งเป็นเครื่องมือการหาค่าดีที่สุด โดยระบุวิธีเป็น 'SLSQP' (ศึกษารายละเอียดเพิ่มเติมจากเวปไซต์ของไซไพ หากสนใจ) โดยภายใน เมท็อด train ได้กำหนดค่า minf และ gradf ซึ่งคือ ฟังก์ชันจุดประสงค์ และฟังก์ชันเกรเดียนต์ ตามลำดับ พร้อมทั้งข้อจำกัดแบบอสมการ ineq_cons.

หมายเหตุ การใช้งานจริง สิ่งที่ต้องการ คือการทำนายกลุ่มของข้อมูล. เมท็อด decision_score ใช้คำนวณค่าฟังก์ชันแบ่งแยก ซึ่งจะนำไปใช้ตัดสินกลุ่ม. ส่วนค่าของ \(\boldsymbol{w}\) และ \(b\) นั้น เป็นรายละเอียดภายใน ไม่จำเป็นต้องรายงาน และการใช้งานจริงของซัพพอร์ตเวกเตอร์แมชชีน ก็จะไม่มีการคำนวณค่า \(\boldsymbol{w}\) ออกมา เพราะว่า รูปแบบการคำนวณถูกแปลงไป เพื่อใช้ประโยชน์จากฟังก์ชันเคอร์เนล. ดูแบบฝึกหัด 1.0.0.1.2 สำหรับโปรแกรมซัพพอร์ตเวกเตอร์แมชชีนที่ใช้งานจริง.

class primal_SVM:
    def __init__(self):
        self.bopt = None
        self.wopt = None
        self.phi = None
            
    def train(self, x, y, wb0, 
                    options={'ftol': 1e-9, 'disp': True}):
        assert (x.shape[1] == y.shape[1]) and (y.shape[0] == 1) 

        N = x.shape[1]
        # projected x to z
        z = self.phi(x)
        assert z.shape[1] == x.shape[1]         
        D = z.shape[0] # number of projected dimensions
        
        if wb0 is None: # w: (D,1), b: scalar
            wb0 = np.random.normal(0, 1, D+1) 

        def primal_ineq(w, b):
            w = w.reshape((-1,1))
            b = np.asscalar(b)            
            cineq = y.reshape((1,-1)) * \
               (np.dot(w.T,z.reshape((D,-1))) + b) -1  
            return cineq.reshape((-1,)) # (M,) 
            
        def primal_dc(w, b):
            gradw = y.reshape((1,-1)) * z.reshape((D,-1))
            gradb = y.reshape((1,-1))                    
            dc = np.hstack( (gradw.T, gradb.T) )            
            return dc.reshape((-1,D+1)) # (M,D+1) 
        
        # inequality constraints: y[i] * ( w.T x[i] + b)-1 >= 0 
        ineq_cons = {'type': 'ineq', 
               'fun' : lambda wb: primal_ineq(wb[:-1], wb[-1]),     
               'jac' : lambda wb: primal_dc(wb[:-1], wb[-1])} 
        
        # Objective        
        def primal_f(wb): # primal loss: minimization form
            w = wb[:-1].reshape((-1,1)) # D x 1
            L = 0.5 * np.dot(w.T, w) # scalar
            return np.asscalar(L)

        def primal_grad(wb): # gradient of primal loss
            w = wb[:-1].reshape((-1,1)) # D x 1
            pgrad = np.vstack((w, 0))            
            return pgrad.reshape((-1,))   # (D,)
        
        minf = lambda wb: primal_f(wb)
        gradf =  lambda wb: primal_grad(wb)
        res = optimize.minimize(minf, wb0, method='SLSQP', 
          jac=gradf, constraints=ineq_cons, options=options)
        
        if not res.success:
            return res

        # Train succeeds.
        self.wopt = res.x[:-1].reshape((-1,1))
        self.bopt = res.x[-1]
        return res
    
    def decision_score(self, x):        
        # Project to feature space
        z = self.phi(x)
        assert z.shape[0] == self.wopt.shape[0]

        # Compute the score
        yhat = np.dot(self.wopt.T, z) + self.bopt
        return yhat        # 1 x N
4.0.0.1.2 แบบฝึกหัด

ปัญหาเดียวกับแบบฝึกหัด 1.0.0.1.1 แต่แก้ปัญหาจากปัญหาคู่. \[\begin{eqnarray} \underset{\boldsymbol{\alpha}}{\mathrm{maximize}} & \sum_{i=1}^N \alpha_i - \frac{1}{2}\sum_{i=1}^N \sum_{j=1}^N \alpha_i \alpha_j y_i y_j k(\boldsymbol{x}_i, \boldsymbol{x}_j) \nonumber \\ \mbox{s.t.} & \nonumber \\ & \begin{array}{ll} \sum_{i=1}^N \alpha_i y_i = 0, & \\ 0 \leq \alpha_i \leq C & \mbox{ สำหรับ } i =1, \ldots, N. \end{array} \nonumber \end{eqnarray}\] เนื่องจาก ปัญหาคู่ สำหรับกรณีแบ่งแยกได้โดยสมบูรณ์ กับกรณีทั่วไปต่างกัน เพียงข้อกำหนด \(\alpha_i \leq C\) ซึ่งหากเลือกค่า \(C\) ขนาดใหญ่ก็จะให้ผลแบบเดียวกับกรณีแบ่งแยกได้โดยสมบูรณ์ ตัวอย่างข้างล่างนี้ จึงใช้รูปแบบที่มีอภิมานพารามิเตอร์ \(C\).

โปรแกรมในรายการ [code: cSVM] แสดงตัวอย่างโปรแกรมซัพพอร์ตเวกเตอร์แมชชีน. สังเกต วิธีการเขียนโปรแกรมจะใช้การทำเวคตอไรเซชั่นมากที่สุดเท่าที่จะทำได้ เนื่องจากประสิทธิภาพการคำนวณและความยืดหยุ่น. ตัวอย่าง เช่น หากการคำนวณค่าพารามิเตอร์ \(b\) คือ \(b_o = y_i - \sum_{j \in S} \alpha_j y_j k(\boldsymbol{x}_j, \boldsymbol{x}_i)\) สำหรับ \(i \in \{j: 0 < \alpha_j < C \}\). นั่นคือ เทียบเท่า \(b_o = y_i - (\boldsymbol{\alpha}^T \odot \boldsymbol{y}) \cdot \boldsymbol{K}_{:,i}\) สำหรับ \(i \in \{j: 0 < \alpha_j < C \}\). หมายเหตุ โปรแกรม [code: cSVM] คำนวณค่า \(b\) ด้วยค่าเฉลี่ย ซึ่งจะซับซ้อนกว่าตัวอย่างการทำเวคตอไรเซชั่นที่อภิปรายข้างต้นเล็กน้อย.

คล้ายกับตัวอย่างในแบบฝึึกหัด 1.0.0.1.1 คำสั่งข้างล่าง แสดงตัวอย่างการฝีก และการอนุมานด้วยซัพพอร์ตเวกเตอร์แมชชีน

svm = cSVM()
svm.kernel = lambda xq, xp: np.dot(xq.T, xp) # linear kernel
C = 1
res = svm.train(datax, datay, C=C)
svm.decision_score(testx)

ในตัวอย่าง ใช้อภิมานพารามิเตอร์ \(C=1\) ฝึกด้วยข้อมูล datax และ datay ที่ต้องเป็นชนิด np.array สัดส่วน (D, N) และ (1, N) ตามลำดับ เมื่อ D และ N แทนจำนวนมิติของอินพุต และจำนวนจุดข้อมูล ตามลำดับ. คำสั่งสุดท้าย ใช้คำนวณค่าฟังก์ชันแบ่งแยกสำหรับ ข้อมูลทดสอบ testx.

จงศึกษาวิธีการเขียนโปรแกรม ทดลองใช้งาน สังเกตผล อภิปราย และสรุป. ทดลองค่า \(C\) ต่าง ๆ และรายงานดังตัวอย่างในรูป [fig: csvm different Cs].

class cSVM:
    def __init__(self):
        self.epsilon = 0.001
        self.bopt = None
        self.sv = None
        self.sy = None
        self.salpha = None
        self.kernel = None
            
    def train(self, x, y, C=1, a0=None,
              options={'ftol': 1e-9, 'disp': True}):
        assert (x.shape[1] == y.shape[1]) and (y.shape[0] == 1) 

        N = x.shape[1]
        if a0 is None:
            a0 = np.random.normal(0, 1, N)

        # parameter bounds: 0 <= alpha_i <= C for all i's
        bounds = optimize.Bounds([0 for i in range(N)], 
                                 [C for i in range(N)])
        
        # inequality constraints: dummy
        ineq_cons = {'type': 'ineq', 
                     'fun' : lambda a: np.array([0]),  # (1,)
                     'jac' : lambda a: np.zeros((1,N))}   # (M,N)
        
        # equality constraint: sum_i y_i alpha_i = 0
        eq_cons = {'type': 'eq', 'fun' : lambda a: np.dot(y, 
                         a.reshape((-1, 1))).reshape((-1,)),
           'jac' : lambda a: y.reshape((1,N))}                      
        
        # Objective
        K = self.kernel(x, x)     # N x N
        H = np.dot(y.T, y) * K    # N x N
        
        def dual_minf(a, H): # dual loss in minimization form
            a = a.reshape((-1,1))
            Q = 0.5 * np.dot(a.T, np.dot(H, a)) - np.sum(a) 
            return np.asscalar(Q)

        def dual_grad(a, H, N): # gradient of dual loss
            dQ = np.dot(H, a.reshape((-1,1))) - np.ones((N,1)) 
            return dQ.reshape((-1,))   # (N,)
        
        minf = lambda a: dual_minf(a, H)
        gradf =  lambda a: dual_grad(a, H, N)
        res = optimize.minimize(minf, a0, method='SLSQP', 
              jac=gradf, constraints=[ineq_cons, eq_cons], 
              bounds=bounds, options=options)
        
        if not res.success:
            return res
        
        alpha = res.x.reshape((-1,1))
        sv_ids = np.where(alpha > self.epsilon)[0]
        svp_ids = np.where( np.logical_and(alpha > self.epsilon, 
                                  alpha < C - self.epsilon) )[0]
        Ns = len(sv_ids)
        Np = len(svp_ids)
        
        if Np == 0: # No support vector on the edge
            print('# No support vector on the edge.')
            svp_ids = sv_ids
            Np = Ns
        
        # support vectors
        self.sv = x[:, sv_ids] # D x Ns
        self.sy = y[0, sv_ids].reshape((1,-1)) # 1 x Ns        
        spy = y[0, svp_ids].reshape((1,-1)) # 1 x Np
        
        # support alphas
        self.salpha = alpha[sv_ids]
        
        # optimal b
        sK = K[np.repeat(sv_ids, Np), 
               np.tile(svp_ids, Ns)].reshape((Ns, Np)) 
        self.bopt = np.mean(spy - \
                       np.dot(self.salpha.T * self.sy, sK))
        return res

    def decision_score(self, x):
        assert x.shape[0] == self.sv.shape[0] # x in D x N
        # Compute support kernels
        sK = self.kernel(x, self.sv) # N x Ns
        assert (sK.shape[0] == x.shape[1]) 
                      and (sK.shape[1] == self.sv.shape[1])

        yhat = np.dot(sK, self.salpha*self.sy.reshape((-1,1))) \
               + self.bopt
        return yhat.T        # 1 x N
4.0.0.1.3 แบบฝึกหัด

จงสร้างข้อมูลที่ไม่สามารถแบ่งแยกสมบูรณ์ได้เชิงเส้น โดยจะสร้างให้มีลักษณะใดก็ได้ แต่ควรทำให้สามารถตรวจดูได้สะดวก เช่น อินพุตควรจะเป็นสองมิติ. ตัวอย่างอาจจะเช่นที่แสดงในรูป 5. ทดลองใช้ซัพพอร์ตเวกเตอร์แมชชีน กับเคอร์เนลเชิงเส้น และเคอร์เนลเกาส์เซียนที่ค่า \(\sigma\) ต่าง ๆ. ดูรูป [fig: csvm linear kernel on wave datapoints] กับ [fig: csvm gaussian kernels] สำหรับตัวอย่าง. ออกแบบการทดลอง เพื่อศึกษาผลของ \(C\) และ \(\sigma\). ทดลอง สังเกตผล อภิปราย และสรุป.

ตัวอย่าง คำสั่งข้างล่างแสดงการกำหนดค่าเคอร์เนลของตัวแปรวัตถุ (จากcSVM) ให้เป็นเคอร์เนลเกาส์เซียน (ใช้ \(\sigma = 2\))

svm.kernel = lambda xq, xp: gaussian(xq, xp, sigma=2)

โดยโปรแกรม gaussian แสดงในรายการ [code: gaussain kernel].

def gaussian(xq, xp, sigma=1):
    assert xq.shape[0] == xp.shape[0]   # xq: D x Nx, xp: D x Ns 
    Nx = xq.shape[1]
    Ns = xp.shape[1]
    K = np.zeros((Nx, Ns))
    
    c = -1/(2*sigma**2)    
    for i in range(Nx):
        vi = xq[:,[i]] - xp # (D,1)-(D,Ns): broadcast to (D,Ns)
        K[i,:] = np.exp(c*np.sum(vi**2, axis=0))  # (Ns,)
    
    return K # Nx x Ns
ต้วอย่างข้อมูลที่ไม่สามารถแบ่งแยกสมบูรณ์ได้เชิงเส้น.