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) 단계

  1. 큰 텐서의 ndim에 맞도록 작은 텐서에 (브로드캐스팅 축이라고 부르는)축이 추가된다.
  2. 작은 텐서가 새 축을 따라서 큰 텐서의 크기에 맞도록 반복된다.

 

텐서 점곱(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

[그림1] 텐서 크기 변환

 

전치(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

 

케라스 창시자에게 배우는 딥러닝

단어 하나, 코드 한 줄 버릴 것이 없다!창시자의 철학까지 담은 딥러닝 입문서케라스 창시자이자 구글 딥러닝 연구원인 저자는 ‘인공 지능의 민주화’를 강조한다. 이 책 역시 많은 사람에게

www.yes24.com

 

728x90
반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기