1. 강의 정리
Conditionals and Loops (최성철 교수님)
1) 조건문: 조건에 따라 특정한 동작을 하게하는 명령어
조건을 나탄내는 기준과 실행해야 할 명령으로 구성되며 if, else, elif 등의 예약어를 사용.
- 'x==y' 와 'x is y'의 차이
'x==y'는 값이 동일한지 검사하지만 'x is y'는 동일한 위치의 id값을 가지고 있는지에 대한 여부를 판단. 파이썬에서 -5~256는 이미 파이썬에서 메모리를 할당되어있기 때문에 True를 반환하지만 이 범위를 넘어가면 False 반환. - 삼항 연산자
조건문을 사용하여 참일 경우와 거짓일 경우의 결과를 한 줄에 표현. value = 12 is_even = True if value % 2 == 0 else False print(is_even) # 리턴값: True
2) 반복문: 정해진 동작을 반복적으로 수행하게 하는 명령문
반복 시작 조건, 종료 조건, 수행 명령으로 수성되었으며 for, while 등의 명령 키워드를 사용.
range()는 마지막 숫자 바로 앞까지 리스트를 만들어줌. ex) range(1,5) = [1,2,3,4]
또한 간격을 두고 세기, 역순 수행 등이 가능.
문자열은 한자씩 리스트로 처리하고 리스트 안의 문자열들은 각각의 문자열로 처리한다.
for문과 while문의 차이는 정해진 횟수가 있는가임. for문은 정해진 횟수동안 반복되지만 while의 경우 조건이 만족하지 않을 때까지 계속 loop문을 실행
반복문을 실행할 때에는 debugging을 위해서 print문으로 출력하면서 loop문이 어떻게 돌아가는지 확인이 가능한데, 여기서 디버깅은 코드의 오류를 발견하여 수정하는 과정으로 문법적 에러, 논리적 에러를 찾기 위한 테스트이다.
String and advanced function concept (최성철 교수님)
1) 문자열
시퀀스 자료형으로 문자형 data를 메모리에 저장한다. 영문자 한 글자는 1byte의 메모리 공간을 사용한다. 여기서 1byte = 8bit = 256까지 저장 가능.
정수형의 경우 int는 4바이트, long은 무제한의 크기를 가지며 실수형인 float는 8바이트를 가진다.
문자열의 각 문자는 개별 주소(offset)을 가지며 이 주소를 사용해 할당된 값을 가져오는게 인덱싱이다. 인덱싱은 0부터 시작. 문자열의 주소값을 기반으로 문자열의 부분값을 반환하는 슬라이싱(Slicing)도 가능.
문자열은 덧셈과 뺄셈 연산이 가능하며 in 명령으로 포함여부 체크를 할 수 있다.
함수명 | 기능 | 함수명 | 기능 |
len(a) | 문자열의 문자 개수 반환 | a.upper() | 대문자로 변환 |
a.lower() | 소문자로 변환 | a.capitalize() | 첫문자를 대문자로 변환 |
a.title() | 띄워쓰기 후 첫글자만 대문자 | a.count(문자) | 문자의 횟수 반환 |
a.find(문자), a.rfind(문자) | 문자가 들어간 위치 반환 | a.startwith(문자) | 문자로 시작하는 문자열 여부 반환 |
a.endwith(문자) | 문자로 끝나는 문자열 여부 반환 | a.strip() | 좌우 공백을 없앰 |
a.rstrip(), a.lstrip() | 오른쪽/왼쪽 공백을 없앰 | a.split() | 공백을 기준으로 나눠 리스트로 반환 |
a.split(문자) | 문자를 기준으로 나눠 리스트로 반환 | a.isdigit() | 문자열이 숫자인지 여부 반환 |
a.islower() | 문자열이 소문자인지 여부 반환 | a.isupper() | 문자열이 대문자인지 여부 반환 |
''를 사용하여 다양한 문자 표현 가능
2) function
함수에서 parameter를 전달하는 방식으로 값에 의한 호출(Call by Value), 참조에 의한 호출(Call by Reference), 객체 참조에 의한 호출(Call by Object Reference)이 있다.
벡터 (임성빈 교수님)
1) 벡터란?
숫자를 원소로 가지는 리스트(list) 또는 배열(array)로 공간에서 한 점을 나타냄. 이 점은 원점으로부터 상대적 위치를 표현하며 숫자를 곱해주면 길이만 변화.
- 스칼라곱: 주어진 벡터의 길이를 변환시키는 것으로 숫자의 크기가 1보다 크면 원래 벡터의 길이를 이전보다 길게, 1보다 작으면 길이를 줄인다. 0보다 작으면 반대 방향이 됨.
벡터끼리 같은 모양을 가지면 덧셈, 뺄셈, 성분곱을 계산할 수 있다.
2) 벡터의 노름(norm)
: 원점에서부터의 거리. 노름의 종류에 따라 기하학적 성질이 달라짐.
- L1-norm: 변화량의 절대값의 합
ex) Robust 학습, Lasso 회귀 - L2-norm: 유클리드 거리 -> np.linalg.norm을 이용해 구현 가능
ex) Laplace 근사, Ridge 회귀
def l1_norm(x):
x_norm = np.abs(x)
x_norm = np.sum(x_norm)
return x_norm
def l2_norm(x):
x_norm = x*x
x_norm = np.sum(x_norm)
x_norm = np.sqrt(x_norm)
return x_norm
L1,L2-norm을 활용해 두 벡터 사이의 거리를 뺄셈을 통해 구할 수 있습니다. 두 벡터 사이의 거리를 계산할 때는 벡터의 뺄셈을 이용합니다. 두 벡터 사이의 거리를 이용하여 각도도 계산할 수 있는데, 제2 코사인 법칙에 의해 두 벡터 사이의 각도를 계산할 수 있습니다.
$cos\theta = \frac{2<x,y>}{2||x||_2||y||_2}$ 이때, 분자를 쉽게 계산하는 방법이 내적입니다.
def angle(x, y):
v = np.inner(x, y) / (l2_norm(x) * l2_norm(y)) # np.inner: 내적 계산(l2-norm만)
theta = np.arccos(v) # np.arccos: 코사인의 역
return theta
3) 내적
내적은 정사영(orthogonal projection)된 벡터의 길이와 관련 있으며 정사영의 길이를 벡터 y의 길이 $||y||$ 만큼 조정한 값입니다. $Proj(x)$의 길이는 코사인법칙에 의해 $||x||cos\theta$가 됩니다.
$내적 <x,y>= ||y||Proj(x) = ||x||_2||y||_2cos\theta$
행렬 (임성빈 교수님)
1) 행렬이란?
행렬(matrix)은 벡터를 원소로 가지는 2차원 배열이며 행(row)과 열(column)이라는 인덱스(index)를 가집니다. 행렬의 특정 행(열)을 고정하면 행(열)벡터라 부릅니다.
- 전치행렬(trasnspose matrix): 행과 열의 인덱스가 바뀐 행렬
2) 행렬을 이해하는 방법
벡터가 공간에서 한 점을 의미한다면 행렬은 여러 점들을 나타냅니다. 행렬의 행벡터 $x_i$는 $i$번째 데이터를 의미하며 $x_{ij}$는 $i$번째 데이터의 $j$번째 변수의 값을 말합니다.
행렬끼리 같은 모양을 가지면 덧셈, 뺄셈을 계산할 수 있습니다. 성분곱은 각 인덱스 위치끼리 곱하는 것으로 벡터와 똑같습니다. 스칼라곱도 차이가 없습니다. 행렬 곱셈(matrix multiplication)은 $i$번째 행벡터와 $j$번째 열벡터 사이의 내적을 성분으로 가지는 행렬을 계산합니다. (numpy에선 @연산을 사용합니다.)
numpy에서의 내적은 앞에서 이야기한 것과 조금은 다른 의미를 가집니다. np.inner는 $i$번째 행벡터와 $j$벡터 행 벡터 사이의 내적을 성분으로 가지는 행렬을 계산하기 때문에 수학에서 말하는 내적과는 다릅니다. np.inner를 사용하려면 반드시 transpose를 해서 사용해줘야 합니다. 이때도 행 벡터의 길이가 같아야 내적을 계산할 수 있습니다.
행렬은 벡터공간에서 사용되는 연산자(operator)로 이해합니다. 행렬곱을 통해 벡터를 다른 차원의 공간으로 보내거나 패턴을 추출할 수 있고 데이터를 압축할 수도 있습니다. (모든 선형변환(linear transform)은 행렬곱으로 계산할 수 있습니다.)
3) 역행렬
어떤 행렬 $A$의 연산을 거꾸로 되돌리는 행렬을 역행렬(inverse matrix)이라 부르고 $A^{-1}$라 표기합니다. 역행렬은 행과 열의 숫자가 같고 행렬식(determinant)이 0이 아닌 경우에만 계산할 수 있습니다.
np.linalg.inv(X) # 역행렬
만일 역행렬을 계산할 수 없다면 유사역행렬(pseudo-inverse) 또는 무어-펜로즈(Moore-Penrose) 역행렬 $A^+$을 이용합니다. 이때, $n \geq m$ 인 경우 $A^+ = (A^TA)^{-1}A^T$ 이고, $n \leq m$ 인 경우 $A^+ = A^T(AA^T)^{-1}$ 입니다.
np.linalg.pinv(Y) # 유사역행렬
- 응용1: 연립방정식 풀기
- $n \leq m$인 경우로 식이 변수 개수보다 작거나 같아야 합니다. np.linalg.pinv를 이용하면 연립방정식의 해를 구할 수 있습니다. $n \leq m$ 이면 무어-펜로즈 역행렬을이용하면 해를 하나 구할 수 있습니다.
- 응용2: 선형회귀분석
$n \geq m$ 인 경우로 데이터가 변수 개수보다 많거나 같아야 합니다. np.linalg.pinv를 이용하면 데이터를 선형모델(linear model)로 해석하는 선형회귀식을 찾을 수 있습니다. - $X\beta = \hat y \approx y \Rightarrow \beta = X^+y = (X^TX)^{-1}X^Ty$
이때의 $y$는 L2-norm을 최소화 하는 값을 찾습니다. Moore-Penrose 역행렬을 이용하면 $y$에 근접하는 $\hat y$를 찾을 수 있습니다. 위 식의 $\beta$는 최적의 선형회귀 계수 입니다.
# sklearn 회귀분석
from sklearn.linear_model import LinearRegression
model = LinearRegression()
model.fit(X, y)
y_test = model.predict(x_test)
# Moore-Penrose 역행렬
X_ = np.array([np.append(x,[1]) for x in X]) # intercept 항(y절편) 추가
beta = np.linalg.pinv(X_) @ y
y_test = np.append(x, [1]) @ beta
경사하강법 - 순한맛 (임성빈 교수님)
1) 미분
미분(differentiation)은 변수의 움직임에 따른 함수값의 변화를 측정하기 위한 도구로 최적화에서 제일 많이 사용하는 기법이며 변화율의 극한으로 정의합니다. 미분은 함수 $f$의 주어진 점 $(x,f(x))$ 에서의 접선의 기울기를 구합니다. 미분을 계산하기 위해서는 함수의 모양이 매끄러워야(연속) 합니다. 한 점에서 접선의 기울기를 알면 어느 방향으로 점을 움직여야 함수값이 증가하는지/감소하는지 알 수 있습니다. 함수값을 증가시키고 싶다면 미분값을 더하고 감소시키고 싶으면 미분값을 뺍니다. 미분값을 더하면 경사상승법(gradient ascent)이라 하며 함수의 극대값의 위치를 구할 때 사용합니다(목적함수를 최대화 할 때 사용). 미분값을 빼면 경사하강법(gradient descent)이라 하며 함수의 극소값의 위치를 구할 때 사용합니다(목적함수를 최소화 할 때 사용). 경사상승/경사하강 방법은 극값에 도달하면 움직임을 멈춥니다.
import sympy as sym
from sympy.abc import x
sym.diff(sym.poly(x**2 + 2*x + 3), x)
# sym.diff: 미분, sym.poly: 다항함수로 인식
2) 경사하강법: 알고리즘
var = init # 시작점
grad = gradient(var) # 미분을 계산하는 함수
while(abs(grad) > eps):
'''
컴퓨터로 계산할 때 미분이 정확히 0이 되는 것은 불가능하므로
eps 보다 작을 때 종료하는 조건 필요
'''
var = var - lr * grad # lr은 학습률로서 미분을 통해 업데이트하는 속도 조절
grad = gradient(var) # 종료조건 성립하기 전까지 미분값을 계속 업데이트
변수가 벡터이면? 벡터가 입력인 다변수 함수의 경우 편미분(partial differentiation)을 사용합니다. 각 변수 별로 편미분을 계산한 그레디언트(gradient) 벡터를 이용하여 경사하강/경사상승법에 사용할 수 있습니다.
-> $e_i$는 $i$번째 값만 1이고 나머지는 0인 단위벡터 입니다.
import sympy as sym
from sympy.abc import x, y
sym.diff(sym.poly(x**2 + 2*x + 3) + sym.cos(x + 2*y), x)
# >> s*x + 2*y - sin(x + 2*y)
-> 앞서 사용한 미분값인 $f'(x)$ 대신 벡터 $\nabla f$ 를 사용하여 변수 $x = (x_1,...,x_d)$를 동시에 업데이트 가능합니다. 그레디언트 벡터 $\nabla f(x,y)$는 각 점$(x,y)$에서 가장 빨리 증가하는 방향으로 흐르며 $-\nabla f$는 $\nabla (-f)$ 랑 같고 이는 각 점에서 가장 빨리 감소하게 되는 방향과 같습니다.
경사하강법 - 매운맛 (임성빈 교수님)
1) 경사하강법 - 선형회귀분석
선형회귀분석에서는 무어-펠로즈 역행렬을 사용하면 쉽게 구할 수 있지만 경사하강법은 좀 더 일반적인 경우에서도 적용이 가능하기 때문에 사용됩니다. 경사하강법으로 선형회귀 계수를 구하기 위해서는 선형회귀의 목적식 $||y-X_\beta||$ 을 최소화하는 $\beta$를 찾아야 하므로 아래와 같은 그레디언트 벡터를 구해야 합니다.
목적식을 최소화하는 $\beta$를 구하는 경사하강법 알고리즘은 다음과 같습니다.
$=$
for t in range(T): # T:학습횟수
error = y - X @ beta
grad = - transpose(X) @ error
beta = beta - lr * grad
# 선형회귀 목적식을 계산해서 beta를 업데이트
경사하강법은 미분가능하고 볼록(convex)한 함수에 대해서는 적절한 학습률과 학습횟수를 선택했을 때 수렴이 보장되어 있습니다. 특히, 선형회귀의 경우 목적식 $||y-X_\beta||_2$ 은 회귀계수 β에 대해서 볼록함수이기 때문에 알고리즘을 충분히 돌리면 수렴이 보장됩니다. 하지만 비선형회귀 문제의 경우 목적식이 볼록하지 않을 수 있으므로 수렴이 항상 보장되지는 않습니다.
2) 확률적 경사하강법(stochastic gradient descent)
확률적 경사하강법은 모든 데이터를 사용해서 업데이트하는 대신 데이터 한개 또는 일부(mini-batch)를 활용해서 업데이트합니다. 볼록이 아닌(non-convex) 목적식은 SGD를 통해 최적화할 수 있습니다. 한개만 사용하는 것은 비효율적이기 때문에 mini-batch를 활용한 SGD를 많이 사용합니다.
SGD는 데이터의 일부를 가지고 파라미터를 업데이트하기 때문에 연산자원을 좀 더 효율적으로 활용하는데 도움이 됩니다. 전체 데이터 $(X,y)$ 를 쓰지 않고 미니배치 $(X_{(b)},y_{(b)})$ 를 써서 업데이트 하므로 연산량이 $b/n$으로 감소합니다.
미니배치 연산
경사하강법은 전체데이터 $D=(X,y)$ 를 가지고 목적식의 그레디언트 벡터인 $\nabla_\theta L(D,\theta)$ 를 계산합니다. 여기서 $L(D,\theta)$ 는 전체데이터 $D$와 파라미터 $\theta$ 로 측정한 목적식입니다.SGD는 미니배치 $D_{(b)}$ 를 가지고 그레디언트 벡터를 근사해서 계산합니다. 이때, 미니배치는 확률적으로 선택하므로 목적식의 모양이 바뀌게 됩니다. 따라서 극소점이나 극대점에서 목적식이 확률적으로 변하기 때문에 탈출이 가능하고 non-convex 함수여도 최소점을 찾는데 활용 가능 합니다.
2. 과제 수행 과정 / 결과물 정리
X
3. 피어세션 정리
- 그라운드룰 추가
- 과제 및 학습계획 수립
- 3분 발표 계획 및 ppt 제작
4. 학습 회고
잊고 있던 벡터, 행렬, 경사하강법 등의 기초적인 지식들을 다시 다질 수 있었습니다.
'네이버 부스트캠프 > LEVEL-1' 카테고리의 다른 글
[부스트캠프][WK-02 / Day6] 딥러닝 기초 (0) | 2021.08.10 |
---|---|
[부스트캠프][WK-01 / Day5] 파이썬 기초 4, numpy/pandas (0) | 2021.08.06 |
[부스트캠프][WK-01 / Day4] AI Math 3 (0) | 2021.08.06 |
[부스트캠프][WK-01 / Day3] 파이썬 기초 3, AI Math 2 (0) | 2021.08.06 |
[부스트캠프][WK-01 / Day1] 파이썬 기초 (0) | 2021.08.04 |