웹에서 input 데이터를 API Gateway 로 보내려고 AJAX를 사용했다.

아래 코드는 웹에서 클릭 버튼을 눌렀을때, input 데이터들을 api 로 전달해주고 + output 데이터들을 받아오는 Funtion 이다

index.js

function clickclick(){
    let form = $("#ajax-upload-form");
    let formData = new FormData(form[0]);

    formData.append('inputdata_one', $("#inputdata_one").val());
    formData.append('inputdata_two', $("#inputdata_two").val());
	//formData 에 전달해줄 INPUT 데이터값들을 추가로 붙여준다. 

    this.result = []
    $.ajax({
    type: "POST",
    url: 'https://vvvvvv.execute-api.us-east-1.amazonaws.com/pp/predict',  //api gateway URL
    header: {
        "Content-Type": "application/json",	//Content-Type 설정
        "X-HTTP-Method-Override": "POST",
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Methods': 'POST',
        'Access-Control-Allow-Headers': '*',
        'Access-Control-Allow-Age': 3600
    },
    dataType: "json",
    data: formData,
    AccessControlAllowOrigin: '*',
    crossDomain: true,
    contentType: false,
    async: false,
    enctype: 'multipart/form-data',
    processData: false,

    success: function (data, status) { //람다에서 제대로 잘 돌아왔을때,
        let result = data['body'] //API 에서 건너온값 data 중 'body'부분만 솎아낸다
        result = result.replace("\"", ""); 
        result = result.split('&');  //result가 여러개라 &로 구분하였기 때문에 끊어줌
        
        console.log("data : ", data) //잘들어온건지 확인하고 싶어서
        console.log(result[0]) //잘나눠졌는지 확인하고 싶어서
    },
    error: function (e) {
        console.log("ERROR : ", e);
        $("#btnSubmit").prop("disabled", false);
        alert(e.message);
    }
    });
}

 

index.html 일부 (파일올리고 제출하는 부분)

                    <form method="POST" enctype="multipart/form-data" id="ajax-upload-form" name="upload-form">
                        <input type="file" name="upload-file" id="upload-file" onchange="loadFile(this)" required>
                        <input type="button" value="Submit" id='ajax-submit'>
                    </form>

 

이렇게 웹에서 input 데이터들을 api 를 통해서 람다에서 받아보면 아래처럼 data가 들어온다.

 

body = "------WebKitFormBoundaryWvqm9JrHYYK3TJSv\r\nContent-Disposition: form-data; name=\"upload-file\"; filename=\"sample.json\"\r\nContent-Type: application/json\r\n\r\n[{\"A\":1278.751,\"B\":7.168,\"C\":4025.032,\"D\":9.056,\"E\":56.962,\"F\":4646.806}]\r\n------WebKitFormBoundaryWvqm9JrHYYK3TJSv\r\nContent-Disposition: form-data; name=\"inputdata_one\"\r\n\r\nGGGGGGGG\r\n------WebKitFormBoundaryWvqm9JrHYYK3TJSv\r\nContent-Disposition: form-data; name=\"inputdata_two\"\r\n\r\n3333333\r\n------WebKitFormBoundaryWvqm9JrHYYK3TJSv--"

 

위는 data['body'] 부분이다.

인풋파일3개 (json 파일1개, 입력값2개) 가 잘 들어있는지 확인해보자면,

 

[{\"A\":1278.751,\"B\":7.168,\"C\":4025.032,\"D\":9.056,\"E\":56.962,\"F\":4646.806}] 이부분은 input 파일인 sample.json 안의 내용이다.

 

그외에 두가지 인풋이 더 있었는데 잘 살펴보면

inputdata_one : GGGGGGGG

inputdata_two : 3333333

로 들어가있음을 확인할수 있다.

 

해당 인풋파일 3개를 추출해내기 위해서 사용한 파싱방법

    json_feature = json.loads(body[body.find('['): body.rfind(']')+1]) 
    // json 파일안의 내용 뽑아내기
    
    body = body.replace('\n',"")
    body = body.replace('\r',"")
    body = body.replace('-',"")
	
    INPUTTWO = (body[body.find('inputdata_one')+14: body.rfind('WebKitFormBoundary')])
    body = (body[: body.rfind('WebKitFormBoundary')])
    INPUTONE = int(body[body.find('inputdata_one')+14: body.rfind('WebKitFormBoundary')])

 


1. EFS 사용

- 람다 저장소안에 패키지며 필요한 파일들 전부넣기보다 EFS를 활용하는 방법

- EFS안에 필요한 패키지들(파이썬,텐서플로우,넘피 등등) 세팅 + 필요한 파일들(트레이닝된 DL 모델) 등등 세팅해놓는다

- EFS 세팅은 EC2 인스턴스에서 EFS 마운트한다음에 해주면 된다 ( EC2 인스턴스 종료하고 다시켜면 또 마운트해서 연결해줘야한다. 인스턴스 종료안하고 계속 켜두면 계속 연결된 상태로 있다)

- 람다에서 프로비저닝해준다음 api 배포 해주면 끝

2.  ECR (Container) 사용

- 도커로 이미지를 만들어서 사용하는 방법이다.

- 필요한 패키지들은 requirements.txt에 지정,  필요한 파일들은 깃클론해서 복사(COPY로 옮겨준다) , app.py (람다에서 실행될 코드) 등등 세팅해준다음 이미지로 만들어준다

- ECR 에서 이미지로 만들고 배포

- 람다에서 새로 하나 만드는데 이미지로 만들기 선택하고, ECR 에서 배포한 이미지를 선택해주면 된다.

- EFS 에 비해 프로비저닝 비용이 들지 않는다

# python3.8 lambda base image
FROM public.ecr.aws/lambda/python:3.8

# copy requirements.txt to container
# 설치할 패키지들을 requirements.txt 에 기재
COPY requirements.txt ./   

# installing dependencies
RUN pip3 install --upgrade --ignore-installed pip setuptools
RUN pip3 install -r requirements.txt
RUN yum install git -y

# Copy function code to container
COPY feature_info.py ./   # host 에서 Container 로 file copy
COPY app.py ./            # host 에서 Container 로 file copy
RUN git clone https://github.com/ ~~~  # 사용할 파일들 불러오기

# setting the CMD to your handler file_name.function_name
CMD [ "app.lambda_handler" ]  # app.py 에서 handler 함수를 시작하도록 세팅

 

 

https://gallery.ecr.aws/

 

ECR Public Gallery

Amazon ECR Public Gallery is a website that allows anyone to browse and search for public container images, view developer-provided details, and see pull commands

gallery.ecr.aws

ㄴ람다 베이스 이미지는 여기서 불러와 서 사용할수 있다.

 

 

'<Cloud> > AWS' 카테고리의 다른 글

Lambda, API Gateway, AJAX 주거니 받거니  (0) 2021.08.31
서버리스 활용 1)EFS , 2)ECR  (0) 2021.08.31
Lambda Container 파일 접근 위치 + 파일 형식  (0) 2021.08.25
Lambda Container 연습  (0) 2021.08.25
EC2 user data 에 start.sh  (0) 2021.05.09

- 람다에서 기본적인 파일위치는 /tmp

- 작업 디렉토리 접근 경로 /var/task (Lambda Container 사용시)

작업 디렉터리(Working directory)에 함수에 대한 작업 디렉터리의 전체 경로를 입력합니다. 다음 예제에서는 Lambda의 AWS 기본 이미지에 대한 작업 디렉터리를 보여줍니다 (참조 https://docs.aws.amazon.com/ko_kr/lambda/latest/dg/lambda-dg.pdf )

COPY app.js package.json /var/task/

ㄴ DOCKERFILE 에서 다음과 같이 파일들을 /var/task 로 옮겨야한다.

model_dnn = tf.keras.models.load_model(f"/var/task/model_dnn")
# 람다에서 모델을 불러올땐 이런식으로 모델을 불러와야한다

추가 참조 : https://alestic.com/2014/11/aws-lambda-environment/

- trained 모델은 pb 형태로 저장하고 불러와야 에러가 안남 

'<Cloud> > AWS' 카테고리의 다른 글

서버리스 활용 1)EFS , 2)ECR  (0) 2021.08.31
Lambda Container Dockerfile 작성예시  (0) 2021.08.25
Lambda Container 연습  (0) 2021.08.25
EC2 user data 에 start.sh  (0) 2021.05.09
Flask + EC2 튜토리얼  (0) 2021.05.09

람다에서 이와같은 에러가 났을경우,  일반구성 -> 메모리 용량을 늘리면 해결된다.

  • 참조한 영상 (쉽고 괜찮다)

https://www.youtube.com/watch?v=23fE57EFRK4

https://github.com/srcecde/aws-tutorial-code/blob/master/lambda/container-image/app.py

 

: EC2(우분투) 세팅
sudo apt-get update    # sudo yum update 
sudo apt-get install docker-compose  #sudo yum install docker-compose
sudo apt install awscli -y

mkdir lambda-docker  //파일생성
// 그리고 여기에 깃허브에 올라와있는 파일 3개(app.py, requirements.txt, Dockerfile 업로드)
vim app.py
vim Dockerfile
vim requirements.txt
: EC2(centos version) 세팅
# centos버전

sudo yum update
# docker-compose 설치
sudo curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# docker-compose 실행 권한 부여
sudo chmod +x /usr/local/bin/docker-compose

# 설치된 docker-compose 실행 확인
docker-compose --version

sudo yum install docker
aws configure

# https://league-cat.tistory.com/347 도커 에러 참조

sudo yum install git -y
# git clone ~~~~~ 
sudo service docker start
sudo usermod -a -G docker ec2-user

 

: ECR 접속해서 리파지토리만들기

: 만든 리파지토리 눌러서 '푸시명령보기' 누르고 나오는 명령어 차례차례 터미널에 입력

** 추가적으로 맨앞에 sudo 꼭 붙여야 한다

** 중간에 에러두번나는데

  1. aws configure 로 해결

https://stackoverflow.com/questions/60583847/aws-ecr-saying-cannot-perform-an-interactive-login-from-a-non-tty-device-after

  1. sudo apt-get install gnupg2 pass로 해결 (우분투일떄만 해주면 됨

: 다 만들면 람다에서 컨테이너 이미지로 새로생성 가능

 

S3 버킷안에 있는거 복사해오기(EC2로)
aws s3 cp s3://ys-profet-package-model/profet_trained_model/ ./s3_file/  (에러)

https://stackoverflow.com/questions/45109533/aws-cli-s3-copying-file-locally-using-the-terminal-fatal-error-an-error-occu 참조

aws s3 cp s3://ys-profet/package_model_for_lambda_container/ ./s3_file --recursive

 

 

< 도커 용어정리 >

CMD ? ENTRYPOINT? → 컨테이너 실행시 동작 명령어 (전자) , 컨테이너 구동시 실행할 명령어 (후자)

ARG?

ARG 명령어 는 빌드 시 전달할 수 있는 변수를 정의합니다 . Dockerfile에 정의되면 이미지를 빌드하는 동안 --build-arg 플래그로 전달할 수 있습니다. Dockerfile에 여러 ARG 명령어가 있을 수 있습니다. ARG는 Dockerfile에서 FROM 명령어 앞에 올 수 있는 유일한 명령어입니다.2019. 9. 16.

https://github.com/heowc/programming-study/issues/90

alpine?

http://labs.brandi.co.kr/2021/01/20/hwangsg.html

초반에는 직접 빌드하여 올려두고 사용하였으나 현재는 각종 공식 업체에서 기본 이미지를 생성하여 제공하고 있고, Dockerfile에 alpine버전으로 가져와서 필요한 것만 빌드하여 저용량으로 이미지를 수월하게 만들 수 있게 되었습니다. 이렇게 생성된 이미지를 가지고 실행하면 컨테이너가 생성되고 해당 공간은 내부에 전혀 영향 없는 독립적인 별개의 공간으로 활용 할 수 있습니다. docker-compose를 이용하면 더 쉽게 여러 개의 컨테이너를 실행 할 수 있습니다.

https://jonnung.dev/docker/2020/04/08/optimizing-docker-images/ (좋음!)

  • RUN, ADD, COPY 이 3가지 단계만이 레이어로 저장되고, CMD, LABEL, ENV, EXPOSE 등과 같이 메타 정보를 다루는 부분은 임시 레이어로 생성되지만 저장되지 않아 도커 이미지 사이즈에 영향을 주지 않는다.
  • ..
  • 그래서 Alpine 리눅스 이미지를 사용한다면 모든 Python 패키지에서 C 코드를 컴파일 해야 하므로 도커 이미지를 빌드하는 시간이 상당히 많이 소모된다. → GCC 나온이유!!!!!!
  • 추가로 덧붙이자면 Alpine 리눅스 이미지를 베이스 이미지로 사용한 Python 이미지는 용량도 크고, 몇 가지 버그들에 대한 취약점도 갖고 있다고 한다.
도커관련해서 최적화하는 방법 !!!!!!
  • 이미지 레이어 개수를 줄이는 것이 좋다.(성능영향엔 별상관없긴한데 최적화 측면에서 도움됨+ 가독성,유지보수에좋음)
RUN apt-get update && apt-get install -y \
    gcc \
    git \
    locales
  • 애플리케이션 코드 복사 명령(COPY) 은 자주 변경되지 않는 명령문 다음에 오는 것이 이미지 빌드 시간을 단축하는 데 유리하다.
  • 이전 단락에서 의존성 패키지를 명시한 파일로 requirements.txt를 사용했다. 이 파일은 Python의 공식 패키지 관리자인 PIP에서 사용하는 관행적으로 지칭하는 파일이다.Python 개발 환경을 기준으로 봤을 때 PIP는 패키지별 상호 의존성에 관계를 관리할 때 부족한 면이 있다. 그래서 요즘은 좀 더 발전된 Locking 시스템을 갖춘 Pipenv나 Poetry를 사용하는 것을 추천한다.
  • 이 도구들을 이용해 생성된 Lock 파일 (예: Pipfile)을 기반으로 패키지가 설치될 수 있도록 한다면 위 (3) 단락에서 설명한 캐시 레이어의 장점을 얻을 수 있고, 예상치 못한 패키지 버전 업데이트도 방지할 수 있다.
  • 멀티-스테이지 빌드
     는 위 (2), (3), (4) 단락에서 했던 노력보다 훨씬 더 효과적으로 도커 이미지 사이즈를 줄이는 방법이다.
  • 멀티-스테이지 빌드는 Dockerfile 1개에 FROM 구문을 여러 개 두는 방식이다.각 FROM 명령문을 기준으로 스테이지를 구분한다고 했을 때 특정 스테이지 빌드 과정에서 생성된 것 중 사용되지 않거나 불필요한 모든 것들을 무시하고, 필요한 부분만 가져와서 새로운 베이스 이미지에서 다시 새 이미지를 생성할 수 있다.

https://dodonam.tistory.com/126 참조

 

https://stackoverflow.com/questions/59747986/how-to-use-tensorflow-2-0-with-aws-lambda →  (EFS,Container)

 

Uploaded by Notion2Tistory v1.1.0

 

 

케라스 sequential 로 만든 모델 저장하는법 & 불러오는법

코드 참조 : https://tykimos.github.io/2017/06/10/Model_Save_Load/

참조 :https://mylifemystudy.tistory.com/69

https://ssongnote.tistory.com/12

 

  • 케라스에서 모델 구성하는법
# 0. 사용할 패키지 불러오기
from keras.utils import np_utils
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Activation
import numpy as np
from numpy import argmax

# 1. 데이터셋 생성하기

# 훈련셋과 시험셋 불러오기
(x_train, y_train), (x_test, y_test) = mnist.load_data()

# 데이터셋 전처리
x_train = x_train.reshape(60000, 784).astype('float32') / 255.0
x_test = x_test.reshape(10000, 784).astype('float32') / 255.0

# 원핫인코딩 (one-hot encoding) 처리
y_train = np_utils.to_categorical(y_train)
y_test = np_utils.to_categorical(y_test)

# 훈련셋과 검증셋 분리
x_val = x_train[:42000] # 훈련셋의 30%를 검증셋으로 사용
x_train = x_train[42000:]
y_val = y_train[:42000] # 훈련셋의 30%를 검증셋으로 사용
y_train = y_train[42000:]

# 2. 모델 구성하기
model = Sequential()
model.add(Dense(units=64, input_dim=28*28, activation='relu'))
model.add(Dense(units=10, activation='softmax'))

# 3. 모델 학습과정 설정하기
model.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy'])

# 4. 모델 학습시키기
model.fit(x_train, y_train, epochs=5, batch_size=32, validation_data=(x_val, y_val))

# 5. 모델 평가하기
loss_and_metrics = model.evaluate(x_test, y_test, batch_size=32)
print('')
print('loss_and_metrics : ' + str(loss_and_metrics))

# 6. 모델 사용하기
xhat_idx = np.random.choice(x_test.shape[0], 5)
xhat = x_test[xhat_idx]
yhat = model.predict_classes(xhat)

for i in range(5):
    print('True : ' + str(argmax(y_test[xhat_idx[i]])) + ', Predict : ' + str(yhat[i]))
위 코드 관련된 내용

** reshape 관련참조 https://supermemi.tistory.com/12

** utils.to_categorical

** model.compile → optimizer,loss,metrics 지정해줌.

** loss 함수 참조 https://hororolol.tistory.com/375

** train (val , train ) / test 이렇게 나눠짐

** predict vs predict_class

  • predict 의 경우

[[0.22520512],[0.9520419 ],[0.9672848 ],[0.02690617]]

  • predict_classes 의 경우

[[0],[1],[1],[0]]

** argmax

 

Q. 저장한 모델은 어떻게 다시 불러오고 불러온 모델을 어떤식으로 활용하는지
  • 모델을 저장한다. 무엇을 저장하는건지

모델은 1. 모델 아키텍쳐 (모델이 어떤레이어로 쌓여있는지= 즉 모델구성) 2. 모델가중치(처음에는 임의의값으로 초기화되어있지만, 훈련셋으로 학습하면서 갱신됨) 로 이루어짐. 모델을 저장한다는 의미는 이 두개를 저장한다는 말.

  • 위코드를 실행하고나면 ~~.h5 파일이 생김. 여기에 들어있는 정보들은

(1) 모델구성정보 (2) 가중치 (3) 손실함수등등 학습설정(model.compile해준거) (4) 재학습을 할수있도록 마지막 학습상태 들로 구성되어있다.

→ 만약에 (1) 모델구성정보와 (2) 가중치를 따로 각각 저장하고 불러오는 케이스일경우, 모델을 불러온다음, model.compile을 설정해주어야한다.

 

 

Python sklearn 로 만든 모델 저장하는법

참조: https://cocook.tistory.com/46

https://www.python2.net/questions-889925.htm

Tensorflow 만든 모델 저장,불러오는법

TENSORFLOW

model.save()를 호출하면 다음과 같은 파일들이 저장된다.

  • model's architecture/config
  • model's weight values
  • model's compilation information (if compile() was called)
  • optimizer and its state

model.save('my_custom_model')시 저장되는 디렉토리는 다음과 같다.

my_custom_model 
└ assets (dir) 
└ variables (dir) 
└ saved_model.pb (file)

불러올때는 아래처럼 불러오면 된다

model_dnn = load_model('my_custom_model')

 

 

람다에서 불러올때 h5로 불러오면 에러가 나고, pb 형태로만 인식이 되나보다. 변환해주면 됨

**KERAS (.H5)→ Tensorflow (.pb) 형식

https://coredump064.tistory.com/80 참조 (h5→pb)

 

본인이 변환해서 저장한 saved_dnn_model 형태는 파일형태로 다음과 같았다.

saved_dnn_model
ㄴkeras_metadata.pb
ㄴsaved_model.pb
ㄴvariables
ㄴassets

 

 

Uploaded by Notion2Tistory v1.1.0

AJAX

  • 자바스크립트의 라이브러리중 하나
  • 브라우저가 가지고있는 XMLHttpRequest 객체를 이용해서 전체 페이지를 새로 고치지 않고도 페이지의 일부만을 위한 데이터를 로드하는 기법 이며 JavaScript를 사용한 비동기 통신, 클라이언트와 서버간에 XML 데이터를 주고받는 기술이다. (https://velog.io/@surim014/AJAX란-무엇인가)
  • 단순히 웹화면에서 무언갈 부르거나 데이터를 조회하고 싶을때 페이지전체를 새로고침하지않기위해 사용한다.
  • 기본적으로 HTTP 프로토콜은 클라이언트쪽에서 Request를 보내고 서버쪽에서 Response를 받으면 이어졌던 연결이 끊기게 되어있다. 그래서 화면의 내용을 갱신하기 위해서는 다시 request를 하고 response를 하며 페이지 전체를 갱신하게 된다. 하지만 이렇게 할 경우, 엄청난 자원낭비와 시간낭비를 초래 → ajax를 사용
  • 서버에서 데이터를 http get, post, json 의 모든방식으로 전송한후 서버측 응답을 받으럐때 사용, http get방식으로 전송한후 서버측 응답을 json형식으로 받을떄는 $get.JSON 을 사용한다.
var serverAddress = 'https://hacker-news.firebaseio.com/v0/topstories.json';

// jQuery의 .get 메소드 사용
$.ajax({
    url: ,
    type: 'GET',
    success: function onData (data) {
        console.log(data);
    },
    error: function onError (error) {
        console.error(error);
    }
});
<script>

$(document).ready(function() {
     jQuery.ajax({
           type:"GET",
           url:"/test",
           dataType:"JSON", // 옵션이므로 JSON으로 받을게 아니면 안써도 됨
           success : function(data) {
                 // 통신이 성공적으로 이루어졌을 때 이 함수를 타게 된다.
                 // TODO
           },
           complete : function(data) {
                // 통신이 실패했어도 완료가 되었을 때 이 함수를 타게 된다.
                 // TODO
           },
           error : function(xhr, status, error) {
                 alert("에러발생");
           }
     });
});
</script>

출처: https://marobiana.tistory.com/77 [Take Action]
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="ko"  xml:lang="ko">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 <head>
  <script src="./js/jquery-1.11.3.min.js"></script>
  <script type="text/javascript">
	$(document).ready(function() {
		$("#btn1").click(function() {
			$.ajax({
				type:"post",
				url:"./list.json",
				dataType:"text",
				success:function(data) {					
					$.each(JSON.parse(data), function(index, entry) {
						console.log("menu : " + entry["menu"] + ", page " + entry["page"]);
						$("#" + entry["menu"]).html( entry["menu"] + ", page " + entry["page"]);
					});
			}});
		});
	});
  </script>
 </head>
 <body>
	<div id="human"></div>
	<div id="animal"></div>
	<div id="fruit"></div>
	<button id="btn1">button</button>
 </body>
</html>


출처: https://leojin.tistory.com/entry/Ajax-로-json-파일-내용-읽기

header:{"Content-Type":"application/json"}

ajax로 서버에 데이터를 보낼때 header 중 content-type이 존재하는데 이를 설정하지않으면 디폴트값으로 application/x-www-form-urlencoded; charset=UTF-8 타입으로 지정됨.

그래서 json형태의 데이터를 주고싶을떄는 위의 헤더를 지정해주어야함.

문제 → request안에 포함된 json형태의 데이터를 받았을때 보통 vo,dto에서 담아 다시 사용하는데, ajax는 데이터를 문자열화해주지않아서 보낼 데이터를 json.stringfy()로 감싸주어야함

그렇지않을경우 json데이터를 인식을 못함

기본값은 true, 기본적을 key,value 값을 쿼리 스트링을 변환해서 보내줌. 이게 False 로 지정되어있으면 쿼리 String으로 설정하지않음 , 이것은 파일 전송시에 사용한다고함

전제조건 : 내가보고있는 페이지에서 다른페이지의 rest api를 호출해서 데이터를 json으로 가져오려고함. 내가 이용하는 페이지주소랑 데이터를 가지고 오기위한 서버 도메인이 서로 다를경우 crossdomain이라고 부름.

  • formData

비동기 업로드를 위해 ajax formData를 사용함. 평소엔 안쓰임 , 이미지를 ajax로 업로드할때 필요함.

  • *** 비동기?
    • 비동기 처리 ? 특정 코드의 연산이 끝날떄까지 코드의 실행을 멈추지않고 다음코드를 먼저 실행하는 자바스크립트의 특성을 의미함. → 제이쿼리의 ajax를 많이씀.
    • function getData() {
      	var tableData;
      	$.get('https://domain.com/products/1', function(response) {
      		tableData = response;
      	});
      	return tableData;
      }
      
      console.log(getData()); // undefined
      
      // get 부분이 ajax로 통신을 하는 부분임. http~ 에 get 요처응ㄹ 날려서 product정보를 요청함. 
      // 한마디로 쉽게 말하면 지정된 url에 데이터를 하나 보내주세요 라는 요청을 날리는것과 같음. 
      // http 서버에서 받아온 데이터를 respose 인자에 담김
      // getdata는 뭐임?? undefined 왜? 왜냐 이전에 미리 return 해줘서 그럼. 기다려주지않고 바로
      리턴해버려서 undefined를 출력하게됨. 
      // 이런식으로 특정로직의 실행이 끝날떄까지 기다려주지않고 나머지 코드를 먼저 실행해버리는게 비동기처리라는것임
      콜백함수로 비동기처리 방식의 문제점 해결하기
    • function getData(callbackFunc) {
      	$.get('https://domain.com/products/1', function(response) {
      		callbackFunc(response); // 서버에서 받은 데이터 response를 callbackFunc() 함수에 넘겨줌
      	});
      }
      
      getData(function(tableData) {
      	console.log(tableData); // $.get()의 response 값이 tableData에 전달됨
      });

중요 : ajax formData 사용시에 contentTYpe, processData 옵션을 false로 설정해야함 !!!

사용법은 두가지가있음

(1) form 에 작성된 전체데이터 보내기 (2) form 에 작성된것 중 필요한것만 선택해서 보내기

//후자 (2)  방법
var formData = new formData();
formData.append([key],[value]);
//append는 전체데이터중에 필요한것만 선택해서 보낼때를 의미함. 더해준다는 의미가 아님.

formData.append('username', 'Chris'); //이런식으로 쓰인다~

<form id="myForm" name="myForm">
  <div>
    <label for="username">Enter name:</label>
    <input type="text" id="username" name="username">
  </div>
  <div>
    <label for="useracc">Enter account number:</label>
    <input type="text" id="useracc" name="useracc">
  </div>
  <div>
    <label for="userfile">Upload file:</label>
    <input type="file" id="userfile" name="userfile">
  </div>
  <input type="submit" value="Submit!">
</form>

/////////////////////////////////////////////////////////////////////////////

let myForm = document.getElementById('myForm');
let formData = new FormData(myForm);
  • document.getElementById

id 로 요소를 찾고 이를 나타내는 elements 객체를 반환

  • param(obj)

폼 요소들의 값을 변환해서 직렬화한 문자열로 표현함.

  • datatype

내가보는 데이터타입 아님, 서버가 응답(response)할떄 보내줄 데이터타입임. 이는 success function에 전달될 argument의 형태를 지정하는데 사용된다고 한다

→ 한마디로 서버측에서 전송받은 데이터의 형식

  • processData

일반적으로 서버에 전달되는 데이터는 query string이라는 형태로 전달된다. data 파라미터로 전달된 데이터를 내부적으로 query string으로 만드는데 파일전송의 경우 이렇게 하면안된다.

-기본값은 true

-해당값이 true →> data 값들이 쿼리 스트링 형태인 Key=value & key2=value2 형태로 전달이된다. 하지만 리헌식으로 진행하면 file값들이 제대로 전달되지않음

-해당값이 false → { key1 : 'value1', key2 : 'value2' } 형태로 전달

  • contentType

디폴트값은 "application/x-www-form-urlencoded; charset=UTF-8" 인데 , multipart/form-data로 전송이 되게 false로 넣어줌.

  • data

http 요청후 return하는 값임

  • url

요청이 전송되는 url 이 포함되는 문자열

  • type

http 요청방식 (Get/Post)

  • async

요청시 동기유무를 선택할수 있다 ( true/False)

.ajax 에서 string으로 보내서 전송하고,

success 후에는 돌려받은걸 다시 json파일로 변환해서 출력한다

  • enctype1. application/www-form-urlencoded2. multipart/form-data3. text/plain출처: https://dydals5678.tistory.com/113
  • 이 형식은 인코딩을 하지 않은 문자 상태로 전송한다.
  • 파일이나 이미지를 서버로 전송할 경우 이 방식을 사용한다. 그렇게 하지 않으면 웹 서버로 데이터를 넘길때 파일의 경로명만 전송되고 파일 내용이 전송되지 않기 때문이다. 그리고 이떄 메소드는 post값으로 지정해줘야 한다 (핵중요)
  • 디폴트값이다. enctype을 따로 설정하지 않으면 이 값이 설정된다. 폼데이터는 서버로 전송되기 전에 URL-Encode 된다.
  • enctype 은 다음 3가지값을 지정가능

JSON 메모

  • JSON.stringify(value)

→ 인수로 전달받은 자바스크립트 객체를 문자열로 변환해서 반환해줌

예제1

<html>
<body>
	<p id="json"></p>
	<script>
		var dog = {name: "식빵", family: "웰시코기", age: 1, weight: 2.14};	// 자바스크립트 객체
		
		var data = JSON.stringify(dog);	// 자바스크립트 객체를 문자열로 변환함.
		document.getElementById("json").innerHTML = data; // json 데이터 불러옴

	</script>
</body>
</html>
//output : {"name":"식빵","family":"웰시코기","age":1,"weight":2.14}ㅁ

예제2

var obj = { name: "John", age: 30, city: "New York" }; 
var myJSON = JSON.stringify(obj); 
document.getElementById("demo").innerHTML = myJSON; 
//결과값 {"name":"John","age":30,"city":"New York"}
  • JSON.parse(text)

→인수로 전달받은 문자열을 자바스크립트 객체로 변환해서 반환해줌

<html>
<head>
	<title>parse</title>      
</head>
<body>
	<p id="json"></p>
	<script>
		// JSON 형식의 문자열
		var data = '{"name": "식빵", "family": "웰시코기", "age": 1, "weight": 2.14}';
		
		var dog = JSON.parse(data);	// JSON 형식의 문자열을 자바스크립트 객체로 변환함.
		document.getElementById("json").innerHTML = dog + "<br>";
		document.getElementById("json").innerHTML += dog.name + ", " + dog.family;
	</script>
</body>
</html>

//결과 
[object Object]
식빵, 웰시코기
const json = '{"result":true, "count":42}';
const obj = JSON.parse(json);

console.log(obj.result);
// expected output: true
  • toJSON()

→ 자바스크립트의 Date 객체를 Json 형식의 문자열로 반환해서 변환

 

 

예제1

추가 참조 :  https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=mk1126sj&logNo=221016837263

https://developer.mozilla.org/en-US/docs/Web/API/FormData/FormData

https://grip.news/archives/1397

https://galid1.tistory.com/398

<그래프 두개로 그리기>

- 안 붙은 그래프

바그래프 가로길이 0.36 반띵하면0.18

i 를 x축 중심 이라고 하면 바1은 -0.18 ,바2는 +0.18 해서 두 그래프가 딱붙어서 출력

x= [ i-0.20 for i in range(7)]
x2= [ i+0.20 for i in range(7)]
x_middle= [ i for i in range(7)]

plt.bar(x, original,color='darkgray',width=0.36,label='label1', edgecolor='black')
plt.bar(x2, (a+b+c+d)/4 ,color='white',width=0.36,label='lable2',edgecolor='black',hatch='/')

- 붙은 그래프

바그래프 가로길이 0.36 반띵하면 .018

i 를 x축 중심 이라고 하면 바1은 -0.20 ,바2는 +0.20 해서 두 그래프두개 0.4 띄워서  출력

x= [ i-0.18 for i in range(7)]
x2= [ i+0.18 for i in range(7)]
x_middle= [ i for i in range(7)]

plt.bar(x, original,color='darkgray',width=0.36,label='label1', edgecolor='black')
plt.bar(x2, (a+b+c+d)/4 ,color='white',width=0.36,label='lable2',edgecolor='black',hatch='/')

 

<화살표 그리기>

- 바가 7개면 7번 for 문돌려주고

- plt.arrow ( 시작하는점x, 시작하는점 y , 시작점에서 x축방향으로 이동할만큼, 시작점에서 y축방향으로 이동할만큼  )

- head_width (화살표머리 가로) , head_length(화살표머리 세로) 

- fc, ec : 화살표머리랑 화살표대 색깔 

- width : 화살표대 넓이 (설정안하면 실선)

for i in range(7):
    plt.arrow(i+0.20, original[i], 0, -((original-(a+b+c+d)/4))[i]+0.8, head_width = 0.18, 
             head_length = 0.8,fc="k", ec="k",width=.06)
plt.show

<라벨달기>

- 바그래프안에 label = 'label1' 이런식으로 라벨달아주고

plt.bar(x, original,color='darkgray',width=0.36,label='label1', edgecolor='black')
plt.bar(x2, (a+b+c+d)/4 ,color='white',width=0.36,label='lable2',edgecolor='black',hatch='/',yerr=[(0,0,0,0,0,0,0),(original-(a+b+c+d)/4)] ,error_kw=dict(lw=2, capsize=0, capthick=2))

- 바그래프에 달아준 라벨을 표시해준다.

loc ( 그래프안에서 x , 그래프안에서 y )

plt.legend(fontsize=62,loc=(0.005,0.86))

 

<바그래프 칠하기,선긋기,테두리선>           

- edgecolor :바 테두리선 색 (안해주면 색없음)

- inewidth : 바 테두리선 두께

-  hatch : 빗금  ('/' , '//', '\\' 'x' ...)

- color : 바안에 칠하기 (검색ㄱ)

plt.bar(x, original,color='darkgray',width=0.36,label='label1', edgecolor='black',linewidth=0.5)
plt.bar(x2, (a+b+c+d)/4 ,color='white',width=0.36,label='lable2',edgecolor='black',linewidth=0.5,hatch='/',yerr=[(0,0,0,0,0,0,0),(original-(a+b+c+d)/4)] )

 

<x 축 돌리기>

- rotation = 95 (수직으로)

- rotation=0 (안돌림)

plt.xticks(x_middle,['a','b','c','d','e','f','g'])
plt.xticks(rotation=90,fontsize=80,ha="right")
# ha는 오른쪽을 기준으로 맞추라는뜻

 

<바그래프 위에 텍스트 표시>

o= ['%','%','%','%','%','%','%']
for i, v in enumerate(x2):
    plt.text(v, original[i], str (round(((original-(a+b+c+d)/4)/original*100)[i],1))+o[i] ,                 
             fontsize = 60, 
             color='black',
             #weight="bold",
             horizontalalignment='center',
             verticalalignment='bottom')

 

<바그래프 사이에 간격 표시하기>

- yerr=[(0,0,0,0,0,0,0), 간격 ] ,error_kw=dict(lw=2, capsize=3, capthick=2))

- capsize : 가로축 길이 (0으로 하면 걍 실선으로 표시됨)

- capthick : 가로축 두께

plt.bar(x, original,color='darkgray',width=0.36,label='label1', edgecolor='black')
plt.bar(x2, (a+b+c+d)/4 ,color='white',width=0.36,label='lable2',edgecolor='black',hatch='/',yerr=[(0,0,0,0,0,0,0),(original-(a+b+c+d)/4)] ,error_kw=dict(lw=2, capsize=0, capthick=2))

- yerr=[1,1,1,1,1,1,1] 로 바꾸면

<바그래프 x 축 rotation 위치 조정하기>

https://stackoverflow.com/questions/43152502/how-can-i-rotate-xticklabels-in-matplotlib-so-that-the-spacing-between-each-xtic  참조

 

 

1. 일단 opencv로 동영상을 잘라준다

2. yolo 적용해서 object detection 감지 ( 아래 사이트 참조)

coco.names
0.00MB
yolov3.cfg
0.01MB
yolo_object_detection.zip
2.76MB

* yoloc3.weighs 는 아래에서 다운로드받아서 쓰기 

 

YOLO object detection using Opencv with Python - Pysource

We’re going to learn in this tutorial YOLO object detection. Yolo is a deep learning algorythm which came out on may 2016...

pysource.com

 

mp4_cctv_list=[]
for i in file_list:
    # 현재 디렉토리에 있는 모든 파일 리스트를 가져온다
    
    path = "./task1/"+str(i)
    file_listttt = os.listdir(path)
    mp4_cctv = [file for file in file_listttt if file.endswith(".mp4")]
    mp4_cctv_list.append(mp4_cctv)


for j in range(1,len(file_list)):
    mp4_cctv = "./task1/"+str(file_list[j-1])+"/"+str(mp4_cctv_list[j-1][0])

    try : 
        # -------------------- 동영상 쪼개기 ------------------------------------------------------------   
        import cv2
        n=119  #동영상을 119개로 쪼개줄것임

        vidcap = cv2.VideoCapture(mp4_cctv)     
        total_frames = vidcap.get(cv2.CAP_PROP_FRAME_COUNT)
        frames_step = total_frames//n
        for i in range(n):
            #here, we set the parameter 1 which is the frame number to the frame (i*frames_step)
            vidcap.set(1,i*frames_step)
            success,image = vidcap.read()  
            #save your image
            globals()['col{}.jpg'.format(i)]= image
            #cv2.imwrite(globals()['./col{}.jpg'.format(i)],image)
            
            # 저장해줄 위치 지정해줌
            cv2.imwrite('./new2/col'+str(i)+'.jpg',image)
        vidcap.release()
        
        # -------------------- yolo ------------------------------------------------------------
        # Yolo 로드
        net = cv2.dnn.readNet("yolov3.weights", "yolov3.cfg")
        classes = []
        with open("coco.names", "r") as f:
            classes = [line.strip() for line in f.readlines()]
        layer_names = net.getLayerNames()
        output_layers = [layer_names[i[0] - 1] for i in net.getUnconnectedOutLayers()]
        colors = np.random.uniform(0, 255, size=(len(classes), 3))

        for k in range(119):  #수정 119로
            # 이미지 가져오기
            print('사진' ,k)
            img = cv2.imread("./new2/col"+str(k)+".jpg")
            img = cv2.resize(img, None, fx=0.4, fy=0.4)
            height, width, channels = img.shape

            # Detecting objects
            blob = cv2.dnn.blobFromImage(img, 0.00392, (416, 416), (0, 0, 0), True, crop=False)
            net.setInput(blob)
            outs = net.forward(output_layers)

            # 정보를 화면에 표시

            class_ids = []
            confidences = []
            boxes = []
            for out in outs:
                for detection in out:
                    scores = detection[5:]
                    class_id = np.argmax(scores)
                    confidence = scores[class_id]
                    if confidence > 0.5:
                        # Object detected
                        center_x = int(detection[0] * width)
                        center_y = int(detection[1] * height)
                        w = int(detection[2] * width)
                        h = int(detection[3] * height)
                        # 좌표
                        x = int(center_x - w / 2)
                        y = int(center_y - h / 2)
                        boxes.append([x, y, w, h])
                        confidences.append(float(confidence))
                        class_ids.append(class_id)

            indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4)

            font = cv2.FONT_HERSHEY_PLAIN
            label_lists=[]
            for i in range(len(boxes)):
                if i in indexes:
                    x, y, w, h = boxes[i]
                    label = str(classes[class_ids[i]])
                    color = colors[i]
                    cv2.rectangle(img, (x, y), (x + w, y + h), color, 2)
                    cv2.putText(img, label, (x, y + 30), font, 3, color, 3)
                    label_lists.append(label)

            cv2.imshow("Image", img) 
            cv2.waitKey(1)
            cv2.destroyAllWindows()
            print(label_lists)
            df['mp4'][:][k]=label_lists


        #맥에서 opencv 안닫힐때 꿀팁
        cv2.destroyAllWindows()
        cv2.waitKey(1)
        cv2.waitKey(1)
        cv2.waitKey(1)
        cv2.waitKey(1)

 
    except :
        print('exept',file_list[j-1],j-1)
#맥에서 opencv 팝업창 안닫힐때 꿀팁
cv2.destroyAllWindows()
cv2.waitKey(1)
cv2.waitKey(1)
cv2.waitKey(1)
cv2.waitKey(1)

출처 : https://stackoverflow.com/questions/6116564/destroywindow-does-not-close-window-on-mac-using-python-and-opencv

 

이 방법은 k-means 방법처럼, 클러스터 개수 가정해줄 필요가 없습니다. 또 이방법에서 주목한점이 군집간 거리를 활용하는 방법입니다.

.............................................................................................................................

  • 군집간 거리 측정 방식

-method : single, complete, average, centroid, ward linkage 방식이 존재

-Centroid : 두 군집의 중심점(centroid)를 정의한 다음 두 중심점의 거리를 군집간의 거리로 측정

-Single : 최단 연결법, 모든 데이터 조합에서 데이터 사이 거리를 측정해서 가장

최소 거리(작은 값)를 기준으로 군집 거리를 측정

-Complete : 최장 연결법으로 두 클러스터상에서 가장 먼 거리를 이용해서 측정하는 방식

-Average : 평균 연결법, 두 군집의 데이터들 간 모든 거리들의 평균을 군집간 거리로 정의(위에서 singe.complete를 합쳐준 방법이라하면 되겠다)

-Ward : 와드연결법은 군집분석의 각 단계에서 데이터들을 하나의 군집으로 묶음으로써 생기는 정보의 손실을 군집의 평균과 데이터들 사이의 오차제곱합(SSE)으로 아래와 같이 측정한다.

.............................................................................................................................

<코드부분>

Xi = np.array([[0,17,21,31,23],[17,0,30,34,21],[21,30,0,28,39],[31,34,28,0,43],[23,21,39,43,0]]) dists = squareform(Xi) #여기서 flat하게 바꾸어 주어야한다.이거 안해주고 넣으면 어딘가 이상해짐  Z = linkage(dists, method='single')  # method는 여기서 변경해주면 된다 dendrogram(Z)   # 아래 그래프 출력 plt.axhline(20, color='k', ls='--');  #임계치값(20)에 대해 점점이 가로줄을 그어줌

 

shc.fcluster(Z, 20, criterion='distance')  #임계치20에 줄을 그어서 나누어지는 군집들

→ [a,b][c][d][e] 이렇게 나누어짐을 확인할수 있습니다.

 

 

 

<개념부분>

첫번째줄에서, 임계값을 주지않으면, 총 1개의 군집이 출력됩니다. (method별로 만들어지는 dendrogram 모양이다릅니다)

두번쨰 줄에서 임계값을 줌으로써 여러개의 군집으로 나누어줄수 있습니다.

 

 

이것은 method 별로 유사도를 처리하는 방법이 다른것을 자세히 나타내 줍니다.

(single 은 가장 가까운 거리를 채택, complete 는 가장 먼거리를 채택, average는 이 두개의 평균을 채택합니다.)

e.g. single linkage 방법에서 abce, d 사이의 거리를 구할때, d와 ab간의 거리 31, d와 c간의 거리 28, d와 e간의 거리 43중에 가장 작은값인 28을 선택해줍니다. 만약 complete linkage 방법이였다면, 43을 선택해주었을것입니다.

(centroid , ward 이 두가지 메소드는 계산과정에서 (x,y)축을 필요로 하기 때문에 x,y축에서 pdist로 유사도를 구하는 방식이 아니라 처음부터 유사도를 집어넣어서 계산하는  방법에는 바람직하지 않음

 

 

 

 

 

 

 

 

먼저 간단히 논문의 개요를 살펴보자면, 요즘 머신러닝은 이기종 리소스를 보유한 전담 작업자가 아니라, 클러스터에서 더많이 훈련이 됩니다. 이떄, 다른워커보다 훨씬 느리게 실행되는 스트래글러는 부정적인 영향을 미칩니다. (오른쪽 그림, 빨간색 화살표) 여기서 스트래글러가 의미하는것은 적은수의 스레드가 주어진 반족을 실행하는데 다른 스레드보다 오래걸릴떄 발생하는 문제를 의미합니다. 모든 스레드는 동기화되어야해서 모든 스레드는 가장 느린 스레드(스트래글러)의 속도로 진행할수밖에 없기 때문입니다. 이 논문의 핵심은 이 샘플 배치의 크기를 적절하게 조정해서 작업자의 부하를 즉각적인 처리기능에 맞게 조정하는것입니다.

이 논문에서는 ML 워크로드의 스트래글러를 제거하기 위해 SEMI Dynamic Load balancing이라는 새로운 방법을 제안합니다. 그리고 이방법을 이용해서 LP_BSP를 구현합니다. 여기서 BSP란 병렬 소프트웨어와 하드웨어 개발의 기준이 되는 모델로 PRAM 모델의 일종입니다.

**Pram ⇒ 공유 메모리르를 사용해서 프로세스간에 병렬 통신을 지원하는 구조입니다.

이 체계에서 빠른 작업자는 각 iteraiton이 끝날때마다 느린 작업자(스트래글러)를 기다려야함으로 스트래글러는 모델의 학습 효율성을 저하시킵니다. 이 기존의 BSP모델의 단점을 보완한것이 LP-BSP 모델입니다.

들어가기 앞서서 이 논문에서 자주 쓰이는 개념들에 대해 간단히 짚고 넘어갑니다. 클러스터는 다음과 같이 두가지 종류로 나뉘는데, 전자의 경우, 전용 클러스터라고 불리며 후자의 경우 비전용 클러스터라고 합니다.

전자는 높은 효율성을 보이지만, 유지관리 비용이 많이 들고 널리 엑세스가 불가함으로 쉐어링이 되지 않는 문제를 가지고있습니다.

후자의 경우, 비전용 클러스터로 앞서 설명한 이기종 하드웨어로 구성되어있으며, cpu 와 gpu의 빠른 발전속도에 맞게 aws같은곳에서 이기종 하드웨어 세트로 모델을 학습시킬수 있습니다. 이 경우 dynamic하게 리소스들이 할당되며, 싸고 용량문제가 비교적 적게 발생합니다.

최근 비전용 클러스터(위에서 설명드린) 에서 주로 모델 훈련이 이루어지는 한편, 더 심각한 스트레글러 문제가 발생합니다. 스트래글러의 경우에도 크게 두가지로 나뉠수가 있는데 비결정론적 스트래글러, 결정론적 스트레글러로 나뉠수가 있습니다.

전자의 경우, os 지터같은 일시적인 장애로 인해 발생하며, 일시적이로 아주 미미합니다

** os jiter: e.g. 백그라운드 데몬 프로레서의 에약 / 비동기 이벤트 처리로 인해 발생하는 간섭

하지만 후자의 경우, 전자에 비해 훨씬 심각하고 오래 지속됩니다. 그리고 이는 앞서 설명드린 비전용 클러스터에서만 발생합니다.

간단히 말하면, 스트래글러는 적은 수의 스레드에서 주어진 반복을 실행해야하는데 다른 스레드보다 오래걸릴때 발생하는 문제입니다 모든 스레드가 동기화되어야해서 각 스레드는 iteraiton마다 가장 느린 스레드의 속도로 진행되어 문제가 발생하는것입니다.

이제 이런 스트래글러를 해결하기위해 과거에 행해졌던 여러가지 시도들에 대해 살펴봅니다.

ASP 방식은 다른 worker를 기다리지 않고 독립적으로 다음 반복을 수행합니다. 이렇게 하면 컴퓨팅 주기를 낭비하지않고 하드웨어적으로 효율이 높습니다. 그런데 가장큰 문제가 global하게 매개변수가 동기화가 제대로 되지않아 부실한 매개변수를 사용하게 될 확률이 높아집니다. 이는 앉은 품질의 업데이트를 만들어내기 때문에 더 많은 Iteraitondl 필요하게되고 결국엔 그렇게 효과적인 스트래글러 해결방법은 아닌듯합니다.

SSP 방식은 앞서 ASP 와 BSP를 섞어놓은 방법입니다. 매개변수 비활성이 특정한 임계값에 도달할때만 스트래글러를 기다려줍니다. 하지만, SSP는 주로 비결정적 스트레글러에만 초점을 맞춘 방법이기 때문에, 결정적 클러스터에 적용할경우 지연이 자주 발생할수 있습니다. ASP 와 BSP가 섞인 방법이기 떄문에 여전히 스트래글러가 발생시 기다려야하는 문제가 남아있고 해결되지 않았습니다.

Redundant execution이라는 방법은, 스트래글러 worker에 여러 복사본을 두어서 먼저 완료된 작업의 결과만 받아들이는 방법입니다. 그런데 이 방법은 차선책일뿐, 일부의 스트래글러만 완화해주지만 최악의 스트래글러의 경우 전혀 도움이 되지 않습니다. 복제본이 모두 느리다면 큰 효과가 없기 때문입니다. 또 복제본을 만들기 때문에 추가적인 리소스를 소비해야 한다는것이 단점입니다.

지금까지의 방법들은 전부 스트래글러가 발생할경우 이를 완화하는 방법들만을 다루었지 스트레글러의 근본원인에 대해 서는 다루지 않았습니다. 애초에 스트레글러가 발생하는것을 방지하면 더 근본적으로 문제를 해결할수 있습니다. 이를 위해서는 로드밸런싱 기술에 의존할 필요가 있습니다. 이 로드밸런싱(부하분산) 은 병렬처리에서의 고전적인 연구주제이며 두가지 (static , dynamic) 방식으로 나뉩니다.

전자는 정적 부하분산방법이고 후자는 동적 부하분산 방법입니다.

정적 부하분산은 라운드 로빈같이 정적인 양을 다루며, 동적 부하분산은 부하가 많은 작업자의 일을 런타임부하가 적은 작업자로 재분배해줍니다

아래 그림은 FLEXRR 이라고 최근의 Dynamic한 load balancing 방법입니다. 주어진 임계값에 대해서 다른 작업자보다 뒤처지면(slow) Fast한 작업자에게 일을 제공합니다

이 논문에서는 이 dynamic load balancing 개념을 사용해서 Sem-dynamic loac balancing이라는 전략을 제공합니다

앞서 말한방법들을 바탕으로 새로운 전략을 내놓았습니다. 각 iteraiton 안에서는 정적으로 부하를 유지하지만, 다른 iteraiton에서는 동적으로 유지합니다. 이게 무슨말이냐 하면, 각 iteraiton의 경계부분에서 각 worker들의 상태를 측정합니다. 요즘에는 iteration의 크기가 아주 작고 iteraiton안에서도 엄청나게 큰 변화가 일어나는것이 아니기 때문에 (위 그래프에서 보면 배치 사이즈별로 iteraion time이 몇초 혹은 0.몇초 대로 굉장히 작음을 알수있습니다) iteraiton 의 경계부분에서 측정해도 충분합니다.

한마디로 iteraiton 전부를 볼필요없이 경계부분만 살펴본다는것입ㄴ디ㅏ

두번쨰로, 각 경계에서 스태글러를 감지해냅니다.

세번쨰로, 각 iteraiton 별 경계에서 스트래글러를 감지해내고 배치크기를 조정해줍니다.

이러한 로드밸런싱 전략을 사용할것이라고 합니다.

이제 앞에서 load balancing 전략을 정해주었으니, 비전용 클러스터에서 효율적인 분산학습을 위해 LB-BSP라는 새로운 방법을 제시합니다. 먼저 모델학습 반복과정에서 iteration이 걸리는 총 시간은 t 이고, 이 t는 tm + tp로 이루어집니다 (위 피피티에 설명)

x 는 배치를 의미합니다. 그런데 정해놓고 보니, cpu와 gpu 클러스터에 각각 다른 문제가 발생합니다. cpu 클러스터에서는 ti와 xi가 선형적으로 증가하는데 ( 배치 사이즈가 커지면 프로세싱 시간인 t도 늘어난다) , Gpu는 비선형적입니다. 그래서 cpu와 gpu를 각각 따로따로 살펴보기로 합니다.

cpu는 gpu같은 가속기가 없기 때문에 다음과같은 상황에서 주로 쓰입니다 ( 피피티 위에 설명)

그리고 앞 피피티에서 말한것처럼 x,v 간에 선형관계를 이루고 있습니다. 그리고 t에서 tp가 99퍼를 차지하고 있기 떄문에 tm은 무시해도 별 영향이 없습니다.

Γ (x) 값이 선형적이기 떄문에 tp와 배치사이즈(x) 는 비례하게됩니다. 그래서 다음 반복에 대해 작업자 배치 크기를 결정하기 위해서는 현재 반복에서 샘플처리속도만 알면됩니다.

그런데 문제가, 샘플처리속도가 항상 일정한것이 아니라 동적으로 달라지기 때문에, NARX라는 방법을 사용합니다

NARX는 RNN의 일종으로 과거속도와 현재속도, cpu및 메모리 사용량같은 과거와 현재값을 모두 받아들이는 방법이라, 보다 좋은 성능을 보인다고 합니다.

위 알고리즘을 간단히 살펴보면, 이전 피피티에서 언급했던 샘플 처리 속도 (v)의 과거 값 / CPU 및 메모리 사용량 (c / m)의 두 구동 리소스의 현재 과거 값들을 받아옴을 확인할수 있습니다.

tp와 해당 함수의 식을 조합해서 v(속도)를 구하고 이 속도를 F (NARX 함수) 에 넣어서 계산해줍니다. 앞 피피티의 연산식을 활용하여 새로운 배치사이즈를 리턴해줍니다.

앞서 cpu 클러스터에 대해 살펴보았고 이번에는 gpu 클러스터에 대한 성능을 특성화 한다음 알고리즘을 제시해주었습니다. 우선 gpu의 성능으로는 앞서 cpu에서는 tm을 무시해주었지만 gpu에서는 무시해주면 안됩니다. gpu에서 계산은 cpu에서보다 훨씬 빠르고 이에따라 통신시간도 무시할수 없어졌습니다.

또 gpu를 수행하기 위한 일련의 준비작업(메모리간에 매개변수 교환, 처리커널 시작..)에도 상당한 오버헤드가 발생하기 떄문에 이 것들도 무시할수 없어졌습니다.

세번쨰로, tesla100 같은 최신의 고급 gpu의 경우 샘플배치가 너무 작아서 일정 크기이상으로 샘플 배치크기를 줄인다면 성능이 확 떨어지게 됩니다.

네번쨰, 각 반복동안 중간겨로가와 매개변수등을 모두 gpu 메모리에 저장해야함으로, 최대 배치크기를 제한해야합니다. (메모리부족을 예방하기위해)

앞 피피티에서 살펴본것들을 바탕으로 다음 알고리즘을 살펴보면

우선 각 iteration에서 가장 느린 작업자를 스트래글러로 지정해주고 가장 빠른 작업자를 리더로 지정해줍니다.

먼저 위 피피티에서 세번쨰문제를 해결하기위해 특정 배치크기 이하로 떨어지는것을 예방해줍니다.

두번쨰로 여전히 스트래글러의 크기가 리더보다 크다면, 리더의 배치크기를 조금 줄여주고, 스트래글러의 배치크기를 조금 늘려주는 방향으로 균형을 잡아갑니다

세번쨰로 반대가 된다면 파인튜닝을 통해 스위치 해줍니다.

*파인튜닝 : 기존에 학습되어져 있는 모델을 기반으로 아키텍쳐를 새로운 목적으로 변형하고 이미 학습된 모델 weights 로 부터 학습을 업데이트하는 방법을 의미합니다.

마지막으로 cpu,gpu별로 결과값을 살펴보면, 그래프 3개짜리에서 보면 (A) 그래디언트 업데이트당 시간의 평균 / worker의 수를 의미합니다. (B)는 통계적 효율성으로 목표하는 정확도에 도달하는데 필요한 업데이트수를 의미합니다. (한마디로 목표한 정확도에 이르기까지 반복하는 iteraion수를 의미합니다.) (c)는 목표정확도에 도달하는데 필요한 전체시간을 보여줍니다.(=목표한 정확도에 도달하는데 필요한 전체 시간)

세개 그래프 값에서 모두 LB-BSP 이 가장 적은 업데이트수와 시간을 가짐을 확인할수 있습니다.

아래그래프 2개를 보면, 마이크로 벤치마크를 실시한것으로 인스턴스 4개만 실시한것을 비교한것입니다. ( 인스턴스 4개를 합쳐준것을 cluster A라고 부릅니다) iteraion 횟수가 점점 늘어날수록 일정한값에 도달함을 알수 있습니다. 또 iteraion 횟수가 점점 늘어날수록 4개 인스턴스 값의 배치 처리시간이 거의 같아져서 straggler 문제가 해결됨을 확인할수 있습니다

cpu에서도 살펴봅니다. 여기선 table B 와 같이 인스턴스들을 합친 cluster-B를 만들어 살펴봅니다.

figure 9 는 cluaster B 에서 서로 다른방식으로 SVM 과 ResNet-32를 훈련할떄의 평균반복시간을 보여줍니다. LB-BSP가 가장 짧은 시간으로 최고의 효율성을 이끌어낼수있음을 확인할수 있습니다.

FIgure 10은 NARX 모델을 사용했을떄의 예측성능을 추가로 평가해준것입니다. 클러스터 B에서 m4.2xlarge 인스턴스 하나에 대한 resnet-32 훈련 프로세스에서 무작위로 iteration을 골라 살펴본것입니다. 이를 통해 NARX가 기존의 방법 뿐만아니라 프로세싱 속도 예측도 잘한다는 추가적인 기능도 확인할수 있습니다.

+)

  • NARX 그래프에 대한 내용에서 accuracy 라고 잘못 설명했던 부분을 정정합니다.

→ 그래프의 내용은 m4.2xlarge 스턴스 하나에 대한 ResNet-32 훈련 프로세스에서 iteration을 무작위로 선택한 구간으로, LP-BSP의 성능을 나타내기위한 지표라기보다 , NARX의 성능을 더 보여주기위해 추가적으로 진행해준 실험에 대한 표였습니다. (cluster-B 를 사용해서 prediction을 실시해준 결과를 나타낸준것 )

  • 19p Figure 4 그래퍼에서 xo 가 의미하는것은 최대 배치사이즈 제한값입니다. 메모리 부족문제를 방지하기위해서 배치사이즈크기의 최대값을 지정해준것을 의미합니다
  • adcanced details - user data 부분에 sh파일 넣어주면된다
  • sh 파일안에 pip3 install -r requirements.txt 이걸 넣어주면 올인원에 끝내줄수있음
  • 그러면 터미널에서 일일이 Pip3 ~~ 안깔아줘도 됨

https://arifulislam-ron.medium.com/flask-web-application-to-classify-image-using-vgg16-d9c46f29c4cd

ERROR : 크롬, 사파리에서 안열림, 네이버 웨일에서는 열림

# 시작코드

export FLASK_APP=main.py

flask run --host=0.0.0.0 --port=5000

'<Cloud> > AWS' 카테고리의 다른 글

Lambda Container 연습  (0) 2021.08.25
EC2 user data 에 start.sh  (0) 2021.05.09
Flask + EC2 튜토리얼  (0) 2021.05.09
Aws acedemy Module1  (0) 2021.03.09
AWS S3,Lamda,CLI 활용한 파일 upload/download  (0) 2021.01.13

<텍스트파일 생성후 저장>

[학번@linux-pplab ~]$ cat << END > file.txt

> Hello!

> My job is student.

> Good bye.

> END

[학번@linux-pplab ~]$ cat file.txt

혹은 touch 파일이름

 

 

<파일삭제>

>rm 파일이름

**sudo rm-rf / 포맷수준 삭제

rm -r home/     #디렉토리 삭제

 

<작성하던 텍스트파일 나가기>

vim/ vi로 파일열기~~~

Esc + shift키 + ;키

 

 q (그냥나가기)변경사항없을떄

Wq(저장후나가기)

 q! 변경사항무시하고 그냥 나가기(저장x) 이렇게해줘야 다음에들어갈떄 안물어봄

 

 

<파일수정>

i 수정

i ->ctrl->dd 한줄삭제

 

<ls>

ls-al은 ls-a이랑 ls-l를 동시에 사용하기위한 명령어

ls -a 는 숨김파일도 보여주는 -a

ls -l은 https://www.leafcats.com/137     ,

http://www.incodom.kr/Linux/%EA%B8%B0%EB%B3%B8%EB%AA%85%EB%A0%B9%EC%96%B4/ls참조

 

ls-h -h는 스위치옵션이라고 kb/mb/gb 단위로 쉽게 파일사이즈 확인이 가능

 

<디렉터리, 파일생성>

mkdir dir

ls -ld dir

rm file1.txt.    # 파일삭제

'<문법>' 카테고리의 다른 글

SQL 정리 (기초탄탄, SQL 톺아보기 (입문과정))  (2) 2024.09.18

+ Recent posts