φυβλαςのβλογ
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
蒙古语
语言学
maya
概率论
与日本相关的日记
与中国相关的日记
-- 与北京相关的日记
-- 与香港相关的日记
-- 与澳门相关的日记
与台湾相关的日记
与北欧相关的日记
与其他国家相关的日记
qiita
其他日志

按类别分日志



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

  查看日志

  推荐日志

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