728x90
반응형

spring

0. 서론

회사에서 프로젝트를 진행하면서 최근에 코드 합칠 일이 많았다.
프로젝트 초기에는 형상관리를 위한 SVN 저장소가 없는 상태였고, 자동 빌드배포를 위한 CM서버도 구축되어 있지 않았기 때문에
각자 맡은 모듈을 각자의 프로젝트로서 생성하여 구현하였다.
그 후, SVN 저장소가 생성되고 CM서버 구축도 막바지였기 때문에 각자 작성한 코드를 합쳐서 하나의 프로젝트로 SVN에 올려야 했다.

코드 합치는 과정은 순탄치가 않았다.
서비스 백엔드 서버에 필요한 로그인-인증 코드, 연동 서버에 필요한 SOAP연동-배치 코드로 총 두 번의 합치는 과정이 있었다.
합치는 두 번의 과정에서 공통적으로 bean생성 오류가 있었고, bean생성 순서가 꼬였던 것이 원인이었다.

한 번은 main에서의 어노테이션 한 개를 지워서 해결했고(어떤 어노테이션인지는 회사pc로 확인 후 작성할 에정),
다른 한 번은 @Configuration어노테이션이 선언된 config 파일의 위치를 바꿔서 해결하였다. => 프로젝트(디렉토리) 구조에 따라 bean생성 순서가 달라진다.

두 번의 삽질을 경험하니... Bean이란 놈이 어떻게 생성되는지가 궁금해진다.

1. Bean 이란?

Bean이란?
Spring의 IoC(제어의 역전)특성을 활용하는 Spring Container에 의해 관리되는 Java 객체.
개발자가 작성한 new연산자에 의해 생성되는 것이 아닌, Application이 실행될 때 ApplicationContext에 의해 생성되고 관리되는 객체이다.

IoCDI에 대한 개념은 👉여기에서 확인

Life Cycle

BeanSpring Container에 의해 생성되고 관리되기 때문에 Java객체인 Bean의 생명주기(Life Cycle)도
객체생성 -> 의존설정 -> 초기화 -> 사용 -> 소멸
형태로 Spring Container에 의해 관리된다.

Bean 사용 이유

Bean은 위와 같은 Life Cycle로 Spring Container에 의해 관리된다.
그래서 해당 application으로 요청이 올 때마다 객체를 생성하는 것이 아닌,
Spring Container에 의해 초기화 과정에서 생성된 Bean객체를 활용하기 때문에 성능상 이점이 있다.

또한, 의존성 관리와 java 객체의 life cycle관리에도 용이하게 때문에 Bean을 활용한다.

Bean의 생성

Bean은 다음과 같이 두 가지 방법으로 생성될 수 있다.

  1. @Component어노테이션을 활용한 자동등록 방식
  2. @Configuration + @Bean어노테이션을 활용한 수동등록 방식

2. Bean 생성 방식

@Component 활용 자동 방식

Bean으로 등록하고자 하는 클래스에 @Component 어노테이션을 붙이는 방식이다.

@Component
public class testClass {

    public void testMethod() {
        ...
    }

}

위와 같이 클래스이름 상단에 @Component어노테이션을 붙이면 Bean으로 등록된다.
뿐만 아니라 @Component어노테이션을 활용하는 @Controller, @Service, @Repository어노테이션을 붙인 클래스도 Bean으로 등록된다.

@Comfiguration + @Bean 활용 수동 방식

아래 코드와 같이 @Configuration어노테이션을 붙여도 Bean으로 등록된다.
@Configuration어노테이션 역시 하위 어노테이션으로 @Component어노테이션이 있기 때문이다.

@Configuration
public class Config {

    @Bean
    public SimpleBean simpleBean() {
        return new SimpleBean();
    }

    @Bean
    public SimpleBeanConsumer simpleBeanConsumer() {
        return new SimpleBeanConsumer(simpleBean());
    }

}

@Configuration어노테이션을 붙이는 방식은 클래스 내부 메소드에 @Bean어노테이션을 붙이는 방식이 수반된다.

여기서 궁금증이 생길 것이다.

@Configuration + @Bean 수동 방식은 왜 활용하는 것인가?

클래스에 @Component어노테이션 하나만 붙여도 Bean으로 등록되어 Spring Container가 관리할 수 있도록 IoC(제어의 역전)형태가 만들어진다. 그런데 굳이 @Configuration어노테이션을 붙이고 내부 메소드에도 @Bean어노테이션을 붙여서 Bean으로 등록해야 할까?

@Component를 이용한 자동방식과 @Configuration + @Bean을 이용한 수동방식의 차이를 이해하면 궁금증이 해결될 것이다.
아래 예제를 보자.

=== 1 ===

@Component
public class Config {

    @Bean
    public SimpleBean simpleBean() {
        return new SimpleBean();
    }

    @Bean
    public SimpleBeanConsumer simpleBeanConsumer() {
        return new SimpleBeanConsumer(simpleBean());
    }

}

=== 2 ===

@Configuration
public class Config {

    @Bean
    public SimpleBean simpleBean() {
        return new SimpleBean();
    }

    @Bean
    public SimpleBeanConsumer simpleBeanConsumer() {
        return new SimpleBeanConsumer(simpleBean());
    }

}

1번 코드와 2번 코드는 클래스에 붙은 어노테이션을 제외하면 차이가 없다. 하지만 동작 상에는 큰 차이가 있다.

@Component가 붙은 1번 코드에서 simpleBeanConsumer메소드가 실행되면 의존관계에 있는 simpleBean메소드가 실행되어 새로운 SimpleBean객체가 생성된다.

하지만,
@Configuration이 붙은 2번 코드에서 simpleBeanConsumer메소드가 실행되면 의존관계에 있는 simpleBean메소드가 실행되는데, 새로운 SimpleBean객체가 생성되진 않고 Bean등록 과정에서 Spring Context에 등록된 SimpleBean Bean이 불러와진다.

1번 코드에서는 객체를 새로 생성하지만, 2번 코드에서는 기존에 생성된 객체를 불러온다는 큰 차이가 있다는 것이다.
2번 코드를 @Component어노테이션을 활용하여 아래 코드와 같이 재구성해보면 이해가 쉬울 것이다.

@Component
public class Config {

    @Autowired
    SimpleBean simpleBean;

    @Bean
    public SimpleBean simpleBean() {
        return new SimpleBean();
    }

    @Bean
    public SimpleBeanConsumer simpleBeanConsumer() {
        return new SimpleBeanConsumer(simpleBean);
    }

}

이러한 두 방식의 차이는 CGLIB(Code Generation Library)가 두 어노테이션에 동작하는 방식이 다르기 때문에 발생한다고 한다.
@Configuration어노테이션 내부에서 호출된 메소드가 @Bean어노테이션이 붙은 메소드라면 Spring Context에 등록된 Bean을 반환하도록 되어있다고 한다. (자세한건 CGLIB에 대해 알아보면서 파악하면 될 것 같다.)

중간 정리

@Component를 활용한 자동방식과 @Configuration + @Bean을 활용한 수동방식의 차이는 Spring Context에 등록된 Bean을 반환하냐 안하냐의 차이이다. 이러한 차이가 발생한 이유는 두 어노테이션에 CGLIB가 작동하는 방식이 다르기 때문이다.

이러한 특징때문에 자동방식은 보통 비즈니스 로직을 구현할 때 활용된다.
그리고 수동방식은 config class와 같은 기술 지원 로직에 활용된다. 해당 방식은 context 내부에 등록된 Bean을 적극 활용하기 때문에 application 전반에 영향을 미쳐야 하는 기술지원 로직에 적합하기 때문이다.

3. Bean 생성 과정

Bean은 자동/수동방식 공통적으로 @ComponentScan어노테이션에 의해 등록된다.
그리고 @ComponentScan어노테이션은 @SpringBootApplication어노테이션의 하위 어노테이션이기 때문에 일반적으로 루트 클래스에서 동작하게 된다.

@ComponentScan어노테이션은 지정된 클래스부터 @Component어노테이션이 붙은 하위 클래스를 스캔하기 시작한다.
@Configuration, @Controller, @Service, @Repository 어노테이션도 역시 포함이다.
그리고 스캔된 클래스들은 위 Bean의 Life Cycle 섹션에서 언급했던 것처럼 객체생성 -> 의존설정 -> 초기화 과정을 거쳐 Bean으로 등록된다.

마무리

사실 고백하자면... 일주일이 넘도록 이 글 하나만 썼다. Bean에 대해 파도파도 끝이 없어서 어디서부터 어떻게 써야할지 고민을 많이 했다.
결국 타협해서 Bean 개념에 대해 간단히 짚고 생성방식과 과정에 대해서만 작성했다.

관련하여 다룰 개념들이 아직도 많은데, 추후에는 프록시패턴, 데코레이터패턴 등과 같은 디자인 패턴들을 심도있게 다뤄볼까 한다.
또한, 위에서 언급했던 CGLIB에 대해 다뤄봐도 좋을 것 같고,
시간이 좀 더 지나면 코드를 보면서 Spring Context의 구조와 동작 방식도 파악해보면 좋을 것 같다.

반응형
728x90
반응형

Spring

0. 서론

새로 참여하게된 비대면 고객케어 솔루션 프로젝트에서 로그인 연동 개발을 맡게 되었고, 다른 팀원분이 작성한 인증 관련 코드를 합쳐야 했다.


해당 인증관련 코드에는 Spring Security 프레임워크가 활용되었고, 적절하게 잘 합치기 위해서는 해당 코드에 대한 이해가 수반되어야 했다.
이를 위해 Spring Security에 대해 알아보았다.

1. 사전 학습

A. Spring Security란?

Spring Security는 Spring기반 애플리케이션의 보안을 담당하는 Spring 하위 프레임워크 중 하나로서, 해당 프레임워크를 활용하여 인증인가에 대한 처리를 진행하게 된다.

B. 인증과 인가

  • 인증(Authentication) : 접근을 요청한 사용자와 입력한 사용자정보가 일치하는지 확인하는 절차. 여기서 사용자는 접근주체, 사용자정보는 접근 시 입력했던 ID/PW와 같은 정보를 가리킨다.
  • 인가(Authorization) : 접근 사용자의 권한으로 요청 자원에 접근할 수 있는지 확인하는 절차. 예를들어 '/config' 라는 path로 사용자가 접근했을 때, Spring Security가 해당 path로의 권한이 사용자에게 있는지 확인한 후, 없다고 판단이 되면 접근을 통제하게 된다.

C. 인증 처리 flow

상황을 가정해보자.

국민 플랫폼인 naver가 Spring Security 프레임워크를 활용하여 인증과 인가처리를 한다고 가정해보자.

사용자 A는 naver에 가입되어 있지 않고, 사용자 B는 naver에 가입되어 있다.
이때, 두 사용자가 naver를 활용하기 위해 로그인이라는 행위를 통해 인증을 시도한다면,
가입되어 있지 않은 사용자 A는 인증처리가 되지 않을 것이고,
가입되어 있는 사용자 B는 인증처리에 성공하여 naver를 활용할 수 있게 될 것이다.

naver는 Spring Security를 통해 자체 인증 로직을 구성했을 것이다.
그리고 해당 인증 로직은 일반적으로 로그인을 시도한 사용자의 정보가 자체 DB에 있는지 확인하는 절차일 것이다.

사용자 B의 정보는 가입되어 있는 사용자이기 때문에 자체 DB에 해당 정보가 저장되어 있을 것이고,
사용자 A의 정보는 가입되어 있지 않은 사용자이기 때문에 자체 DB에 해당 정보가 저장되어 있지 않을 것이다.
그렇기 때문에, 자체 DB를 확인하는 절차를 통해 인증을 수행하는 naver에 사용자 A가 로그인을 시도할 경우, 인증처리가 되지 않는 것이다.

이러한 상황을 Spring Security에 적용해보자.(다음 글에서...)

D. Dispatcher-Servlet과 Filter

일반적으로 Spring Framework는 아래 사진과 같은 flow를 통해 Http 요청이 처리된다.

dispatchef-servlet filter

Security의 동작원리를 이해하기 위해 짚고 넘어가자.

위 사진에서 참고할 주요 키워드는 Web Context, Spring Context, Filter, Dispatcher Servlet이다.

  1. Web Context : Servlet Context라고도 불린다. Tomcat과 같은 Servlet Container에 의해 실행된다.
    a. Servlet : 웹 프로그래밍을 위한 Java 기술이다. HTTP요청/응답 처리, 동적 웹사이트 처리 등의 작업을 수행한다. 그리고 이러한 Servlet이 객체형태로 구현된 것을 Servlet Context라고 한다.

  2. Spring Context : Spring MVC를 처리하는 Java 객체이다. Spring Container에 의해 실행된다. Spring Context의 proxy역할을 하는 Dispatcher ServletServlet Context에 의해 관리되기 때문에, 위 사진과 같은 구조로 구성되어 있다고 한다.

  3. Dispatcher Servlet : 위에서 언급한 것처럼 Spring Context의 proxy 역할을 하는 Java 객체이다. Servlet Context를 통해 들어온 HTTP요청을 분석하여 Spring Context내부의 어떤 Controller를 호출할 지 결정하고, 호출된 Controller 내부 비즈니스 로직에 의해 반환된 응답 객체를 HTTP응답으로서 client에 반환하거나 매핑된 view에 연결시켜준다.

  4. Filter : Dispatcher Servlet에 HTTP요청이 전달되기 전후에 http url path에 맞게 실행되는 기능이다. Servlet Context가 실행되는 Servlet Container에 의해 실행되고, Spring Context내부의 Spring Bean을 주입받아 처리될 수도 있다.

위 사진에 대한 설명을 최대한 간략하게 적어봤는데, 사실 이렇게 간단하게 언급할 수 있는 내용은 아니었다. 추후에 별도로 자세히 알아봐야겠다.

이어서

Spring Security를 알아보기 위해 사전에 알고 있어야할 개념들이 너무나 방대했고 파악하는 데 시간이 오래걸렸다. 하지만 위 개념들을 먼저 알고있어야 Security에 대한 이해가 쉬울 것 같아서 먼저 언급하였다.

위에서 언급한 개념들은 Spring Security와 밀접한 관련이 있다. 우리가 Java 소스코드로 구현한 비즈니스 로직은 일반적으로 Spring Context로 구현되어 실행될 것이다. 그리고 Security에서 제공하는 인증인가기능은 Spring Context가 아닌 Servlet ContextFilter단에서 실행될 것이다.

다음 글부터는 본격적으로 Spring Security에 대해 알아볼 것이다.

반응형
728x90
반응형

spring

Spring Framework의 특징 세 가지중 하나인 AOP를 알아볼 것이다.

Spring삼각형

1. AOP

: 관점지향프로그래밍(Aspect Oriented Programming)이다. 쉽게 말해서 관점을 나눠서 프로그래밍 하겠다는 건데, 특정 로직을 비즈니스적인 관점과 부가적인 관점으로 나눠서 나눈 관점 기준으로 모듈화하여 프로그래밍하는 것이다.

AOP

예를 들면, 비즈니스적인 관점이라 하면 말그대로 우리가 구현하고자 하는 서비스의 핵심적인 로직부분을 가리키는 관점이고, 부가적인 관점은 해당 로직이 없어도 비즈니스에 아무런 영향이 없는 부분을 가리키는 DB연결로직이나 로깅 등을 가리키는 관점이다.

그리고 각 로직마다 반복되는 부분을 흩어진 관심사(Crosscutting Concerns)라고 하는데, AOP에서는 이러한 부분을 위에서 언급한 관점지향적으로 모듈화하여 프로그래밍할 것이다.

2. AOP의 사례

AOP의 대표적인 2가지 사례를 알아볼 것이다.

A. logging

: 로깅(logging) 기능은 로직마다 반복적이고 공통적으로 활용되는 대표적인 부가기능 중 하나이다. 이러한 로깅기능을 AOP를 활용하여 프로그래밍 한다면 아래와 같이 코딩할 수 있다.

  • ParameterAop.java
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect
@Component
public class ParameterAop {

    @Pointcut("execution(* com.example.aop.controller..*.*(..))")
    private void cut(){}

    @Before("cut()")
    public void before(JoinPoint joinPoint){
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        System.out.println(method.getName());
        Object[] args = joinPoint.getArgs();
        for(Object obj : args){
            System.out.println("type : "+obj.getClass().getSimpleName());
            System.out.println("value : "+obj);
        }
    }

    @AfterReturning(value = "cut()", returning = "returnObj")
    public void afterReturn(JoinPoint joinPoint, Object returnObj){
        System.out.println("return obj");
        System.out.println(returnObj);
    }
}
  • RestApiController.java
import com.example.aop.annotation.Decode;
import com.example.aop.annotation.Timer;
import com.example.aop.dto.User;
import org.springframework.util.StopWatch;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api")
public class RestApiController {

    @GetMapping("/get/{id}")
    public String get(@PathVariable Long id, @RequestParam String name){
        // TODO

        return id+ " "+ name;
    }

    @PostMapping("/post")
    public User post(@RequestBody User user){


        return user;
    }

}

ParameterAop.java파일에서 AOP로 모듈화할 클래스를 정의하였다.
AOP로 모듈화하기 위해서는 클래스명에 @Aspect어노테이션을 명시해주어야 한다.
@PointCut어노테이션은 모듈화된 클래스가 적용될 클래스의 경로를 지정해준다.
지정된 경로의 클래스의 메소드가 실행될 때마다 AOP로 정의된 클래스의 메소드가 실행될 것이다.
위의 코드에서 cut()메소드는 @PointCut으로 적용된 클래스의 메소드인 RestApiController.get()RestApiController.post()를 가리키게 된다.

@Before어노테이션은 지정된 메소드가 실행되기 바로 이전에 실행될 메소드에 명시된다. 해당 어노테이션에 지정된 메소드는 cut()메소드이다.
위 코드에서 before()메소드의 파라미터로 받는 JoinPointcut()메소드에서 정보를 가져올 때 활용되는 객체이다.
위 코드에서 JoinPoint객체는 HTTP 메소드와 cut()메소드에서 활용된 파라미터 값을 가져오기 위해서 활용되고 있다.

@AfterReturning어노테이션은 @Before어노테이션과 반대로 지정된 메소드가 실행된 후 바로 실행될 메소드에 명시된다. 해당 어노테이션에 지정된 메소드 역시 cut()메소드이다.
그리고 @AfterReturning어노테이션에서 returning값을 지정해주면 cut()메소드에서 반환된 값이 returning값으로 지정된 변수에 입력되어 활용할 수 있다. 위 코드에서는 returnObj변수에 활용되고 있다.

위 사례의 코드와 같이 프로그래밍을 한다면, 특정 비즈니스 로직이 실행되기 전후에 로깅기능을 모듈화하여 사용할 수 있다.

B. Timer

: 타이머(Timer)기능은 특정 로직의 실행시간을 확인시켜주는 기능이다. 이 또한 비즈니스로직과 관련이 없는 기능이기 때문에 아래와 같이 AOP로 모듈화할 수 있다.

  • TimerAop.java
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

@Aspect
@Component
public class TimerAop {

    @Pointcut("execution(* com.example.aop.controller..*.*(..))")
    private void cut(){}

    @Pointcut("@annotation(com.example.aop.annotation.Timer)")
    private void enableTimer(){}

    @Around("cut() && enableTimer()")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        Object result = joinPoint.proceed();

        stopWatch.stop();
        System.out.println("total time : "+stopWatch.getTotalTimeSeconds());
    }
}
  • Timer.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Timer {
}
  • RestApiController.java
import com.example.aop.annotation.Decode;
import com.example.aop.annotation.Timer;
import com.example.aop.dto.User;
import org.springframework.util.StopWatch;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api")
public class RestApiController {

    @Timer
    @DeleteMapping("/delete")
    public void delete() throws InterruptedException {

        // db logic
        Thread.sleep(1000 * 2);

    }

}

Timer 기능도 역시 로깅 기능을 구현할 때와 마찬가지로 AOP를 활용하여 모듈화시켰고 코드상의 차이도 크게 없다.
하지만 두 가지정도 차이나는 부분이 있는데, 해당부분만 언급해보겠다.

첫 번째 차이는 로깅 기능을 구현할 때에는 경로 지정방식으로 @PointCut어노테이션에 해당 기능이 활용될 클래스의 경로를 지정하였는데,
Timer 기능을 구현할 때에는 @PointCut어노테이션에 특정 어노테이션을 지정하여, 지정된 어노테이션이 붙은 클래스나 메소드가 실행될 때에만 Timer기능이 실행될 수 있도록 하였다.
이를 위해 Timer라는 별도의 인터페이스를 Timer.java와 같이 작성하였다.
여기서 @Target어노테이션은 임의로 선언된 어노테이션인 @Timer어노테이션이 붙을 수 있는 타입을 지정하는 어노테이션이다.
위 코드에서는 메소드와 클래스에 붙을 수 있도록 지정하였다.
그리고 @Retention어노테이션은 임의로 선언된 어노테이션인 @Timer어노테이션의 생명주기(Life Cycle)을 지정하는 어노테이션이다.
위 코드에서는 런타임으로 생명주기를 지정하였고, 실행될 동안에는 계속 유효한 어노테이션으로 사실상 안죽는 어노테이션이라는 말이다.

두 번째 차이는 로깅 기능을 구현할 때에는 @Before어노테이션과 @AfterReturning어노테이션을 활용하여 실행시점과 동작을 정의하였는데,
타이머 기능을 구현할 때에는 @Around어노테이션을 활용하여 비즈니스로직의 전후를 하나의 메소드에서 정의할 수 있도록 하였다.
이를 활용한 이유는 타이머 기능같은 경우는 시간데이터를 비즈니스로직이 실행되기 전후에 공유되어야 하는데, before/after로 메소드가 나뉘어 실행될 경우 시간데이터가 공유될 수 없기 때문이다.
@Around어노테이션도 마찬가지로 타겟 메소드를 지정하여 특정 로직이 실행될 때마다 실행될 수 있도록 설정할 수 있다.
그리고 before/after 어노테이션을 활용할 때와 다른점은 비즈니스 로직을 감싸는 형태로 메소드가 실행된다는 점이다.
TimerAop.javaaround()메소드를 보면, joinPoint.proceed()로 비즈니스 로직이 실행되는 부분이 있고,
전후로 stopWatch.start()stopWatch.stop()이 실행시켜서 전후에 어떤 메소드가 실행될지 프로그래밍 하였다.
그리고 stopWatch객체를 활용하여 비즈니스 로직의 시작시간과 끝나는시간을 기록하였고, stopWatch.getTotalTimeSeconds()메소드를 통해 기록된 시간의 차이를 알 수 있다.

마무리

: 위 두 사례에서 본 것과 같이 AOP는 비즈니스 관점과 부가적인 관점을 나누어 비즈니스 로직과 부가적인 로직을 분리시켜주는 프로그래밍 방식이다.
@Aspect가 명시된 클래스에서 부가 기능들이 비즈니스 로직의 어떤 시점에 실행되고 어떤 방식으로 실행되는지, 어떤 타겟에서 실행되는지 설정할 수 있고, 이를통해 부가 기능을 철처하게 모듈화시킬 수 있다.

이어서

기존 계획은 AOP를 알아본 이후에 PSA도 함께 알아보려 했으나, DB와 같이 보는 것이 좋을 것 같아서 후순위로 조금 미루려한다.
대신 이어서 SOAP를 알아보려 한다. 요즘은 REST연동 방식이 대세라곤 하지만, 레거시한 시스템에서는 아직 많이 활용되는 방식이라 알아두면 좋을 것 같고, 실제로 나는 로그인 연동기능을 구현할 때, SOAP때문에 많이 애먹었어서 해당 부분을 까먹기전에 다뤄보려한다.

다음은 SOAP을 알아보자!

반응형
728x90
반응형

1. Regression 이란?

: 학습데이터를 기반으로 넓은 범위의 데이터 중 하나를 추정하는 방식이다. 머신러닝의 Supervised-learning 유형 중 하나이다.

위 예시는 Predicting exam score 문제이고 Regression의 대표적인 예시이다.
그리고 테이블의 데이터는 학습데이터이고, 그 중 y컬럼의 데이터는 x컬럼 데이터에 대한 추정치로 출력되는 label데이터이다.

2. Linear Regression

: 입력데이터에 따라 출력데이터가 선형적으로 출력되는 Regression

null

공부한시간에 비례하여 시험성적이 높게 나오는 Predicting exam score 예시처럼
인풋값에 따라 어느정도 규칙성을 가지고 선형적으로 변하는 학습데이터 training-sets을 갖는다.
그리고 training-sets를 인풋값 x, 출력값 y로 설정하여 Hypothesis를 사진 속 H(x)와 같이 추정할 수 있다.

인풋값에 따라 출력값을 최대한 유사하게 추정하려면, 주어진 training-sets에 따른 정확한 Hypothesis가 정해져야 한다.

3. Cost function

null

cost functiontraining-setsHypothesis의 유사도를 측정하기 위해 활용되는 함수이다.
(H(x) : Hypothesis에 대한 출력값, y : 실제 출력값)
해당 함수를 통해 주어진 training-sets에 대한 정확한 Hypothesis를 구할 수 있다.

계산 방법은 위 사진처럼 임의의 Hypothesis를 정해놓고, 각 training-sets과의 차이를 계산하면 된다.
그리고 계산된 차이가 가장 적은 Hypothesis가 최적의 Hypothesis가 되는 원리이다.

이 때, 각 training-sets에 대해 계산된 차이는 음수가 되면 안된다.
이를 방지하기 위해 각 training-sets에 대해 계산된 차이를 제곱하여 차곡차곡 더한다.

null

위 사진은 임의의 Hypothesis에 대한 cost를 구하기 위한 수식을 나타낸다.
그리고 training-sets 데이터이 갯수가 3개라고 가정하였다.
각 데이터에 대해 계산된 차이를 제곱하고 더하여 데이터의 갯수인 3만큼 나누면 cost가 구해진다.

null

결론적으로 cost function은 위 사진의 수식처럼 W, b에 대한 수식처럼 나타낼 수 있다.
그리고 위 수식대로 계산된 cost값 중 최소 cost값을 찾는 과정이 Linear Regression에서의 학습이다.

이어서

TensorFlow에서의 Linear Regression구현에 대해 알아볼 것이다.
그리고 이전에 TensorFlow활용법에 대해 간단하게 살펴볼 것이다.

반응형

'개발 > AI' 카테고리의 다른 글

[AI] Softmax Regression  (0) 2023.10.01
[NLP] Embedding  (0) 2023.09.23
[AI] Logistic Regression  (0) 2023.09.10
[AI] Machine Learning (머신러닝) - 개념  (0) 2023.01.18
[AI] 서론  (2) 2023.01.18

+ Recent posts