인공지능

전처리(2)

yul_S2 2023. 1. 8. 09:53
반응형

6. 가중치를 기록할 변수와 학습률 파라미터 추가

# 1.  SingleLayer클래스에 변수를 추가

class SingleLayer:
 
    def __init__(self, learning_rate=0.1):
        self.w = None
        self.b = None
        self.losses = []
        self.w_history = []         ### 인스턴스 변수 w_history 만들기
        self.lr = learning_rate     ### 학습률 파라미터 적용

w_history는 가중치를 기록하는 변수이다.

가중치 바뀔 때마다 w_history 리스트에 가중치 기록
넘파이 배열을 리스트에 추가하면 실제 값이 복사되는 것이 아니라 배열을 참조하기 때문에 가중치 변수 self.w의 값이 바뀔 때마다 그 값을 복사하여 w_history 리스트에 추가해야한다.
w_grad에 학습률 self.lr을 곱하는 연산을 추가하여 가중치 업데이트 양을 조절한다.

learning_rate는 하이퍼 파라미터이다. 
가중치의 업데이트 양을 조절할 목적으로 사용된다.

학습률에 따라 최적의 해를 구하는 과정이 달라질 수 있다.

학습률이 너무 커도 작아도 안정적인 학습이 불가능하다.
보통 0.001, 0.01등의 로그 스케일로 학습률을 지정한다.

 

 

 

# 3.  가중치 기록하고 업데이트 양 조절하기

def fit(self,x,y,epochs=100):
        self.w =np.ones(x.shape[1])
        self.b = 0
        self.w_history.append(self.w.copy()) ### 가중치 기록
        np.random.seed(42)
        for i in range(epochs) :   # epochs만큼 반복
                loss = 0
                ### 인덱스 섞기
                indexes = np.random.permutation(np.arange(len(x)))
                for i in indexes :     # 모든샘플에 대해 반복
                    z = self.forpass(x[i])
                    a = self.activation(z)
                    err = -(y[i]-a)
                    w_grad, b_grad = self.backprop(x[i],err) #역방향 계산
                    self.w -= self.lr * w_grad       #가중치 업데이트(학습률 적용)
                    self.b -= b_grad                  #절편 업데이트
                    #가중치 기록
                    self.w_history.append(self.w.copy())
                    #안전한 로그게산 위한 클리핑
                    a = np.clip(a,1e-10, 1-1e-10)
                    #손실 누적
                    loss += -(y[i]*np.log(a)+(1-y[i])*np.log(1-a))
                #에포크마다 평균 손실 저장
                self.losses.append(loss/len(y))

w_history 가중치를 기록하는 변수이다.

가중치 바뀔 때마다 w_history 리스트에 가중치 기록
넘파이 배열을 리스트에 추가하면 실제 값이 복사되는 것이 아니라 배열을 참조하기 때문에 가중치 변수 self.w의 값이 바뀔 때마다 그 값을 복사하여 w_history 리스트에 추가해야한다.
w_grad에 학습률 self.lr을 곱하는 연산을 추가하여 가중치 업데이트 양을 조절한다.

 

 

 

 

# 4. 최종코드 (단일층 신경망의 SingleLayer 클래스 이용)

class SingleLayer:
 
    def __init__(self, learning_rate=0.1):
        self.w = None
        self.b = None
        self.losses = []
        self.w_history = []         ### 인스턴스 변수 w_history 만들기
        self.lr = learning_rate     ### 학습률 파라미터 적용
 
    def forpass(self, x):
        z = np.sum(x * self.w) + self.b  # 직선 방정식을 계산
        return z
 
    def backprop(self, x, err):
        w_grad = x * err  # 가중치에 대한 그래디언트를 계산
        b_grad = 1 * err  # 절편에 대한 그래디언트를 계산
        return w_grad, b_grad
 
    def activation(self, z):
        z = np.clip(z, -100, None)  # 안전한 np.exp() 계산을 위해
        a = 1 / (1 + np.exp(-z))  # 시그모이드 계산
        return a
 
    def fit(self,x,y,epochs=100):
        self.w =np.ones(x.shape[1])
        self.b = 0
        self.w_history.append(self.w.copy()) ### 가중치 기록
        np.random.seed(42)
        for i in range(epochs) :   # epochs만큼 반복
                loss = 0
                ### 인덱스 섞기
                indexes = np.random.permutation(np.arange(len(x)))
                for i in indexes :     # 모든샘플에 대해 반복
                    z = self.forpass(x[i])
                    a = self.activation(z)
                    err = -(y[i]-a)
                    w_grad, b_grad = self.backprop(x[i],err) #역방향 계산
                    self.w -= self.lr*w_grad  #가중치 업데이트(학습률 적용)
                    self.b -= b_grad          #절편 업데이트
                    #가중치 기록
                    self.w_history.append(self.w.copy())
                    #안전한 로그게산 위한 클리핑
                    a = np.clip(a,1e-10, 1-1e-10)
                    #손실 누적
                    loss += -(y[i]*np.log(a)+(1-y[i])*np.log(1-a))
                #에포크마다 평균 손실 저장
                self.losses.append(loss/len(y))
 
    def predict(self, x):
        z = [self.forpass(x_i) for x_i in x]  # 정방향 계산
        return np.array(z) > 0  # 스텝 함수 적용
 
    def score(self, x, y):
        return np.mean(self.predict(x) == y)

 

 

# 5. 모델 훈련하고 평가

layer1 = SingleLayer()
layer1.fit(x_train, y_train)
print(layer1.score(x_val, y_val))
# 0.9120879120879121

 

 

 

# 6. 그래프

w2 = []
w3 = []
for w in layer1.w_history:
    w2.append(w[2])
    w3.append(w[3])
plt.plot(w2, w3)
plt.plot(w2[-1], w3[-1], 'ro')
plt.xlabel('w[2]')
plt.ylabel('w[3]')
plt.show()

▶layer1 객체의 인스턴스 변수 w_history에는 100번의 에포크 동안 변경된 가중치가 기록되어있다.

세번째요소(w[2]), 네번째요소(w[3])는 각각 mean perimeter와 mean area 특성에 대한 가중치이다.

최종으로 결정된 가중치는 점으로 표시

 

w[2]의 스케일은 0~2500이고, w[3]의 스케일은 0~700이기 때문에 상대적으로 작은 w[3]의 값이 크게 변동된다.

이런 현상을 스케일 조정으로 줄일 수 있다.

 

 

 

 

 

 

반응형