코딩일지/TIL: Today I Learned

20221206 TIL

야언 2022. 12. 6. 16:16

오늘의 한 일

  • 최종 프로젝트 - yolov5 사물인식 모델 학습 관련
  • 소셜 로그인

 

 

 

YOLOv5 모델 커스텀 트레이닝

 

 

1번 로보플로우를 이용하여 수작업 라벨링과

2번 방법에서 고민하던 도중에 아무리 생각해도 이미 라벨 박스 데이터가 있는데 이것을 이용하지 않으면 안될 것 같아 2번 방법을 더욱 고민해보았다.

 

json형태의 라벨을 yolov5에 맞춰 커스텀 하는 방법에 대해 고민중, 상호 튜터님께 질문드려 답을 얻을 수 있었다.

 

json 형태의 aihub 라벨링

여기서 우리가 원하는 것은 x, y 좌표와 width height를 가로 세로 비율로 나눠서 0~1의 값으로 나열하는 형태의 txt파일로 저장하는것.

 

 

import glob
import json

json_list = glob.glob('*.json')


for json_file in json_list:
    with open(json_file, 'r', encoding='UTF-8') as f:
        data = json.load(f)
        width = 1920
        height = 1080
        
        # x, y, 너비, 높이 구하기
        label_x = data['labelingInfo'][1]['box']['location'][0]['x']/width
        label_y = data['labelingInfo'][1]['box']['location'][0]['y']/height
        label_width = data['labelingInfo'][1]['box']['location'][0]['width']/width
        label_height = data['labelingInfo'][1]['box']['location'][0]['height']/height
        
        # 소수점 6번째까지
        # label_x = round(data['labelingInfo'][1]['box']['location'][0]['x']/width, 6) 
        # label_y = round(data['labelingInfo'][1]['box']['location'][0]['y']/height, 6)
        # label_width = round(data['labelingInfo'][1]['box']['location'][0]['width']/width, 6)
        # label_height = round(data['labelingInfo'][1]['box']['location'][0]['height']/height, 6)
        
        # 확인용
        # print(f'0, {label_x}, {label_y}, {label_width}, {label_height}')
        
        # .txt파일 저장
        file_name = json_file.split('.')[0] + '.txt' 
        with open(file_name, 'a', encoding='UTF-8') as f1:
            f1.write(f'0 {label_x} {label_y} {label_width} {label_height}')

 

이상의 함수로 class(0), x, y, width, height 의 형태를 가진 txt파일로 저장할 수 있었다.

 

사실 생각해볼 수 있는 방법이였던것 같은데 glob라던지 json 모듈, write 함수 등 직접 써보질 않아서 감이 안잡혔던 것 같다 ㅠㅠ

 

어쨋든 라벨링을 txt파일로 교체 후 train - valid - test 폴더에 70 20 10의 비율로 이미지와 라벨링 데이터를 넣고 data.yaml파일을 만들어주면 학습준비 완료

 

data.yaml

# Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]

train: sample/train/images  
val: sample/valid/images 

# Classes
names:
  0: erosion_ulcer

 

데이터 학습은 petdic 프로젝트때 한 것과 같이 코랩 환경에서 진행할 예정.

 

이미지 크기가 커서 epoch 조절을 얼마나 해야할지, 클래스는 몇 개를 넣어야 할지 고민이다..

 

일단 실험용으로 이미지 100장을 추려서 학습을 진행시켜봤는데 pt모델로 검증을 해보니 다 no detection만 뜨던데 이것도 문제다.. 

 

 

 

트러블슈팅

 

 

yolov5에서 요구하는 x, y의 값이 꼭지점이 아니라 센터값이였던거임~~~

 

label x label y값에 width, height를 1/2한 값을 더해주는것으로 해결

 

 

 

 

소셜 로그인 관련

 

 

포스트맨 get요청으로 보내면 여기서 안넘어가지네 ㅋㅋ

 

액세스키, 리프레시키 발급 완료
회원가입까지 확인 완료

 

 

일단 저번 프로젝트때 왜 발급까지만 성공했다고 하는지 알겠다. 발급과 계정 생성까지는 가능했는데

이걸 어떻게 토큰을 유지한 채로 프론트엔드(아마도 index.html)페이지로 보내지? views.py에서 해결해야 할 것 같은데?

 

자잘한건 참조했던 페이지와 동일하니 views.py만

참조 : https://velog.io/@kjyeon1101/%EC%86%8C%EC%85%9C%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EA%B5%AC%EA%B8%80

 

[DRF] 구글 소셜로그인 (JWT)

DRF + jwt + 소셜로그인초기 환경 세팅dj-rest-auth는 업데이트가 중단된 django-rest-auth 대신 사용하는 패키지로, 회원가입과 로그인, 소셜로그인 기능을 제공해준다. 추가적으로 비밀번호 찾기/리셋,

velog.io

 

user/views.py

 

# 소셜 로그인 연습중
from django.conf import settings
from allauth.socialaccount.models import SocialAccount
from dj_rest_auth.registration.views import SocialLoginView
from allauth.socialaccount.providers.google import views as google_view
from allauth.socialaccount.providers.oauth2.client import OAuth2Client
from django.http import JsonResponse
import requests
from json.decoder import JSONDecodeError
from django.shortcuts import redirect


state = getattr(settings, 'STATE')
BASE_URL = 'http://localhost:8000/'
GOOGLE_CALLBACK_URI = BASE_URL + 'user/google/callback/'

def google_login(request):
    """
    Code Request
    """
    scope = "https://www.googleapis.com/auth/userinfo.email"
    client_id = getattr(settings, "SOCIAL_AUTH_GOOGLE_CLIENT_ID")
    return redirect(f"https://accounts.google.com/o/oauth2/v2/auth?client_id={client_id}&response_type=code&redirect_uri={GOOGLE_CALLBACK_URI}&scope={scope}")
def google_callback(request):
    client_id = getattr(settings, "SOCIAL_AUTH_GOOGLE_CLIENT_ID")
    client_secret = getattr(settings, "SOCIAL_AUTH_GOOGLE_SECRET")
    code = request.GET.get('code')
    """
    Access Token Request
    """
    token_req = requests.post(
        f"https://oauth2.googleapis.com/token?client_id={client_id}&client_secret={client_secret}&code={code}&grant_type=authorization_code&redirect_uri={GOOGLE_CALLBACK_URI}&state={state}")
    token_req_json = token_req.json()
    error = token_req_json.get("error")
    if error is not None:
        raise JSONDecodeError(error)
    access_token = token_req_json.get('access_token')
    """
    Email Request
    """
    email_req = requests.get(
        f"https://www.googleapis.com/oauth2/v1/tokeninfo?access_token={access_token}")
    email_req_status = email_req.status_code
    if email_req_status != 200:
        return JsonResponse({'err_msg': 'failed to get email'}, status=status.HTTP_400_BAD_REQUEST)
    email_req_json = email_req.json()
    email = email_req_json.get('email')
    """
    Signup or Signin Request
    """
    try:
        user = User.objects.get(email=email)
        # 기존에 가입된 유저의 Provider가 google이 아니면 에러 발생, 맞으면 로그인
        # 다른 SNS로 가입된 유저
        social_user = SocialAccount.objects.get(user=user)
        if social_user is None:
            return JsonResponse({'err_msg': 'email exists but not social user'}, status=status.HTTP_400_BAD_REQUEST)
        if social_user.provider != 'google':
            return JsonResponse({'err_msg': 'no matching social type'}, status=status.HTTP_400_BAD_REQUEST)
        # 기존에 Google로 가입된 유저
        data = {'access_token': access_token, 'code': code}
        accept = requests.post(
            f"{BASE_URL}user/google/login/finish/", data=data)
        accept_status = accept.status_code
        if accept_status != 200:
            return JsonResponse({'err_msg': 'failed to signin'}, status=accept_status)
        accept_json = accept.json()
        accept_json.pop('user', None)
        return JsonResponse(accept_json)
    except User.DoesNotExist:
        # 기존에 가입된 유저가 없으면 새로 가입
        data = {'access_token': access_token, 'code': code}
        accept = requests.post(
            f"{BASE_URL}user/google/login/finish/", data=data)
        accept_status = accept.status_code
        if accept_status != 200:
            return JsonResponse({'err_msg': 'failed to signup'}, status=accept_status)
        accept_json = accept.json()
        accept_json.pop('user', None)
        return JsonResponse(accept_json)
class GoogleLogin(SocialLoginView):
    adapter_class = google_view.GoogleOAuth2Adapter
    callback_url = GOOGLE_CALLBACK_URI
    client_class = OAuth2Client

 

계정이 없다면 회원가입 후, 있다면 바로 토큰 발급

 

JsonResponse로 return하므로 마지막 페이지가 각 토큰을 표시한 페이지인것 같다.

 

이제 이 발급받은 토큰들을 로컬스토리지에 저장한 채로 프론트엔드의 index.html로 보내야 하는데.. 어떻게?