컴퓨터공학/인공지능

[인공지능] 5장. 딥러닝과 텐서플로1

NIMHO 2023. 4. 10. 16:00
728x90

5.1 딥러닝의 등장

1980년대의 깊은 신경망

- 구조적으로는 쉬운 개념이다.

     - 다층 퍼셉트론에 은닉층을 많이 두면 깊은 신경망

- 하지만 학습이 잘 안 된다.

     - 그레이디언트 소멸 문제

     - 작은 데이터셋 문제

     - 과다한 계산 시간

 

5.1.1 딥러닝의 기술 혁신

딥러닝은 새로 창안된 이론이나 원리는 빈약하다.

- 신경망의 구조와 동작, 학습 알고리즘의 기본 원리는 거의 동일하다.

 

딥러닝의 기술 혁신 요인

- 값싼 GPU 등장

- 데이터셋 커짐

- 학습 알조리즘의 발전

     - ReLU 활성 함수

     - 구제 기법

     - 다양한 손실 함수와 옵티마이저 개발

 

학술적인 측면의 혁신 사례

- 컨볼루션 신경망이 딥러닝의 가능성을 열었다.

     - 1990년대 LeCun은 필기 숫자에서 획기적인 성능 향상

     - AlexNet은 컨볼루션 신경망으로 자연 영상 인식이 가능하다는 사실을 보여줬다.

- 음성 인식에서 혁신

 

5.1.2 딥러닝 소프트웨어

대표적인 딥러닝 소프트웨어

- 현재는 텐서플로와 파이토치가 대세

 

5.2 텐서플로 개념 익히기

5.2.1 텐서플로와 넘파이의 호환

tf가 제공하는 random 클래스의 uniform 함수로 난수 생성

- [0, 1] 사이의 난수를 2*3 행렬에 생

import tensorflow as tf

print(tf.__version__)
a = tf.random.uniform([2, 3], 0, 1)
print(a)
print(type(a))

 

tensorflow와 numpy로 2*3 난수 행렬 생성 후 더한다.

import tensorflow as tf
import numpy as np

t = tf.random.uniform([2, 3], 0, 1)
n = np.random.uniform(0, 1, [2, 3])

print(t)
print(n)

res = t + n
print(res)

 

5.2.2 텐서 이해하기

딥러닝에서 텐서

- 다차원 배열을 텐서라 부른다.

     - 데이터를 텐서로 표현한다.

     - 신경망의 가중치(매개변수)를 텐서로 표현한다.

- 넘파이는 ndarray 클래스, 텐서플로는 Tensor 클래스로 표현한다. (둘은 호환된다.)

 

0~5차원 구조의 텐서의 예

- 0차원 : iris label

- 1차원 : iris 샘플 하나

- 2차원 : iris 샘플 여러 개, 명암 영상 한 장

- 3차원 : 명암 영상 여러 개, 컬러 영상 한 장

- 4차원 : 컬러 영상 여러 개, 컬러 동영상 하나

- 5차원 : 컬러 동영상 여러 개

 

텐서플로가 제공하는 데이터셋의 텐서 구조

- MNIST, cifar10, Boston housing, Reuters 데이터셋의 텐서 구조 확인

import tensorflow as tf
import tensorflow.keras.datasets as ds


# mnist 읽고 텐서 모양 출력
(x_train, y_train), (x_test, y_test) = ds.mnist.load_data()
yy_train = tf.one_hot(y_train, 10, dtype=tf.int8) # 원핫코드로 변환
print('mnist : ', x_train.shape, y_train.shape, yy_train.shape)

# cifar10
(x_train, y_train), (x_test, y_test) = ds.cifar10.load_data()
yy_train = tf.one_hot(y_train, 10, dtype=tf.int8) # 원핫코드로 변환
print('cifar10 : ', x_train.shape, y_train.shape, yy_train.shape)

# boston housing
(x_train, y_train), (x_test, y_test) = ds.boston_housing.load_data()
print('boston : ', x_train.shape, y_train.shape)

# reuters
(x_train, y_train), (x_test, y_test) = ds.reuters.load_data()
print('reuters : ', x_train.shape, y_train.shape)

728x90

5.3 텐서플로 프로그래밍 기초

sklearn 라이브러리로는 다양한/복잡한 딥러닝 구현이 어렵다.

그래서 딥러닝 전용 프레임워크인 텐서플로나 파이토치를 사용해야 한다.

 

5.3.1 sklearn의 표현력 한계

from sklearn import datasets
from sklearn.neural_network import MLPClassifier
from sklearn.model_selection import train_test_split

# 1
digit=datasets.load_digits()
x_train,x_test,y_train,y_test=train_test_split(digit.data,digit.target,train_size=0.6)

# 2
mlp=MLPClassifier(hidden_layer_sizes=(100),learning_rate_init=0.001,batch_size=32,max_iter=300,solver='sgd',verbose=True)
# 3
mlp.fit(x_train,y_train)

딥러닝은 sklearn의 #2로는 표현이 불가능하다.

- 다양한 형식의 layer를 구성할 수 없다.

 

텐서 플로나 파이토치는 딥러닝의 복잡도를 지원할 수 있게 완전히 새로 설계한다.

 

5.3.2 텐서플로로 퍼셉트론 프로그래밍

Variable 함수는 그레이디언트를 구하고 가중치를 갱신하는 연산을 지원한다.

import tensorflow as tf

# OR 데이터 구축
x = [[0.0, 0.0], [0.0, 1.0], [1.0, 0.0], [1.0, 1.0]]
y = [[-1], [1], [1], [1]]

# 퍼셉트론
w = tf.Variable([[1.0], [1.0]])
b = tf.Variable(-0.5)

# 퍼셉트론 동작
s = tf.add(tf.matmul(x, w), b)
o = tf.sign(s)

print(o)

 

아래 코드는 퍼셉트론을 학습하는 프로그램 5-5이다.

import tensorflow as tf

# OR 데이터 구축
x = [[0.0, 0.0], [0.0, 1.0], [1.0, 0.0], [1.0, 1.0]]
y = [[-1], [1], [1], [1]]

# 가중치 초기화화
w = tf.Variable(tf.random.uniform([2, 1], -0.5, 0.5))
b = tf.Variable(tf.zeros([1]))

# 옵티마이저
opt = tf.keras.optimizers.SGD(learning_rate=0.1)

# 전방 계산
def forward():
  s = tf.add(tf.matmul(x, w), b)
  o = tf.tanh(s)
  return o

# 손실 함수 정의
def loss():
  o = forward()
  return tf.reduce_mean((y - o) ** 2)

# 500세대까지 학습 (100세대마다 학습 정보 출력)
for i in range(500):
  opt.minimize(loss, var_list=[w, b])
  if i % 100 == 0:
    print('loss at epoch ', i, ' = ', loss().numpy())

# 학습된 퍼셉트론으로 OR 데이터를 예측
o = forward()
print(o)

 

5.3.3 케라스 프로그래밍

[프로그램 5-5]의 문제점

- 신경망 동작을 직접 코딩해야 한다.

- 케라스는 이런 부담을 덜기 위해서 탄생했다.

 

프로그래밍의 추상화

- 컴퓨터 프로그래밍은 추상화를 높이는 방향으로 발전해 왔다.

- 텐서플로 자체가 아주 높은 추상화 수준이지만 추가로 추상화할 여지가 있다.

- 케라스는 이 여지를 활용한 라이브러리이다.

     - model.add(Dense(노드 개수, 활성함수,...)) 방식의 코딩

 

케라스로 퍼셉트론 프로그래밍

- tensorflow.keras : tensorflow의 하위 클래스로 keras

- keras 클래스의 중요한 세 가지 하위클래스

model 클래스 : Sequential과 functional API 모델 제작 방식 제공
layers 클래스 : 다양한 종류의 층 제공
optimizers 클래스 : 다양한 종류의 옵티마이저 제공

 

전형적인 절차

- 데이터 구축 → 신경망 구조 설계 → 학습 → 예측

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.optimizers import SGD

# OR 데이터 구축축
x = [[0.0, 0.0], [0.0, 1.0], [1.0, 0.0], [1.0, 1.0]]
y = [[-1], [1], [1], [1]]

n_input = 2
n_output = 1

# Sequential 클래스로 객체를 생성
perceptron = Sequential()
# add 함수로 Dense(완전 연결) 층을 쌓는다.
perceptron.add(Dense(units=n_output, activation='tanh', input_shape=(n_input,), 
                     kernel_initializer='random_uniform', bias_initializer='zeros'))

# 신경망 학습습
perceptron.compile(loss='mse', optimizer=SGD(learning_rate=0.1), metrics=['mse'])
perceptron.fit(x, y, epochs=500, verbose=2)

# 학습된 신경망으로 예측
res = perceptron.predict(x)
print(res)

 

Dense로 완전연결층을 쌓는 방식이다.

- 아래 그림은 units와 input_shape 매개변수에 대한 설명이다.

5.4 텐서플로로 다층 퍼셉트론 프로그래밍

5.4.1 MNIST 인식

다층 퍼셉트론으로 MNIST 인식하는 프로그램

- 퍼셉트론을 코딩한 위 프로그램과 디자인 패턴 공유.

- 복잡도만 다르지 핵심은 같다.

 

단계 1 : 데이터 준비

import numpy as np
import tensorflow as ts
from tensorflow.keras.datasets import mnist

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.optimizers import Adam

# MNIST 읽어 와서 신경망에 입력할 형태로 변환
(x_train, y_train), (x_test, y_test) = mnist.load_data()

# 텐서 모양으로 변환 - 2차원 구조 텐서를 1차원 구조로 변환(reshape)
x_train = x_train.reshape(60000, 784)
x_test = x_test.reshape(10000, 784)

# ndarray로 변환환
x_train = x_train.astype(np.float32) / 255.0
x_test = x_test.astype(np.float32) / 255.0

# 원핫 코드로 변환
y_train=tf.keras.utils.to_categorical(y_train,10)
y_test=tf.keras.utils.to_categorical(y_test,10)

 

단계 2 : 신경망 구조 설계

- Sequential 모델을 생성하여 mlp 객체에 저장

- 은닉층 추가 (input_shape는 입력층, units는 현재 쌓고 있는 은닉층으로 설정)

- 출력층 추가 (input_shape는 생력 가능, units는 현재 쌓고 있는 출력층으로 설정)

n_input = 784
n_hidden = 1024
n_output = 100

mlp = Sequential()
mlp.add(Dense(units=n_hidden, activation='tanh', input_shape=(n_input,),
              kernel_initializer='random_uniform', bias_initializer='zeros'))
mlp.add(Dense(units=n_output, activation='tanh',
              kernel_initializer='random_uniform', bias_initializer='zeros'))

 

단계 3 : 신경망 학습

- compile 함수로 학습을 준비한다. (loss 매개변수는 손실 함수, optimizers는 옵티마이저로 설정)

-  fit 함수는 실제 학습을 수행한다.

     (batch_size는 미니배치 크기, epochs는 최대 세대수, validation_data는 학습 도중에 사용할 검증 집합 설정)

 

단계 4 : 예측

- evaluate 함수로 정확률 측정

# 손실 함수로 mse 사용, 옵티마이저로 Adam 사용
mlp.compile(loss='mean_squared_error',optimizer=Adam(learning_rate=0.001),metrics=['accuracy'])

# 학습 도중 발생한 정보를 hist에 저장해둔다.
hist=mlp.fit(x_train,y_train,batch_size=128,epochs=30,validation_data=(x_test,y_test),verbose=2)

res=mlp.evaluate(x_test,y_test,verbose=0)
print("정확률은",res[1]*100)

 

5.4.2 학습 곡선 시각화

hist 객체가 가진 정보를 이용해 학습 곡선을 그린다.

import matplotlib.pyplot as plt

# 정확률 곡선
plt.plot(hist.history['accuracy'])
plt.plot(hist.history['val_accuracy'])
plt.title('Model accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['Train','Validation'], loc='upper left')
plt.grid()
plt.show()

# 손실 함수 곡선
plt.plot(hist.history['loss'])
plt.plot(hist.history['val_loss'])
plt.title('Model loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['Train','Validation'], loc='upper right')
plt.grid()
plt.show()

 

5.4.3 fashion MNIST 인식

fasion MNIST 데이터셋

- MNIST와 비슷하다.

- 내용이 패션 관련 그림이고 레이블이 {T-shirt/top, Trouser, Pullover,...)인 점만 다르다.

 

원래는 train_set과 test_set을 나누는 부분이 아래와 같다.

from tensorflow.keras.datasets import mnist

(x_train, y_train), (x_test, y_test) = mnist.load_data()

 

fashion MNIST는 이 부분만 달라지고 나머지는 동일하다. (아래 코드와 같이 변경)

from tensorflow.keras.datasets import fashion_mnist

(x_train, y_train), (x_test, y_test) = fashion_mnist.load_data()
728x90