[AI504] (draft) Practice 1. Numpy

[AI504] (draft) Practice 1. Numpy

작성자
권진현권진현
카테고리
AI504
태그
AI
AI504
작성일
2024년 07월 06일

목차

Reference

📃
Programming for AI (AI504) at KAIST GSAI Practice 1 : Numpy

Practice

Practice는 Jupiter notebook을 이용하여, Google Colab에서 진행됩니다.
공개되어 있는 실습 코드.ipynb 파일들을 Colab에서 열어서 사용하시면 됩니다.
제 글의 코드 중 일부는, 여러 가지 방법을 테스트하는 과정에서 원본 코드와 다르게 변형되었습니다.

실습 코드

numpy library를 import합니다.
import numpy as np
아래는 뒤에서 유용하게 사용할 함수들입니다.
def print_obj(obj, name): print("%s:\n%s\n" % (name, obj)) def check_each(a, b): return (a == b).astype('bool') def check_mean(a, b): return np.mean(a == b).astype('bool')
 

Scalars, Vectors, Matrices

Numpy의 array를 선언합니다. 여러 가지 차원으로 만들 수 있습니다.
Scalar 값이 1. 과 같이 표시된 것은, float type임을 나타냅니다.
a = np.array(1.) b = np.array([1., 2., 3.]) c = np.array([[1., 2., 3.], [4., 5., 6.]])
print_obj(a, "a") print_obj(b, "b") print_obj(c, "c")
출력 결과
a: 1.0 b: [1. 2. 3.] c: [[1. 2. 3.] [4. 5. 6.]]
 
ndim 은 Numpy array의 차원을 나타내는 값입니다. scalar 값은 0차원입니다.
print_obj(a.ndim, "a.ndim") print_obj(b.ndim, "b.ndim") print_obj(c.ndim, "c.ndim")
출력 결과
a.ndim: 0
b.ndim: 1
c.ndim: 2
 
shape 는 Numpy array의 각 차원별 길이라고 생각할 수 있습니다. 예를 들어 길이 3의 1차원 배열이 2개 들어있는 c는 (2, 3)입니다.
Shape가 헷갈릴 때를 대비하여 제가 찾은 방법은, 가장 바깥쪽부터 Tree를 순회하듯이 안으로 들어가며 child의 개수를 센다고 생각하는 것입니다.
c = [[1., 2., 3.], [4., 5., 6.]] 을 생각해보면, 가장 바깥에서 보았을 때 2개의 child(1차원 배열)를 가집니다. 각 child(1차원 배열)는 3개의 child(scalar)를 가집니다. 순서대로 써 주면 (2, 3)입니다.
print_obj(a.shape, "a.shape") print_obj(b.shape, "b.shape") print_obj(c.shape, "c.shape")
출력 결과
a.shape: ()
b.shape: (3,)
c.shape: (2, 3)
 

Tensors (N-dimensional array)

더 높은 차원에서도 같은 기능을 사용할 수 있습니다.
d = np.array([[[1., 2., 3.], [4., 5., 6.]], [[7., 8., 9.], [10., 11., 12.]]]) e = np.array([[[[1., 2., 3.], [1., 2., 3.]], [[4., 5., 6.], [4., 5., 6.]]], [[[7., 8., 9.], [7., 8., 9.]], [[10., 11., 12.], [10., 11., 12.]]]])
print_obj(d, "d") print_obj(d.ndim, "d.ndim") print_obj(d.shape, "d.shape") print_obj(e, "e") print_obj(e.ndim, "e.ndim") print_obj(e.shape, "e.shape")
출력 결과
d: [[[ 1. 2. 3.] [ 4. 5. 6.]]
[[ 7. 8. 9.] [10. 11. 12.]]]
d.ndim: 3
d.shape: (2, 2, 3)
e: [[[[ 1. 2. 3.] [ 1. 2. 3.]]
[[ 4. 5. 6.] [ 4. 5. 6.]]]
[[[ 7. 8. 9.] [ 7. 8. 9.]]
[[10. 11. 12.] [10. 11. 12.]]]]
e.ndim: 4
e.shape: (2, 2, 2, 3)
# Quiz: What is the shape of [[[1], [2], [3]], [[4], [5], [6]]]?
코드
example = np.array([[[1], [2], [3]], [[4], [5], [6]]]) print(example.shape)
출력 결과
example = np.array([[[1], [2], [3]], [[4], [5], [6]]]) print(example.shape)
 

Definining Numpy arrays

원하는 값이 들어 있는 Numpy array를 선언하는 방법들입니다.

상수로 채우기

  • numpy.ones() : 1. 으로 채워진 array를 원하는 shape에 맞게 만듭니다.
    • 공식 문서에 나타난 함수 형태는 numpy.ones(shapedtype=Noneorder='C'*device=Nonelike=None) 입니다.
    • a = np.ones(10) print(a) a = np.ones((2, 5)) print(a)
      출력 결과
      [1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] [[1. 1. 1. 1. 1.] [1. 1. 1. 1. 1.]]
  • numpy.zeros() : 0. 으로 채워진 array를 원하는 shape에 맞게 만듭니다.
    • 공식 문서에 나타난 함수 형태는 numpy.zeros(shapedtype=floatorder='C'*like=None) 입니다.
    • a = np.zeros((2, 5)) a
      출력 결과
      array([[0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.]])
  • numpy.full() : 원하는 값으로 채워진 array를 원하는 shape에 맞게 만듭니다.
    • 공식 문서에 나타난 함수 형태는 numpy.full(shapefill_valuedtype=Noneorder='C'*device=Nonelike=None) 입니다.
    • a = np.full((2,5), 5) a
      출력 결과
      array([[5, 5, 5, 5, 5], [5, 5, 5, 5, 5]])

난수로 채우기

  • numpy.random.random() : [0.0, 1.0) 범위의 랜덤 값을 원하는 shape에 맞게 채운 array를 만듭니다.
    • 공식 문서에 나타난 함수 형태는 random.random(size=None) 입니다.
    • numpy.random.random_sample() 의 alias입니다. 이 함수의 공식 문서를 따라가 보면, 균일 분포(Uniform distribution)를 따르는 것을 확인할 수 있습니다. 를 따르는 난수를 만들고 싶다면, (b - a) * random_sample() + a 와 같이 사용하면 됩니다.
    • a = np.random.random((2, 3, 4)) a
      출력 결과 (random 값)
      array([[[0.24357383, 0.34716465, 0.14068691, 0.05884086], [0.3063829 , 0.11157136, 0.38942725, 0.72143984], [0.28681114, 0.56505687, 0.5016722 , 0.44774679]], [[0.44229731, 0.85518321, 0.21396388, 0.91448339], [0.21117673, 0.3398618 , 0.79922104, 0.62609722], [0.86361199, 0.16361286, 0.92321251, 0.91571351]]])
  • numpy.random.normal() : 정규분포(Normal distribution)를 따르는 난수를 원하는 shape에 맞게 채운 array를 만듭니다.
    • 공식 문서에 나타난 함수 형태는 random.normal(loc=0.0scale=1.0size=None) 입니다. loc은 평균(Mean), scale은 표준편차(Standard deviation)에 해당하는 값입니다.
    • a = np.random.normal(0, 10, (2, 3, 4)) a
      출력 결과 (random 값)
      array([[[-30.09166202, 15.35941141, -6.52358696, 21.21958735], [ -6.71765646, -7.10020775, -6.01215388, 9.61856523], [ 9.95170664, 4.79350909, 6.13716296, -0.50547168]], [[ 1.12400471, -15.01510694, -20.61491567, 4.60278202], [ 2.94193321, 3.61323383, 6.09604655, -15.6912707 ], [-14.6617754 , -12.05169949, -5.27005904, 11.72837321]]])
 

arange

Python의 range 객체와 유사한 개념입니다. 0, 1, 2, … 가 순서대로 채워진 array를 만듭니다.
a = np.arange(10) a
출력 결과
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
astype() 으로 type을 지정할 수 있습니다.
a = np.arange(10).astype(float) a
출력 결과
array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])
 
reshape() 는 Numpy array의 모양을 바꿔 줍니다.
a = np.arange(10).reshape((5,2)) a
출력 결과
array([[0, 1], [2, 3], [4, 5], [6, 7], [8, 9]])
 
# Quiz: Create a 4-by-3-by-2 tensor filled with 0.0 to 23.0
코드
example2 = np.arange(24).astype(float).reshape((4, 3, 2)) example2
출력 결과
array([[[ 0., 1.], [ 2., 3.], [ 4., 5.]], [[ 6., 7.], [ 8., 9.], [10., 11.]], [[12., 13.], [14., 15.], [16., 17.]], [[18., 19.], [20., 21.], [22., 23.]]])
 
 

Indexing & Slicing

Python에서 기본으로 제공하는 Indexing과 Slicing을 그대로 사용할 수 있습니다. Python 문법과 일치하기에, 출력 결과는 생략합니다.
# Indexing and slicing a vector a = np.arange(10) print_obj(a, "a") print_obj(a[0], "a[0]") print_obj(a[1], "a[1]") print_obj(a[-1], "a[-1]") print_obj(a[-3], "a[-3]") print_obj(a[0:10], "a[0:10]") print_obj(a[0:], "a[0:]") print_obj(a[:10], "a[:10]") print_obj(a[:], "a[:]") print_obj(a[7:], "a[7:]") print_obj(a[:5], "a[:5]") print_obj(a[2:5], "a[2:5]") # Quiz: What is a[-4:]? # Quiz: What is a[:-8]? print_obj(a[0:10:2], "a[0:10:2]") print_obj(a[0:10:3], "a[0:10:3]") print_obj(a[2:6:3], "a[2:6:3]") print_obj(a[::-1], "a[::-1]") print_obj(a[8:5:-1], "a[8:5:-1]") print_obj(a[8:5], "a[8:5]") # Quiz: Create [9, 6, 3] using a. print_obj(a[:2:-3], "a[:2:-3]")
# Indexing a matrix a = np.arange(9).reshape((3,3)) print_obj(a, "a") print_obj(a[0][0], "a[0][0]") print_obj(a[0,0], "a[0,0]") print_obj(a[1,1], "a[1,1]") print_obj(a[1,0], "a[1:0]") # Quiz: How to access the last row? print_obj(a[2], "a[2]") print_obj(a[-1], "a[-1]") # Quiz: How to access the second column? print_obj(a[:,1], "a[:,1]") # Quiz: How to create [8, 5] using a? print_obj(a[:0:-1, 2], "a[:0:-1, 2]")
# Indexing and slicing a 3D tensor a = np.arange(4*3*2).reshape((4, 3, 2)) print_obj(a, "a") print_obj(a[2, 1, 0], "a[2, 1, 0]") # Quiz: What would be a[0]? print_obj(a[0], "a[0]") # Quiz: What would be a[0, 1]? print_obj(a[0,1], "a[0,1]") # Quiz: Create [[0, 2, 4], [6, 8, 10]] print_obj(a[:2, :, 0], "a[:2, :, 0]")
마찬가지로 (To be written..)