[FC] Tensorflow 패키지 소개


패스트캠퍼스 데이터사이언스스쿨의 김도형 박사님 수업을 듣고 강의자료를 요약한 글입니다. 개인적으로 참고하기 위한 요약노트이니 보다 자세한 내용을 원하시는 분은 https://datascienceschool.net 에 올라와 있는 강의자료를 참고하시기 바랍니다.


TensorFlow 기본 사용법

  1. 텐서 정의
  2. 텐서 연산 정의
  3. 세션 정의
  4. 세션 사용

그래프와 세션

  • 텐서플로는 모든 연산을 자체적인 CPU가 아닌 외부에 분산된 GPU에서 처리한다고 가정 ➜ 컴퓨터 자체적으로 이뤄지는 연산은 없음
  • 텐서(Tensor) 계산 과정은 모두 그래프(Graph)라는 객체 내에 저장됨
  • 그래프를 계산하려면 외부 컴퓨터에 이 그래프 정보를 전달하고 그 결과값을 받아야 하는데, 이 통신과정은 세션(Session)이라는 객체가 담당
  • 모든 텐서 계산은 해당하는 텐서를 포함하는 그래프를 세션 객체에 전달해 원격 실행한 후에 값을 볼 수 있음

그래프

  • 그래프의 구성
    • 노드(node): 상수형 텐서, 변수형 텐서, 연산(operation)
    • 간선(edge): 노드로부터 출력되는 텐서 자료형
  • 따라서 텐서 자료형을 만들거나 연산자를 연결하면 모두 그래프에 들어가야 함
  • 그래프를 명시적으로 지정하지 않으면 기본 그래프(default graph)에 할당
  • 현재 기본 그래프에 대한 정보 얻기
print(tf.get_default_graph())
  • tf.Graph 클래스로 명시적으로 그래프 생성하기
my_graph = tf.Graph()

with my_graph.as_default():
my_x = tf.constant(3)
my_y = my_x ** 2

세션

  • Theano의 함수(function)와 비슷한 역할
  • 실제로 계산 그래프를 생성하고 값을 계산하기 위한 환경을 제공
  • Theano의 함수와 달리 세션 생성과 실행 시작, 종료를 다음과 같은 방법으로 명시해야 함
    • 세션 생성: Session 객체 생성. 분산 환경에서는 계산 노드와의 연결을 만듦
    • 세션 사용: run 메서드에 그래프를 입력하면 출력 값을 계산하여 반함. 분산 환경에서는 계산 노드로 그래프를 보내 계산을 수행
    • 세션 종료: close 메서드. with 문을 사용하면 명시적으로 호출하지 않아도 됨
  • 두 개의 상수형 텐서를 생성하고 세션을 통해 실행하기
x = tf.constant(3)
y = x**2

sess = tf.Session()
print(sess.run(x))
print(sess.run(y))
sess.close()
3
9
  • with 구문을 사용한 세션 구현 ➜ with 블럭을 나갈 때 자동으로 close 메서드가 호출됨
with tf.Session() as sess:
out = sess.run([x, y])
print(out)
[3, 9]
  • 직접 그래프를 만들 경우 ➜ 세션 생성시 해당 그래프를 인수로 주어야 함. (하나의 세션은 하나의 그래프만 받을 수 있음)
with tf.Session(graph=my_graph) as sess:
out = sess.run([my_x, my_y])
print(out)
[3, 9]

인터랙티브 세션과 eval() 메서드

  • 텐서플로는 간단한 작업이라도 세션을 통해야지만 가능함
  • 이런 불편을 해소하기 위해 파이썬 콘솔이나 주피터노트북을 사용하는 경우 인터랙티브 세션(Interactive Session)을 제공
  • 인터랙티브 세션을 생성한 후에는 텐서의 eval() 메서드를 호출하기만 하면 명시적으로 세션을 지정하지 않더라도 자동으로 세션이 호출되어 텐서의 값이 출력됨
interactive_sess = tf.InteractiveSession()

x.eval(), y.eval()
(3, 9)
  • as_default() 메서드로 with문 안에서 인터랙티브 세션처럼 사용하기
with tf.Session().as_default():
print([x.eval(), y.eval()])
[3, 9]

텐서 자료형

  • Tensor 클래스로 구현된 텐서는 NumPy의 다차원배열 ndarray 클래스처럼 다차원 배열 정보를 다루기 위한 자료형
  • ndarray와 다른 점은 ndarray는 직접 데이터를 저장하기 위한 자료형이지만 Tensor 클래스는 텐서플로의 계산 그래프 안에서 다차원 데이터를 표현하는 객체라는 차이

텐서 자료형의 종류

  • 상수형(Constant): 미리 주어진 값으로 고정된 텐서
  • 변수형(Variable): 세션 내에서 값이 바뀔 수 있는 텐서
  • 플레이스홀더(Placeholder): 고정된 값을 갖지만 값이 미리 주어지지 않고 나중에 넣을 수 있음

상수형 텐서

  • 숫자나 배열을 tf.constant()를 이용해 상수형 텐서 객체 생성하기
c = [1, 2, 3, 4, 5, 6, 7]
c_tensor = tf.constant(c)
print(c_tensor, type(c_tensor))
Tensor("Const_1:0", shape=(7,), dtype=int32) <class 'tensorflow.python.framework.ops.tensor'>
  • 다양한 메서드를 활용해 상수형 텐서 생성하기
    • 대부분의 메서드에서는 배열의 크기를 지정하는 shape 또는 데이터 자료형을 지정하는 dtype 인수를 받음
    • shape 인수는 (행 넘버, 열 넘버) 형태의 튜플이나 리스트로 전달함
    • dtype 인수는 지정하지 않을 경우 tf.float32 자료형 즉, 32비트 부동소수점 자료형을 사용함
c_tensor = tf.constant(c)
print(c_tensor)
Tensor("Const_9:0", shape=(7,), dtype=int32)

tf.zeros(shape)

zero_tensor = tf.zeros((2, 3))
zero_tensor.eval()

array([[0., 0., 0.],
[0., 0., 0.]], dtype=float32)

tf.ones(shape)

ones_tensor = tf.ones((2, 3))
ones_tensor.eval()

array([[1., 1., 1.],
[1., 1., 1.]], dtype=float32)

tf.fill(shape, value)

filled_tensor = tf.fill((2, 3), 2)
filled_tensor.eval()

array([[2, 2, 2],
[2, 2, 2]], dtype=int32)

tf.zeros_like(tensor)

tf.zeros_like(filled_tensor).eval()

array([[0, 0, 0],
[0, 0, 0]], dtype=int32)

tf.ones_like(tensor)

tf.ones_like(filled_tensor).eval()

array([[0, 0, 0],
[0, 0, 0]], dtype=int32)
  • range 메서드를 사용해 열(sequence)로 구성된 상수형 텐서 만들기

tf.range(start, limit=None, delta=1)

tf.range(5).eval()
array([0, 1, 2, 3, 4], dtype=int32)
  • linspace 메서드를 사용해 열(sequence)로 구성된 상수형 텐서 만들기
    • start 값이 부동소수점이 되도록 함

tf.linspace(start, stop, num)

tf.linspace(0.0, 5, 11).eval()
array([0. , 0.5, 1. , 1.5, 2. , 2.5, 3. , 3.5, 4. , 4.5, 5. ],
dtype=float32)
  • 랜덤한 값을 가지는 상수형 텐서 자료형 만들기

tf.random_uniform(shape, minval=0, maxval=None, seed=None)

tf.random_normal

tf.truncated_normal

tf.random_shuffle

tf.random_crop

tf.random_uniform((2, 3), seed=0).eval()
array([[0.10086262, 0.9701668 , 0.8487642 ],
[0.04828131, 0.04852307, 0.77747464]], dtype=float32)
  • convert_to_tensor 함수로 NumPy ndarray 자료형 변환하기
np_array = np.arange(10)
tf.convert_to_tensor(np_array).eval()
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

플레이스홀더

  • tf.placeholder 명령으로 구현
  • 플레이스홀더(Placeholder) 텐서 자료형은 상수형 텐서와 같은 역할을 하지만 크기만 설정하고 값은 미리 주지 않음
  • 플레이스홀더의 값은 session을 사용한 그래프의 연산 중에 설정할 수 있음
  • 신경망 모형의 경우 대부분 배치(batch) 단위의 학습이 이루어지기 때문에 학습용 데이터는 플레이스 홀더에 넣음
  • 플레이스홀더는 데이터의 타입과 크기를 인수로 설정해 생성하고, session을 실행할 때 feed_dict 인수로 플레이스홀더에 데이터를 지정함
  • 플레이스홀더에 들어가는 데이터 크기의 달라질 때는 shape 인수를 설정할 때 달라지는 차원의 값을 정수가 아닌 None으로 설정
  • 다음은 플레이스홀더 x의 열의 갯수는 10개이지만 행의 갯수는 미정인 경우
x = tf.placeholder(dtype=tf.int32, shape=(None, 10))  # 행의 갯수는 미정, 열의 갯수는 10개
value = np.arange(30).reshape(3, 10)

with tf.Session() as sess:
x_assigned = sess.run(x, feed_dict={x: value})
print(x_assigned)
[[ 0  1  2  3  4  5  6  7  8  9]
[10 11 12 13 14 15 16 17 18 19]
[20 21 22 23 24 25 26 27 28 29]]

변수형 텐서

  • tf.Variable 클래스로 구현
  • session 내에서 값이 변할 수 있음
  • 변수형 텐서를 선언하려면 초기값으로 설정할 값을 입력
var = tf.Variable(tf.zeros((2, 3)))
var
<tf.variable 'variable:0' shape="(2," 3) dtype="float32_ref">

초기화 연산자

  • 변수형 텐서를 생성할 때 입력한 초기값은 initial_value 라는 속성에 저장되고 아직 해당 변수형 텐서의 값으로 할당되어 있지 않음 ➜ 이 상태에서 바로 eval을 실행하면 에러 발생
  • 초기화 연산자는 세션에 변수형 텐서가 들어간 다음에 변수형 텐서의 초기값을 변수형 텐서의 값으로 할당하는 추가 작업을 수행
var.initial_value
<tf.tensor 'zeros_1:0' shape="(2," 3) dtype="float32">
  • 각 변수에는 initializer라는 이름의 초기화 메서드가 있어 이를 세션에서 실행시키면 초기값이 변수로 할당됨
interactive_sess.run(var.initializer)
var.eval()
array([[0., 0., 0.],
[0., 0., 0.]], dtype=float32)
  • 그래프 내의 모든 변수의 초기화 연산을 한꺼번에 수행하려면 tf.global_variables_initializer() 함수를 사용
  • 모든 변수를 생성하기 전에 tf.global_variable_initializer() 함수를 실행하면면 나중에 생성된 변수에 대해서는 초기화 연산이 이루지지 않아 에러가 발생
global_init = tf.global_variables_initializer()
interactive_sess.run(global_init)
print(var.eval())
var1 = var + 2
print(var1.eval())
[[0. 0. 0.]
[0. 0. 0.]]
[[2. 2. 2.]
[2. 2. 2.]]

name 속성과 이름 공간

  • 모든 텐서는 op.name 속성에 이름(name) 문자열을 가지고 있음
  • 텐서를 생성할 때 name 인수를 사용하면 각 텐서에 이름을 수동으로 할당할 수 있음
v1 = tf.Variable(2, name="v1")
v2 = tf.add(v1, 3, name="v2")
print(v1.op.name)
print(v2.op.name)
v1
v2
  • name 속성을 주지 않으면 자동 생성
v3 = tf.constant(1)
v4 = tf.Variable(1)
print(v3.op.name)
print(v4.op.name)
Const_3
Variable_1
  • 노드 이름은 중복되지 않아야 함
  • 이름 공간(name scope)를 사용해 중복 방지
  • tf.name_scope() 문맥 안에서 변수를 생성하면 이름 앞에 이름공간 문자열이 추가됨
with tf.name_scope("scope1"):
v5 = tf.Variable(2, name="v5")
v6 = tf.add(v5, 3, name="v6")
print(v5.op.name)
print(v6.op.name)
scope1/v5
scope1/v6

강의자료 분량이 많아 ‘[FC] Tensorflow 패키지 소개(2)’에서 이어가겠습니다.

© 2019 THE DATASCIENTIST All Rights Reserved.
Theme by hiero