φυβλαςのβλογ
phyblas的博客



pytorch เบื้องต้น บทที่ ๑๓: การแยกข้อมูลฝึกและข้อมูลตรวจสอบ
เขียนเมื่อ 2018/09/19 09:05
แก้ไขล่าสุด 2022/07/09 17:49
>> ต่อจาก บทที่ ๑๒



ในบทที่ ๑๑ ได้อธิบายการนำรูปมาใช้เป็นข้อมูล และบทที่ ๑๒ ได้แสดงตัวอย่างการนำมาใช้ในโครงข่ายประสาทเทียมแบบคอนโวลูชัน (CNN)

แต่ว่าในนั้นใช้ข้อมูลตัวอย่างของ MNIST ซึ่งถูกเตรียมไว้โดยแยกชุดข้อมูลฝึกกับข้อมูลตรวจสอบไว้คนละชุดกันอยู่แล้ว จึงนำมาใช้ได้เลย

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

น่าเสียดายว่า pytorch ไม่ได้เตรียมคำสั่งที่สะดวกในการแบ่งชุดข้อมูลเอาไว้ ทำให้มีความยุ่งยากเล็กน้อยในการเขียน

การสุ่มแบ่งชุดข้อมูลอาจทำได้โดยใช้ SubsetRandomSampler ภายในมอดูลย่อย torch.utils.data

SubsetRandomSampler เป็นคลาสที่จะเก็บเลขดัชนีแล้วจะทำการสุ่มลำดับให้ค่าออกมา
from torch.utils.data import SubsetRandomSampler as Sarasa
srs = Sarasa([1,3,5,9])
print([x for x in srs])
print([x for x in srs])

ได้ค่าที่สุ่มลำดับต่างกันไปใน ๒ ครั้ง
[3, 5, 9, 1]
[9, 5, 1, 3]

(เนื่องจากชื่อยาว ในที่นี้ขอย่อเป็น Sarasa)

เวลาที่นำมาใช้กับ DataLoader จะใส่ในคีย์เวิร์ด sampler เพื่อเป็นตัวบอกว่าจะเอาข้อมูลลำดับที่เท่าไหร่บ้าง
import numpy as np
import matplotlib.pyplot as plt
import torchvision.datasets as ds
import torchvision.transforms as tf
from torch.utils.data import DataLoader as Dalo

data = ds.MNIST('~/pytorchdata/mnist',transform=tf.ToTensor(),download=1)
sampler = Sarasa(np.arange(0,31,2))
plt.figure(figsize=[6.4,0.4])
rup = Dalo(data,batch_size=16,sampler=sampler)
plt.axes([0,0,1,1]).imshow(np.hstack([x for x,z in rup][0][:,0]),cmap='gray')
sampler = Sarasa(np.arange(1,32,2))
plt.figure(figsize=[6.4,0.4])
rup = Dalo(data,batch_size=16,sampler=sampler)
plt.axes([0,0,1,1]).imshow(np.hstack([x for x,z in rup][0][:,0]),cmap='gray')
plt.show()





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



ต่อมาเพื่อทดสอบ ขอลองใช้กับข้อมูลรูปต่างๆ (วงกลม, สามเหลี่ยม, สี่เหลี่ยม, ดาว, กากบาท) ที่ตัวเองสร้างเตรียมขึ้นมาเพื่อใช้เป็นตัวอย่าง

โหลด >> https://phyblas.hinaboshi.com/triamhai/ruprang-misi-25x25x1000x6.rar
(รายละเอียดเกี่ยวกับชุดข้อมูล https://phyblas.hinaboshi.com/20180811)



อาจสร้างฟังก์ชันสำหรับเตรียมรูป แล้วใช้ ดังนี้
def triam_rup(folder_rup,satsuan_truat,n_batch_fuek,n_batch_truat):
    tran_fuek = tf.Compose([
        tf.RandomVerticalFlip(), # เนื่องจากเป็นรูปร่างอิสระ จะพลิกบนล่างหรือซ้ายขวาก็ได้
        tf.RandomHorizontalFlip(),
        tf.ToTensor(),
        tf.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))])
    tran_truat = tf.Compose([
        tf.ToTensor(),
        tf.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))])
    rup_fuek = ds.ImageFolder(folder_rup,transform=tran_fuek)
    rup_truat = ds.ImageFolder(folder_rup,transform=tran_truat)
    n = len(rup_fuek) # จำนวนข้อมูลทั้งหมด
    n_truat = int(n*satsuan_truat) # จำนวนข้อมูลตรวจสอบ
    sumlueak = np.random.permutation(n) # สร้างตัวสุ่มเลือก
    sf = Sarasa(sumlueak[n_truat:]) # sampler ของข้อมูลฝึก
    st = Sarasa(sumlueak[:n_truat]) # sampler ของข้อมูลตรวจสอบ
    rup_fuek = Dalo(rup_fuek,batch_size=n_batch_fuek,sampler=sf)
    rup_truat = Dalo(rup_truat,batch_size=n_batch_truat,sampler=st)
    return rup_fuek,rup_truat

folder_rup = 'ruprang-misi-25x25x1000x6' # โฟลเดอร์ใหญ่ที่ใส่รูปแยกเป็นโฟลเดอร์ย่อยต่างๆไว้
rup_fuek,rup_truat = triam_rup(folder_rup,0.2,64,100000)
rup_truat = list(rup_truat)[0]

satsuan_truat คือสัดส่วนของข้อมูลตรวจสอบ

n_batch_fuek,n_batch_truat คือขนาดมินิแบตช์ของข้อมูลฝึกและข้อมูลตรวจ

ข้อมูลตรวจสอบเราไม่ได้จะทำมินิแบตช์แต่จะให้ดึงออกมาเตรียมทั้งชุดไว้คำนวณทีเดียวก็เลยให้ใส่เลขเยอะๆไป (ในที่นี้ใส่ 100000)

ต่อมาลองสร้าง CNN แบบง่ายๆแล้วทำการฝึกโดยบันทึกทั้งคะแนนในการทำนายชุดข้อมูลฝึกและชุดข้อมูลตรวจสอบ
import torch
import time

relu = torch.nn.ReLU()
maxp = torch.nn.MaxPool2d(2)
ha_entropy = torch.nn.CrossEntropyLoss()

class Plianrup(torch.nn.Module):
    def __init__(self,*k):
        super(Plianrup,self).__init__()
        self.k = k
    
    def forward(self,x):
        return x.reshape(x.size()[0],*self.k)

class Prasat(torch.nn.Sequential):
    def __init__(self,eta=0.001):
        super(Prasat,self).__init__(
            torch.nn.Conv2d(3,16,4,1,0),
            torch.nn.BatchNorm2d(16),
            relu,
            maxp,
            torch.nn.Conv2d(16,16,4,1,0),
            torch.nn.BatchNorm2d(16),
            relu,
            maxp,
            Plianrup(-1),
            torch.nn.Linear(16*4*4,32),
            torch.nn.BatchNorm1d(32),
            relu,
            torch.nn.Linear(32,6)
        )
        self.opt = torch.optim.Adam(self.parameters(),lr=eta)
        
    def rianru(self,rup_fuek,rup_truat,n_thamsam=200,ro=10):
        X_truat,z_truat = rup_truat
        self.khanaen_truat = []
        self.khanaen_fuek = []
        khanaen_sungsut = 0
        t_roem = time.time()
        for o in range(n_thamsam):
            self.train()
            X_fuek,z_fuek = [],[]
            for Xb,zb in rup_fuek:
                a = self(Xb)
                J = ha_entropy(a,zb)
                J.backward()
                self.opt.step()
                self.opt.zero_grad()
                X_fuek.append(Xb)
                z_fuek.append(zb)
            X_fuek,z_fuek = torch.cat(X_fuek),torch.cat(z_fuek)
            self.eval()
            khanaen_fuek = self.ha_khanaen_(X_fuek,z_fuek)
            khanaen_truat = self.ha_khanaen_(X_truat,z_truat)
            self.khanaen_fuek.append(khanaen_fuek)
            self.khanaen_truat.append(khanaen_truat)
            print('%d ครั้งผ่านไป ใช้เวลาไป %.1f นาที ทำนายข้อมูลฝึกแม่น %.4f ข้อมูลตรวจสอบแม่น %.4f'%(o+1,(time.time()-t_roem)/60,khanaen_fuek,khanaen_truat))
            
            if(khanaen_truat>khanaen_sungsut):
                khanaen_sungsut = khanaen_truat
                maiphoem = 0
            else:
                maiphoem += 1
            if(ro>0 and maiphoem>=ro):
                break
    
    def thamnai_(self,X):
        return self(X).argmax(1)
    
    def ha_khanaen_(self,X,z):
        return (self.thamnai_(X)==z).numpy().mean()



prasat = Prasat()
prasat.rianru(rup_fuek,rup_truat)

plt.plot(prasat.khanaen_fuek,'#aa33bb')
plt.plot(prasat.khanaen_truat,'#33bb22')
plt.legend([u'ข้อมูลฝึก',u'ข้อมูลตรวจสอบ'],prop={'family':'Tahoma','size':14})
plt.show()




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



>> อ่านต่อ บทที่ ๑๔


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

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

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

หมวดหมู่

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

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

目录

从日本来的名言
模块
-- numpy
-- matplotlib

-- pandas
-- manim
-- opencv
-- pyqt
-- pytorch
机器学习
-- 神经网络
javascript
蒙古语
语言学
maya
概率论
与日本相关的日记
与中国相关的日记
-- 与北京相关的日记
-- 与香港相关的日记
-- 与澳门相关的日记
与台湾相关的日记
与北欧相关的日记
与其他国家相关的日记
qiita
其他日志

按类别分日志



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

  查看日志

  推荐日志

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