728x90
반응형
텐서 연산(tensor operation)
- 심층 신경망이 학습한 모든 변환을 수치 데이터 텐서에 적용하는 몇 종류의 텐서 연산으로 나타낼 수 있다.
- 텐서 덧셈이나 텐서 곱셈 등
원소별 연산
- relu 함수의 덧셈은 원소별 연산(element-wise operation)이다.
- 이 연산은 텐서에 있는 각 원소에 독립적으로 적용된다.
- 고도의 병렬 구현(1970~1990년대 슈퍼컴퓨터의 구조인 벡터 프로세서(vector processor)에서 온 용어인 벡터화된 구현을 말한다.)이 가능한 연산이라는 의미
# 원소별 연산
def naive_relu(x):
assert len(x.shape) == 2 # x는 2D 넘파이 배열
x = x.copy() # 입력 텐서가 바뀌지 않게 복사
for i in range(x.shape[0]):
for j in range(x.shape[1]):
x[i,j] = max(x[i,j], 0)
return x
def naive_add(x,y):
assert len(x.shape) == 2
assert x.shape == y.shape
x = x.copy()
for i in range(x.shape[0]):
for j in range(x.shape[1]):
x[i,j] += y[i,j]
return x
# 같은 원리로 원소별 곱셈, 뺄셈 등도 가능
def naive_sub(x, y):
assert len(x.shape) == 2
assert x.shape == y.shape
x = x.copy()
for i in range(x.shape[0]):
for j in range(x.shape[1]):
x[i, j] -= y[i,j]
return x
def naive_mul(x,y):
assert len(x.shape) == 2
assert x.shape == y.shape
x = x.copy()
for i in range(x.shape[0]):
for j in range(x.shape[1]):
x[i,j] *= y[i,j]
return x
- 넘파이 배열을 다룰 때는 최적화된 넘파이 내장 함수로 이런 연산을 처리할 수 있다.
- 넘파이 시스템에 설치된 BLAS(Basic Linear Algebra Subprogram)구현에 복잡한 일들을 위임한다.
- BLAS는 고도로 병렬화되고 효율적인 저수준의 텐서 조작 루틴이며, 전형적으로 포트란, C언어로 구현되어 있다.
브로드캐스팅(broadcasting) 단계
- 큰 텐서의 ndim에 맞도록 작은 텐서에 (브로드캐스팅 축이라고 부르는)축이 추가된다.
- 작은 텐서가 새 축을 따라서 큰 텐서의 크기에 맞도록 반복된다.
텐서 점곱(tensor product)
- 점곱 연산(dot operation)은 가장 널리 사용되고 유용한 텐서 연산이다.
- 원소별 연산과 반대로 입력 텐서의 원소들을 결합시킨다.
- 넘파이, 케라스, 씨아노, 텐서플로에서는 원소별 곱셈을 * 연산자를 사용한다.
- 텐서플로에서는 dot 연산자가 다르지만 넘파이와 케라스는 점곱 연산에 보편적인 dot 연산자를 사용한다.
# 점곱 연산
import numpy as np
z = np.dot(x,y)
z = x * y
# 점곱 연산 x와 y의
def naive_vetor_dot(x,y):
assert len(x.shape) == 1
assert len(y.shape) == 1
assert x.shape[0] == y.shape[0]
z = 0.
for i in range(x.shape[0]):
x += x[i] * y[i]
return z
# 행렬 x와 벡터 y 사이의 점곱
def naive_matrix_vector_dot(x,y):
assert len(x.shape) == 2
assert len(y.shape) == 1
assert x.shape[1] == y.shape[0] # x의 두 번째 차원이 y의 첫 번째 차원과 같아야 한다.
z = np.zeros(x.shape[0])
for i in range(x.shape[0]):
for j in range(x.shape[1]):
z[i] += x[i, j] * y[i]
return z
- ndim이 1보다 크면 dot 연산에 교환 법칙이 성립되지 않는다.
- dot(x,y)와 dot(y,x)는 다르다.
두 행렬 간의 점곱
# 두 행렬 간의 점곱
def naive_matrix_dot(x, y):
assert len(x.shape) == 2
assert len(y.shape) == 2
assert x.shape[1] == y.shape[0] # x의 두 번째 차원이 y의 첫 번째 차원과 같아야 한다.
z = np.zeros((x.shape[0], y.shape[1])) # 이 연산은 0이 채워진 크기의 벡터를 만든다.
for i in range(x.shape[0]):
for j in range(y.shape[1]):
row_x = x[i, :]
column_y = y[:, j]
z[i, j] = naive_vector_dot(row_x, column_y)
return z
텐서 크기 변환(tensor reshaping)
- 특정 크기에 맞게 열고 행을 재배열한다는 뜻
- 크기가 변화된 텐서는 원래 텐서와 원소 개수가 동일하다.
# 텐서 크기 변환
x = np.array([[0, 1],
[2, 3],
[4, 5]])
print(x.shape) # 3,2
x = x.reshape((6,1)) # 2차원이라서 (())
x
전치(transposition)
# 전치 transposition
x = np.zeros((300, 20)) # 0으로 채워진 300,20 행렬 만들기
x = np.transpose(x)
print(x.shape)
렐루(relu)
- 렐루 함수는 입력이 0보다 크면 입력을 그대로 반환하고, 0보다 작으면 0을 반환한다.
BLAS
- 기본 선형 대수 하위 프로그램은 벡터 더하기, 스칼라 곱셈, 내적, 선형 조합 및 행렬 곱셈과 같은 일반적인 선형 대수 연산을 수행하기위한 일련의 저수준 루틴을 규정하는 사양입니다.
- 선형 대수 라이브러리를위한 사실상의 표준 저수준 루틴입니다.
출처 :
www.yes24.com/Product/Goods/65050162?OzSrank=1
728x90
반응형
최근댓글