귀납적 학습(Inductive Learning) 예제(C++)

|

귀납적 학습(Inductive Learning)은 구체적인 데이터 값들을 기반으로 특정 규칙이나 지식을 학습하는 것을 말합니다.

간단한 예제를 살펴보도록 하겠습니다. 다음과 같은 데이터가 있다고 가정합시다.

A B C D E F G H I J Value
1 0 0 0 0 0 1 0 0 1 1
0 1 0 1 0 1 1 1 0 1 1
0 1 0 0 0 1 1 0 1 0 0
1 0 0 1 1 0 1 0 0 1 1
1 0 0 1 1 0 1 1 1 1 1

A부터 J까지의 값의 패턴에 따라 Value 값이 결정이 된다고 할 때, 과거 기록들을 학습하면 향후 A부터 J까지의 값이 주어지면 Value 값을 추측할 수 있습니다.

다음 코드는 Value 값을 예측할 수 있는 A부터 J까지의 값들의 패턴을 추출하는 예제입니다.

C++ 예제 코드

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

static const int DATA_COUNT = 30;
static const int COMPANY_COUNT = 10;

// File에서 데이터를 읽어들임
void loadData(int data[DATA_COUNT][COMPANY_COUNT], int value[DATA_COUNT]) {
  freopen("data.txt", "r", stdin);
  setbuf(stdout, NULL);

  for (int i = 0; i < DATA_COUNT; i++) {
    for (int j = 0; j < COMPANY_COUNT; j++) {
      scanf("%d", &data[i][j]);
    }
    scanf("%d", &value[i]);
  }
}

// 초기 AnswerSheet는 랜덤값으로 설정
void createRandomAnswerSheet(int answer[COMPANY_COUNT]) {
  for (int i = 0; i < COMPANY_COUNT; i++) {
    answer[i] = (rand() % 3);
  }
}

// 점수 계산
int getScore(int data[DATA_COUNT][COMPANY_COUNT], int value[DATA_COUNT], int answer[COMPANY_COUNT]) {
  int score = 0;

  for (int i = 0; i < DATA_COUNT; i++) {
    int point = 0;

    for (int j = 0; j < COMPANY_COUNT; j++) {
      if (answer[j] == 2) {
        point++;
      } else if (answer[j] == data[i][j]) {
        point++;
      }

      if ((point == COMPANY_COUNT) && (value[i] == 1)) {
        score++;
      } else if ((point != COMPANY_COUNT) && (value[i] == 0)) {
        score++;
      }
    }
  }

  return score;
}

int main() {
  srand(time(NULL));

  int score;
  int data[DATA_COUNT][COMPANY_COUNT];
  int value[DATA_COUNT];
  int answer[COMPANY_COUNT];

  int bestScore = 0;
  int bestAnswer[COMPANY_COUNT];

  loadData(data, value);

  for (int i = 0; i < 100000; i++) {

    createRandomAnswerSheet(answer);

    score = getScore(data, value, answer);

    if (score > bestScore) {
      for (int j = 0; j < COMPANY_COUNT; j++) {
        bestAnswer[j] = answer[j];
      }
      bestScore = score;

      for (int j = 0; j < COMPANY_COUNT; j++) {
        printf("%1d ", bestAnswer[j]);
      }
      printf(" --> score: %d\n", bestScore);
    }
  }

  printf("\n\n");
  for (int j = 0; j < COMPANY_COUNT; j++) {
    printf("%1d ", bestAnswer[j]);
  }
  printf(" --> score: %d\n", bestScore);

  return 0;
}
</pre>

코드를 간략하게 설명하면, 

1. 무작위로 랜덤 패턴을 생성(createRandomAnswerSheet)  
이 때 패턴은 숫자 0, 1, 2를 사용(2는 와일드 카드)
2. 생성된 랜덤 패턴과 과거 데이터 기록과 유사성 비교  
유사성이 있으면 score + 1  
3. 가장 높은 score를 획득한 AnswerSheet 추출

과 같습니다.

과거 데이터 기록의 패턴은 0 또는 1의 값을 가지지만 항상 일정한 규칙을 갖고 있는 것은 아니기 때문에 와일드카드(Wildcard)인 2라는 값을 사용합니다.

랜덤 패턴과 과거 데이터 기록 유사성은 A부터 J까지 각 값들을 비교해서 유사성이 있으면 `point` 변수를 1 씩 증가시킵니다.

그리고 해당 패턴과 일치하면서 `Value` 값이 `1`이 되거나, 해당 패턴과 일치하지 않으면서 `Value` 값이 `0`이 되는 경우에 `score` 값을 1 증가시켜줍니다.

리눅스의 디렉토리 구분

|

리눅스의 디렉토리 구분

디렉토리 설명
/bin 리눅스의 기본 유틸리티들이 위치함
/sbin 리눅스의 시스템 유틸리티들이 위치함
/dev 시스템에 연결되어 있는 디바이스 파일들이 위치하는 디렉토리
/lib 공유 라이브러리(Shared Library)들이 위치함
/boot 시스템 부팅과 관련된 파일들(ex. 리눅스 커널 이미지 등)
/home 일반 사용자의 홈 디렉토리
/root 슈퍼 유저(root)를 위한 디렉토리. 일반 사용자들은 접근 못 함
/etc 시스템 설정과 관련된 파일들이 위치함
/proc 프로세스와 커널의 상태를 제공하는 가상 파일 시스템
/usr 서드 파티 유틸리티나 프로그래밍과 관련된 파일들이 위치함
/usr/include 프로그래밍과 관련된 헤더 파일이 위치함
/usr/lib 프로그래밍과 관련된 정적/공유 라이브러리들이 위치함
/usr/bin, /usr/sbin 서드 파티나 확장 유틸리티를 위한 디렉토리
/usr/local 시스템 관리자가 시스템을 위해 설치하는 유틸리티나 헤더 파일, 라이브러리 등이 위치함
/usr/share 시스템에서 사용하는 공유 파일들을 위한 디렉토리
/var 가변적으로 변하는 log나 메일 등의 파일이 위치함
/mnt 시스템에 마운트되는 장치들을 위한 디렉토리
/opt 기본적으로 설치된 프로그램들을 제외한 나머지 프로그램들 및 애드온 패키지를 위한 디렉토리
/selinux SELinux(Security Enhanced) 파일 시스템으로 보다 향상된 보안을 위한 파일 시스템이 존재

socketpair 예제

|

socketpair

주로 프로세스간 통신을 위해 소켓을 생성할 때 사용하는 방법 중 하나입니다. socketpair() 함수는 주소를 갖지 않는 한 쌍의 소켓을 생성해줍니다. 이 소켓들을 이용해서 부모 프로세스와 자식 프로세스간 통신을 수행할 수 있습니다.


예제 코드

예제 코드는 다음과 같습니다.

#include <cstdio>
#include <unistd.h>
#include <sys/socket.h>
#include <cstring>
#include <sys/wait.h>

int main(int argc, char **argv) {
  int ret, socket_fd[2];
  char buffer[] = "hello. snowdeer.";
  char line[BUFSIZ];

  ret = socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fd);
  if (ret == -1) {
    perror("socketpair error!!");
    return -1;
  }

  printf("socket 1 : %d\n", socket_fd[0]);
  printf("socket 2 : %d\n", socket_fd[1]);

  pid_t pid;
  int status;
  if ((pid = fork()) < 0) {
    perror("fork error!!");
  } else if (pid == 0) {
    write(socket_fd[0], buffer, strlen(buffer) + 1);
    printf("Data send : %s\n", buffer);

    close(socket_fd[0]);
  } else {
    wait(&status);

    read(socket_fd[1], line, BUFSIZ);
    printf("Data received : %s\n", line);

    close(socket_fd[1]);
  }

  return 0;
}

ps 명령어 옵션

|

ps 명령어의 옵션

옵션 설명
u 프로세스 사용자 이름과 시작 시간을 출력
f 프로세스 정보를 한 줄로 자세히 출력
l 프로세스 정보를 한 줄로 좀 더 길고 자세하게 출력
e 환경에 대한 정보도 출력
a 다른 사용자들의 프로세스들도 모두 표시
x 로그인 상태에서 아직 완료되지 않은 프로세스들을 표시
r 현재 실행 중인 프로세스들을 표시
j 작업 중심 형태로 출력

UNIX에서의 시간

|

UNIX 시간

UNIX 시간은 UTC 1970년 1월 1일 00:00:00 이후부터 현재까지 흐른 시간을 초(seconds)로 환산한 값입니다. 지역 시간 기반이 아닌 영국의 그리니치 천문대를 기준으로 한 UTC 시간입니다.


UNIX 시간 가져오기

시스템의 시간을 가져오기 위해서는 time() 함수를 이용합니다. 현재 날짜와 시간을 정수로 리턴합니다. time() 함수를 사용하기 위해서는 time.h 파일을 include 해야 합니다.

time_t time(time_t *timep);

time() 함수 외에도 BSD(Berkeley Software Distribution) UNIX에서 제공하는 시간 관련 함수들이 있습니다. gettimeofday() 함수를 이용해서 시간을 가져올 수 있습니다. (settimeofday() 함수를 이용해 시간을 설정할 수도 있습니다.) gettimeofday() 함수를 사용하기 위해서는 sys/time.h 파일을 include 해야 합니다.

int gettimeofday(struct timeval *tv, struct timezone *tz);
int settimeofday(const struct timeval *tv, const struct timezone *tz);


timeval 구조체

timeval 구조체는 다음과 같은 구조로 되어 있습니다.

struct timeval {
  time_t tv_sec;        // 초
  useconds_t tv_usec;   // 마이크로 초
}

POSIX에서는 gettimeofday() 함수와 비슷한 역할을 하는 clock_gettime() 함수를 제공합니다.

int clock_getres(clockid_t clk_id, struct timespec *res);
int clock_gettime(clockid_t clk_id, struct timespec *tp);
int clock_settime(clockid_t clk_id, const struct timespec *tp);

첫 번째 인자인 clockid_t는 시계의 종류를 의미합니다. POSIX 표준에서는 CLOCK_REALTIME(시스템 전역의 시간), CLOCK_MONOTONIC(부팅 시간 등의 소요 시간)의 두 가지를 제공합니다. 비표준으로 CLOCK_MONOTONIC_RAW, CLOCK_PROCESS_CPUTIME_ID(프로세스 단위의 CPU 사용 시간), CLOCK_THREAD_CPUTIME_ID(Thread 단위의 CPU 사용 시간) 등의 값을 사용할 수도 있습니다.

clock_gettime() 함수는 time() 함수나 gettimeofday() 함수에 비해 Thread에 더 안전합니다.