1. 딥러닝
- 여러 비선형 변환 기법의 조합을 통해 높은 수준의 추상화를 시도하는 머신러닝 알고리즘의 집합
- 연속된 층(Layer)에서 점진적으로 의미있는 표현을 배우는 방식
- 기존의 머신러닝 방법은 1~2가지의 데이터 표현을 학습하는 얕은 학습을 수행하지만 딥러닝은 수백개 이상의 층 이용
- 데이터로부터 표현을 학습하는 수학 모델
- 층을 통과할 때마다 새로운 데이터 표현을 만들어가면서 학습
1-1) 작동 원리
- 층에서 입력 데이터가 처리되는 내용은 일련의 숫자로 이루어진 층의 가중치에 저장이 되는데 이는 그 층의 가중치를 parameter로 갖는 함수로 표현
- 이 가중치를 알아내려면 데이터를 관찰해야 하고 신경망의 출력이 기대하는 것보다 얼마나 벗어났는지 측정
- 딥러닝은 기본적으로 지도학습
- 지도학습은 오차를 줄여나가는 작업이므로 오차를 측정하는 함수가 존재해야 하는데 이를 손실함수라고 한다.(Loss Function)
- 딥러닝은 손실 함수의 값이 감소하는 방향으로 가중치 값을 수정해나가는 것
- 초창기에는 네트워크의 가중치를 랜덤하게 할당하고 랜덤한 변환을 연속적으로 수행하는 방식을 사용했는데 이 방식은 수행을 많이 하게 되면 오히려 손실 점수가 높아지게 된다.
작동원리
1-2) 특징
- 딥러닝이 확산된 가장 큰 요인은 많은 문제에서 기존의 머신러닝 알고리즘보다 성능이 우수하기 때문
- 특성 공학을 완전히 자동화 함
- 기존의 머신러닝 알고리즘들은 대부분 알고리즘이 이해할 수 있도록 데이터를 변화하는 작업을 직접 수행
- 딥러닝은 데이터의 좋은 표현을 스스로 만들어낸다.
- 딥러닝이 학습할 때의 특징
- 층을 거치면서 점진적으로 더 복잡한 표현을 만들어냄
- 점진적인 표현을 만드는 작업을 순차적으로 하는게 아니고 공동으로 학습
1-3) 최근 경향
- 2010년대 후반까지는 Kaggle에서 GBM과 Deep Learning을 사용한 모델이 우승을 차지했는데 GBM은 구조적인 데이터에 사용하고 Deep Learning은 이미지 분류와 지각에 관한 문제에 사용
- GBM 모델 중에서도 XGBoost가 주로 이용
- 패턴 인식 분야에서는 최근 거의 무조건 Deep Learning 사용
- 딥러닝을 많이 사용하게 된 이유는 하드웨어의 발전과 데이터의 증가
1-4) 장점
- 성능이 우수
- 특성 공학이 자동
- 구조화되지 않은 데이터 학습 능력이 뛰어남
1-5) 제한
- 학습 데이터가 많아야 함
- 네트워크가 만들어 낸 특성을 해석하기가 어려움
- 컴퓨팅 자원이 많이 필요
- 데이터의 크기가 기가 바이트를 넘지 않는다면 딥러닝과 머신러닝은 별 차이가 없다.
1-6) 딥러닝 패키지
- Torch
- C로 구현된 라이브러리로 페이스북에서 Torch로 만들 PyTorch를 내놓으면서 유명
- 연구용으로 많이 사용
- Theano
- Numpy 배열과 관련성이 높은 패키지로 계산을 많이 하는 연구에 이용
- 구글의 오픈소스인 Tensorflow가 Theano에서 영감을 얻은 라이브러리
- 프로덕션 구현이 강력 - PC, Android, Web용 라이브러리 제공
- CuDNN
- CUDA Deep Neural Network의 약자로 GPU 구현을 위한 라이브러리 제공
2. 인공 신경망 (ANN - Artificial Neural Network)
- 근원: 지능적인 기계를 만드는 법에 대한 영감을 얻으려면 뇌 구조를 살펴보는 것이 합리적이라고 판단
- 인공 신경망은 뇌에 있는 생물학적 뉴런의 네트워크에서 영감을 받은 머신러닝 모델이지만 새를 보고 비행기에 대한 영감을 얻었다고 해서 비행기 날개를 새처럼 펄럭 거릴 필요는 없는데 인공 신경망도 생물학적 뉴런에서 점점멀어지고 있음
- 일부에서는 neuron이라는 표현 대신에 unit이라고 지칭
- 1943년에 워런 매컬러의 논문에서 처음 소개
2-1) 뉴런을 이용한 논리 연산
- 가장 처음 만든 모델은 하나 이상의 이진 입력과 이진 출력 하나를 가짐
- 이 모델을 가지고 not, or, and 연산 수행
2-2) Perceptron
- 입력과 출력이 이진이 아닌 숫자이고 각각의 입력 연결은 가중치와 연관되어 있음
- 입력의 가중치 합을 계산한 뒤 계산된 합에 함수(계단 함수 - step function)를 적용해서 결과를 출력
- 가장 많이 사용되는 계단 함수: heaviside와 sign function
- heaviside는 가중치의 합이 0보다 작으면 0, 0보다 크거나 같으면 1을 리턴하는 함수
- sign function은 가중치의 합이 0보다 작을 때 -1, 0일 때 0, 0보다 클 때 1을 리턴하는 함수
- 이러한 perceptron이 여러개 모여서 하나의 Layer를 구성하게 되고 이전 층의 모든 뉴런과 연결된 것을 Fully Connected Layer(완전연결층) 또는 Dense Layer(밀집층)
- 입력은 입력 뉴런이라고 하는 특별한 뉴런에 주입이 되는데 이러한 입력 뉴런으로 구성된 레이러를 Input Layer라고 부른다.
- 이 레이어가 다른 점은 편향 특성이 더해지는데 (x0 = 1) 이 편향 특성은 항상 1을 출력하는 특별한 종류의 뉴런이라고 해서 편향 뉴런(Bias Neuron)이라고 표현
- Perceptron은 선형 분류 모형의 형태를 갖게 됨
- 논리 연산 중 XOR 문제를 해결하지 못함
2-3) MLP
- Perceptron이 지닌 한계점을 극복하기 위해서 여러개의 Layer를 쌓아 올린 MLP(Multi Layer Perceptron)이 등장
- Perceptron은 기본적으로 Input과 Output Layer로만 구성되지만 MLP는 이 중간에 Hidden Layer를 추가한 형태
- Hidden Layer는 여러개의 Perceptron이 모여있는 구조
- Hidden Layer를 여러개 쌓으면 깊어지기 때문에 이를 Deep Learning이라고 부름
- Input에서 Weight을 계산하고 Hidden Layer를 거쳐서 Output을 만들어내는데 이 과정을 Feed Forward라고 한다.
2-4) Activation Function
- 어떤 신호를 받아서 이를 적절히 처리해서 출력해주는 함수
- Input과 Weight를 받아서 연산을 수행해주는 함수
- 신경망은 비선형 Activation Function을 선호
- 선형 함수: Sign Function, Heaviside Step
- Sigmoid(로그함수 - 1/(1 + e의 -x승))
- Sigmoid 함수는 입력 값이 0 이하이면 0.5 이하의 값을 출력하고 0 이상이면 0.5 이상의 값을 출력하는데 입력 값에 대해서 0과 1 사이의 값으로 Scailing 해주는 개념의 함수
- Sign Function과 Heaviside는 선형이고 Sigmoid는 비선형
- 대부분의 경우 비선형이 선형보다 우수한 성능을 발휘하기 때문에 신경망은 비선형을 선호
- Sigmoid 함수는 복잡한 문제를 해결할 수는 있지만 Back Propagation 과정 중 Gradient Vanishing(소멸) 현상이 발생할 수 있음
- 모델이 깊어질수록 이러한 현상이 자주 발생
- softmax 함수
- Sigmoid를 일반화시킨 함수로 다중 클래스 분류에 가장 적합
- ReLU (Rectified Linear Unit)
- 전체 입력이 0보다 크면 출력은 순입력(가중치를 곱하고 편향을 더한 값)과 같고 전체 입력이 0보다 작거나 같으면 0을 출력
- y = max(0, 가중치*입력 + 편향)
- ReLU는 입력이 양수이고 기울기가 0이어도 일정한 기울기를 가지게 됨
- 양수만 보면 선형이지만 0이나 0보다 작을 때 0의 값을 갖도록 해서 비선형을 만들어 냄
- 음수일 때도 기울기를 가지도록 만들어진 함수가 있는데 이 함수는 PReLU
- Hyperbolic Tangent : tanh
- 출력이 0인 지점에서 기울기를 가짐
2-5) Learning Rate 학습률
- 경사 하강법에서 가중치를 업데이트 할 때 간격
- 숫자가 커지면 최적의 지점을 찾지 할 수 있고 너무 작은 값을 선택하면 학습 속도가 느려질 수 있음
- 신경망에서는 0.01 아래의 값을 사용하는 것을 권장
2-6) Back Propagation 역전파
- Input 에서 Output 까지 계산을 수행하고 그 결과와 실제 답과의 오차를 구해서 오차가 작아지는 형태로 가중치를 조정해야 하는데, 가중치를 조정할 때 뒤에 있는 가중치를 먼저 업데이트 한다고 해서 역전파 알고리즘이라고 부름
- 한번 Feed Forward 로 작업을 수행하고 Back Propagation을 수행하면 1번의 epoch 라고 함
- 알고리즘을 수행할 때 모든 데이터를 가지고 한꺼번에 하지는 않고 일반적으로 mini batch 라고 부르는 작은 단위로 실행
3. TensorFlow
- 구글이 만든 Deep Learning에 초점을 맞춘 라이브러리
- GPU 지원
- 분산 컴퓨팅을 지원: 여러 대의 컴퓨터에서 동시에 학습 가능하고 예측도 가능
- 플랫폼에 중립적인 포맷으로 내보낼 수 있음
- 리눅스를 사용하는 파이썬 환경에서 Tensorflow 모델을 훈련시키고 이 모델을 안드로이드에서 실행할 수 있음
3-1) API
- 거의 모든 운영체제를 지원하고 Tensorflow Lite를 이용하면 안드로이드 와 iOS 같은 모바일 운영체제에서도 실행되고 Python API를 많이 이용하지만 C++, Java, Go(golang), Swift API도 제공됨
- Tensorflow Hub에서 사전에 훈련된 신경망을 쉽게 다운로드 받아서 사용할 수 있음
- https://www.tensorflow.org/resources
3-2) 연산
- 가장 저 수준의 연산은 C++ 코드로 만들어져 있음
- 연산들이 여러 종류의 커널에서 수행: CPU, GPU, TPU 등
- TPU는 Deep Learning 연산을 위해 특별하게 설계된 ASIC Chip
3-3) 설치
pip install tensorflow
- numpy 버전과 tensorflow 버전이 서로 충돌할 때가 있다.
버전확인
import tensorflow as tf
print(tf.__version__)
4. Tensorflow 사용
4-1) Tensor 생성
- numpy의 ndarray와 유사한 방식으로 생성
- immutable 데이터(변경 불가)는 tf.constant로 생성
tf.constant(42) # 스칼라
tf.constant([[1., 2., 3.], [4., 5., 6.]]) # 행렬
t = tf.constant([[1., 2., 3.], [4., 5., 6.]])
t
<tf.Tensor: shape=(2, 3), dtype=float32, numpy= array([[1., 2., 3.], [4., 5., 6.]], dtype=float32)> |
print(t[:, 1]) #1번째 열: 하나의 열이라서 1차원 배열
print()
print(t[:, 1:]) #1번째 열부터 모든 열
print()
print(t[..., 1, tf.newaxis])
tf.Tensor([2. 5.], shape=(2,), dtype=float32) tf.Tensor( [[2. 3.] [5. 6.]], shape=(2, 2), dtype=float32) tf.Tensor( [[2.] [5.]], shape=(2, 1), dtype=float32) |
- 1차원 배열이 2차원 배열이 된다.
4-2) 연산
- numpy 의 ndarray 와 거의 동일한 방식으로 연산을 수행하고 함수 나 메서드의 이름도 거의 일치
print(t + 10)
print()
print(tf.square(t))
print()
print(t @ tf.transpose(t))
tf.Tensor( [[11. 12. 13.] [14. 15. 16.]], shape=(2, 3), dtype=float32) tf.Tensor( [[ 1. 4. 9.] [16. 25. 36.]], shape=(2, 3), dtype=float32) tf.Tensor( [[14. 32.] [32. 77.]], shape=(2, 2), dtype=float32) |
- tensorflow나 numpy에서 배열을 가지고 산술연산을 하는 경우 실제로는 함수 호출
- python 에서는 __이름__ 형태로 메서드를 만드는 경우가 있는데 이러한 함수들은 Magic Function 이라고 부르는데 사용을 할 때 메서드 이름을 호출하는 것이 아니라 다른 연산자를 이용한다.
- 이렇게 연산자의 기능을 변경하는 것을 연산자 오버로딩
- 객체 지향에서만 가능합니다.
- + 는 숫자 두 개를 더하는 기능을 가지고 있는데 tensorflow 나 numpy 에서는 __add__를 정의해서 이 메서드를 호출하도록 한다.
- 이름이 다른 함수도 있음
- np.mean -> tf.reduce_mean
- tf.float32 는 제한된 정밀도를 갖기 때문에 연산을 할 때 마다 결과가 달라질 수 있음
- 동일한 기능을 하는 함수나 클래스를 Keras 가 별도로 소유하고 있는 경우도 있음
- Keras는 Tensorflow 의 저수준 API(Core 에 가까운 쪽)
4-3) Tensor와 numpy의 ndarray
- 2개의 데이터 타입은 호환이 되서 서로 변경이 가능
- Tensor를 ndarray 로 변환하고자 하는 경우는 numpy() 메서드를 호출해도 되고 numpy 의 array 함수에 Tensor를 대입해도 된다.
- ndarray를 가지고 Tensor를 만들고자 할 때는 contant 나 variable 같은 함수에 대입
ar = np.array([2, 3, 4])
print(tf.constant(ar))
tf.Tensor([2 3 4], shape=(3,), dtype=int32) |
ar = np.array([2, 3, 4])
print(tf.constant(ar))
[2 3 4] [2 3 4] |
4-4) 타입 변환
- Data Type이 성능을 크게 감소시킬 수 있음
- Tensorflow 는 타입을 절대로 자동 변환하지 않는다.
- 데이터 타입이 다르면 연산이 수행되지 않음
- 타입이 다른데 연산을 수행하고자 하는 경우에는 tf.cast 함수를 이용해서 자료형을 변경해야 함
- Tensorflow 가 형 변환을 자동으로 하지 않는 이유는 사용자가 알지 못하는 작업은 수행을 하면 안된다는 원칙 때문
#ndarray는 이렇게 자료형이 다른 경우 자동으로 자료형을 변경해서 연산을 수행
print(np.array([1, 2, 3]) + np.array([1.6, 2.3, 3.4]))
[2.6 4.3 6.4] |
#자료형이 달라서 에러가 발생
print(tf.constant(2.0) + tf.constant(40))
InvalidArgumentError: cannot compute AddV2 as input #1(zero-based) was expected to be a float tensor but is a int32 tensor [Op:AddV2] name: |
t1 = tf.constant(40)
#형 변환 한 후 연산 수행
print(tf.constant(2.0) + tf.cast(t1, tf.float32))
tf.Tensor(42.0, shape=(), dtype=float32) |
4-5) 변수
- 일반적인 데이터는 직접 변경을 하지 않기 때문에 constant 로 생성해서 사용하면 되는데 역전파 알고리즘을 수행하게 되면 가중치가 업데이트된다고 했는데 가중치는 수정되어야 하기 때문에 constant로 생성되면 안됨
- 수정되어야 하는 데이터는 tf.Variable 을 이용해서 생성
- 데이터를 수정하고자 하는 경우는 assign 함수를 이용
- assign_add 나 assign _sub를 이용해서 일정한 값을 더하거나 빼서 수정할 수 있음
- 배열의 일부분을 수정할 때는 assign 함수나 scatter_update() 나 scatter_nd_update ()를 이용
#변수 생성
v = tf.Variable([[1, 2, 3], [4, 5, 6]])
print(v)
print(id(v))
#이 경우는 데이터를 수정한 것이 아니고
#기존 데이터를 복제해서 연산을 수행한 후 그 결과를 가리키도록 한 것
#참조하는 위치가 변경됨
v = v * 2
print(v)
print(id(v))
#내부 데이터 수정
v = tf.Variable([[1, 2, 3], [4, 5, 6]])
print(v)
print(id(v))
#이 경우는 id 변경없이 데이터를 수정
v.assign(2 * v)
print(v)
print(id(v))
<tf.Variable 'Variable:0' shape=(2, 3) dtype=int32, numpy= array([[1, 2, 3], [4, 5, 6]])> 2832592070160 tf.Tensor( [[ 2 4 6] [ 8 10 12]], shape=(2, 3), dtype=int32) 2832590246432 <tf.Variable 'Variable:0' shape=(2, 3) dtype=int32, numpy= array([[1, 2, 3], [4, 5, 6]])> 2832592070992 <tf.Variable 'Variable:0' shape=(2, 3) dtype=int32, numpy= array([[ 2, 4, 6], [ 8, 10, 12]])> 2832592070992 |
4-6) Data구조
- 종류
- SparseTensor: 0이 많은 Tensor를 효율적으로 나타내는데 tf.sparse 패키지에서 이 Tensor에 대한 연산을 제공
- TensorArray: Tensor의 list
- RaggedTensor: list 의 list
- stringtensor: 문자열 텐서인데 실제로는 바이트 문자열로 저장됨
- set
- queue
4-7) Tensorflow 함수
- 일반 함수는 python 의 연산 방식에 따라 동작하지만 Tensorflow 함수를 만들게 되면 Tensorflow 프레임워크가 자신의 연산 방식으로 변경해서 수행을 하기 때문에 속도가 빨라질 가능성이 높음
- 생성방법
- 함수를 정의한 후 tf.function 이라는 decorator를 추가해도 되고 tf.function 함수에 함수를 대입해서 리턴받아도 됨
- 함수를 변경하는 과정에서 Tensorflow 함수로 변경이 불가능하면 일반 함수로 변환
4-8) 난수 생성
- tf.random 모듈을 이용해서 난수를 생성
5. 뉴런 생성
- 뉴런을 추상화하면 Perceptron
5-1) 입력 -> 뉴런 -> 출력
- 이런 여러 개의 뉴런이 모이면 Layer 라고 하며 이런 Layer의 집합이 신경망
5-2) 뉴런의 구성
- 입력, 가중치, 활성화 함수, 출력으로 구성
- 입력과 가중치와 출력은 일반적으로 정수나 실수
- 활성화 함수는 뉴런의 출력 값을 정하는 함수
- 간단한 형태의 뉴런은 입력에 가중치를 곱한 뒤 활성화 함수를 취하면 출력을 얻어 낼 수 있음
- 뉴런은 가중치를 처음에는 랜덤하게 초기화를 해서 시작하고 학습 과정에서 점차 일정한 값으로 수렴
- 학습 할 때 변하는 것은 가중치
- 활성화 함수는 시그모이드나 ReLU 를 주로 이용
- 최근에는 주로 ReLU를 주로 이용
- 뉴런을 직접 생성
#시그모이드 함수
import math
def sigmoid(x):
return 1 / (1 + math.exp(-x))
#입력
x = 1
#출력
y = 0
#한번 학습
w = tf.random.normal([1], 0, 1) #가중치
output = sigmoid(x * w)
print(output)
0.5174928205334988 |
#학습률을 0.01 로 설정해서 경사하강법을 수행
#학습 횟수 - epoch
for i in range(1000):
#출력을 생성
output = sigmoid(x * w)
#출력 오차를 계산
error = y - output
#가중치 업데이트
w = w + x * 0.1 * error
#횟수 와 오차 그리고 출력값을 확인
if i % 100 == 0:
print(i, error, output)
0 -0.000905242523688215 0.000905242523688215 100 -0.0008971286421305708 0.0008971286421305708 200 -0.0008891556201675512 0.0008891556201675512 300 -0.0008813285493673459 0.0008813285493673459 400 -0.0008736348299158559 0.0008736348299158559 500 -0.0008660738198464301 0.0008660738198464301 600 -0.0008586448693105883 0.0008586448693105883 700 -0.000851337993012676 0.000851337993012676 800 -0.0008441600044856342 0.0008441600044856342 900 -0.0008370967242979266 0.0008370967242979266 |
- 입력 데이터가 0 이고 가중치를 업데이트하는 식이 w + x * 0.1 * error 라서 x 가 0이 되면 가중치를 업데이트 할 수 없음
- 단순하게 시그모이드 함수를 적용하면 이 경우 최적점에 도달할 수 없고 계속 0.5 만 출력
- 입력 데이터 0에서 기울기가 없어지는 현상 - 기울기 소실 문제(Gradient Vanishing)
- 이 경우에는 시그모이드 함수 대신에 0에서 기울기를 갖는 ReLU를 사용하거나 시그모이드 함수에 데이터를 대입할 때 편향을 추가해서 해결
#입력
x = 0
#출력
y = 1
#학습률을 0.01 로 설정해서 경사하강법을 수행
#학습 횟수 - epoch
for i in range(1000):
#출력을 생성
output = sigmoid(x * w)
#출력 오차를 계산
error = y - output
#가중치 업데이트
w = w + x * 0.1 * error
#횟수 와 오차 그리고 출력값을 확인
if i % 100 == 0:
print(i, error, output)
0 0.5 0.5 100 0.5 0.5 200 0.5 0.5 300 0.5 0.5 400 0.5 0.5 500 0.5 0.5 600 0.5 0.5 700 0.5 0.5 800 0.5 0.5 900 0.5 0.5 |
5-3) AND를 구현
- AND 연산
0 0 -> 0
0 1 -> 0
1 0 -> 0
1 1 -> 1
- 입력 피처는 2개이고 출력은 1개, 가중치는 2개가 되어야 한다.
가중치는 입력 피처마다 설정됨
#입력과 출력 데이터 생성
X = np.array([[0,0], [0,1], [1,0], [1,1]])
y = np.array([[0], [0], [0], [1]])
#가중치 초기화
w = tf.random.normal([2], 0, 1) #입력 피처가 2개이므로 가중치도 2개
b = tf.random.normal([1], 0, 1) #편향
#학습
for i in range(3000):
#샘플이 여러 개이므로 에러는 모든 샘플의 에러 합계로 계산
#에러 합계를 저장할 변수
error_sum = 0
#4는 입력 데이터의 개수
for j in range(4):
#출력
output = sigmoid(np.sum(X[j] * w)+ 1*b)
#오차
error = y[j][0] - output
#가중치 업데이트 - 학습률은 0.1
w = w + X[j] * 0.1 * error
#편향 업데이트
b = b + 1 * 0.1 * error
#에러 값을 추가
error_sum += error
#100번 훈련을 할 때 마다 에러의 합계를 출력
if i % 100 == 99:
print(i, error_sum)
99 -0.17735192112485976 199 -0.11300731067658454 299 -0.08377195476035765 399 -0.06660772360599848 499 -0.05523404708400695 599 -0.047131021104291515 699 -0.0410676336021214 799 -0.036362474376702675 899 -0.03260789231152378 999 -0.02954500410502825 1099 -0.026999358822200475 1199 -0.024851178654502953 1299 -0.023015025341699566 1399 -0.02142777432262047 1499 -0.020043216619398396 1599 -0.018823937643251798 1699 -0.017743068185467267 1799 -0.01677645680136907 1899 -0.015911195444538048 1999 -0.01512755414717172 2099 -0.014419652551368074 2199 -0.013772095486375625 2299 -0.013179941576847973 2399 -0.01263622946061431 2499 -0.012136535236976859 2599 -0.011673507060527888 2699 -0.011244035558989098 2799 -0.010844459250993976 2899 -0.010471849788373774 2999 -0.01012400105746833 |
#예측한 값 확인
for i in range(4):
print('X:', X[i], "y:", y[i], sigmoid(np.sum(X[i]*w) + b))
X: [0 0] y: [0] 7.0765703582980925e-06 X: [0 1] y: [0] 0.01685800433498835 X: [1 0] y: [0] 0.016892931634238755 X: [1 1] y: [1] 0.9765455899723378 |
5-4) XOR 문제
#입력과 출력 데이터 생성 - 같으면 0 다르면 1
X = np.array([[0,0], [0,1], [1,0], [1,1]])
y = np.array([[0], [1], [1], [0]])
#가중치 초기화
w = tf.random.normal([2], 0, 1) #입력 피처가 2개이므로 가중치도 2개
b = tf.random.normal([1], 0, 1) #편향
#학습
for i in range(3000):
#샘플이 여러 개이므로 에러는 모든 샘플의 에러 합계로 계산
#에러 합계를 저장할 변수
error_sum = 0
#4는 입력 데이터의 개수
for j in range(4):
#출력
output = sigmoid(np.sum(X[j] * w)+ 1*b)
#오차
error = y[j][0] - output
#가중치 업데이트 - 학습률은 0.1
w = w + X[j] * 0.1 * error
#편향 업데이트
b = b + 1 * 0.1 * error
#에러 값을 추가
error_sum += error
#100번 훈련을 할 때 마다 에러의 합계를 출력
if i % 100 == 99:
print(i, error_sum)
99 0.016761352459349288 199 0.0033813217285643127 299 0.000681716543979527 399 0.00013744418256744773 499 2.769994422202604e-05 599 5.5935759204484015e-06 699 1.125229269538508e-06 799 2.149941442652903e-07 899 1.9544921903147383e-08 999 4.746623760709667e-08 1099 4.746623760709667e-08 1199 4.746623760709667e-08 1299 4.746623760709667e-08 1399 4.746623760709667e-08 1499 4.746623760709667e-08 1599 4.746623760709667e-08 1699 4.746623760709667e-08 1799 4.746623760709667e-08 1899 4.746623760709667e-08 1999 4.746623760709667e-08 2099 4.746623760709667e-08 2199 4.746623760709667e-08 2299 4.746623760709667e-08 2399 4.746623760709667e-08 2499 4.746623760709667e-08 2599 4.746623760709667e-08 2699 4.746623760709667e-08 2799 4.746623760709667e-08 2899 4.746623760709667e-08 2999 4.746623760709667e-08 |
# 일정 epoch 이후에 에러값이 변경되지 않음
#예측한 값 확인
for i in range(4):
print('X:', X[i], "y:", y[i], sigmoid(np.sum(X[i]*w) + b))
X: [0 0] y: [0] 0.5128175691057347 X: [0 1] y: [1] 0.49999997485429043 X: [1 0] y: [1] 0.4871823676059484 X: [1 1] y: [0] 0.47438160794816525 |
- 4개의 출력 결과가 비슷
#가중치 와 편향을 출력
print('가중치:', w)
print("편향:", b)
가중치: tf.Tensor([-0.10256328 -0.05128161], shape=(2,), dtype=float32) 편향: tf.Tensor([0.05128151], shape=(1,), dtype=float32) |
- 첫 번째 가중치가 두번째 가중치보다 2배 정도 더 크다.
- 첫번째 데이터의 영향력이 커져서 첫번째 데이터에 의해서 값이 결정될 가능성이 높다.
- XOR 문제는 하나의 선으로는 해결할 수 없는 문제
- 이런 경우는 여러 개의 선을 그어서 해결 - Layer를 여러 개 만들어야 한다.
6. MLP
6-1) XOR 문제 해결
import numpy as np
#입력과 출력 데이터 생성 - 같으면 0 다르면 1
X = np.array([[0,0], [0,1], [1,0], [1,1]])
y = np.array([[0], [1], [1], [0]])
#2개의 완전 연결층을 가진 모델을 생성
#units 는 뉴런의 개수이고 activation은 출력을 계산해주는 함수
#input_shape는 맨 처음 입력 층에서 피처의 모양
model = tf.keras.Sequential([
tf.keras.layers.Dense(units=2, activation='sigmoid', input_shape=(2, )),
tf.keras.layers.Dense(units=1, activation='sigmoid')
])
#lr 부분이 에러가 발생하면 learning_rate 로 수정하시면 됩니다.
model.compile(optimizer=tf.keras.optimizers.SGD(learning_rate=0.1), loss='mse')
#모델을 확인
model.summary()
# 훈련
#batch_size는 한 번에 연산되는 데이터의 크기(Mini Batch)
history = model.fit(X, y, epochs=10000, batch_size=1)
# 결과 확인
result = model.predict(X)
print(result)
# 측정치 변화량 (손실의 변화량)
import matplotlib.pyplot as plt
plt.plot(history.history['loss'])
7. Tensorflow Data API
- Machine Learning을 하는 경우 대규모 데이터 세트를 사용해야 하는 경우가 있는데 이 경우 Data를 Load 하고 Preprocessing 을 수행하는 작업은 번거로운 작업이며 데이터를 어떻게 사용할 것인가 하는 것도 어려운 작업(Multi Threading, Queue, Batch, Prefetch 등) 중 하나
- Tensorflow Data API
- dataset 객체를 만들고 Data를 읽어올 위치와 변환 방법을 지정하면 이러한 작업을 자동으로 처리
- Data API는 텍스트 파일(csv, tsv 등), 고정 길이를 가진 이진 파일, Tensorflow의 TFRecord 포맷을 사용하는 이진 파일에서 데이터를 읽을 수 있다.
- 관계형 데이터베이스나 Google Big Query 와 같은 NoSQL 데이터베이스에서 데이터를 읽어올 수 있다.
- Tensorflow에서는 One Hot Encoding 이나 BoW Encoding, embedding 등의 작업을 수행해주는 다양한 Preprocessing 층도 제공
7-1) 프로젝트
- TF 변환
- TF Dataset(TFDS)
- dataset을 다운로드할 수 있는 편리한 함수 제공
- 이미지 넷과 같은 대용량 dataset이 포함되어 있음
dataset = tf.data.Dataset.range(10) #0~9 까지의 데이터를 가지고 데이터셋을 구성
print(dataset)
<_RangeDataset element_spec=TensorSpec(shape=(), dtype=tf.int64, name=None)> |
# 대다수의 데이터 셋은 이터레이터 구현
for item in dataset:
print(item)
tf.Tensor(0, shape=(), dtype=int64) tf.Tensor(1, shape=(), dtype=int64) tf.Tensor(2, shape=(), dtype=int64) tf.Tensor(3, shape=(), dtype=int64) tf.Tensor(4, shape=(), dtype=int64) tf.Tensor(5, shape=(), dtype=int64) tf.Tensor(6, shape=(), dtype=int64) tf.Tensor(7, shape=(), dtype=int64) tf.Tensor(8, shape=(), dtype=int64) tf.Tensor(9, shape=(), dtype=int64) |
- 데이터에 마지막이 batch 개수에 맞지 않는 경우 drop_remainder=True를 설정하면 마지막 배치는 사용하지 않음
dataset = dataset.repeat(5).batch(5)
for item in dataset:
print(item)
tf.Tensor([0 1 2 3 4], shape=(5,), dtype=int64) tf.Tensor([5 6 7 8 9], shape=(5,), dtype=int64) tf.Tensor([0 1 2 3 4], shape=(5,), dtype=int64) tf.Tensor([5 6 7 8 9], shape=(5,), dtype=int64) tf.Tensor([0 1 2 3 4], shape=(5,), dtype=int64) tf.Tensor([5 6 7 8 9], shape=(5,), dtype=int64) tf.Tensor([0 1 2 3 4], shape=(5,), dtype=int64) tf.Tensor([5 6 7 8 9], shape=(5,), dtype=int64) tf.Tensor([0 1 2 3 4], shape=(5,), dtype=int64) tf.Tensor([5 6 7 8 9], shape=(5,), dtype=int64) |
# 데이터 변환
dataset1 = dataset.map(lambda x : x * 2)
for item in dataset1:
print(item)
tf.Tensor([0 2 4 6 8], shape=(5,), dtype=int64) tf.Tensor([10 12 14 16 18], shape=(5,), dtype=int64) tf.Tensor([0 2 4 6 8], shape=(5,), dtype=int64) tf.Tensor([10 12 14 16 18], shape=(5,), dtype=int64) tf.Tensor([0 2 4 6 8], shape=(5,), dtype=int64) tf.Tensor([10 12 14 16 18], shape=(5,), dtype=int64) tf.Tensor([0 2 4 6 8], shape=(5,), dtype=int64) tf.Tensor([10 12 14 16 18], shape=(5,), dtype=int64) tf.Tensor([0 2 4 6 8], shape=(5,), dtype=int64) tf.Tensor([10 12 14 16 18], shape=(5,), dtype=int64) |
# 원하는 데이터만 추출
dataset = tf.data.Dataset.range(10)
dataset = dataset.filter(lambda x : x % 2 == 1)
for item in dataset:
print(item)
tf.Tensor(1, shape=(), dtype=int64) tf.Tensor(3, shape=(), dtype=int64) tf.Tensor(5, shape=(), dtype=int64) tf.Tensor(7, shape=(), dtype=int64) tf.Tensor(9, shape=(), dtype=int64) |
dataset = tf.data.Dataset.range(10)
dataset = dataset.take(3)
for item in dataset:
print(item)
tf.Tensor(0, shape=(), dtype=int64) tf.Tensor(1, shape=(), dtype=int64) tf.Tensor(2, shape=(), dtype=int64) |
# 데이터 shuffling
- 경사하강법은 훈련 세트에 있는 데이터들이 독립적이고 동일한 분포를 가졌을 때 최고의 성능을 발휘
- 셔플링을 할 때 주의할 점은 랜덤 시드를 부여해서 shuffling 되는 순서를 동일하게 만들어야 한다.
dataset = tf.data.Dataset.range(10).repeat(3)
dataset = dataset.shuffle(buffer_size=3, seed=42).batch(7)
for item in dataset:
print(item)
tf.Tensor([0 3 4 2 1 5 8], shape=(7,), dtype=int64) tf.Tensor([6 9 7 2 3 1 4], shape=(7,), dtype=int64) tf.Tensor([6 0 7 9 0 1 2], shape=(7,), dtype=int64) tf.Tensor([8 4 5 5 3 8 9], shape=(7,), dtype=int64) tf.Tensor([7 6], shape=(2,), dtype=int64) |
- https://tensorflow.org/datasets 에 가면 널리 사용되는 dataset을 다운로드 할 수 있음
- tfds.load 함수를 호출하면 Data를 다운로드하고 dataset 의 디셔너리로 Data를 리턴
- minist 데이터 가져오기
#!pip install tensorflow_datasets
import tensorflow_datasets as tfds
datasets = tfds.load(name="mnist")
#dict 형태로 데이터를 가져옵니다.
print(type(datasets))
#모든 키 확인
print(datasets.keys())
print(type(datasets['train']))
#하나의 데이터도 dict 로 되어 있음
for item in datasets['train']:
#print(type(item))
#print(item.keys())
#print(item['label'])
plt.imshow(item['image'])
break
'Python' 카테고리의 다른 글
[Python] 딥러닝 _ Keras (0) | 2024.03.20 |
---|---|
[Python] 연관 분석 (0) | 2024.03.18 |
[Python] 연관분석 실습 _ 네이버 지식인 크롤링 (4) | 2024.03.15 |
[Python] 감성 분석 실습 (3) | 2024.03.14 |
[Python] 차원 축소 (0) | 2024.03.12 |