3 minute read

Trouble Shooting

에러 0. 큰 파일의 github push 오류.

개요

  • 어제 글 작성을 마무리하고, 제작한 코드를 pycharm에서 push하려는 순간 push가 거부당했다.
  • 100MB이상의 파일을 github에 업로드하려해서 막힌 경우.
  • 생성한 데이터셋 (.npz)파일이 100MB를 넘는것이 이유였다.
  • 문제는, local repository에 commit할때 .npz파일이 포함되어, commit history를 날려버리지 않는 이상 계속 오류가 날수밖에 없는 상황이었다.

    해결(?) 과정

  • 방법1.
    • 이 글의 내용을 기반으로 git repo에서 큰 파일을 지우고 BFG를 이용하여 repo를 청소한 후, 재업로드 실행.
    • 실패.
  • 방법2.
    • 어차피 혼자 제작하는 프로젝트이니, 리포지토리를 삭제하고 새로 만들었다.
    • pycharm에서도 프로젝트를 새로 만들어 코드와 리소스를 붙여넣기 한 후, 리포지토리를 연동하여 해결했다.
    • 이걸 해결이라 보긴 애매하지만, 잘 작동하니 해결된것으로 했다.

에러 1.이미지 데이터 ndarray load 오류

개요

  • 어제 잠들기 전까지 계속 연구했었던 ndarray 문제.
  • 저장된 npz파일에서 뽑아낸 array가 tensor로 변환되지 않던 문제.

해결 과정

  • 낮에 맨정신으로 코드를 다시 살펴보던 도중, npz로 파일을 저장하는 코드에서
    xy = (X_train, X_test, Y_train, Y_test)
    

    로 묶어주는 부분을 제거하고,

np.savez('./img_data_crop.npz',X_train=X_train,X_test=X_test,Y_train=Y_train,Y_test=Y_test)

와 같이 세이브할때 인수를 넣어준 다음,

with np.load('./img_data_crop.npz',allow_pickle=True) as data:
   X_train = data['X_train']
   Y_train = data['Y_train']
   X_test = data['X_test']
   Y_test = data['Y_test']

으로 데이터를 호출하니 tensor로 변환할수 없다는 오류메세지는 출력되지 않았다.

  • 조금 더 조사해본 결과, 이런 튜토리얼을 확인할수 있었다.
    • 내용을 요약하면, tensor 연산을 하면 ndarray는 자동으로 tensor로 변환된다는것이었다.
    • 여태 내가 겪은 에러들의 경우, 한차례 데이터가 묶여있어 이상하게 출력이 되는것이 원인이었던것.

에러 2. Dst tensor is not initialized.

개요.

  • 에러1을 해결하자 대신 나타난 에러 메시지이다.

    해결 과정

  • 구글링을 하자, 이런 글을 발견할수 있었다.
    • 해당 글에서는 원인을 크게 두가지로 설명한다.
      1. GPU의 메모리 부족
      2. 잘못된 차원의 dataset이 input됨
  • GPU 메모리 부족으로 간주하고, batch-size를 줄이는 등의 작업을 진행했으나 여전히 메모리 부족현상이 관찰됨.
  • 오류가 나는 코드인
    test_dataset = tf.data.Dataset.from_tensor_slices((X_test,Y_test))
    

    를 중점으로 조사한 결과, stackoverflow의 글 하나를 발견할수 있었다.

    • 해당 글에 따르면, 내가 사용하고 있던 from_tensor_slices는 소량의 데이터를 가공하는데에만 유용하기 때문에 메모리 에러가 발생한다고 한다.
    • 해당 글에서는 TFRecodeDataSet을 활용하는 방안을 제시해주어서, 해당 내용에 대해 학습하고 적용해보기로 했다.

TFRecord?

  • 참고한 글
  • Tensorflow로 기계학습을 할 때, 학습 데이터 세트를 읽어들이는 방법은 네가지가 존재한다.
    1. 사전에 메모리를 모든 데이터에 로드
    2. Python 코드로 조금씩 읽어들여가면서 feed_dict그래프에 입력한다.
    3. TFRecord로부터 그래프상에 Threading과 Queues를 활용하면서 읽는다
    4. Dataset API를 사용한다.
  • 1번은 데이터 세트가 작을때는 고속으로 데이터를 그래프에 입력하는것이 가능하나, 데이터가 큰 경우 메모리 부족이 발생해 속도가 낮아지거나, 메모리 할당 오류가 발생한다.

  • 2번은 싱글 스레드를 사용할 경우, 데이터 읽어들이기와 학습을 동시에 하게 되는 경우가 발생해 전체 학습 시간이 길어진다.

  • TFRecord를 사용한다면 3번이나 4번의 방법으로 Tensorflow 그래프에 입력하게 된다.

  • 예제를 아무리 찾아보아도 제대로 적용할수가 없어, 기본적인 텐서플로우의 파이프라인에 대해 이해하고 넘어갈 필요를 느꼈다.

Tensorflow 파이프라인 개념정리

  • Tensorflow의 튜토리얼의 내용을 기반으로 작성했다.

    데이터세트 생성

  • 데이터 소스
    • 메모리 또는 하나 이상의 파일에 저장된 데이터로부터 Dataset을 구성
      • tf.data.Data.from_tensors()
      • tf.data.Dataset.from_tensor_slices()
      • tf.data.TFRecordDataset()
        • 입력데이터가 TFRecord 형식일때 사용.
  • 데이터 변환
    • 하나 이상의 tf.data.Dataset 객체로부터 데이터 세트를 구성
      • Dataset.map()
        • 요소별 변환
      • Dataset.batch()
        • 다중 요소 변환

데이터 세트의 정의 및 특징

  • 데이터세트 = 동일한 중첩 구조를 가지는 시퀀스.
    • 중첩 구조
      • tuple
      • dict
      • NamedTuple
      • list(단, tf.stack을 사용한 명시적 구성 필요)
  • 데이터세트는 tf.TypeSpec에 의해 표현된다.
    • 데이터 세트의 종류
      • tf.Tensor
      • tf.sparse.SparseTensor
      • tf.RaggedTensor
      • tf.TensorArray
      • tf.data.Dataset
  • Dataset.element_spec를 사용하여 구조 확인 가능.

입력 데이터 읽기

  • Numpy 데이터 읽기
    • Dataset.from_tensor_slices()가 가장 간단.
      • 하지만, 오늘 결과를 봤듯이, 큰 데이터는 메모리 부족으로 오류가 발생한다.
    • Dataset.from_generator()
      • 파이썬 generator를 활용해 데이터를 읽어들인다.
      • from_generator에 파이썬 generator callable함수를 인수로 넣어 tf.data.Dataset으로 변환한다.
      • Python GIL의 영향을 받는다.
        • Python GIL이란?
        • 간단히 말해서, 멀티스레딩이 안된다는 소리.
        • Python GIL도 중요한 개념같아보이니 언젠가 따로 정리해봐야겠다.
      • from_generator()의 예시로 제시된 ImageDataGenerator를 활용해 데이터셋의 생성을 성공할수 있었다.
        • 굳이 numpy를 통해 따로 데이터셋을 생성하려던 나의 시도가 헛수고가 되어버렸지만, 그래도 된다는 사실이 기쁘다.

공부를 위해 정리하는것 역시 좋지만,

지금 당장은 작업이 급하기 때문에 정리는 여기까지만 진행하고, 나중에 프로젝트 완료후 되짚어보는 방식으로 정리하도록 해야겠다.

ImageDataGenerator

  • tf.keras.preprocessing.image.ImageDataGenerator
  • 하위의 함수들과 함께 사용하여 이미지 데이터를 데이터셋으로 변환한다.
  • 이번에 사용한것은 flow_from_directory 함수다.
    • 상위 디렉터리를 입력받아 하위 디렉터리를 class로 하는 데이터셋을 생성한다.
  • 파이프라인 튜토리얼에서 함께 언급된 from_generator까지 활용한 최종 코드는 다음과 같다.

다음 할 일

  • 생성한 이미지셋을 모델에 넣고 학습시키려 했으나, Shape mismatch에러가 발생했다.
    • 어제까지는 밥숟가락도 안들던 아기를 보는 기분이라면,
      오늘은 한숟가락 먹고 맛없다고 뱉어내는 아기를 보는 기분이다.
    • 학습이라도 하려 했다는것에 일단 기뻐하기로 했다.
  • Shape mismatch에러면 분명 차원수 맞추기에 관련된 문제일테니, 구글링과 노가다를 통해 디버깅해야겠다.