示例#1
0
    def __init__(self,
                 input_size,
                 hidden_size,
                 output_size,
                 weight_init_std=0.01):
        """신경망의 구조(모양) 결정"""
        np.random.seed(106)

        # 가중치 / 편향 행렬들을 초기화
        self.params = dict()
        self.params['W1'] = weight_init_std * np.random.randn(
            input_size, hidden_size)
        self.params['b1'] = np.zeros(hidden_size)
        self.params['W2'] = weight_init_std * np.random.randn(
            hidden_size, output_size)
        self.params['b2'] = np.zeros(output_size)

        # layer 생성/초기화
        self.layers = OrderedDict()
        # 딕셔너리에 데이터가 추가된 순서가 유지되는 딕셔너리
        self.layers['affine1'] = Affine(self.params['W1'],
                                        self.params['b1'])  # Affine
        self.layers['relu'] = Relu()  # Relu
        self.layers['affine2'] = Affine(self.params['W2'], self.params['b2'])
        self.last_layer = SoftmaxWithLoss()
示例#2
0
    def __init__(self,
                 input_size,
                 hidden_size,
                 output_size,
                 weight_init_std=0.01):  # 난수들을 선택할 때 0에 가까운 수들을 더 선택할 것이냐
        """ 신경망의 구조(모양) 결정
            input size: number of variables
            output size: i.e. 숫자 이미지 -> 10개, iris -> 3개
        """
        np.random.seed(106)

        # 가중치/편향 행렬들을 초기화
        # W1, b1, W2, b2 와 같은 값들을 리스트로 만들어두면 나중에 iteration하기 쉽다
        self.params = dict()
        self.params['W1'] = weight_init_std * np.random.randn(
            input_size, hidden_size)
        self.params['b1'] = np.zeros(hidden_size)  # 편향은 모두 0으로 준다
        self.params['W2'] = weight_init_std * np.random.randn(
            hidden_size, output_size)
        self.params['b2'] = np.zeros(output_size)

        # n in randomn stands for normalization (정규분포)
        # 정규분포 is a bell-like graph which is symmetric (평균을 기준으로 좌우가 대칭)  # 평균 0, 표준편차 1
        # 정규분포를 확률 분포라고 생각하면, 임의의 값을 꺼낼 때 -0.5 와 0.5 사이의 값을 가장 많이 리턴해준다
        # random number로 해주어야해요 - 표준편차를 1로 시작하면 모든 값이 같아서 나중엔 학습의 효과가 없을 수도 있어요 (그래서 std = 0.01을 해주었다)

        # 위의 방법대로라면 저장한 순서대로 반복문에서 출력되는 것이 보장되지 않는다
        # layer 생성/초기화
        self.layers = OrderedDict()
        # 딕셔너리에 데이터가 추가된 순서가 유지되는 딕셔너리
        # 순서가 중요하기 때문에 (Affine - ReLU - Affine - SoftmaxWithLoss => forward그리고 backward는 이 반대 순서대로 진행되어야하기 때문)
        self.layers['affine1'] = Affine(self.params['W1'], self.params['b1'])
        self.layers['relu'] = Relu()
        self.layers['affine2'] = Affine(self.params['W2'], self.params['b2'])
        self.last_layer = SoftmaxWithLoss()
示例#3
0
# Affine 클래스에서 W1과 b1 합치기
affine1 = Affine(W1, b1)
# print('affine1 =',affine1) # only shows its direction
relu = Relu()
# print('affine_relu =', relu) # only shows its direction

# 출력층의 뉴런 갯수: 3개
# W shape: (3, 3), b.shape: (3,)
W2 = np.random.randn(3, 3)
b2 = np.random.rand(3)
print('W2 =', W2)
print('b2 =', b2)

affine2 = Affine(W2, b2)
# 가장 마지막 레이어:
last_layer = SoftmaxWithLoss()

# forward의 반대를 타고가다보면 gradient를 구할 수 있다
# 마지막 layer의 뉴런의 갯수는 무엇을 분류하는 것이냐에 따라 다르다 (i.e. 숫자 이미지 = 10개, 개과 고양이 분류 = 2개, 등등)

# 각 레이어들을 연결: forward propagation

# Affine -> relu
Y = affine1.forward(X)
print('Y_shape = ', Y.shape)

Y = relu.forward(Y)
# 왜 Y는 넣어준걸까? affine1의 출력 값 -> Y!
# Y를 relu에 넣어줘야함 -> 변수를 공유해서 쓴다
print('Y shape =', Y.shape)
示例#4
0
class TwoLayerNetwork:
    def __init__(self,
                 input_size,
                 hidden_size,
                 output_size,
                 weight_init_std=0.01):
        """신경망의 구조(모양) 결정"""
        np.random.seed(106)

        # 가중치/편향 행렬들을 초기화
        self.params = dict()
        self.params['W1'] = weight_init_std * np.random.randn(
            input_size, hidden_size)
        self.params['b1'] = np.zeros(hidden_size)
        self.params['W2'] = weight_init_std * np.random.randn(
            hidden_size, output_size)
        self.params['b2'] = np.zeros(output_size)

        # layer 생성/초기화
        self.layers = OrderedDict()
        # 딕셔너리에 데이터가 추가된 순서가 유지되는 딕셔너리
        self.layers['affine1'] = Affine(self.params['W1'], self.params['b1'])
        self.layers['relu'] = Relu()
        self.layers['affine2'] = Affine(self.params['W2'], self.params['b2'])
        self.last_layer = SoftmaxWithLoss()

    def predict(self, X):
        """입력 데이터 X의 예측값을 리턴."""
        # Y1 = self.layers['affine1'].forward(X)
        # Y2 = self.layers['relu'].forward(Y1)
        # Y3 = self.layers['affine2'].forward(Y2)
        # return Y3
        for layer in self.layers.values():
            X = layer.forward(X)
        return X

    def loss(self, X, Y_true):
        """입력 데이터 X와 실제 값(레이블) Y_true가 주어졌을 때,
        손실(cross-entropy)를 계산해서 리턴."""
        # 출력층(SoftmaxWithLoss) 전까지의 forward propagation을 계산
        Y_pred = self.predict(X)
        # 출력층 바로 전 계층의 출력값을 입력으로 사용해서 손실(cross-entropy) 계산
        loss = self.last_layer.forward(Y_pred, Y_true)
        return loss

    def accuracy(self, X, Y_true):
        """입력 데이터 X와 실제 값(레이블) Y_true가 주어졌을 때,
        예측 값들의 정확도를 계산해서 리턴.
        accuracy = 예측이 실제값과 일치하는 개수 / 전체 입력 데이터 개수
        X, Y_true는 모두 2차원 배열(행렬)라고 가정.
        """
        Y_pred = self.predict(X)
        predictions = np.argmax(Y_pred, axis=1)
        trues = np.argmax(Y_true, axis=1)
        acc = np.mean(predictions == trues)
        return acc

    def gradient(self, X, Y_true):
        """입력 데이터 X와 실제 값(레이블) Y_true가 주어졌을 때,
        모든 레이어에 대해서 forward propagtion을 수행한 후,
        오차 역전파 방법을 이용해서 dW1, db1, dW2, db2를 계산하고 리턴."""
        gradients = dict()
        # 가중치/편향 행렬에 대한 gradient들을 저장할 딕셔너리

        self.loss(X, Y_true)  # forward propagation

        # back propagation
        dout = 1
        dout = self.last_layer.backward(dout)

        layers = list(self.layers.values())  # [afine1, relu, affine2]
        layers.reverse()  # 리스트를 역순으로 바꿈. [affine2, relu, affine1]
        for layer in layers:
            dout = layer.backward(dout)

        # 모든 레이어에 대해서 역전파가 끝나면,
        # 가중치/편향 행렬들의 gradient를 찾을 수 있다.
        gradients['W1'] = self.layers['affine1'].dW
        gradients['b1'] = self.layers['affine1'].db
        gradients['W2'] = self.layers['affine2'].dW
        gradients['b2'] = self.layers['affine2'].db

        return gradients
示例#5
0
class TwoLayerNetwork:
    def __init__(self,
                 input_size,
                 hidden_size,
                 output_size,
                 weight_init_std=0.01):
        """신경망의 구조(모양) 결정"""
        np.random.seed(106)

        # 가중치 / 편향 행렬들을 초기화
        self.params = dict()
        self.params['W1'] = weight_init_std * np.random.randn(
            input_size, hidden_size)
        self.params['b1'] = np.zeros(hidden_size)
        self.params['W2'] = weight_init_std * np.random.randn(
            hidden_size, output_size)
        self.params['b2'] = np.zeros(output_size)

        # layer 생성/초기화
        self.layers = OrderedDict()
        # 딕셔너리에 데이터가 추가된 순서가 유지되는 딕셔너리
        self.layers['affine1'] = Affine(self.params['W1'],
                                        self.params['b1'])  # Affine
        self.layers['relu'] = Relu()  # Relu
        self.layers['affine2'] = Affine(self.params['W2'], self.params['b2'])
        self.last_layer = SoftmaxWithLoss()

    def predict(self, X):
        # Y = self.layers['affine1'].forward(X)
        # Y = self.layers['relu'].forward(Y)
        # Y = self.layers['affine2'].forward(Y)
        # 위 3개의 식과 아래의 식은 같다
        # orderedDict이므로 저장한 순서대로 values가 출력된다.
        for layer in self.layers.values():
            X = layer.forward(X)
        return X

    def loss(self, X, y_true):
        """입력 데이터 X와 실제 값(레이블) Y_true가 주어졌을 때,
        손실(cross-entropy)를 계산해서 리턴"""
        # 출력층(SoftmaxWithLoss) 전까지의 forward propagation을 계산
        Y_pred = self.predict(X)
        # 출력층 바로 전 계층의 출력값을 입력으로 사용해서 손실(cross-entropy)을 계산
        loss = self.last_layer.forward(Y_pred, y_true)
        return loss

    def accuracy(self, X, Y_true):
        """입력 데이터 X와 실제 값(레이블) Y_true가 주어졌을 때,
            예측 값들의 정확도를 계산해서 return"""
        Y_pred = self.predict(X)
        predictions = np.argmax(Y_pred, axis=1)
        trues = np.argmax(Y_true, axis=1)
        result = trues == predictions  # 정답과 예측값의 비교(bool) 결과를 저장한 배열
        return np.mean(result)  # True = 1, False = 0 으로 대체된 후 평균 계산됨.
        # (1 + 1 + ... + 0 + ...) / 전체 개수

    def gradient(self, X, Y_true):
        """입력 데이터 X와 실제 값(레이블) Y_true가 주어졌을 때,
            모든 레이어에 대해서 forward propagation을 수행한 후,
            오차 역전파 방법을 이용해서 dW1, db1, dW2, db2를 계산하고 리턴."""
        # 가중치/ 편향 행렬에 대한 gardients를 저장할 dictionary
        gradients = dict()

        loss = self.loss(X, Y_true)  # forward propagation

        # back propagation
        dout = 1
        dout = self.last_layer.backward(dout)

        layers = list(self.layers.values())  # [affine1, relu, affine2] 순서로 저장됨
        layers.reverse()  # 리스트를 역순으로 바꿔주는 함수 [ affine2, relu, affine1 ]
        for layer in layers:
            dout = layer.backward(dout)

        # 모든 레이어에 대해서 역전파가 끝나면, 가중치/편향 행렬의 gradient를 찾을 수 있다.
        gradients['W1'] = self.layers['affine1'].dW
        gradients['b1'] = self.layers['affine1'].db
        gradients['W2'] = self.layers['affine2'].dW
        gradients['b2'] = self.layers['affine2'].db

        return gradients
示例#6
0
class TwolayerNetwork:
    def __init__(self,
                 input_size,
                 hidden_size,
                 output_size,
                 weight_init_std=0.01):  # 난수들을 선택할 때 0에 가까운 수들을 더 선택할 것이냐
        """ 신경망의 구조(모양) 결정
            input size: number of variables
            output size: i.e. 숫자 이미지 -> 10개, iris -> 3개
        """
        np.random.seed(106)

        # 가중치/편향 행렬들을 초기화
        # W1, b1, W2, b2 와 같은 값들을 리스트로 만들어두면 나중에 iteration하기 쉽다
        self.params = dict()
        self.params['W1'] = weight_init_std * np.random.randn(
            input_size, hidden_size)
        self.params['b1'] = np.zeros(hidden_size)  # 편향은 모두 0으로 준다
        self.params['W2'] = weight_init_std * np.random.randn(
            hidden_size, output_size)
        self.params['b2'] = np.zeros(output_size)

        # n in randomn stands for normalization (정규분포)
        # 정규분포 is a bell-like graph which is symmetric (평균을 기준으로 좌우가 대칭)  # 평균 0, 표준편차 1
        # 정규분포를 확률 분포라고 생각하면, 임의의 값을 꺼낼 때 -0.5 와 0.5 사이의 값을 가장 많이 리턴해준다
        # random number로 해주어야해요 - 표준편차를 1로 시작하면 모든 값이 같아서 나중엔 학습의 효과가 없을 수도 있어요 (그래서 std = 0.01을 해주었다)

        # 위의 방법대로라면 저장한 순서대로 반복문에서 출력되는 것이 보장되지 않는다
        # layer 생성/초기화
        self.layers = OrderedDict()
        # 딕셔너리에 데이터가 추가된 순서가 유지되는 딕셔너리
        # 순서가 중요하기 때문에 (Affine - ReLU - Affine - SoftmaxWithLoss => forward그리고 backward는 이 반대 순서대로 진행되어야하기 때문)
        self.layers['affine1'] = Affine(self.params['W1'], self.params['b1'])
        self.layers['relu'] = Relu()
        self.layers['affine2'] = Affine(self.params['W2'], self.params['b2'])
        self.last_layer = SoftmaxWithLoss()

        # backward propagation: since it is a propagation with order, we can just reverse the process above

    def predict(self, X):
        """ 입력데이터를 전달을 받아서, 입력받은 데이터가 무엇이 되느냐를 예측하는 함수
            입력값을 입력 받아서, softmaxwithloss가기 직전에 모든 값들의 확률?을 리턴한 값을 사용 (왜냐하면 swl는 CE값 1개만 리턴해준다) (affine2 까지 진행된 값)
            확률로 표현되어 있어도 되고, 아니여도 상관없다 (output 중에서 가장 큰 값이 무엇이냐가 제일 중요; 대소비교)  """

        # How predict works
        # Y1= self.layers['affine1'].forward(X) #첫번째 출력값
        # Y2 = self.layers['relu'].forward(Y1)
        # Y3 = self.layers['affine2'].forward(Y2) # this is the data that we want to process

        # could shorten the code using for-loop
        for layer in self.layers.values():
            X = layer.forward(X)
        return X
        # we can (creer/confiar en) the for-loop because we used ordered dict
        # We can use the code regardless the number of layers

        # how I thought
        # X 가 무슨 값을 돌려줄 것인지 predict
        # X = self.layers['affine2']
        # # affine2의 output column을 빼서 one_hot_label의 자리 비교
        # print('X =', X)

    def loss(self, X, Y_true):
        """ 손실 함수, 끝까지 가기 위한 함수 -> 문제를 끝까지 넘겨서 예측값을 줘야하고 (forward) -> 실제값(정답지)를 가지고 있어서 비교할 수 있게 해주어야한다
            최종 리턴: cross_entropy """

        #SoftmaxWithLoss, 가장 마지막 출력층 전까지의 forward를 먼저 계산
        Y_pred = self.predict(
            X)  # predict: 입력값을 주면 예측값을 주는 함수 -> softmax전까지의 값을 계산
        loss = self.last_layer.forward(Y_pred, Y_true)
        return loss  # 만들어진 ce를 리턴

    def accuracy(self, X, Y_true):
        """ 손실의 반대 개념 이라고 생각해도 된다.
            입력 데이터 X와 실제 값(레이블) Y_true가 주어졌을 때,
            예측 값들의 정확도를 계산해서 리턴.
            accuracy = 예측이 실제값과 일차하는 개수/ 전체 입력 데이터 개수
             # X에서 적어도 2개 이상의 값을 넘겼을 때, n개에 대한 예측값
            X, Y_true는 모두 2차원 배열(행렬)라고 가정.
             """
        Y_pred = self.predict(X)
        predictions = np.argmax(Y_pred, axis=1)
        trues = np.argmax(Y_true,
                          axis=1)  #one_hot_encoding에서 1이 어디에 들어가 있느냐를 찾는 것
        # (어짜피 0,1밖에 없으니까, 1이 제일 큰 값. 행별로 비교하면 각 행에서 가장 큰 값이 1)
        # predictions = trues
        acc = np.mean(predictions == trues)  # true와 false로 이루어진 리스트 => 0,1
        # 1들만 더해짐 (true values) -> 일치하는 갯수/ 전체 갯수
        return acc

    def gradient(self, X, Y_true):
        """ X: 입력 데이터와 Y_true: 실제 데이터가 주어졌을 때,
            모든 레이어에 대해서 forward propagation을 수행한 후,
            오차 역전파 방법을 이용해서 dW1, db1, dW2, db2를 계산하고 리턴
            -> W와 b의 값 수정을 위해서 gradient를 찾는다 """
        gradients = dict()

        # loss 1개만 호출하면 모든 레이어에 대해 forward가 호출이 된다( 마지막 레이어 포함)
        self.loss(X, Y_true)  #forward propagation

        # back propagation
        dout = 1
        dout = self.last_layer.backward(dout)
        # 반복문을 사용한다
        layers = list(self.layers.values(
        ))  #[Affine1, ReLU, Affine2] # 순서가 있는 딕셔너리 -> 순서대로 값들이 꺼내진다
        # 리스트로 만드는 이유: 우리가 원하는 것 -> 반대로 하기 위해서 -> We cannot change the order from a dictionary, but we can from a list
        layers.reverse(
        )  # 리스트를 역순으로 바꿈 # ordered dict에는 reverse함수가 따로 없어서 value 꺼내기 -> 순서 바꾸기 해줌
        # layer에서 for-loop을 사용한다
        for layer in layers:
            dout = layer.backward(dout)
            # 입력해준 dout으로 backward시키고, 그걸 가지고 또 backward,,,

            # 모든 레이어에 대해서 역전파가 끝나면, 가중치/편향들의 gradient를 찾을 수 있다
            gradients['W1'] = self.layers['affine1'].dW
            gradients['b1'] = self.layers['affine1'].db
            gradients['W2'] = self.layers['affine2'].dW
            gradients['b2'] = self.layers['affine2'].db
            # __init__ 에서 저장 가능하게 만들었기 때문에, 이런 코드들이 가능하다

        return gradients