검색
검색
공개 노트 검색
회원가입로그인

[이솦] 파이선으로 배우는 AI 기초 21

요약
  • 머신러닝과 딥러닝에서 중요한 역할을 하는 것은 행렬 연산이다.
  • 파이썬의 넘파이 라이브러리는 다차원 배열 및 행렬 연산을 효율적으로 수행할 수 있는 기능을 제공한다.
  • 넘파이를 활용하여 기본적인 사칙연산뿐만 아니라 연립방정식 해결까지 가능하다.

이솦 | EBS 소프트웨어·인공지능 교육

현대 기계학습및 딥러닝을 동작 시키는 대부분의 연산은 행렬 연습이다. 다양한 형태를 가진 이미지의 특성을 추출하여 어떤 이미지인가 인식할때도 행렬 연산을 사용한다.

이미지는 픽셀로 되어 있는데 픽셀은 숫자 이기도 하다. 이미지의 가로 세로 값이 대부분 -1로 되어 있는 3*3 행렬을 곱하면 이미지의 테두리, 보통 엣지라고 하는 부분만 부각된 이미지를 얻을수 있다. 이때 사용하는 것이 행렬 연산이다.

이미지 인식을 비롯한 다양한 인공지능 분야에서는 행렬 연산과 더불어 다양한 수학 연산을 한다.

파이썬의 외부 모듈중 넘파이 (numpy)는 이런 행렬 연산을 아주 편리하게 할수 있는 기능을 제공해 준다.

오늘은 넘파이 라이브러리의 행렬 연산을 이용해서 연립 방정식을 풀어보자.

Numpy

넘파이는 수학에서의 행렬이나 다차원 배열을 쉽게 처리할수 있도록 지원하는 파이선의 라이브러리이다. 다차원 배열 외에도 수치 계산을 위한 다양한 함수를 제공하고 있다.

넘파이에서 사용하는 수치 데이터의 중류는 4가지이다.

스칼라(scala), 벡터(vector), 행렬(matrix), 텐서(tensor) 이다.

스칼라는 숫자로 이루어져 있고, 크기를 포현하며, 42, 24 같은 숫자이다. 스칼라의 수학적 정의에는 크기만 있고 방향이 없는 물리량이다.

벡터는 스칼라의 집합이며 여러개의 숫자가 보여 있는 형태이다. 크기와 방향이 있다. 컴퓨터의 배열을 통해 말하면 1차원 배열이 벡터이다. 배열은 컴퓨터 용어로, 컴퓨터에서 사용하는 값의 묶음 형태이다. 행벡터와 열 벡터가 있다. 가로는 행벡터, 세로로 있으면 열 벡터이다.

행렬은 벡터의 집합이며 1개 이상의 행과 열로 구성된 2차원 배열이다.

텐서는 3차원 이상의 배열이다. 행렬안에 행렬이 있다. 1차원 텐서를 벡서, 2차원 텐서를 행렬이라고 하기도 한다.

텐서플로 라는 라이브러리 기억 나는가? 딥러닝 모델 내에서 텐서가 연산을 통해 이동하면서 모양이 바뀌며 출력에 도달한다.

이제 코드로 구연해 보자.

import numpy as np
arr = np.array([20, 25, 41])
print (arr)

넘파이를 불러오고, arr변수를 만들고 넘파이에서 배열이라는 의미늬 array()라는 함수를 사용했다. 리스트 값을 함수의 인자로 입력하면 array()함수가 1차원 배열 즉 벡터로 변환해 준다. 벡터는 행벡터와 열벡터가 있다. 행벡터는 하나의 행으로 만들어진 벡터라서 나오는 결과물은 행벡터이다. 열백터로 만들려면 여러개의 행과 1개의 열로 구성되어 있어서 array()함수로 구현할때는 각행의 값을 []묶어 주어야 한다.

import numpy as np
arr = np.array([[20], [25], [41]])
print (arr)

이렇게 하면 행이 3개인 열백터가 나온다. 머신러닝 코드를 실행할때 꼭 열벡터로 처리해 줘야 할때가 많으니 조심해라.

이번에도 array()함수로 행렬을 만들어보자.

arr = np.array([[1, 2], [3, 4], [5, 6]])
print (arr)

여기에는 import가 안보이는데 처음에 넘파이를 import하는것은 한번이면 된다. 이건 3행 2열로 구성된 행렬이다.

넘파이에서 제공하는 함수 중에서는 배열을 생성하는 재미 있는 함수 들이 있다. 0으로 채워진 배열, 1로 채워진 배열을 만들수 있다. 이 함수들을 이용하면 배열을 쉽게 만들수 있다.

arr = np.zeros((2, 3))
arr

zeros(2,3) 이라고 하면 2행 3열 의 행렬을 만들되 모든 값이 0으로 채워진다.

arr = np.ones((3, 4))
arr

ones()는 이름에서 알수 있듯이 1로 채워진 배열을 만든다. 매개변수에 적당한 값으 넣으면 행렬을 만들수가 있다. 이렇게 하면 3행 4열짜리 1로 채워진 행렬을 만들수 있다.

twos()는 없다. 이유는 기본적으로 0또는 1로 초기화 해야할때가 많기 때문이다.

벡터및 행렬등을 이용하는 목적은 연산을 효율적으로 하기 위함이다. 그러므로 연산을 연습해 보자. 이제 배열을 이용해서 행렬을 만들고 사칙연산을 해보자.

가장 간단한 4칙연산을 할 행렬 2개를 만들어보자.

arr1 = np.array([[1, 2], [3, 4]])
print(arr1)
arr2 = np.array([[2, 2], [2,2]])
print(arr2)

1,2와 3,4가 구성된 2차원으로 구성된 배열 즉 2*2 행렬을 만들었다. 그후 연산을 해줄 곱해줄 값을 모두 2로 두성된 2*2 행렬을 만들었다.

덧샘을 해보자. 방법은 2가 이다. 뺄샘도 마찬가지이다.

print(arr1 + arr2)
print(np.add(arr1, arr2))

덧샘기호 +를 이용하거나 함수 add()를 사용한다. 함수의 경우 더할 두 배열을 매개 변수로 넣어 준다. 결과를 확인하면 + 기호를 쓴것과 함수를 사용한 결과가 같다.

print(arr1 - arr2)
print(np.subtract(arr1, arr2))

뺄셈은 연산기호 -또는 subtract함수를 사용한다. 덧셈과 마찬가지로 함수에 배열 두개를 인자로 넣어 준다.

print(arr1 * arr2)
print(np.multiply(arr1, arr2))

곱셈도 덧셈, 뺄샘과 유사하다. 연산기호 *를 사용할수 있으며, multipy()라는 함수를 이용할수 있다.

print(arr1 / arr2)
print(np.divide(arr1, arr2))

나누기 기호 / 를 사용하거나 divide()함수를 이용할수 있다.

지금까지는 배열과 배열, 행렬과 행렬의 연산이었는데, 넘파이 배열은 스칼라 값과도 연산을 할수 있다.

print(arr1 * 3)
print(np.multiply(arr1, 3))

즉 2*2형태의 배열 즉 행렬에 스칼라 값 3을 곱해 주는 코드이다. 연산기호 *를 사용할수 있으며, multiply()라는 함수를 이용할 수 있다.

그런데 학창 시절 배운 행렬곱과 지금 행렬곱은 조금 다르다. 즉 지금 해본것은 배열에 대한 사칙 연산을 한것이고 실제 행렬, 벡터 곱은 내적 (dot product)을 해줘야 한다.

백터와 행렬에 대한 곱은 규칙이 있다.

백터 곱두 벡터의 요소 개수 동일, 첫번째 벡터가 행 벡터, 두번째 벡터가 열 벡터
행렬 곱첫번째 행렬의 열 크기와 두번째 행렬의 행 크기 동일

그럼 벡터 2개와 행렬 2개를 만들어서 실제로 곱을 해보자.

vec1 = np.array([[1, 2, 3]])
vec2 = np.array([[4], [5], [6]])
mat1 = np.array([[1, 2, 3], [4, 5, 6]])
mat2 = np.array([[1, 2], [3, 4], [5, 6]])

vec1 은 행 벡터로 1,2,3 이라는 값을 가지고 있다. vec2는 열 벡터로 4,5,6의 값을 가지고 있다. mat1은 2*3의 행렬이고 mat2 는 3*2의 행렬이다. mat1의 열과 mat2의 행값이 같은걸 확인해봐라.

먼저 벡터 2개를 곱해보자.

vec1.dot(vec2)

이렇게 하면 1*4+2*5+3*6 총 32가 나온다. numpy의 dot 연산자를 활용해서 계산을 할때는 두번째 항목을 메소드로 입력해 준다. 벡터곱의 결과는 벡터가 아닌 스칼라가 나온다. 각 요소의 곱의 합이 나온다.

행렬 곱은 다음과 같다.

mat1.dot(mat2)

이렇게 하면 2*3 행렬과 3*2 행렬을 곱하면 가로 와 세로 행렬을 곱하기 떄문에 총 2*2 행렬이 나온다. 앞 행렬의 크기와 뒤 행렬의 크기가 같아야 곱을 할수 있다. 4*3 행렬과 3*5 행렬을 곱하면? 4*5 행렬이 된다.

핵심비법

지금까지 numpy를 배웠는데 알아 챘는가? 결국 numpy의 인자로 사용하는것은 파이선의 리스트 이다. 그런데 왜 리스트로 그냥 연산을 하지 않고 numpy의 배열을 이용할까? 그 이유는 리스트는 메모리 공간을 사용할때 비연속 공간을 사용하고 배열을 연속공간을 사용하기에 배열은 연산속도가 리스트에 비해 빠르다. 그리고 배열은 단일 데이터행을 사용한다. 리스트는 여러가지 자료를 입력할수 있던것 기억나는가? 배열은 한가지 형태만 쓸수 있다.

import numpy as np

a= [1, 2, 'a', 'b']

b = np.array([1, 2, 'a', 'b'])
print(b)

이렇게 numpy로 array로 리스트를 선언하고 출력해 보면 숫자가 문자열로 바뀌어서 저장된다. 연산을 해서 더하면 리스트는 데이터를 추가하지만, 배열은 요소의 값을 계산한다.

그럼 머신러닝에서는 여러 종류의 데이터를 이용해야되서 리스트를 더 활용하는거 아닌가 생각할수도 있지만, 자연어를 처리하던, 그림을 처리하던 머신러닝의 모델 내부에서는 모두 숫자로 처리된다. 그러니 숫자로 된 텐서를 잘 처리하면 된다. 그래서 numpy가 효율적으로 사용된다.

연립 방정식풀이

2X + 3Y= 4

5X + 6Y=5

이걸 코드로 표현하면 이렇게 된다.

import numpy as np
A = np.array([[2, 3], [5, 6]])
B = np.array([4, 5])
C=np.linalg.solve(A, B)
print(C)

numpy에서 연립 방정식을 풀때 사용하는 함수는 linalg이고 solve 즉 선형 방정식을 풀라는 함수 이다.

요약

머신러닝의 행렬 연산은 numpy라이브러리를 활용한다.

넘파이는 스칼라, 벡터, 행렬, 텐서에 대한 연산을 수행할수 있다.

벡터의 곱과 행렬의 곱 연산은 내적을 이용해야 된다.

머신 러닝에 사용될 데이터가 문자든, 숫자든, 문장이든 결국 처리과정을 통해 내부적으로는 숫자로 처리되어 연산하게 됩니다. 머신러닝에서 가장 많이 사용하는 연산중 하나는 행렬 연산이다. 오늘은 넘파이를 공부했다.

gpt에게 numpy를 물어보니 더 알려 준다. 참 공부할게 많다.

배열 생성 및 기본 연산

python

코드 복사

import numpy as np # 1D 배열 생성 a = np.array([1, 2, 3]) b = np.array([4, 5, 6]) # 배열 간 덧셈 result_add = a + b print("Array addition:", result_add) # 배열 간 곱셈 result_mul = a * b print("Array multiplication:", result_mul) # 배열 간 내적 (Dot product) result_dot = np.dot(a, b) print("Dot product:", result_dot)

2. 배열 형태 조작

python

코드 복사

# 2D 배열 생성 matrix = np.array([[1, 2, 3], [4, 5, 6]]) # 배열의 형태 확인 print("Shape of matrix:", matrix.shape) # 배열의 형태 변경 (2x3 -> 3x2) reshaped_matrix = matrix.reshape(3, 2) print("Reshaped matrix:\n", reshaped_matrix)

3. 배열 연산 및 통계 계산

python

코드 복사

# 3x3 배열 생성 matrix = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) # 배열의 각 요소의 합 sum_all = np.sum(matrix) print("Sum of all elements:", sum_all) # 행 별 합 sum_axis_0 = np.sum(matrix, axis=0) print("Sum along rows:", sum_axis_0) # 열 별 합 sum_axis_1 = np.sum(matrix, axis=1) print("Sum along columns:", sum_axis_1) # 평균 값 mean_value = np.mean(matrix) print("Mean value:", mean_value)

4. 난수 생성

python

코드 복사

# 3x3 랜덤 배열 생성 random_matrix = np.random.rand(3, 3) print("Random matrix:\n", random_matrix) # 정규분포에서 난수 생성 random_normal = np.random.randn(3, 3) print("Random normal distribution matrix:\n", random_normal)

5. 배열 브로드캐스팅

python

코드 복사

# 1D 배열 a = np.array([1, 2, 3]) # 2D 배열 b = np.array([[4], [5], [6]]) # 브로드캐스팅을 이용한 덧셈 broadcast_result = a + b print("Broadcast result:\n", broadcast_result)

공유하기
카카오로 공유하기
페이스북 공유하기
트위터로 공유하기
url 복사하기
조회수 : 50
heart
T
페이지 기반 대답
AI Chat