AI & BigData/모두를 위한 딥러닝(정리)

텐서플로우(Tensor Flow) #11_ TensorFlow Manipulation

Tigercow.Door 2018. 4. 11. 19:09


안녕하세요.

이번 포스팅에서는 텐서플로우(tensorflow)를 다루는 방법에 대해서 이야기해보도록 하겠습니다.

우리가 그 동안 TensorFlow를 이용해 몇가지 실습을 진행해보았지만 뒤로 갈수록 TensorFlow에 대한 복잡도가 커질 것 입니다.

따라서 이번 포스팅에서는 TensorFlow를 더 잘 다루기 위해 공부해보도록 합니다.


* 해당 포스트의 모든 내용은 김성훈 교수님의 '모두를 위한 딥러닝'을 바탕으로 제작되었습니다.

관련한 상세 내용은 아래 링크를 참고해주세요.

https://hunkim.github.io/ml/



1. Simple ID array and slicing


첫번째로 알아볼 내용은 1차원 배열입니다.


1
= np.array([0.1.2.3.4.5.6.])
cs


위와 같이 1차원 배열이 있습니다.

이때 배열에 대해서 rank와 shape이라는 2가지 용어가 있습니다.

rank 란 특정 배열의 차원을 이야기하고,

shape 이란 특정 배열이 어떻게 생겼는지, 즉 몇개의 요소가 있는지를 이야기 합니다.

즉 위에서 t 배열의 rank는 1이고 shape은 7입니다.


배열에서 특정한 요소를 확인하기 위해서는 그 요소의 인덱스를 이용합니다.

t 배열에서 2. 이라는 요소는 t[2]라고 표현되겠죠?

또한 인덱스에는 음수도 사용될 수 있습니다.

음수는 배열의 가장 마지막 인덱스부터 카운팅을 하게 되므로, t[-1] 은 6. 이라는 요소를 반환합니다.

또한 슬라이싱을 이용하여, t[:3] = [0., 1., 2.] 또는 t[2:-1] = [2., 3., 4., 5., 6.] 처럼 나타낼 수 있습니다.

슬라이싱에 관한 자세한 사항은 다음 글을 참고하시면 좋을 것 같습니다.


http://doorbw.tistory.com/37?category=677823



2. 2D Array


2D array 또한 위와 같은 rank, shape, indexing, slicing 이 가능합니다.


1
2
3
4
5
6
7
8
import numpy as np
import pprint
pp = pprint.PrettyPrinter(indent=4)
 
t2 = np.array([[0.1.2.],[3.4.5.],[6.7.8.],[9.10.11.],[12.13.14.]])
pp.pprint(t2)
print(t2.ndim) # rank 확인
print(t2.shape) # shape 확인
cs


위의 코드와 같이 2차원 배열인 t2 를 만들고 rank와 shape을 확인해보면 다음과 같습니다.




3. Rank, Shape, Axis

(여기서부터는 jupyter notebook을 사용하였습니다.)



위와 같이 각 1,2,3차원 배열에 따른 rank 와 shaped을 확인할 수 있습니다.

rank가 명시적으로 나오지 않아도, shape을 출력했을때 그 출력값이 어떤 형태인지를 확인해서 rank를 확인할 수 있습니다.

shape을 굳이 확인하지 않아도 rank를 쉽게 확인하는 방법은, 배열에서 대괄호 쌍의 개수를 세어보면 됩니다.


그리고 새롭게 축(Axis)라는 개념을 알아보겠습니다.

axis의 개수는 rank의 값과 동일합니다.

axis를 카운트하는 방식은 배열에서 가장 바깥쪽 덩이를 시작으로 0부터 카운트 합니다.

즉, 위 코드에서 제일 마지막 t배열은


[

[

[1,2,3],[4,5,6]

],

[

[7,8,9],[10,11,12]

]

]

와 같은 형태를 가질텐데, 이때 빨간색 부분이 axis = 0 이고, 파란색 부분이 axis = 1, 검은색 부분이 axis = 2 입니다.

또한 가장 안쪽에 있는 axis 는 -1로 표현하기도 합니다.



4. Matmul VS multiply


우리가 shape 에 대해서 알아본 이유 중 하나는, 배열끼리 곱셈을 진행할 때 shape이 일치해야 곱셈이 가능하기 때문입니다.

shape 전체가 일치해야 한다는 것이 아니고 곱셈이 진행되는 앞의 배열의 마지막 shape 값과 뒤 배열의 첫번째 shape 값이 일치해야 합니다.



위의 코드와 같이 matmul 함수를 이용한 두 배열의 곱의 올바른 결과값을 나타내었습니다.


그런데 이렇게 배열의 곱셈을 할때 실수나 기타 이유 등으로 아래와 같이 코드를 작성할 때가 있습니다.


단순히 우리가 편히 사용했던 곱셈 기호( * )를 사용하면 위 처럼 우리가 원하는 배열의 곱셈에 대한 결과 값이 아닌 다른 값이 나오게 됩니다.

이 차이점을 주의 하시길 바랍니다.



5. Broadcasting


Broadcasting 이란 shape 이 맞지 않을때에도 shape을 자동적으로 맞추어주고 계산하는 것입니다.

먼저 아래 코드를 확인해보도록 하겠습니다.



위의 코드에서는 shape이 같은 두 배열을 더했을 때, 올바른 결과를 출력하는 것을 볼 수 있습니다.

그런데, shape이 다른 두 행렬을 더했을때는 어떨까요?


위의 코드에서 matrix1 의 shape 은 (1, 2)이고 matrix2의 shape은 (1)입니다. 이렇게 서로 shape이 다른 두 배열을 더했는데 오류가 발생하지 않고 결과가 나왔습니다.

결과 값을 확인해보면 matrix2의 요소인 10이라는 숫자가 matrix1의 각각의 요소에 더해졌다는 것을 알 수 있습니다.

즉, 자동적으로 matrix2의 배열이 [[10, 10]] 으로 변환되어 계산되는 것입니다.

이러한 것이 broadcasting 입니다.

물론 강력하고 좋은 기능일 수 있지만, 잘못사용할수도 있는 기능이기에 항상 배열의 shape을 잘 살펴보고 사용해야 합니다.



6. Reduce mean


이번에는 우리가 많이 사용했었던 reduce mean 입니다.



위에서 1과 2에 대한 평균을 구했는데 결과는 1이 나왔습니다. 왜 그럴까요?

reduce_meand에 대한 결과 값 또한 자료형의 영향을 받기 때문입니다. 현재 1과 2가 int형으로 작성되어 있기 때문에 평균값 또한 int형으로 출력되었습니다.

따라서, reduce mean을 이용할때는 floating point형에 주의하시길 바랍니다.



또한 우리가 위에서 알아보았던 axis를 사용하여 axis 별로 평균값을 구할 수 있습니다.


첫번째에서는 axis = 0 을 기준으로 reduce_mean 을 실행하였고 2번째는 axis = 1, 세번째는 axis = -1 을 기준으로 하였습니다.

세번째의 axis = -1은 위에서 말씀드린 것처럼 가장 안쪽에 대한 axis를 말하는 것이므로 axis = 1과 결과가 동일합니다.



7. Reduce sum



이번에는 reduce_sum 입니다. reduce_mean과 사용 방식이 동일합니다.

그리고 우리가 많이 사용하는 방법 중 하나가 맨 마지막에 있는 코드처럼, 제일 안쪽에 있는 값들에 대해 먼저 합을 구하고 그에 대한 평균을 구하는 것입니다.



8. Argmax


Argmax 는 우리가 설정하는 axis에 따라 가장 큰 값을 가지는 요소의 위치(인덱스)를 반환합니다.



위의 코드와 같이, axis = 0 일때는 0과 2중 2가 크므로 인덱스 1을 반환하고, 1과 1에 대해서는 같은 값이므로 첫번째 인덱스 0 을 반환하고 0과 2중 2가 크므로 인덱스 0을 반환합니다.



9. Reshape


Reshape은 우리가 매우 많이 사용하게 되므로 중요합니다.



위의 코드와 같이 배열 t의 초기 shape은 (2, 2, 3)입니다.

이를 reshape 함수를 통해 우리가 원하는 shape으로 변환할 수 있습니다.

이때 -1은 컴퓨터에게 자율적으로 맡기는 값입니다.

reshape을 하면 데이터가 무작위로 섞이는건 아닐까 하고 걱정할 수도 있겠지만, 보통 reshape을 할때 가장 마지막 요소(위의 코드에서는 3)는 건들이지 않고 reshape을 하기 때문에 데이터가 섞이는 일은 없을 것입니다.



10. Reshape - squeeze, expand


이번에는 reshape 중에서도 좀 특별한 squeeze와 expand에 대해서 알아보겠습니다.


squeeze는 그 단어대로, 차원을 하나로 합쳐버리는? 그런 역할을 하는 함수이고 expand는 squeeze와 반대로 차원을 늘리는 함수입니다.



위의 코드와 같이 squeeze와 expand를 구현할 수 있습니다.



11. One-hot


그리고 우리가 또 뒤로갈수록 자주 이용하는 것 중 하나가 one-hot encoding 입니다.

one-hot 이란 예를 들어 아래 그림과 같이 있을때,

여기서 색칠되어 있는 4번칸을 인덱스로 나타내는 것이 아니고, 단순히 0 또는 1로만 나타냅니다. 즉 위의 그림은 [0,0,0,1,0,0] 과 같이 나타낼 수 있겠죠.


이를 코드로 구현해보면 다음과 같이 사용될 수 있습니다.


첫번째 코드는 인덱스로 나타낸 배열의 상태를 one_hot으로 나타내었고, 두번째는 동일한 과정을 진행후 보기 좋게 reshape을 진행하였습니다.

여기서 depth는 요소의 개수로 생각할 수 있습니다. 즉 위에서 본 막대그래프의 depth는 6이겠죠.



12. Casting


Casting이란 우리가 언어에 대해 공부할때 학습했던 것처럼, 형변환을 의미합니다.


위의 코드처럼 우리가 float형의 데이터를 int형으로 바꾸거나, true나 false와 같은 값도 int형으로 바꿀 수 있습니다.



13. Stack


stack이란 것은 말그대로 쌓는 것 입니다.


위와 같이 배열들을 쌓아 올리는 함수입니다.

위에서 축에 대한 개념들을 알아보았으니 직접 축에 대한 값을 바꿔가면서 확인해봐도 좋을 것 같습니다.



14. Ones and Zeros like



Ones and Zeros like 함수는 위와 같이 우리가 어떤 배열의 모습을 그대로 가지면서 0 또는 1로 채워진 배열을 얻고 싶을 때 사용합니다.



15. Zip


마지막으로 알아볼 것은 zip 이라는 함수 입니다.



zip 함수는 위와 같이 우리가 어떤 배열들에 대해서 한번에 다루고 싶을 때 사용할 수 있는 함수입니다.



이번 포스팅에서는 15개 정도의 개념을 알아보았습니다.

지난 실습들에서 사용되었던 것들도 있고 아닌 것들도 있는데, 여러분들께서 직접 코드를 구현해서 테스트해보신다면 더 쉽게 이해할 수 있을 것이라 생각 됩니다.

제가 진행했던 내용은 jupyter notebook 파일로 아래에 첨부해두었습니다.


TensorFlow Manipulation.ipynb


728x90