아래와 같은 순서로 책을 보시면 파이썬 => 판다스 => 머신러닝, 딥러닝을 공부할 수 있습니다. 제가 정리한 글에 있습니다.
https://steemit.com/kr/@papasmf1/73cj22
핸즈온 머신러닝 책의 소스는 아래의 깃허브에 있습니다. 참고하실 수 있습니다.
https://github.com/rickiepark/handson-ml
제가 테스트하고 실습하는 환경은 맥에 아나콘다 최근 패키지를 설치해서 주피터랩으로 실행하고 있습니다. 아나콘다 패키지를 사용하는 경우에 텐서플로는 쉽게 설치할 수 있습니다. ^^
9장 텐서플로 시작하기를 정리했습니다. ^^
텐서플로는 수치 계산을 위한 강력한 오픈소스 소프트웨어 라이브러리로 특히 대규모 머신러닝에 맞춰 세밀하게 튜닝되어 있습니다. 먼저 파이썬으로 수행할 계산 그래프를 정의한 다음, 텐서플로가 최적화된 C++코드를 사용해 이 그래프를 효율적으로 실행시킵티다.
무엇보다도 계산 그래프를 여러 부분으로 나누어 여러 CPU나 GPU에서 병렬로 실행할 수 있습니다. 텐서플로는 분산 컴퓨팅도 지원하므로 수백 대의 서버에 게산을 나누어 납득할만한 시간 안에 대규모 데이터셋으로 거대한 신경망을 훈련시킬 수 있습니다.
텐서플로의 주요 기능입니다.
윈도우, 모바일, 맥뿐만 아니라 iOS와 안드로이드 같은 모바일 기기에서도 실행됩니다.
사이킷런과 호환되는 매우 간결한 파이썬 API인 TF.Learn을 제공합니다. 앞으로 보게 되겠지만 여러 종류의 신경망을 몇줄의 코드로 훈련시킬 수 있습니다.
신경망의 구축, 훈련, 평가를 단순화한 TF-slim이라는 또 다른 간편한 API도 제공합니다.
케라스, 프리티 텐서와 같은 여러가지 고수준 API가 텐서플로를 기반으로 독립적으로 구축되었습니다.
기본 파이썬 API는 복잡도가 높긴 하지만 훨씬 유연합니다.
머신 러닝 연산, 특히 신경망을 만드는데 필요한 연산을 C++로 매우 효율적으로 구현했습니다.
비용 함수를 최소화하는 모델 파라미터를 찾기 위한 여러 가지 고수준의 최적화 노드를 제공합니다. 텐서플로는 우리가 정의한 함수의 그래디언트를 자동으로 계산해 주기 때문에 사용하기 매우 쉽습니다. 이를 자동 미분 이라고 합니다.
텐서보드라는 훌륭한 시각화 도구를 사용해서 계산 그래프와 학습 곡선 등을 웹 브라우저로 확인할 수 있습니다.
구글은 텐서플로의 계산 그래프를 실행할 수 있는 클라우드 서비스도 론칭했습니다.
설치는 기존 아나콘다 패키지가 설치되어 있는 상태에서
conda install tensorflow라고 입력하면 됩니다.
설치에 5분에서 10분정도 걸립니다.
9.2 첫번째 계산 그래프를 만들어 세션에서 실행하기
다음 코드를 계산 그래프를 만듭니다.
import tensorflow as tf
x = tf.Variable(3, name="x")
y = tf.Variable(4, name="y")
f = xxy + y + 2
이게 전부입니다! 꼭 이해해야 할 중요한 점은 이 코드가 뭔가 계산하는 것 같아 보이지만 실제로 어떤 계산도 수행하지 않는다는 사실입니다. 단시 계산 그래프만 만들 뿐입니다. 사실 변수조차도 초기화되지 않습니다. 이 계산 그래프를 평가하려면 텐서플로 세션을시작하고 변수를 초기화한 다음 f를 평가해야 합니다.
다음 코드를 세션을 만들고 변수를 초기화한 다음 f값을 평가하고 세션을 닫습니다. 즉 자원을 해제합니다.
sess = tf.Session()
sess.run(x.initializer)
sess.run(y.initializer)
result = sess.run(f)
print(result)
42
sess.close()
매번 sess.run()을 반복하면 번거로운데 다행히 더 나은 방법이 있습니다.
with tf.Session() as sess:
x.initializer.run()
y.initializer.run()
result = f.eval()
with 블록 안에서는 with문에서 선언한 세션이 기본 세션으로 지정됩니다. 그리고 세션은 with블록이 끝나면 자동으로 종료됩니다.
각 변수의 초기화를 일일이 실행하는 대신 global_variables-initializer()함수를 사용할 수 있습니다. 이 함수는 초기화를 바로 수행하지 않고 계산 그래프가 실행될 때 모든 변수를 초기화할 노드를 생성합니다.
init = tf.global_variables_initializer() # init 노드 준비
with tf.Session() as sess:
init.run() #실제 모든 변수를 초기화한다.
result = f.eval()
주피터나 파이썬 쉘에서는 InteractiveSession을 만드는 편이 편리할 수 있습니다. 일반적인 Session과 유일하게 다른 점은 InteractiveSession이 만들어질 때 자동으로 자신을 기본 세션으로 지정한다는 점입니다. 그러므로 with블록을 사용할 필요가 없습니다.
sess = tf.InteractiveSession()
init.run()
result = f.eval()
print(result)
42
sess.close()
일반적으로 텐서플로 프로그램은 두 부분으로 나뉩니다. 첫 부분은 계산 그래프를 만들고(구성 단계), 두 번째 부분은 이 그래프를 실행합니다(실행 단계). 두번째 부분은 이 그래프를 실행합니다(실행 단계). 구성 단계에서는 훈련에 필요한 계산과 머신러닝 모델을 표현한 계산 그래프를 만듭니다.
9.3 계산 그래프 관리
노드를 만들면 자동으로 기본 계산 그래프에 추가됩니다.
x1 = tf.Variable(1)
x1.graph is tf.get_default_graph()
True
x2.graph is tf.get_default_graph()
False
9.4 노드 값의 생애주기
한 노드를 평가할 때 텐서 플로는 이 노드가 의존하고 있는 다른 노드들을 자동으로 찾아 먼저 평가합니다.
w = tf.constant(3)
x = w + 2
y = x + 5
z = x * 3
with tf.Session() as sess:
print(y.eval()) # 10
print(z.eval()) # 15
10
15
이전 코드에서 처럼 w와 x를 두번 평가하지 않고 y와 z를 효율적으로 평가하려면 텐서플로가 한 번의 그래프 실행에서 y와 z를 모두 평가하도록 만들어야 합니다.
with tf.Session() as sess:
y_val, z_val = sess.run([y, z])
print(y_val) #10
print(z_val) #15
10
15
단일 프로세스 텐서플로에서는 같은 그래프를 재사용하더라도 여러 세션에서 어떤 상태도 공유하지 않습니다. 각 세션은 모든 변수에 대해 고유한 복사본을 가집니다. 분산 텐서플로에서는 변수 상태가 세션이 아니라 서버에 저장되므로 여러 세션이 같은 변수를 공유할 수 있습니다.
9.5 텐서플로를 이용한 선형 회귀
텐서플로 연산operation(줄여서 ops라고도 합니다.)은 여러 개의 입력을 받아 출력을 만들 수 있습니다. 예를 들어 덧셈과 곱셉 연산은 두 개의 입력을 받아 하나의 출력을 만듭니다. 상수와 변수 연산은 입력이 없습니다(소스 연산 source ops이라고 합니나). 입력과 출력은 텐서tensor라는 다차원 배열입니다(그래서 이름이 텐서플로입니다). 넘파일 배열과 비슷하게 텐서는 데이터 타입과 크기를 가집니다. 사실 파이썬 API에서 텐서는 넘파이 ndarray로 나타납니다.
이전 예제에서는 텐서가 하나의 스칼라 값을 가지지만 어떤 크기의 배열에 대해서도 연산이 가능합니다. 예를 들어 다음 코드는 캘리포니아 주택 가격 데이터셋에 선형 회귀를 수행하기 위해 2D배열을 다루고 있습니다.
import numpy as np
from sklearn.datasets import fetch_california_housing
housing = fetch_california_housing()
m, n = housing.data.shape
housing_data_plus_bias = np.c_[np.ones((m, 1)), housing.data]
X = tf.constant(housing_data_plus_bias, dtype=tf.float32, name="X")
y = tf.constant(housing.target.reshape(-1, 1), dtype=tf.float32, nmae="y")
XT = tf.transpose(X)
theta = tf.matmul(tf.matmul(tf.matrix_inverse(tf.matmul(XT, X)), XT), y)
with tf.Session() as sess:
theta_value = theta.eval()
9.6 경사 하강법 구현
9.6.1 직접 그래디언트 계산
reset_graph()
n_epochs = 1000
learning_rate = 0.01
X = tf.constant(scaled_housing_data_plus_bias, dtype=tf.float32, name="X")
y = tf.constant(housing.target.reshape(-1, 1), dtype=tf.float32, name="y")
theta = tf.Variable(tf.random_uniform([n + 1, 1], -1.0, 1.0, seed=42), name="theta")
y_pred = tf.matmul(X, theta, name="predictions")
error = y_pred - y
mse = tf.reduce_mean(tf.square(error), name="mse")
gradients = 2/m * tf.matmul(tf.transpose(X), error)
training_op = tf.assign(theta, theta - learning_rate * gradients)
init = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
for epoch in range(n_epochs):
if epoch % 100 == 0:
print("에포크", epoch, "MSE =", mse.eval())
sess.run(training_op)
best_theta = theta.eval()
9.6.2 자동 미분 사용
앞선 코드가 잘 동작하지만 비용 함수(MSE)의 그래디언트를 수학적으로 유도해야 합니다. 선형 회귀의 경우에는 아주 쉽게 할 수 있지만 심층 신경망에서 하려면 두통이 밀려올 것입니다. 매우 번거롭고 실수하기 쉽기 때문입니다. 기호 미붑능ㄹ 사용해 자동으로 편미분 방정식을 구할 수 있습니다.
def my_func(a, b):
z = 0
for i in range(100):
z = a * np.cos(z + i) + z * np.sin(b - i)
return z
gradients = tf.gradients(mse, [theta])[0]
9.6.3 옵티마이저 사용
앞 절에서 설명한 바와 같이 텐서플로는 자동으로 그래디언트를 계산해 줍니다. 하지만 더 쉬운 방법이 있습니다. 텐서플로는 경사 하강법 옵티마이저를 포함하여 여러 가지 내장 옵티마이저를 제공합니다
optimizer = tf.train.GradientDescentOptimizer(learning_rate = learning_rate)
training_op = optimizer.minimize(mse)
optimizer = tf.train.MomentumOptimizer(learning_rate=learning_rate,
momemtum=0.9)
9.7 훈련 알고리즘에 데이터 주입
미니배치 경사 하강법을 구현하기 위해 이전 코드를 변경해보겠습니다. 이렇게 하려면 매 번복에서 X와 y를 다음번 미니배치로 바꿔야 합니다. 가장 간단한 방법은 플레이스홀더 노드를 사용하는 것입니다.
A = tf.placeholder(tf.float32, shape=(None, 3))
B = A + 5
with tf.Session() as sess:
B_val_1 = B.eval(feed_dict={A: [[1,2,3]]})
B_val_2 = B.eval(feed_dict={A: [[4,5,6], [7,8,9]]})
print(B_val_1)
print(B_val_2)
X = tf.placeholder(tf.float32, shape=(None, n + 1), name="X")
y = tf.placeholder(tf.float32, shape=(None, 1), name="y")
batch_size = 100
n_batches = int(np.ceil(m / batch_size))
def fetch_batch(epoch, batch_index, batch_size):
return X_batch, y_batch
with tf.Session() as sess:
sess.run(init)
for epoch in range(n_epochs):
for batch_index in range(n_batches):
X_batch, y_batch = fetch_batch(epoch, batch_index, batch_size)
sess.run(training_op, feed_dict={X: X_batch, y: y_batch}
best_theta = theta.eval()