
from unagi import Chan,Affin,Relu,Sigmoid_entropy,Adam,Batchnorm
import numpy as npclass Batchnorm(Chan):
    def __init__(self,m,mmt=0.9):
        self.m = m # จำนวนตัวแปรของข้อมูล
        self.param = [Param(np.ones(m)),Param(np.zeros(m))] # ค่า γ และ β
        self.rmu = np.zeros(m) # ค่าเฉลี่ยขณะวิ่ง
        self.rvar = np.zeros(m)+1e-8 # ความแปรปรวนขณะวิ่ง
        self.mmt = mmt # โมเมนตัม
        self.fuekyu = 1
    
    def pai(self,x):
        if(self.fuekyu): # กรณีฝึกอยู่ คำนวณ xn ค่าเฉลี่ยและความแปรปรวนในกลุ่ม
            self.n = len(x)
            mu = x.mean(0)
            self.xc = x-mu
            var = (self.xc**2).mean(0)+1e-8
            self.sigma = np.sqrt(var)
            self.xn = xn = self.xc/self.sigma
            self.rmu = self.mmt*self.rmu + (1.-self.mmt)*mu
            self.rvar = self.mmt*self.rvar + (1.-self.mmt)*var
        else: # กรณีไม่ได้ฝึกอยู่ คำนวณ xn จาก rmu (μR) และ rvar (σR2)
            xc = x - self.rmu
            xn = xc/np.sqrt(self.rvar)
        
        return self.param[0].kha*xn+self.param[1].kha
    
    def yon(self,g):
        self.param[0].g = (g*self.xn).sum(0)
        self.param[1].g = g.sum(0)
        gxn = self.param[0].kha*g
        gsigma = -((gxn*self.xc)/self.sigma**2).sum(0)
        gvar = gsigma/self.sigma/2
        gxc = gxn/self.sigma + (2./self.n)*self.xc*gvar
        gmu = gxc.sum(0)
        gx = gxc - gmu/self.n
        return gximport matplotlib.pyplot as plt
  
n = 350
t = np.random.uniform(0,360,n*2)
r = [np.random.normal(1+0.4*np.sin(np.radians(t[:n])*5),0.2)]
r += [np.random.normal(2+0.4*np.sin(np.radians(t[n:])*5),0.3)]
r = np.hstack(r)
x = r*np.cos(np.radians(t))
y = r*np.sin(np.radians(t))
z = np.repeat([0,1],n)
X = np.array([x,y]).T
plt.axes(aspect=1)
plt.scatter(X[:,0],X[:,1],c=z,edgecolor='k',alpha=0.6,cmap='RdYlGn')
plt.show()
plt.figure(figsize=[6.5,6.5])
ax1 = plt.subplot(211,xticks=[])
ax1.set_title(u'เอนโทรปี',family='Tahoma')
ax2 = plt.subplot(212)
ax2.set_title(u'คะแนน',family='Tahoma')
m = [2,60,60,60,1] # จำนวนเซลล์ในชั้นต่างๆ
n_thamsam = 160 # จำนวนรอบที่ทำซ้ำเพื่อปรับพารามิเตอร์
for b in [0,1]:
    for s in [0.1,1]:
        # กำหนดแบบจำลอง
        chan = []
        param = []
        for i in range(len(m)-1):
            he_kaiming = np.sqrt(2./m[i]) # ค่าน้ำหนักตั้งต้นแบบเหอ ไข่หมิง
            af = Affin(m[i],m[i+1],he_kaiming*s)
            chan.append(af)
            param.extend(af.param)
            if(i<len(m)-2):
                if(b): # ใส่ชั้นแบตช์นอร์ม
                    bn = Batchnorm(m[i+1])
                    chan.append(bn)
                    param.extend(bn.param)
                chan.append(Relu())
        chan.append(Sigmoid_entropy())
        opt = Adam(param,eta=0.001) # ออปทิไมเซอร์
        
        # เริ่มฝึก
        lis_entropy = []
        lis_khanaen = []
        for i in range(n_thamsam):
            # คำนวนไปข้างหน้าในโหมดฝึก เพื่อหาเอนโทรปีแล้วแพร่ย้อนกลับ
            X_ = X
            for c in chan[:-1]:
                c.fuekyu = 1 # ฝึกอยู่
                X_ = c(X_)
            entropy = chan[-1](X_,z)
            lis_entropy.append(entropy.kha) # บันทึกค่าเอนโทรปี
            entropy.phraeyon() # แพร่ย้อนกลับ
            opt() # ปรับพารามิเตอร์
            # คำนวณไปข้างหน้าใหม่ในโหมดใช้งานจริง เพื่อหาคะแนนความแม่นในการทำนาย
            X_ = X
            for c in chan[:-1]:
                c.fuekyu = 0 # ไม่ได้ฝึกอยู่
                X_ = c(X_)
            lis_khanaen.append(((X_.kha.ravel()>0)==z).mean()) # บันทึกคะแนน
            
        ax1.plot(lis_entropy,[':','-'][s==1],color=['r','g'][b])
        ax2.plot(lis_khanaen,[':','-'][s==1],color=['r','g'][b])
plt.legend([u'ไม่มีแบตช์นอร์ม, $\sigma_w$=เหอ/10',
            u'ไม่มีแบตช์นอร์ม, $\sigma_w$=เหอ',
            u'มีแบตช์นอร์ม, $\sigma_w$=เหอ/10',
            u'มีแบตช์นอร์ม, $\sigma_w$=เหอ'],
    prop={'family':'Tahoma','size':15})
plt.tight_layout()
plt.show()
ติดตามอัปเดตของบล็อกได้ที่แฟนเพจ