행렬이 뭐에요?

행렬이란?

  • 행렬은 벡터를 원소로 가지는 2차원 배열
  • 행렬은 행과 열이라는 인덱스를 가진다.
  • 행렬의 특정 행(열)을 고정하면 행(열)벡터라고 부른다.
  • 전치행렬(transpose matrix)은 행과 열의 인덱스가 바뀐 행렬이다.
  • 벡터가 공간에서 한 점이었다면, 행렬은 여러 점을 나타낸다.
  • 행렬끼리 같은 모양을 가지면 덧셈, 뺄셈, 성분곱을 계산할 수 있다.
  • 행렬곱은 i번째 행벡터와 j번째 열벡터 사이의 내적을 성분으로 가지는 행렬을 계산한다.
  • 행렬은 벡터공간에서 사용되는 연산자(operator)로 이해한다.
  • 행렬곱을 통해 벡터를 다른 차원의 공간으로 보낼 수 있다.
  • 행렬곱을 통해 패턴을 추출할 수 있고, 데이터를 압축할 수도 있다.
  • 모든 선형변환(linear transform)은 행렬곱으로 계산할 수 있다.

역행렬

  • 어떤 행렬 A의 연산을 거꾸로 되돌린 행렬을 역행렬이라 한다.
  • 역행렬은 행과 열 숫자가 같고 행렬식(determinant)이 0이 아닌 경우에만 계산할 수 있다.
  • 역행렬을 계산할 수 없다면 유사역행렬(pseudo-inverse) 또는 무어-펜로즈(Moore-Penrose)역행렬을 이용한다.
  • 유사역행렬을 이용하면 데이터를 선형모델로 해석하는 선형회귀식을 찾을 수 있다.
자세히 보기

벡터가 뭐에요?

벡터란?

  • 벡터는 공간에서 한 점 을 나타낸다.
  • 벡터는 원점으로부터의 상대적인 위치 를 표현한다.
  • 벡터에 숫자를 곱해주면(스칼라곱) 길이가 변하지만, 스칼라가 0보다 작다면 반대 방향 이 된다.

  • 벡터는 숫자를 원소로 가지는 리스트 혹은 배열이다.

  • 벡터끼리 같은 모양을 가지면 덧셈, 뺄셈, 성분곱을 계산할 수 있다.
  • 두 벡터의 덧셈은 다른 벡터로부터 상대적인 위치 이동 을 표현한다. (뺄셈은 방향을 뒤집은 덧셈)
    • 벡터 x에 대하여, $x = 0 + x$ 가 성립한다. 즉 x라는 벡터는 원점벡터에서부터의 상대적인 위치를 나타낸다.

벡터의 노름

  • 벡터의 노름(norm)은 원점에서부터의 거리 이다.

  • L1-노름은 각 성분의 변화량의 절대값을 모두 더한 값이다.

  • L2-노름은 피타고라스 정리를 이용하여 유클리드 거리 를 계산한다.
  • 노름의 종류에 따라 기하학적 성질이 달라진다.
    • L1-노름 상의 원은 마름모꼴 (Robust 학습, Lasso 회귀)
    • L2-노름 상의 원은 흔히 알고 있는 원이다. (Laplace 근사, Ridge 회귀)
  • 두 벡터 사이의 거리를 계산할 때는 벡터의 뺄셈을 이용한다.
    • 뺄셈을 거꾸로 해도 거리는 같다.
  • L2-노름에서 두 벡터 사이의 거리를 이용하여, 제2 코사인 법칙에 의해 두 벡터 사이의 각도를 계산할 수 있다.
    • 내적(inner product)을 통해 분자를 쉽게 계산할 수 있다.

벡터의 내적

  • 내적은 두 성분곱의 총합이다.
  • 내적은 정사영(orthogonal projection)된 벡터의 길이와 관련이 있다.
  • Pros(x)는 벡터 y로 정사영된 벡터 x의 그림자 를 의미한다.
  • Proj(x) = ||x||2cos(theta)
  • 내적은 정사영의 길이를 벡터 y의 길이 ||y||만큼 조정한 값이다.
  • = Proj(x) * ||y||2 = ||x||2||y||2cos(theta)
자세히 보기

Tensorflow에서 Value Error: Unknown Layer: Functional 문제

이미지 출처 - https://bugloss-chestnut.tistory.com/entry/Tensorflow-keras-h5-pb-tflite-%EB%B3%80%ED%99%98-%EC%98%A4%EB%A5%98python

문제 원인 및 발생 경위

Tensorflow 로 구현된 사전학습 모델을 사용하게 되면 심심치 않게 해당 오류를 발견할 수 있다. 이것은 로컬 혹은 컨테이너 환경에서의 Tensorflow 버전이 사전학습 모델의 Tensorflow 버전과 일치하지 않아서 생기는 문제이다.

왜냐하면 Tensorflow 2.3 버전에서 model을 저장할 때의 json 구조가 달라졌기 때문이다.

기존의 (Tensorflow 2.2 버전 이전) 모델 저장 구조

1
2
{"class_name": "Model", "config": {"name": "model_1", "layers": [{"name": "input_1", "class_name": "InputLayer" ...

변경 이후 (Tensorflow 2.3 버전 이후) 모델 저장 구조

1
2
{"class_name": "Functional", "config": {"name": "functional_1", "layers": [{"class_name": "InputLayer" ...

- 참고 smecsm.tistory.com/180

필자는 Tensorflow 2.3 버전이 Release 되기 전에 학습되어 공개된 사전학습 모델들을 사용하거나 새로 학습을 시킨 모델을 load하려는 상황에서 Value Error: Unknown Layer: Functional 에러를 자주 보았는데, 이것을 해결하기 위해 상당히 많은 시행착오를 겪었다.

자세히 보기

소켓과 select를 이용한 멀티플렉싱 서버 구축하기

1. 소켓 이해하기

전화를 걸기 위해서는 ‘단연코’ 전화기가 필요하다. 전화기는 멀리 떨어져 있는 두 사람이 대화할 수 있도록 만들어주는 매개체이다. 소켓은 전화기처럼 멀리 떨어져 있는 두 개의 호스트(host)를 연결해주는 매개체 역할을 한다.

1
2
3
4
#include <sys/types.h>
#include <sys/socket.h>

int socket(int domain, int type, int protocol);

우리는 누군가에게 걸려오는 전화를 받게 된다. 그리고 전화를 받으면 ‘여보세요’라는 응답을 주게 된다. 그렇다면, 전화기(소켓)을 만든 이후에 무엇이 더 필요할까? 당연히 전화번호가 필요하다. 그래야 누가 나한테 전화를 할 수 있기 때문이다. 그렇다면, 전화번호를 우리의 전화기에 할당시켜야 하는 것처럼, 소켓에도 일종의 ‘전화번호’가 필요하다. 소켓에서 전화번호의 역할을 하는 것은 바로 IP 주소이며, bind 함수를 이용하여 소켓에 주소를 할당할 수 있다.

1
2
3
#include <sys/socket.h>

int bind(int sockfd, struct sockaddr *myaddr, int addrlen);

이제 전화를 받을 준비가 끝났다. 하지만, 전화가 케이블에 연결되어 있지 않으면 소용이 없다. 즉, 전화선을 연결시키고 전화를 받을 상태를 만들어주어야 한다. 마찬가지로 소켓도 연결 가능한 상태가 되도록 대기를 시켜주어야 하는데, listen 함수를 이용하여 연결 요청이 가능하도록 만들어줄 수 있다.

1
2
3
#include <sys/socket.h>

int listen(int sockfd, int backlog);

자, 이제 전화벨이 울린다. 통화를 하기 위해서는 통화버튼을 눌러야 한다. 즉 누군가 대화를 요청했을 때 이것을 수락해야 한다는 뜻인데 소켓 역시 누군가가 데이터를 주고받기 위해 대화(연결)를 요청했을 때 그 요청을 수락할 수 있어야 한다. 이것을 accept 함수가 수행하게 된다.

1
2
3
#include <sys/socket.h>

int accept(int sockfd, struct sockaddr *addr, int *addrlen);
자세히 보기