앞으로 실습할 모든것인 Shape, Slicing,[텐서의 조작], Tensor, Vector, 텐서의 핵심 속성 그리고 간단한 그래디언트 기반 최적화를 설명하는 장이다. 따라서 엄밀히 말하면 Numpy에 포스팅해야 하지만 케라스 책에 있으므로 여기에 포스팅한다. 

2.1 2장의 도입부 및 MNIST로 인한 전반적인 설명

2.2 신경망을 위한 데이터 표현

신경망은 Tensor라고 불리우는 다차원 넘파이 배열에 데이터를 저장하는 것으로부터 시작된다. 텐서에는 다음과 같은 데이터 형이 존재한다. 

2.2.1 스칼라(0D텐서)

하나의 숫자만 담고 있는 텐서이다. 거의 사용하지 않음. 

2.2.2 벡터(1D텐서)

하나의 축(행/열 등)을 가진 것을 벡터라고 부름. 

2.2.3 행렬 또는 Matrix(2D 텐서)

2개의 축(행/열)을 가지고 있는 데이터 숫자가 채워진 사각 격자임. 

2.2.4 3D텐서 이상

3D텐서는 사진 [R,G,B]를 나타내지만 그 이상인 4D, 5D는 Video를 나타낼 때 사용하는데 우리 눈으로 관찰하기는 불가능하다. 2.2.1 ~ 2.2.4를 각각 넘파이로 표현하여서 나타내보면 다음과 같다. 

먼저 0D 의 경우 이를 Numpy 배열로 생성하여 보면 하나의 값만 들어 있는 것을 알 수 있음. 또한 축이 몇 개 존재하는 지 알아 보기 위해서 ndim command를 실시 해본 결과 0으로 존재하지 않는 것을 알 수 있음.

1차원 배열의 경우는 다음과 같이 우리가 일반적으로 알고 있는 리스트 형태의 벡터가 만들어지고 축이 하나 존재함을 알 수 있음. 그리고 해당 벡터는 5개의 원소를 가지고 있으므로 5차원 벡터라고 함. 단, 이것은 축이 아니고 5D tensor도 아님을 명심해야 함. [5D Tensor는 Tensor가 5겹으로 놓이는 것임.]

가장 많이 쓰이는 matrix 인 2차원 텐서임. 백터와 달리 축이 하나 더 있어서, 데이터를 더 다양하게 표현 할 수 있음을 알 수 있음. 

마지막으로 3차원 Tensor를 표현해 보면 행, 열이 몇 개 쌓여 있는 지 표현하는 값인 z축이 붙었음을 알 수 있음.  나중에  MNIST의 응용과 함께 자세히 알아 볼 것임. 여기까지를 정리해서 신경망의 데이터를 표현하는 Tensor의 핵심속성을 알아보면 다음과 같음. 

2.2.5 핵심속성

축의 개수 : 행/열/깊이 : ndim 명령어로 알아 볼 수 있음.

크기(Shape): 텐서의 각 축을 따라 얼마나 많은 차원이 있는지를 나타내는 것. 앞에 나온 2D에서 Shape는 (3,5) - 3행 5열

3D는 (3, 3,5) - 3쌓여 있음 [3행 5열]

이를 구체적으로 확인 해 보기 위해서 MNIST의 dataset을 load히고 확인해 본다. 

따라서 data를 로드하고 train_image에 대해서 ndim과 shape를 확인해 보면

축의 개수는 3개인데,  28 행 28열이 60000곂 쌓여 있음을 알 수 있다. [여기서는 이미지이므로 28 by 28 pixel이 60000개 있음] 이를  matplotlib으로 확인해 보면

실제로 이미지를 출력해 볼 수 있고, 형태 또한 이전 우리가 예측했던 것과 같음을 알 수 있다. 

지금까지 신경망에 축적되는 데이터의 핵심속성에 대해서 알아 보았고 어떻게 출력해 보는 지 알아 보았다. 기본적으로 데이터를 알더라도 데이터를 적재한 다음에는 무조건 shape나 ndim은 확인해 보는 것이 좋다. 추후에 학습할 때 에러가 날 소지가 다분하기 때문이다. 

2.2.6 넘파이로 텐서 조작하기

이전에는 특정 이미지, 즉, 4번째 이미지 train_images[4]를 선택했다. 하지만 더 많은 이미지를 한 번에 선택해보거나 특정 범위로 이미지를 선택하고 싶을 때가 있다. 즉, slicing하고 싶을 때가 있다. 이렇게 특정 원소들을 선택 하는 것을 Slicing이라고 하는 데 다음 연산을 보자. 먼저 다음예는 11 번쟤부터 101번째까지의 값만 60000개 중에서 Slice하여 새로운 값을 my_slice에 저장한다. 

:(콜론)이 전체 인덱스를 의미하므로 여기서는 28을 뜻함. [28*28]

10~100 이므로 60000개중에서 11~100의 90개를 선택한다. 

주의 할 것은 위의 주석 부분과 같이 :은 생략 가능하다! (하지만 일관되게 써주는 것이 나중에 보는데 편함.)

각 배열의 축(행/열)을 따라 어떠한 인덱스 또는 인덱스 사이도 선택 할 수 있으므로 위와 같이 설정하면 픽셀 에 따른 값을 표현하는 것이 가능하다. 

2.2.7 배치 데이터

일반적으로 사람들이 머신러닝을 하면서 그냥 넘어가는(나의 경우 그랬음) 부분이다. 여기서 짚고넘어가면 좋을 듯 하다. 배치데이터란 딥러닝의 용어로서 일반적으로 딥러닝을 할 때 한 번 반복[Epoch: 이것도 딥러닝 용어임]할 때 모든 데이터를 사용하지 않고 데이터의 일부분만 사용한다. 예를 들어 MNIST 에서는 전체 60000개 중에 128개의 배치를 사용한다고 하면 다음과 같다. 

1st: batch = train_images[:128] / 2nd:  batch = train_images[128:256] ... nth: batch = train_images[128*n:128*(n+1)] 

2.2.8 텐서의 실제 사례

데이터의 종류는 다음과 같다. 

벡터 데이터(sampe, features) 

시계열 데이터(나중에 추가)

이미지(sample, height, width, channels)

동영상(samples, frames,height,width,channels)

2.2.9 벡터 데이터

사진이나 동영상 이외의 일반적으로 다루는 대부분의 데이터. 위에서 보다시피 Feature와 Sample축으로 이루어져 있다. 

 

2.2.10 시계열 데이터

주식 또는 트윗 셋. 나중에 추가

2.2.11 이미지 데이터

이미지 데이터는 앞엑서 봤던 MNIST와 같이 [height, width, color_channel]의 3차원으로 이루어짐. MNIST의 경우 흑백 이미지이므로 컬러 채널이 1이고 컬러 채널은 보통 RGB인 경우 세개이므로 3이다. 

예를 들어 256*256의 RGB이미지 128개의 배치는 (128,256,256,3)크기의 텐서에 저장 될 수 있음. 

- 이미지 데이터 공부하면서 좀 더 Update

2.2.12 비디오 데이터

5D Tensor가 필요한 경우임. 하나의 비디오는 프레임의 연속이고, 각 프레임은 컬러 이미지로 표현 됨. 따라서

프레임의 연속은 [frames, height, width, color_channel] 4D 텐서 로 표현되고

비디오의 배치는 [samples, frames, height, width, color_channel] 5D로 표현됨. 

 

예) 60초짜리 144*256유튜브 비디오 클립을 초당 4프레임으로 샘플링하면 

frames > 240 / samples>4 / height > 144 / width > 256 / color_channel >3

(4, 240, 144, 256, 3).크기의 텐서에 저장

 

이제 2장도 1/3정도 봤습니다. 다음에는 2.3장과 2.4장을 살펴 볼 건데 브로드캐스팅과 텐서의 형태, 그리고 경사하강법의 간단한 이론 정도에 대해서 나오는 것 같습니다. 자세히는 안 봐서 모르겠습니다. 어려운 문제는 없는 것 같으니 함께 포스팅 하는 것으로 하겠습니다. 

 

 

- pip install numpy

로 numpy 인스톨시 에러 발생

Import error: DLL load failed : 지정된 모듈을 찾을 수 없습니다. 


Numpy install 시 conda로 해야 함. 

아나콘다로 인스톨 했을 시애만 해당하는 건지는 모르겠으나 일단 그러함 아마 관련 패키지까지 인스톨해야 해서 그런 것 같음. 따라서 다음과 같은 명령어를 쳐야 함. 

- conda install numpy



import numpy as np import random 
In [18]:
list_data1 = [1,2,3,4] 
In [22]:
list_data1 
Out[22]:
[1, 2, 3, 4]

list를 ndarray로 변환하는 간단한 메서드를 생성합니다.

In [20]:
nd_list_data1 = np.array(list_data1) #array - 순차형 데이터를 ndarray로 변환 
In [21]:
nd_list_data1 
Out[21]:
array([1, 2, 3, 4])

기존에 python 리스트는 그냥 []로 나왔지만 ndarray의 경우 array[]로 나왔습니다.

In [24]:
nd_list_data1.ndim #1차원인 경우 열을 먼저 출력해 줌...? 
Out[24]:
1

차원을 출력하는 메서드는 .ndim이고

In [25]:
nd_list_data1.shape 
Out[25]:
(4,)

 

ndarray의 형태를 출력하는 방법은 .shape입니다. 자주 사용하고 직관적이기 때문에

외워 두시면 좋을 것 같습니다. 참고로 list에는 없는 메서드이기 때문에 참고해 두시면 좋을 것 같습니다.

In [27]:
nd_list_data1.dtype 
Out[27]:
dtype('int64')
In [29]:
zero = np.zeros(2) 
In [30]:
zero 
Out[30]:
array([0., 0.])
In [46]:
zero = np.zeros((3,6)) #내용을 0으로 채워서 ndarray 생성 
In [47]:
zero 
Out[47]:
array([[0., 0., 0., 0., 0., 0.],        [0., 0., 0., 0., 0., 0.],        [0., 0., 0., 0., 0., 0.]])

zeros()는 0으로 초기화된 ndarray를 생성합니다.

In [48]:
zero.shape 
Out[48]:
(3, 6)
In [49]:
np.empty((2,3,2)) #초기화되지 않고 채워진 배열을 반환 
Out[49]:
array([[[6.73898103e+149, 5.30276956e+180],         [3.31033942e-033, 6.97532527e-076],         [4.46234816e-086, 3.36010587e-143]],         [[6.01433264e+175, 6.93885958e+218],         [5.56218858e+180, 3.94356143e+180],         [5.64124820e-038, 9.96020951e-047]]])

empty(층, 행, 열) 메서드는 아무 값이나 랜덤으로 채운 채뤄 배열을 반환.

In [50]:
np.eye(3,3) #희박 행렬 생성.  
Out[50]:
array([[1., 0., 0.],        [0., 1., 0.],        [0., 0., 1.]])

eye는 희박 행렬을 생성하는데, 선형대수에서 많이 사용하는데 저는 선형 대수를 하지 않지만

선형 대수를 하시는 분은 eye 메서드를 그냥 외워 두시면 좋을 것 같습니다.

In [51]:
np.arange(5) #파이썬의 range와 유사. ndarray를 반환.  
Out[51]:
array([0, 1, 2, 3, 4])
In [ ]:
 

                              arange는 range랑 비슷하게, 0 ~ n 까지의 숫자를 생성하기 때문에 초기화를 할 때 잘 쓰는 함수입니다. 

   또는 그래프를 그릴 때 index를 사용 할 수 있겠죠.   

'머신러닝 > 기초 문법' 카테고리의 다른 글

6. IF 문  (0) 2019.02.09
주피터 노트북 블로그에 맞기 정렬하기  (0) 2019.02.08
넘파이 기초 - 색인과 슬라이싱 기초(2)  (1) 2019.01.31
5. 딕셔너리 심화 - (2)  (0) 2019.01.30
5. 딕셔너리 기초 - (1)  (0) 2019.01.29

 

 원래 넘파이랑 판다스는 파이썬을 완전히 끝낸 다음에 포스팅 하려고 했는데 간단한 부분 - (인덱싱이랑 슬라이싱) - 은 먼저 포스팅 하도록 하겠습니다. 코딩은 iPython이 아닌 jupyter notebook에서 작성 했음을 미리 알립니다. 주피터 노트북의 경우 딱 포스트 부분에 맞게 조절하는 방법이 있는 거 같은데 왜 전 안 될 까요ㅠㅠ 아무튼 안 되면 안 되는대로, 딱히 칸을 넘어가는 부분도 없으니까 일단 포스팅 하도록 하겠습니다. 

 

1. 1차원 배열 인덱싱

import numpy as nd

In [2]:

arr = np.arange(10)

In [3]:
arr 
Out[3]:
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

arange메소드는 설명하지 않았지만 파이썬의 리스트에서 range메서드와

비슷한 역할을 합니다. 따라서 주로 초기화 하는데 저는 사용합니다. 그 외에는 거의 사용하는

적이 없는 것 같습니다.

In [4]:
arr[5] 
Out[4]:
5
In [5]:
arr[5:8] 
Out[5]:
array([5, 6, 7])

1차원 ndarray는 list와 거의 동일하게 동작합니다. 그냥 이 부분에 사용 할 수 있는 메서드가

다르다는 점만 있죠. 주로 많이 사용하는 2차원 ndarray에서 부터 주의가 많이 필요합니다.

In [6]:
arr[5:8] = 12 #색인 영역에 대입한 값이 전파된다. - 브로드캐스팅 
In [7]:
arr 
Out[7]:
array([ 0,  1,  2,  3,  4, 12, 12, 12,  8,  9])

위와 같이 값을 전파 시키는 것을 브로드 캐스팅이라고 합니다. 색인 영역을 잘라서 (슬라이싱) 해서 값을 대입한 후,

이 값을 : 이 후부터 전파시키기 때문에 브로드 캐스팅이라고 합니다.

In [8]:
arr[5:8] 
Out[8]:
array([12, 12, 12])
In [9]:
arr_slice = arr[5:8] 
In [10]:
arr_slice[1]=12345 
In [11]:
arr 
Out[11]:
array([    0,     1,     2,     3,     4,    12, 12345,    12,     8,            9])
In [12]:
arr_slice 
Out[12]:
array([   12, 12345,    12])

이 경우  arr_slice의 처음 값이 [5], 그리고 2번째 index인 arr_slice[1]값이 전체 arr[6]이기 때문에 12345가 대입이 됩니다. 

1차원 ndarray는 위에서 언급했다시피 list와 비슷하기 때문에 많이 공부 할 필요가 없지만 2차원 이후로부터 좀 공부를 해야하죠. 

 

이제 살펴보도록 합시다.

2. 2/3차원 배열 인덱싱 

 

arr2d = np.array([[1,2,3],[4,5,6],[7,8,9]]) 
In [15]:
arr2d[1] #2차원 배열에서 단순한 색인 값은 스칼라 값이 아니라 1차원 배열이 된다.  
Out[15]:
array([4, 5, 6])

2차원 ndarray를 생성 하였는데, [123],[4,5,6],[7,8,9] 배열을 하나 더 둘러 싸고 있는

그림입니다. 따라서 1번 index는 [4,5,6]전체 배열이 되겠죠?

In [16]:
#개별 스칼라 요소에 접근 할 때는 [][] 처럼 콤마로 구분 된 색인 리스트로 접근 해야 한다 arr2d[1][0] 
Out[16]:
4

반면에 스칼라 값 하나에 접근 하려면 어느 배열의, 어느 열에 속하는지, 지정 해야합니다.

만약에, 2행[2] 0열[0]이면 arr2d[2][0] 즉, 7을 출력하게 되겠습니다.

In [17]:
arr3d = np.array([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]]) # 3차원 배열의 경우 잘 시용되지 않지만 층,행,열 로 접근 됨 
In [18]:
arr3d[0] #0층 
Out[18]:
array([[1, 2, 3],        [4, 5, 6]])

해당 배열은 0층과 1층으로 나뉘어져 있는데 맨 앞에 있는 것이 층, 그 다음이 행, 그리고 마지막이 열로서,

index로 접근 할 때도 층,행,열로 접근 하면 됩니다. 다음을 살펴 볼까요?

In [19]:
arr3d[1] #1층 
Out[19]:
array([[ 7,  8,  9],        [10, 11, 12]])

 

1층이기 때문에 위와 같이 출력해 줍니다. 반면에 2층은 존재 하지 않기 때문에 index가 존재하지 않는다고

에러 메세지를 출력하는군요. 바람직 합니다.

In [20]:
arr3d[2] #2층 없음 
 
--------------------------------------------------------------------------- IndexError                                Traceback (most recent call last) <ipython-input-20-f1c4238f3db7> in <module> ----> 1 arr3d[2] #2층 없음  IndexError: index 2 is out of bounds for axis 0 with size 2
In [ ]:
arr3d[0]=42 
In [21]:
old_values = arr3d[0].copy() 
In [22]:
arr3d[0]=42 
In [23]:
arr3d 
Out[23]:
array([[[42, 42, 42],         [42, 42, 42]],         [[ 7,  8,  9],         [10, 11, 12]]])

값을 대입 해 봤습니다. 0층에 42 값을 대입했고,

나중에 다시 값을 바꾸기 위해 old_values에 이전에 있던 값들을 복사 해 놨습니다.

In [24]:
arr3d[0]=old_values 
In [25]:
arr3d 
Out[25]:
array([[[ 1,  2,  3],         [ 4,  5,  6]],         [[ 7,  8,  9],         [10, 11, 12]]])

다시 old_values를 0층에 넣었더니 값이 원래대로 변했습니다.

In [26]:
arr3d[1,0] # -> 1층에, 0행 , 열 생략한 상태 
Out[26]:
array([7, 8, 9])

 

3차원 배열의 index가 어떻게 사용되는 지 알아보기 위해서(층,행,열)직접 코딩을 해 봤습니다.

1층, 0행 이니까, (열은 쓰지 않았음)

[7,8,9],

[10,11,12].

중에서

 

[7,8,9]열을 고를 것 같습니다.

 

예상대로 위에서는 해당 열을 골랐습니다. 그럼 이번에는 열을 골라 봅시다.

In [27]:
arr3d[1,1,1] # -> 1층, 1행, 1열 
Out[27]:
11

1층이므로, 
[7,8,9]
[10,11,12]
1행이므로
[10,11,12]
1열이므로

11을 출력 할 것입니다.

 

헷갈리신다면 다시 한 번 보시면 이해가 가실 겁니다. 별로 어렵지 않은 부분이니까요.

 

 

3. 색인과 슬라이싱 기초 / 슬라이스 색인

 

#--------------------슬라이스 색인----------------------# 
In [29]:
arr2d 
Out[29]:
array([[1, 2, 3],        [4, 5, 6],        [7, 8, 9]])
In [30]:
arr3d 
Out[30]:
array([[[ 1,  2,  3],         [ 4,  5,  6]],         [[ 7,  8,  9],         [10, 11, 12]]])
In [31]:
arr2d[:2] #2행까지 슬라이싱 
Out[31]:
array([[1, 2, 3],        [4, 5, 6]])

2차원 ndarray도 1차원 ndarray를 조금 확장 해서 생각해 보시면 됩니다.

층, 행, 열이라고 했는데, 2darray에는 층이라는 게 존재하지 않으므로 신경 쓸 필요가 없습니다.

행을 슬라이스 , 즉, 2행 이상을 모두 잘라서 보여주는 거라고 생각 하시면 됩니다.

In [32]:
arr2d[:2,1:] #2행까지 슬라이싱 하고, 1열이후로 슬라이싱 
Out[32]:
array([[2, 3],        [5, 6]])

뒤에 열이 붙긴 했지만 2행 위를 자르고, 1행 다음으로 자른 슬라이싱을 출력합니다.

위에 슬라이싱 개념을 생각해 보시고 조금 확장 해서 생각해 보시면 될 것 같습니다.

In [33]:
arr2d[1,:2] #arr2d[1,] 이렇게 사용하는 것을 정수 색인이라고 한다. 나중에 다르게 사용되는 것도 있으니 알아두도록 한다.  
Out[33]:
array([4, 5])

해당 1: 이나 :1 이 아닌 1이라고 쓰는 것을 정수 색인이라고 합니다.

나중에 판다스랑 조금 다르게 사용되는 부분이 있으므로 기억해 두시기 바랍니다.

이 부분은 정확히 1행에, [4,5,6] 2열 아래로 자르므로 [4,5]행을 출력합니다.

In [34]:
arr2d[:,:1] #:만 사용하면 전체 축(모든 행 또는 모든 열)을 의미한다. 따라서 원래 차원의 슬라이스를 얻을 수 있다.  
Out[34]:
array([[1],        [4],        [7]])

마지막으로 전체 행을 뜻하는 : 을 알아 봅시다. : 전체 행에서 , :1 1열 전을 얘기하므로,

[1]

[4]

[7]

열만 출력합니다.

 

 

넘파이에는 슬라이스 색인 이외에도 불리언 색인과 팬시 색인이라는 중요한 개념이 있는데 이 부분은 좀 더 공부를 하고 포스팅을 할 예정입니다. 그 이전까지는 파이썬에 집중 해야죠. 그럼 오늘 포스팅은 여기까지 하고 마치도록 하겠습니다. 
 
 
 
 
 
 

 

+ Recent posts