φυβλαςのβλογ
บล็อกของ phyblas



[python] สร้างชุดข้อมูลรูปร่าง ๕ ชนิด สำหรับใช้ฝึกการเรียนรู้ของเครื่อง
เขียนเมื่อ 2018/08/11 10:22
แก้ไขล่าสุด 2021/09/28 16:42
เนื่องจากอยากได้ข้อมูลรูปภาพใหม่ๆมาเพื่อทดสอบเทคนิคการเรียนรู้ของเครื่องในการวิเคราะห์รูปภาพเลยได้ลองคิดหาวิธีสำหรับสร้างชุดข้อมูลใหม่ขึ้นมา

ชุดข้อมูลสามารถหาได้มากมายจากในอินเทอร์เน็ต แต่ถ้าหากสามารถสร้างและปรับแต่งอะไรเองได้ก็คงจะสะดวกไม่น้อย

การสร้างอาจทำง่ายๆโดยใช้แค่ numpy และ matplotlib

เกี่ยวกับวิธีการวาดรูปด้วย matplotlib อ่านได้ใน https://phyblas.hinaboshi.com/numa36

ข้อมูลเป็นรูปร่างต่างๆ ๕ ชนิด ได้แก่
- วงรี
- สามเหลี่ยม
- สี่เหลี่ยม
- ดาว
- กากบาท

และยังมีแบบว่างเปล่าไม่มีรูปอะไรอยู่เลยด้วย รวมทั้งหมดเป็น ๖ กลุ่ม

สามารถกำหนดขนาดรูปที่ต้องการได้เอง

รูปตัวอย่างขนาด 40×40












โค้ดสำหรับสร้าง
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
import os

def sangrup(n,d=25,misi=1,langlai=1,aowang=1,sakun='png',f='ruprang',yaek=1):
    '''n: จำนวนรูปที่จะสร้างต่อชนิด
    d: ขนาดรูป
    misi: มีสีหรือไม่
    langlai: พื้นหลังมีลายหรือไม่
    aowang: เอาภาพพื้นว่างๆด้วยหรือไม่
    sakun: สกุลภาพ
    f: โฟลเดอร์เก็บภาพ
    yaek: แยกรูปแต่ละประเภทไว้คนละโฟลเดอร์
    '''
    
    c = 5+aowang # จำนวนชนิด
    
    # สร้างโฟลเดอร์ใหม่ ถ้ายังไม่มีอยู่
    if(not os.path.exists(f)):
        os.mkdir(f)
    if(yaek):
        for i in range(c):
            fyoi = os.path.join(f,'%d'%i)
            if(not os.path.exists(fyoi)):
                os.mkdir(fyoi)
    
    lw = np.random.uniform(1,4,[n,5]) # ความหนาเส้นขอบ
    if(misi):
        si1,si2 = np.random.uniform(0,1,[2,n,5,3]) # สีผิว, สีเส้นขอบ
        if(langlai):
            phuen = np.random.normal(0,1,[n,d,d,3]).cumsum(1) # สีพื้นหลัง
            phuen -= phuen.min(1)[:,None]
            phuen /= phuen.max(1)[:,None]
            phuen[::2] = phuen[::2].transpose(0,2,1,3)
            phuen *= np.linspace(0,1,n)[:,None,None,None]
            phuen += np.random.uniform(0,np.linspace(1,0,n),[3,n]).T[:,None,None,:]
        else:
            phuen = np.tile(np.random.uniform(0,1,[n,3]),[d,d,1,1]).transpose(2,0,1,3)
    else:
        si1,si2 = np.ones([n,5,3]),np.zeros([n,5,3])
        aowang = 0
        from PIL import Image
    d_2 = (d-1)/2. # จุดกึ่งกลาง
    
    # วงรี
    k,s = np.random.uniform(0.4,0.9,[2,n])*d # กว้าง, สูง
    mum = np.random.uniform(0,180,n) # มุมเอียง
    
    # ฟังก์ชันสร้างจุด
    def sangchut(r,theta):
        x = r*np.cos(np.radians(theta))*d+d_2
        y = r*np.sin(np.radians(theta))*d+d_2
        return np.stack([x,y],2)
    
    # สามเหลี่ยม
    theta = np.random.uniform(0,120,[n,1]) + np.random.normal(np.linspace(0,240,3),15,[n,3])
    r = np.random.uniform(0.25,0.45,[n,3])
    X3 = sangchut(r,theta)
    
    # สี่เหลี่ยม
    theta = np.random.uniform(0,90,[n,1]) + np.random.normal(np.linspace(0,270,4),15,[n,4])
    r = np.random.uniform(0.25,0.45,[n,4])
    X4 = sangchut(r,theta)
    
    # ดาว
    theta = np.random.uniform(0,36,[n,1]) + np.random.normal(np.linspace(0,324,10),6,[n,10])
    r = np.random.uniform(0.35,0.45,[n,10])*(np.arange(10)%2*0.5+0.5)[None,:]
    Xd = sangchut(r,theta)
    
    # กากบาท
    a = np.random.uniform(10,25,n)
    theta = (np.random.uniform(0,360,[n,1])+np.arange(0,360,90).repeat(3)) + np.tile(np.array([-a,a,45*np.ones(n)]).T,4)
    r = np.tile(np.random.uniform(0.35,0.45,[n,1])*np.hstack([np.ones([n,2]),np.random.uniform(0.15,0.35,[n,1])]),4)
    Xk = sangchut(r,theta)
    
    for i in range(n):
        for j in range(c):
            plt.figure(figsize=[1,1])
            ax = plt.axes([0,0,1,1],aspect=1,xlim=[-0.5,d-0.5],ylim=[-0.5,d-0.5])
            if(misi):
                ax.imshow(phuen[i])
            if(j==0):
                ax.add_patch(mpl.patches.Ellipse([d_2,d_2],k[i],s[i],angle=mum[i],fc=si1[i,j],ec=si2[i,j],lw=lw[i,j]))
            elif(j==1):
                ax.add_patch(plt.Polygon(X3[i],fc=si1[i,j],ec=si2[i,j],lw=lw[i,j]))
            elif(j==2):
                ax.add_patch(plt.Polygon(X4[i],fc=si1[i,j],ec=si2[i,j],lw=lw[i,j]))
            elif(j==3):
                ax.add_patch(plt.Polygon(Xd[i],fc=si1[i,j],ec=si2[i,j],lw=lw[i,j]))
            elif(j==4):
                ax.add_patch(plt.Polygon(Xk[i],fc=si1[i,j],ec=si2[i,j],lw=lw[i,j]))
            
            plt.axis('off')
            if(yaek):
                chuefile = os.path.join(f,'%d/%05d.%s'%(j,i+1,sakun))
            else:
                chuefile = os.path.join(f,'%06d.%s'%(i+1+j*100000,sakun))
            plt.savefig(chuefile,dpi=d)
            plt.close()
            if(not misi):
                Image.open(chuefile).convert('L').save(chuefile)
    
    print('สร้างเสร็จแล้ว')

ภาพจะถูกเซฟไว้ แล้วเวลาจะอ่านรูปก็ใช้ glob ค้นทั้งโฟลเดอร์แล้ว imread เพื่ออ่าน เช่นเขียนแบบนี้
from glob import glob
X = np.array([plt.imread(x) for x in sorted(glob(os.path.join(f,'*','*.'+sakun)))])
z = np.arange(5+aowang*misi).repeat(n)

อาจสร้างฟังก์ชันสำหรับดึงภาพได้ในลักษณะแบบนี้
def anrup(sangmai,n,d=25,misi=1,langlai=1,aowang=1,sakun='png',f='ruprang',yaek=1):
    if(sangmai):
        sangrup(n,d,misi,langlai,aowang,sakun,f,yaek)
    if(yaek):
        chuefile = os.path.join(f,'*','*.'+sakun)
    else:
        chuefile = os.path.join(f,'*.'+sakun)
    X = np.array([plt.imread(x) for x in sorted(glob(chuefile))])
    if(misi):
        X = X[:,:,:,:3]
    z = np.arange(5+aowang*misi).repeat(n)
    return X,z


มีตัวเลือกให้สามารถปรับเลือกแบบไม่มีสี หรือไม่ใส่ลายหลัง หรือจะไม่เอาลายที่ไม่มีรูปอะไรมีแค่พื้นหลังเปล่าๆก็ได้

แบบไร้สี



แบบมีสีแต่ไม่ใส่ลายหลัง





ต่อมาลองทดสอบการใช้งานกันดู

เทคนิคที่จะใช้คือวิธีการเพื่อนบ้านใกล้สุด k ตัว ซึ่งเคยพบว่าใช้ได้ผลดีมากกับข้อมูล MNIST
(รายละเอียด https://phyblas.hinaboshi.com/20171028)

เพื่อความง่ายขอใช้แค่แบบไร้สี ขนาด 25×25 ถ้าเป็นแบบมีสีและหลังลายจะไม่มีทางใช้วิธีการนี้ทายได้เลยเพราะมีความซับซ้อน ต้องใช้โครงข่ายประสาทเทียมแบบคอนโวลูชัน

การทดสอบจะทำด้วยการตรวจสอบแบบไขว้ k-fold (รายละเอียด https://phyblas.hinaboshi.com/20171018) ทำการหาเส้นโค้งการเรียนรู้ เพื่อเปรียบเทียบว่าเมื่อใช้ข้อมูลเรียนรู้จำนวนมากแค่ไหนจะสามารถเรียนรู้จนทายได้ถูกต้องแค่ไหน (รายละเอียด https://phyblas.hinaboshi.com/20171024)
from sklearn.neighbors import KNeighborsClassifier as Knn
from sklearn.model_selection import StratifiedKFold
import time

d = 25 # ขนาด
n = 5000 # จำนวนรูปแต่ละชนิด
X,z = anrup(1,n,d,misi=0) # อ่านรูปขึ้นมา ถ้าหากได้สร้างรูปเตรียมไว้แล้วให้ใส่เป็น anrup(0,n,d,misi=0) จะไม่ต้องสร้างใหม่
X = X.reshape(-1,d*d)
sumriang = np.random.permutation(len(z))
X,z = X[sumriang],z[sumriang]

maen_fuek = [],[],[],[],[]
maen_truat = [],[],[],[],[]
nknk = np.arange(2000,20001,2000) # จำนวนข้อมูลที่ใช้ฝึกในแต่ละรอบ
skf = StratifiedKFold(n_splits=5,shuffle=True) # ทำ ๕ ครั้ง หาค่าเฉลี่ยและส่วนเบี่ยงเบนมาตรฐาน
t1 = time.time()
for i,(fuek,truat) in enumerate(skf.split(X,z)):
    X_fuek,X_truat,z_fuek,z_truat = X[fuek],X[truat],z[fuek],z[truat]
    for nk in nknk:
        knn = Knn(n_neighbors=3,n_jobs=-1) # ใช้เพื่อนบ้านใกล้สุด ๓ ตัว
        knn.fit(X_fuek[:nk],z_fuek[:nk])
        maen_fuek[i].append(knn.score(X_fuek[:200],z_fuek[:200])) # ความแม่นของข้อมูลฝึก
        maen_truat[i].append(knn.score(X_truat[:200],z_truat[:200])) # ความแม่นของข้อมูลตรวจสอบ
        print(u'ใช้ %d รอบ %d เวลาผ่านไปแล้ว %.2f วินาที แม่น %.2f'%(nk,i+1,time.time()-t1,maen_truat[i][-1]))

mf = np.array(maen_fuek)
mt = np.array(maen_truat)
plt.errorbar(nknk,mf.mean(0),yerr=mf.std(0),color='#BB5577',capsize=2)
plt.errorbar(nknk,mt.mean(0),yerr=mt.std(0),color='#339955',capsize=2)
plt.xlabel(u'จำนวนข้อมูลฝึก',family='Tahoma')
plt.ylabel(u'ความแม่นยำ',family='Tahoma')
plt.legend([u'ฝึกฝน',u'ตรวจสอบ'],prop={'family':'Tahoma'})
plt.show()

ผลเป็นดังนี้



เมื่อใช้ตัวอย่างสำหรับฝึกเยอะพอ ใช้แค่วิธีการง่ายๆแบบนี้ก็สามารถทำนายได้แม่นยำว่า 95%

ก็หวังว่าจะมีคนเอาไปลองใช้กันดู


-----------------------------------------

囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧

ดูสถิติของหน้านี้

หมวดหมู่

-- คอมพิวเตอร์ >> ปัญญาประดิษฐ์
-- คอมพิวเตอร์ >> เขียนโปรแกรม >> python >> numpy
-- คอมพิวเตอร์ >> เขียนโปรแกรม >> python >> matplotlib

ไม่อนุญาตให้นำเนื้อหาของบทความไปลงที่อื่นโดยไม่ได้ขออนุญาตโดยเด็ดขาด หากต้องการนำบางส่วนไปลงสามารถทำได้โดยต้องไม่ใช่การก๊อปแปะแต่ให้เปลี่ยนคำพูดเป็นของตัวเอง หรือไม่ก็เขียนในลักษณะการยกข้อความอ้างอิง และไม่ว่ากรณีไหนก็ตาม ต้องให้เครดิตพร้อมใส่ลิงก์ของทุกบทความที่มีการใช้เนื้อหาเสมอ

สารบัญ

รวมคำแปลวลีเด็ดจากญี่ปุ่น
มอดูลต่างๆ
-- numpy
-- matplotlib

-- pandas
-- manim
-- opencv
-- pyqt
-- pytorch
การเรียนรู้ของเครื่อง
-- โครงข่าย
     ประสาทเทียม
ภาษา javascript
ภาษา mongol
ภาษาศาสตร์
maya
ความน่าจะเป็น
บันทึกในญี่ปุ่น
บันทึกในจีน
-- บันทึกในปักกิ่ง
-- บันทึกในฮ่องกง
-- บันทึกในมาเก๊า
บันทึกในไต้หวัน
บันทึกในยุโรปเหนือ
บันทึกในประเทศอื่นๆ
qiita
บทความอื่นๆ

บทความแบ่งตามหมวด



ติดตามอัปเดตของบล็อกได้ที่แฟนเพจ

  ค้นหาบทความ

  บทความแนะนำ

ตัวอักษรกรีกและเปรียบเทียบการใช้งานในภาษากรีกโบราณและกรีกสมัยใหม่
ที่มาของอักษรไทยและความเกี่ยวพันกับอักษรอื่นๆในตระกูลอักษรพราหมี
การสร้างแบบจำลองสามมิติเป็นไฟล์ .obj วิธีการอย่างง่ายที่ไม่ว่าใครก็ลองทำได้ทันที
รวมรายชื่อนักร้องเพลงกวางตุ้ง
ภาษาจีนแบ่งเป็นสำเนียงอะไรบ้าง มีความแตกต่างกันมากแค่ไหน
ทำความเข้าใจระบอบประชาธิปไตยจากประวัติศาสตร์ความเป็นมา
เรียนรู้วิธีการใช้ regular expression (regex)
การใช้ unix shell เบื้องต้น ใน linux และ mac
g ในภาษาญี่ปุ่นออกเสียง "ก" หรือ "ง" กันแน่
ทำความรู้จักกับปัญญาประดิษฐ์และการเรียนรู้ของเครื่อง
ค้นพบระบบดาวเคราะห์ ๘ ดวง เบื้องหลังความสำเร็จคือปัญญาประดิษฐ์ (AI)
หอดูดาวโบราณปักกิ่ง ตอนที่ ๑: แท่นสังเกตการณ์และสวนดอกไม้
พิพิธภัณฑ์สถาปัตยกรรมโบราณปักกิ่ง
เที่ยวเมืองตานตง ล่องเรือในน่านน้ำเกาหลีเหนือ
ตระเวนเที่ยวตามรอยฉากของอนิเมะในญี่ปุ่น
เที่ยวชมหอดูดาวที่ฐานสังเกตการณ์ซิงหลง
ทำไมจึงไม่ควรเขียนวรรณยุกต์เวลาทับศัพท์ภาษาต่างประเทศ

บทความแต่ละเดือน

2024年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2023年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2022年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2021年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2020年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

ค้นบทความเก่ากว่านั้น

ไทย

日本語

中文