[go: up one dir, main page]

탑이미지.jpg

Google Play | Indie Games Festival 2018 접수가 시작되었습니다!

Google Play | Indie Games Festival 2018의 전체적인 개요와 함께 수상자에게 수여될 상품, 심사위원 등이 결정되어 본격적인 게임 접수가 시작되었습니다. 2017년 1월1일 이후로 출시 되었거나 베타 버전으로 제작 중인 게임에 한하여 참가가 가능합니다. Android 게임을 개발하고 있는 개인, 그룹 및 단체, 혹은 중소기업은 본 대회에 꼭 도전해 보시기 바랍니다.

또한, 일반 게임 유저들을 대상으로 4월21일(토) 개최되는 파이널 이벤트의 관람 신청도 본격적으로 시작하였습니다.

참가 자격 및 공식 절차에 관한 세부 내용은 반드시 공식 웹사이트에서 확인하시기 바랍니다.

향후 일정

  • 3 월 25 일:게임 접수 마감
  • 4 월 10 일:Top 20 Finalist 발표
  • 4 월 21 일:파이널 이벤트 개최

파이널 이벤트 개요

  • 일시:4 월 21 일(토) 10 - 17 시
  • 장소:넥슨아레나 (서울시 서초구 서초대로77길 54 서초더블유타워 지하 1층)
  • 참여 방법:
    • 게임 개발자 --- 게임 접수 후 Top 20 Finalist에 선정된 게임 개발자.
    • 일반 게임 유저 --- 응모 후 추첨제. 참가비 무료.
  • 당일 일정
    • 10 시:개장. 전시된 Top 20 중 Top 10 투표
    • 13 시:Top 10 투표 마감
    • 14 시:Top 10 발표
    • 14 시 30 분:Top 10 프레젠테이션 및 Top 3 결정
    • 16 시 30 분:시상식
* 대회 참가신청 접수 마감은 3월25일 11:59PM까지입니다.
* 대회에 참가하지 않더라도 일반관람을 신청하실 수 있습니다.


▶ 대회 참가신청 하기
▶ 대회 일반 관람신청 하기 


* 상세 참가 자격조건 / 수상자에게 주어지는 다양한 혜택 / 결승행사 관람 및 세부 진행과정은 홈페이지를 통해 확인해 주시기 바랍니다.

<블로그 원문은 이곳에서 확인하실 수 있으며, 블로그 번역 리뷰는 김태호(Google)님이 참여해 주셨습니다.>

오늘 저희는 구글 모바일 광고(Google Mobile Ads) SDK를 사용하여 테스트 광고를 요청할 때의 동작이 어떻게 변경되었는지 알려드리고자 합니다. 여러분들은 이제 광고 단위를 테스트할 때 현재 테스트 모드에서 작업 중인지 여부를 명확하게 확인할 수 있게 되었습니다.

개발 과정에서 구글 모바일 광고 SDK를 사용할 때는 테스트 광고를 사용하도록 설정하는 것이 좋습니다. 개발 과정에서 테스트 광고가 아닌 광고를 요청하거나 클릭하는 행위는 자칫 자신의 광고 계정에 좋지 않은 영향을 미칠 수 있습니다. 따라서 항상 테스트 광고를 사용하는 것이 중요합니다.

이전에는 테스트 광고를 요청하면 아래 그림과 같은 샘플 광고가 표시되었습니다.
이는 기본적인 부분을 검사하는 정도로는 괜찮았지만, 프로덕션 환경에서 노출되는 실제 광고를 보여주는 것이 아니기에 실제 광고가 애플리케이션에서 어떻게 표시되는지 확인하기엔 어려웠습니다. 예를 들어, 미디에이션 구성을 테스트하거나 애드몹에서 제공하는 다양한 유형의 배너 혹은 전면광고 포맷을 테스트할 수 없었습니다. 이번 업데이트를 통해 이러한 문제를 해결하고자 합니다.

변경된 테스트 광고 동작

Android는 구글 모바일 광고 SDK 11.6.0 이상, iOS는 Google 모바일 광고 SDK 7.26.0 이상을 사용하여 빌드한 앱은 광고주에게 요금을 부과하지 않고 프로덕션 환경에 표시되는 것과 똑같은 광고를 표시하는 새로운 테스트 광고를 사용할 수 있습니다. 덕분에 잘못된 활동으로 인해 계정에 악영향을 미치는 일 없이 광고의 동작을 안전하게 테스트할 수 있습니다.

배너, 삽입형 및 보상형 비디오 테스트 광고의 가운데 위쪽 부분에는 이제 'Test Ad'라는 레이블이 표시되어 반환되는 광고가 사실은 테스트 광고라는 점을 시각적으로 보여줍니다.
샘플 300x250 배너 광고

네이티브 광고의 경우 headline 텍스트 앞에 'Test Ad'라는 텍스트가 추가됩니다.

샘플 네이티브 콘텐츠 광고

미디에이션을 사용하는 광고 단위의 테스트 광고

미디에이션을 사용하는 광고 단위에서는 구글 광고에만 테스트 광고 레이블이 표시되며, 타사 광고 네트워크에서 표시되는 광고에는 테스트 광고 레이블이 표시되지 않습니다. 따라서 타사 광고 네트워크의 테스트가 해당 네트워크에서 규정한 정책을 준수하는지 확인할 책임은 개발자 자신에게 있습니다. 미디에이션 네트워크에서 테스트 광고를 활성화하는 방법에 대한 자세한 내용은 각 미디에이션 네트워크의 관련 미디에이션 가이드를 참조하세요.

구글 모바일 광고 SDK에서 테스트 광고를 활성화하는 방법에 대한 자세한 내용은 테스트 가이드(Android | iOS)를 참조하세요. 궁금한 사항이 있으시면 개발자 포럼에서 문의하시기 바랍니다.


- Eric Leichtenschlag, 모바일 광고 개발자 지원 담당자

<블로그 원문은 여기에서 확인하실 수 있으며, 블로그 번역 리뷰는 곽동현(Machine Learning GDE)님이 참여해 주셨습니다.>

게시자: TensorFlow 팀

이 글은 TensorFlow Dataset 및 Estimator를 소개하는 블로그 시리즈의 제3부입니다. 제1부에서는 사전 제공 Estimator를 중점적으로 다루었고, 제2부에서는 특성 열에 대해 설명했습니다. 제3부에서는 커스텀 Estimator를 만드는 방법을 배웁니다. 특히 Iris(붓꽃) 문제를 해결할 때 DNNClassifier의 동작을 모방하는 커스텀 Estimator를 만드는 방법을 시연해 보겠습니다.

그때까지 기다릴 수 없다면 다음 전체 프로그램을 비교하고 대조해 보세요.

  • 사전 제공 DNNClassifier Estimator로 구현된 Iris의 소스 코드는 여기를 참조하세요.
  • 커스텀 Estimator로 구현된 Iris의 소스 코드는 여기를 참조하세요.

사전 제공 Estimator와 커스텀 Estimator의 비교

그림 1에 나오는 것처럼, 사전 제공 Estimator는 tf.estimator.Estimator 기본 클래스의 서브클래스이고, 커스텀 Estimator는 tf.estimator.Estimator:의 인스턴스입니다.

그림 1. 사전 제공 Estimator와 커스텀 Estimator는 모두 Estimator입니다.

사전 제공 Estimator는 그 자체가 완성된 버전입니다. 하지만 때로는 Estimator의 동작을 보다 세부적으로 제어할 필요가 있습니다. 그것이 바로 커스텀 Estimator가 필요한 이유입니다.

커스텀 Estimator를 생성하여 원하는 동작을 수행할 수 있습니다. 숨겨진 계층을 특별한 방식으로 연결하고 싶으면 커스텀 Estimator를 작성하세요. 모델의 고유 측정함수를측정항목을 사용계산하려면 커스텀 Estimator를 작성하세요. 기본적으로 특정 문제에 맞게 최적화된 Estimator를 원하면 커스텀 Estimator를 작성하세요.

모델 함수(model_fn)는 모델을 구현합니다. 사전 제공 Estimator와 커스텀 Estimator 사용 시 유일한 차이점은 다음과 같습니다.

  • 사전 제공 Estimator의 경우, 누군가가 이미 모델 함수를 작성해 두었습니다. 
  • 커스텀 Estimator의 경우, 자신이 직접 모델 함수를 작성해야 합니다. 
모델 함수는 모든 종류의 숨겨진 계층과 측정함수를 정의하는 광범위한 알고리즘을 구현할 수 있습니다. 입력 함수와 마찬가지로, 모든 모델 함수는 입력 매개변수로 구성된 표준 그룹을 받아들이고 출력 값으로 구성된 표준 그룹을 반환해야 합니다. 입력 함수가 Dataset API를 활용할 수 있는 것처럼, 모델 함수는 Layers API 및 Metrics API를 활용할 수 있습니다.

Iris를 사전 제공 Estimator로: 간략히 살펴보기

Iris를 커스텀 Estimator로 구현하는 방법을 시연하기 전에 이 시리즈의 제1부에서 Iris를 사전 제공 Estimator로 구현한 방법을 다시 떠올려 보세요. 제1부에서는 다음과 같이 사전 제공 Estimator의 인스턴스를 생성하는 방식으로 Iris 데이터세트에 완벽하게 연결된 심층 신경망을 만들었습니다.

# Instantiate a deep neural network classifier.
classifier = tf.estimator.DNNClassifier(
  feature_columns=feature_columns, # The input features to our model.
  hidden_units=[10, 10], # Two layers, each with 10 neurons.
  n_classes=3, # The number of output classes (three Iris species).
  model_dir=PATH) # Pathname of directory where checkpoints, etc. are stored.

앞의 코드는 다음과 같은 특성을 가진 심층 신경망을 만듭니다.
  • 특성 열의 목록. (특성 열의 정의는 앞의 스니펫에는 표시되어 있지 않습니다.) Iris의 경우, 특성 열은 4개의 입력 특성을 숫자로 표현한 것입니다. 
  • 각각 10개의 뉴런을 가진 2개의 완전히 연결된 계층. 완전히 연결된 계층(조밀한 계층이라고도 함)은 후속 계층의 모든 뉴런에 연결됩니다.
  • 3요소 목록으로 구성된 출력 계층. 이 목록의 요소는 모두 부동 소수점 값으로, 이들 값의 합은 1.0이어야 합니다(이 값은 확률 분포임). 
  • 학습된 모델과 다양한 체크포인트가 저장되는 디렉토리(PATH). 
그림 2는 Iris 모델의 입력 계층, 숨겨진 계층 및 출력 계층을 보여줍니다. 명확성과 관련된 이유 때문에 각각의 숨겨진 계층에 4개의 노드만 그렸습니다.

그림 2. Iris의 구현에는 4개의 특성, 2개의 숨겨진 계층 및 로짓(logit) 출력 계층이 포함되어 있습니다.

커스텀 Estimator로 동일한 Iris 문제를 해결하는 방법을 알아봅시다.

입력 함수

Estimator 프레임워크의 가장 큰 장점 중 하나는 데이터 파이프라인을 변경하지 않고 다양한 알고리즘으로 실험할 수 있다는 점입니다. 따라서 제1부에서 언급한 입력 함수 중 많은 부분을 재사용할 것입니다.

def my_input_fn(file_path, repeat_count=1, shuffle_count=1):
  def decode_csv(line):
      parsed_line = tf.decode_csv(line, [[0.], [0.], [0.], [0.], [0]])
      label = parsed_line[-1]  # Last element is the label
      del parsed_line[-1]  # Delete last element
      features = parsed_line  # Everything but last elements are the features
      d = dict(zip(feature_names, features)), label
      return d

  dataset = (tf.data.TextLineDataset(file_path)  # Read text file
      .skip(1)  # Skip header row
      .map(decode_csv, num_parallel_calls=4)  # Decode each line
      .cache() # Warning: Caches entire dataset, can cause out of memory
      .shuffle(shuffle_count)  # Randomize elems (1 == no operation)
      .repeat(repeat_count)    # Repeats dataset this # times
      .batch(32)
      .prefetch(1)  # Make sure you always have 1 batch ready to serve
  )
  iterator = dataset.make_one_shot_iterator()
  batch_features, batch_labels = iterator.get_next()
  return batch_features, batch_labels

입력 함수는 다음 2개의 값을 반환합니다.

  • batch_features: Dictionary사전입니다. Dictionary사전의 키는 특성의 이름이고 사전의 값은 특성의 값입니다. 
  • batch_labels: 배치의 레이블 값 목록입니다. 
입력 함수에 대한 자세한 내용은 제1부를 참조하세요.

특성 열 생성

시리즈의 제2부에서 자세히 설명했듯이, 모델의 특성 열을 정의하여 각 특성의 표현을 지정해야 합니다. 사전 제공 Estimator를 사용하든 커스텀 Estimator를 사용하든, 동일한 방식으로 특성 열을 정의합니다. 예를 들어, 다음은 Iris 데이터세트의 네 가지 특성(모두 숫자)을 나타내는 특성 열을 생성하는 코드입니다.

feature_columns = [
  tf.feature_column.numeric_column(feature_names[0]),
  tf.feature_column.numeric_column(feature_names[1]),
  tf.feature_column.numeric_column(feature_names[2]),
  tf.feature_column.numeric_column(feature_names[3])
]

모델 함수 작성

이제 커스텀 Estimator용 model_fn을 작성할 준비가 되었습니다. 함수 선언부터 시작해 봅시다.

def my_model_fn(
  features, # This is batch_features from input_fn
  labels,   # This is batch_labels from input_fn
  mode):    # Instance of tf.estimator.ModeKeys, see below

처음 2개의 인자는 입력 함수에서 반환된 특성과 레이블입니다. 즉, featureslabels는 모델에서 사용할 데이터에 대한 핸들입니다. mode 인자는 호출자가 훈련, 예측 또는 평가를 요청하는지 여부를 나타냅니다.

일반적인 모델 함수를 구현하려면 다음을 수행해야 합니다.

  • 모델의 계층을 정의합니다. 
  • 세 가지 서로 다른 모드로 모델의 동작을 지정합니다.

모델의 계층 정의

커스텀 Estimator가 심층 신경망을 생성하는 경우 다음 3개의 계층을 정의해야 합니다.

  • 입력 계층 
  • 하나 이상의 숨겨진 계층 
  • 출력 계층 
Layers API(tf.layers)를 사용하여 숨겨진 계층과 출력 계층을 정의합니다.

커스텀 Estimator가 선형 모델을 생성하는 경우 단일 계층을 생성하기만 하면 되며, 이에 대해서는 다음 섹션에서 설명하겠습니다.

입력 계층 정의

tf.feature_column.input_layer를 호출하여 심층 신경망의 입력 계층을 정의합니다. 예:

# Create the layer of input
input_layer = tf.feature_column.input_layer(features, feature_columns)

앞의 행은 입력 계층을 생성하고 입력 함수를 통해 features를 읽고 이전에 정의한 feature_columns를 통해 필터링합니다. 특성을 통해 데이터를 표현하는 다양한 방법에 대한 자세한 내용은 제2부를 참조하세요.

선형 모델의 입력 계층을 생성하려면 tf.feature_column.input_layer 대신 tf.feature_column.linear_model을 호출하세요. 선형 모델에는 숨겨진 계층이 없으므로 tf.feature_column.linear_model의 반환 값이 입력 계층과 출력 계층의 역할을 모두 수행합니다. 즉, 이 함수의 반환 값은 예측입니다.

숨겨진 계층 설정

심층 신경망을 생성하는 경우 하나 이상의 숨겨진 계층을 정의해야 합니다. Layers API는 컨벌루션, 풀링 및 드롭아웃 계층을 포함한 모든 숨겨진 계층 유형을 정의하는 다양한 함수 세트를 제공합니다. Iris의 경우, 단순히 tf.layers.Dense를 두 번 호출하여 각각 10개의 뉴런이 있는 2개의 조밀한 숨겨진 계층을 생성합니다. '조밀하다'는 것은 첫 번째 숨겨진 계층의 각 뉴런이 두 번째 숨겨진 계층의 각 뉴런에 연결된다는 의미입니다. 다음은 관련 코드입니다.

# Definition of hidden layer: h1
# (Dense returns a Callable so we can provide input_layer as argument to it)
h1 = tf.layers.Dense(10, activation=tf.nn.relu)(input_layer)

# Definition of hidden layer: h2
# (Dense returns a Callable so we can provide h1 as argument to it)
h2 = tf.layers.Dense(10, activation=tf.nn.relu)(h1)

tf.layers.Dense에 대한 inputs 매개변수는 선행 계층을 식별합니다. 선행 h1 계층은 입력 계층입니다.

그림 3. 입력 계층은 숨겨진 계층 1로 전달됩니다.
h2에 대한 선행 계층은 h1입니다. 따라서 이제 계층 문자열이 다음과 같이 나타납니다.

그림 4. 숨겨진 계층 1은 숨겨진 계층 2로 전달됩니다.
tf.layers.Dense의 첫 번째 인자는 출력 뉴런 수를 정의합니다(이 경우에는 10).

activation 매개변수는 활성화 함수를 정의합니다(이 경우에는 Relu).

tf.layers.Dense는 다양한 정규화 매개변수를 설정할 수 있는 기능을 비롯한 많은 추가 기능을 제공합니다. 하지만 간단히 하기 위해 다른 매개변수의 기본값을 그냥 받아들이겠습니다. 또한, tf.layers를 살펴보면 소문자 버전을 목격할 수 있습니다(예: tf.layers.dense). 일반적으로 대문자로 시작하는 클래스 버전을 사용해야 합니다(tf.layers.Dense).

출력 계층

tf.layers.Dense를 다시 호출하여 출력 계층을 정의하겠습니다.

# Output 'logits' layer is three numbers = probability distribution
# (Dense returns a Callable so we can provide h2 as argument to it)
logits = tf.layers.Dense(3)(h2)

출력 계층은 h2에서 입력을 받는다는 점에 유의하세요. 따라서 다음과 같이 전체 계층 세트가 연결됩니다.


그림 5. 숨겨진 계층 2는 출력 계층으로 전달됩니다.

출력 계층을 정의할 때 units 매개변수는 가능한 출력 값의 수를 지정합니다. 따라서 units를 3으로 설정하여 tf.layers.Dense 함수가 3요소 로짓 벡터를 구성합니다. 로짓 벡터의 각 셀에는 각각 Setosa, Versicolor 또는 Virginica인 Iris의 확률이 포함되어 있습니다.

출력 계층은 최종 계층이므로 tf.layers.Dense를 호출하면 선택적 activation 매개변수가 생략됩니다.

훈련, 평가 및 예측 구현

모델 함수 생성의 마지막 단계는 예측, 평가 및 훈련을 구현하는 분기 코드를 작성하는 것입니다.

모델 함수는 누군가 Estimator의 train, evaluate 또는 predict 메서드를 호출할 때마다 호출됩니다. 모델 함수의 서명은 다음과 같은 형태입니다.

def my_model_fn(
  features, # This is batch_features from input_fn
  labels,   # This is batch_labels from input_fn
  mode):    # Instance of tf.estimator.ModeKeys, see below

세 번째 인자 mode에 주목하시기 바랍니다. 다음 표에 나오는 것처럼 누군가 train, evaluate 또는 predict를 호출하면 Estimator 프레임워크는 mode parameter가 다음과 같이 설정된 모델 함수를 호출합니다.

표 2. 모드의 값.
호출자가 커스텀 Estimator 메소드 호출...
Estimator 프레임워크는 mode 매개변수가 다음으로 설정된 모델 함수 호출...
train()
ModeKeys.TRAIN
evaluate()
ModeKeys.EVAL
predict()
ModeKeys.PREDICT

예를 들어 커스텀 Estimator를 인스턴스화하여 classifier라는 객체를 생성한다고 가정해 봅시다. 이어서 다음 호출을 수행합니다. (이 시점에서 my_input_fn의 매개변수는 신경 쓰지 마세요.)

classifier.train(
 input_fn=lambda: my_input_fn(FILE_TRAIN, repeat_count=500, shuffle_count=256))

그러면 Estimator 프레임워크는 modeModeKeys.TRAIN으로 설정된 model 함수를 호출합니다.

모델 함수는 3개의 mode 값을 모두 처리할 코드를 제공해야 합니다. 각 모드 값에 대해, 코드에서 호출자가 필요로 하는 정보가 포함된 tf.estimator.EstimatorSpec의 인스턴스를 반환해야 합니다. 각 모드를 살펴봅시다.


PREDICT

model_fnmode == ModeKeys.PREDICT 상태로 호출되면, 모델 함수는 다음 정보를 포함한 tf.estimator.EstimatorSpec을 반환해야 합니다.
  • 모드(tf.estimator.ModeKeys.PREDICT
  • 예측 
예측을 수행하기 전에 모델에 대한 훈련을 실시해야 합니다. 훈련된 모델은 Estimator를 인스턴스화할 때 설정된 디스크의 디렉토리에 저장됩니다.

여기서 다루는 사례에서는 예측 생성 코드가 다음과 같습니다.

# class_ids will be the model prediction for the class (Iris flower type)
# The output node with the highest value is our prediction
predictions = { 'class_ids': tf.argmax(input=logits, axis=1) }

# Return our prediction
if mode == tf.estimator.ModeKeys.PREDICT:
  return tf.estimator.EstimatorSpec(mode, predictions=predictions)

블록이 놀라울 정도로 짧습니다. 이 코드들은 단지 굴러오는 예측을 잡는 긴 호스 끝의 통일 뿐입니다. 결국, Estimator는 예측을 수행하기 위한 어려운 과정을 이미 모두 완료했습니다.
  • 입력 함수는 모델 함수에 추론할 데이터(특성 값)를 제공합니다. 
  • 모델 함수는 이러한 특성 값을 특성 열로 변환합니다. 
  • 모델 함수는 이전에 훈련된 모델을 통해 해당 특성 열을 실행합니다. 
출력 계층은 입력되는 꽃인 3가지 Iris 종 각각의 값을 포함하는 logits 벡터입니다. tf.argmax 메서드는 해당 logits 벡터에서 가장 높은 값을 가진 Iris 종을 선택합니다.

가장 높은 값은 class_ids라는 사전 키에 할당됩니다. 우리는 tf.estimator.EstimatorSpec의 predictions 매개변수를 통해 해당 사전을 반환합니다. 그러면 호출자가 Estimator의 predict 메서드로 다시 전달된 사전을 검사하여 예측을 가져올 수 있습니다.

EVAL

model_fnmode == ModeKeys.EVAL로 호출되면 모델 함수가 모델을 평가하여 손실과 아마도 하나 또는 그 이상의 측정함수를 반환해야 합니다.

tf.losses.sparse_softmax_cross_entropy를 호출하여 손실을 계산할 수 있습니다. 전체 코드는 다음과 같습니다.

# To calculate the loss, we need to convert our labels
# Our input labels have shape: [batch_size, 1]
labels = tf.squeeze(labels, 1)          # Convert to shape [batch_size]
loss = tf.losses.sparse_softmax_cross_entropy(labels=labels, logits=logits)

이제는 측정함수에 주목해 봅시다. 측정함수 반환은 선택 사항이지만 대부분의 커스텀 Estimator는 하나 이상의 측정함수를 반환합니다. TensorFlow는 다양한 종류의 측정함수를계산하는 Metrics API(tf.metrics)를 제공합니다. 간단히 하기 위해, accuracy만 반환하도록 하겠습니다. tf.metrics.accuracy는 예측을 '실제 레이블', 즉 입력 함수가 제공한 레이블과 비교합니다. tf.metrics.accuracy 함수에서는 레이블과 예측이 (이전에 작성한 것과) 동일한 형태를 가져야 합니다. 다음은 tf.metrics.accuracy에 대한 호출입니다.

# Calculate the accuracy between the true labels, and our predictions
accuracy = tf.metrics.accuracy(labels, predictions['class_ids'])

모델이 mode == ModeKeys.EVAL로 호출되면, 모델 함수는 다음 정보를 포함한 tf.estimator.EstimatorSpec을 반환합니다.
  • mode(즉, tf.estimator.ModeKeys.EVAL
  • 모델의 손실 
  • 일반적으로 사전에 포함된 하나 이상의 측정함수
따라서 우리는 유일한 측정함수(my_accuracy)을를 포함하는 사전을 만들 것입니다. 다른 측정함수를 계산했다면 동일한 사전에 추가 키/값 쌍으로 추가했을 것입니다. 그런 다음 해당 사전을 tf.estimator.EstimatorSpeceval_metric_ops 인자에 전달합니다. 블록은 다음과 같습니다.

# Return our loss (which is used to evaluate our model)
# Set the TensorBoard scalar my_accurace to the accuracy
# Obs: This function only sets value during mode == ModeKeys.EVAL
# To set values during training, see tf.summary.scalar
if mode == tf.estimator.ModeKeys.EVAL:
  return tf.estimator.EstimatorSpec(
      mode,
      loss=loss,
      eval_metric_ops={'my_accuracy': accuracy})

TRAIN

model_fnmode == ModeKeys.TRAIN으로 호출되면 모델 함수가 모델을 훈련해야 합니다.

먼저 옵티마이저 객체를 인스턴스화해야 합니다. 다음 코드 블록에서 우리는 Adagrad(tf.train.AdagradOptimizer)를 선택했습니다. 역시 Adagrad를 사용하는 DNNClassifier을 모방할 것이기 때문입니다. tf.train 패키지는 다른 많은 옵티마이저 도구를 제공하므로 자유롭게 실험해 보세요.

이어서 옵티마이저에 대한 목표를 설정하여 모델을 훈련합니다. 목표는 단순히 loss를 최소화하는 것입니다. 그 목표를 분명히 하기 위해 minimize 메서드를 호출합니다.

아래 코드에서 선택적 global_step 인자는 TensorFlow가 처리된 배치 수를 계산하는 데 사용하는 변수를 지정합니다. global_steptf.train.get_global_step으로 설정하면 멋지게 작동할 것입니다. 또한, 훈련 도중에 TensorBoard에 my_accuracy를 보고하기 위해 tf.summary.scalar를 호출합니다. 이 과정에 대한 자세한 설명은 아래의 TensorBoard 섹션을 참조하세요.

optimizer = tf.train.AdagradOptimizer(0.05)
train_op = optimizer.minimize(
  loss,
  global_step=tf.train.get_global_step())

# Set the TensorBoard scalar my_accuracy to the accuracy
tf.summary.scalar('my_accuracy', accuracy[1])

모델이 mode == ModeKeys.TRAIN으로 호출되면 모델 함수는 다음 정보를 포함한 tf.estimator.EstimatorSpec을 반환해야 합니다.
  • 모드(즉, tf.estimator.ModeKeys.TRAIN) 
  • 손실 
  • 훈련 연산의 결과 
코드는 다음과 같습니다.

# Return training operations: loss and train_op
return tf.estimator.EstimatorSpec(
  mode,
  loss=loss,
  train_op=train_op)

이제 모델 함수가 완성되었습니다!

커스텀 Estimator

새 커스텀 Estimator를 만들고 나면 얼른 사용해보고 싶을 것입니다. 다음과 같이

Estimator 기본 클래스를 통해 커스텀 Estimator의 인스턴스화부터 시작하세요.

classifier = tf.estimator.Estimator(
  model_fn=my_model_fn,
  model_dir=PATH)  # Path to where checkpoints etc are stored

Estimator를 사용하여 훈련, 평가 및 예측하는 나머지 코드는 제1부에서 설명한 사전 제공 DNNClassifier의 경우와 동일합니다. 예를 들어, 다음 줄은 모델 교육을 트리거합니다.

classifier.train(
 input_fn=lambda: my_input_fn(FILE_TRAIN, repeat_count=500, shuffle_count=256))


TensorBoard

제1부에서와 같이 TensorBoard에서 일부 훈련 결과를 볼 수 있습니다. 이러한 보고 내용을 보려면 다음과 같이 명령줄에서 TensorBoard를 시작하세요.

# Replace PATH with the actual path passed as model_dir
tensorboard --logdir=PATH

이어서 다음 URL로 이동합니다.

localhost:6006

모든 사전 제공 Estimator는 많은 정보를 TensorBoard에 자동으로 기록합니다. 그러나 커스텀 Estimator를 사용하면 TensorBoard가 단 하나의 기본 로그(손실 그래프)와 TensorBoard에 명시적으로 기록하도록 지시한 정보만 제공합니다. 따라서 TensorBoard는 커스텀 Estimator에서 다음을 생성합니다.

그림 6. TensorBoard는 3개의 그래프를 표시합니다.
간단히 말해, 3개의 그래프가 나타내는 내용은 다음과 같습니다.

  • global_step/sec: 특정 배치(x축)에서 초당 처리된 배치(y축) 수(그라데이션 업데이트)를 보여주는 성능 표시기입니다. 이 보고서를 보려면 (tf.train.get_global_step()에서와 마찬가지로) global_step을 제공해야 합니다. 또한, 충분히 오랜 시간 동안 훈련해야 합니다. 이를 위해 train 메서드를 호출할 때 Estimator에 500 에포크(epoch) 동안의 교육을 요구합니다. 
    • loss: 보고된 손실입니다. 실제 손실 값(y축)은 그다지 의미가 없습니다. 중요한 것은 그래프의 모양입니다. 
  • my_accuracy: 다음 두 가지를 모두 호출할 때 기록된 정확도입니다. 
  • eval_metric_ops={'my_accuracy': accuracy}): EVAL 동안(EstimatorSpec 반환 시) 
  • tf.summary.scalar('my_accuracy', accuracy[1]): TRAIN 동안 
my_accuracyloss 그래프에서 다음 사항에 유의하세요.
  • 주황색 선은 TRAIN을 나타냅니다. 
  • 파란색 점은 EVAL을 나타냅니다. 
TRAIN 동안 주황색 값은 배치가 처리될 때 계속 기록되므로 x축 범위에 걸친 그래프가 됩니다. 반대로 EVAL은 모든 평가 단계 처리에서 단 하나의 값만 산출합니다.

그림 7에 제시된 것처럼 왼쪽의 훈련 및 평가에 대한 보고 기능을 보거나 선택적으로 비활성화/활성화할 수 있습니다. (그림 7은 두 가지 모두에 대해 계속 보고하고 있음을 보여줍니다.)

그림 7. 보고 기능 활성화 또는 비활성화

주황색 그래프를 보려면 전역 단계를 지정해야 합니다. 가장 좋은 방법은 global_steps/sec 보고와 함께 tf.train.get_global_step()optimizer.minimize 호출의 인자로 전달하여 항상 전역 단계를 등록하는 것입니다.

요약

사전 제공 Estimator는 새 모델을 신속하게 만드는 효과적인 방법일 수 있지만, 종종 커스텀 Estimator가 제공하는 추가적인 유연성이 필요한 경우가 있습니다. 다행히 사전 제공 Estimator와 커스텀 Estimator는 동일한 프로그래밍 모델을 따릅니다. 실제로 유일한 차이점은 커스텀 Estimator의 경우 모델 함수를 작성해야 한다는 점입니다. 그 밖의 모든 것은 동일합니다!

자세한 내용은 다음을 참조하세요.

  • 이 블로그 게시물의 전체 소스 코드
  • 커스텀 Estimator를 사용하는 MNIST의 공식 TensorFlow 구현. 또한, 이 모델은 특성 열(그리고 input_layer)을 사용하지 않고 원시 픽셀에서 숫자 값을 취하는 예시입니다. 
  • 커스텀 Estimator를 사용하여 큐레이팅된 예시를 추가로 포함할 수 있는 TensorFlow 공식 모델 저장소
  • TensorFlow Dev Summit에서 제공하는 TensorBoard 동영상에서는 재미있고 교육적인 방식으로 TensorBoard를 소개합니다.

다음 시간까지 TensorFlow 코딩을 즐기시기 바랍니다!

<이 블로그 포스트는 구글의 Developer Advocate Laurence Moroney의 Machine Learning in Firebase: Using Predictions 를 번역한 내용입니다. 블로그 번역은 양찬석(Google), 김태호(Google)님이 참여해 주셨습니다.>

Firebase 예측 (Firebase Prediction) 소개

Firebase 예측은 ‘예측 된 동작’을 기반으로 사용자 그룹을 생성합니다. Firebase 용 Google 애널리틱스를 기반으로 기계 학습을 적용하여, 앱 내에서 돈을 지출 할 가능성이 높은 사용자, 지출하지 않을 사용자, 앱 사용을 중단할 사용자와 계속 앱을 사용할 것 같은 ‘사용자 그룹’을 만들 수 있습니다. 이 그룹은 매일 업데이트되며 Firebase 알림, 원격 구성 등의 타겟팅에 사용할 수 있습니다.

이 블로그 포스트에서는 Firebase 예측의 설정 방법, 작동 방법, 사용자 정의 이벤트를 기반으로 예측을 설정하고 이를 추적하는 방법을 단계별로 설명합니다.


Firebase 예측의 동작 원리

Firebase 예측은 구글의 기계 학습 프레임워크인 텐서플로우(TensorFlow)를 사용합니다. 개발자의 앱에서 ‘Firebase 용 Google 애널리틱스’를 통해 수집된 최근 100일간의 데이터를 가져와 지도 학습(Supervised Learning) 형식으로 학습을 진행합니다. 이를 기반으로 사용자 행동을 예측(ML 용어로는 라벨링) 할 수 있는 주요 피쳐 및 모델을 생성합니다. 기본적으로 위에 언급한 4종류의 행동(구매자 / 비구매자 / 사용자 이탈 / 사용자 유지)을 예측할 수 있는 모델이 생성됩니다. 예를들어 어떤 사용자가 앱 사용을 중지할지 말지 여부(chrum)를 판별하는 경우, 지난 100일간 모든 앱 이벤트를 기반으로 앱 사용을 중지한 사용자의 행동 패턴을 학습합니다. 이렇게 학습된 모델을 기반으로 앞으로 7일내에 앱 사용을 중지할 것으로 예측되는 사용자를 구분합니다. 유사한 방식으로 향 후 7일간 앱을 계속 사용할 유저, 혹은 앱 내에서 아이템등을 구매할 사용자등을 예측할 수 있습니다. 아래 그림을 참고하시기 바랍니다.

Figure 1. Using Features for Predict Labels


Firebase 예측 시작하기

예측을 사용하기 위해서는 몇 가지 사전 조건이 있습니다.

1. 애널리틱스를 앱에 추가합니다. 예측은 Firebase 용 Google 애널리틱스에서 데이터를 가져옵니다. 애널리틱스를 추가하는 것은 매우 간단합니다. 추가로 코드를 작성할 필요 없이 SDK를 탑재하는 것 만으로도 가장 기본적인 이벤트 데이터를 수집할 수 있습니다.

Android의 경우 build.gradle 파일에 다음을 추가하십시오.

  • compile 'com.google.firebase:firebase-core:11.8.0' (Android Gradle Plugin 3.0 미만) 
  • implementation 'com.google.firebase:firebase-core:11.8.0' (Android Gradle Plugin 3.0 이상) 
iOS의 경우 Podfile에 다음을 추가하십시오.

  • pod 'Firebase/Core'

코드를 사용하여 자체 분석 이벤트에 대한 맞춤 분석을 작성하는 방법을 비롯하여 자세한 내용은 https://firebase.google.com/docs/analytics/ 문서를 참고하세요.

2. Firebase 콘솔을 통해 해당 앱을 관리하는 Firebase 프로젝트를 선택합니다. ‘Grow’ 항목에서 ‘Prediction’ 메뉴를 선택합니다.
 
Figure 2. Firebase Console navigation
예측 기능을 아직 사용하지 않았다면, 정책 동의가 필요합니다. 이 때, 안내되는 내용을 잘 살펴보시면 예측 기능에 관한 유용한 정보를 확인하실 수 있습니다. 예측 기능은 최소 한 달에 1만명 이상의 활성 사용자가 있는 경우에 잘 동작할 수 있습니다. 정책 내용을 살펴보시고 ‘예, 수락합니다.’ 버튼을 클릭하면, 예측 기능을 활용할 수 있습니다.

 
Figure 3. Opting in to predictions.
이 후 기본으로 제공되는 4가지 예측 항목을 확인할 수 있습니다. 데이터를 학습하는데 시간이 필요하기 때문에, 각각의 예측 결과는 바로 확인할 수는 없고, 일반적으로 24시간이 지난 후에 확인할 수 있습니다. 다만, 활성 사용자 수가 너무 적거나, 쌓여있는 데이터가 100일 미만인 경우 학습에 더 많은 시간이 걸릴 수도 있습니다.




예측 이해하기

시간이 지나면, 아래와 같이 ‘예측 카드'를 통해 예측 결과를 확인할 수 있습니다. 결과가 좋지않네요. 향후 7일 이내에 앱에서 약 29% 사용자가 앱 사용을 중지 할 것으로 예측되고 있습니다.


조금 더 세부적인 타겟팅을 위해 ‘위험 허용 범위’ 슬라이드를 활용해 보겠습니다. 잘못된 예측(False Positive - 이탈하지 않을 사용자를 이탈 사용자로 판명하는 경우)을 최소화 하고 싶으면, ‘위험 허용 범위'를 ‘Low’로 설정할 수 있습니다. 위험 허용 범위는 ‘Low’, ‘Medium’, ‘High’ 세 단계로 선택할 수 있으며 각 단계 마다 타겟팅 되는 사용자의 수가 달라질 수 있습니다.



정확도 탭을 열어보면, 전반적인 예측 정확도를 확인할 수 있습니다. 예측값의 정확도가 94%로 상당히 높게 나타나고 있습니다. 위험 허용 범위를 변경한 후 값을 확인하면, 예측 정확도도 함께 변경되는 것을 확인할 수 있습니다. 예측된 수치를 신뢰할 수 있다면, 이를 기반으로 여러 실험을 진행할 수 있습니다.‘사용자 타겟팅' 버튼을 선택하여, 해당 예측 값을 기반으로 사용자를 타겟팅하고, Firebase의 다양한 기능을 활용할 수 있습니다.

예측 값 활용하기

예측 결과로 도출된 사용자 그룹은 매일 업데이트 됩니다. 해당 그룹을 대상으로 원격 구성이나 알림 기능을 사용하는 경우, 해당 그룹의 속한 사용자는 하루가 지난 후 다시 변경 될 것 입니다.

  • Firebase 원격 구성은 타겟팅된 사용자를 대상으로 앱 내부 값을 서버단에서 변경할 수 있는 기능입니다. 이를 활용해, 앱 재배포 없이도 사용자 그룹에 따라 앱의 동작 방식을 변경 할 수 있습니다. 예를 들어, Firebase 예측 기능을 통해 향 후 특정 행동을 할 것으로 예측되는 사용자가 있다면, 해당 사용자에게만 특별한 구성 값을 적용할 수 있습니다. 
  • Firebase 알림은 타겟팅된 사용자를 대상으로 푸시 메세지를 보낼 수 있는 기능입니다. 이 때 게임 아이템등 사용자가 다시 앱을 실행하도록 유인할 수 있는 데이터를 첨부할 수 있습니다. 

예측 기능의 활용 예


Halfbrick Studios
‘Dan the Man’은 Halfbrick Studio에서 출시된 매우 인기있는 액션 플랫폼 게임입니다. 이 게임은 이미 Firebase 원격 구성 기능을 활용하고 있었습니다. 여기에 더해 Firebase 예측 기능을 활용해 게임을 이탈할 것으로 예측되는 사용자를 대상으로, 어떻게 사용자 리텐션 비율을 높일 수 있는지 실험을 진행했습니다.

Halfbrick Studio는 사용자를 ‘세번째 스테이지를 클리어한 사용자’와 ‘게임을 이탈할 것으로 예측된 사용자’ 로 나누고 동일한 무료 게임 아이템을 제공했을 때 사용자 리텐션 비율이 어떻게 변경되는지 살펴보았습니다.


Figure 6. Reward for users in Dan the Man.
실험 완료 후, 두 그룹과 아이템을 전혀 제공하지 않는 통제 그룹의 결과를 비교한 결과는 다음과 같았습니다.

Group
1-day retention
7-day retention
Group 0: No Promotion
59.52%
25.35%
Group 1: Gift after Level 3
59.07%
25.34%
Group 2: Predicted to Churn
62.12%
30.24%

표로 정리된 결과에서 알 수 있듯이, 세 번째 스테이지를 클리어한 사용자 그룹을 대상으로 무료 아이템을 제공해도 사용자 리텐션 비율에는 큰 변화가 없었습니다. 하지만, Firebase 예측 결과로 게임을 떠날 것으로 예측된 사용자를 대상으로 무료 아이템을 제공했을 때, 7일 내 사용자 리텐션 비율이 약 20% 향상되는 것을 확인할 수 있습니다.

결과적으로 Halfbrick Studio는 두 가지 교훈을 얻을 수 있었습니다. 첫번째로 세 번째 스테이지를 클리어한 사용자는 비교적 오랫동안 게임을 플레이할 것으로 기대했지만 그렇지 않은 사용자와 비교해 사용자 리텐션 비율에 큰 차이가 없었습니다. 두 번째는 Firebase 예측 기능이 올바르게 동작했고, 이를 기존 데이타와 결합하면 더 효과적으로 활용할 수 있을 것이라는 점 입니다.


Rockbite

앱 수익화도 사용자 리텐션을 높이는 것 만큼이나 중요합니다. Rockbite는 Firebase 예측 기능을 활용해 앱 수익화를 최대화 할 수 있는 방법을 실험했습니다. Rockbite는 향후 게임내에서 구매자로 예측되는 사용자들에게 최적의 UX를 제공하고 싶었습니다. Rockbite 게임에는 ‘크리스탈’과 ‘상자’ 두 종류의 아이템이 있습니다. 사용자는 돈을 내고 크리스탈을 구매하거나 게임을 진행하면서 보상으로 크리스탈을 얻을 수 있습니다. 반면에 상자는 반드시 크리스탈을 통해서만 구매할 수 있습니다. Rockbite는 지금까지의 경험을 기반으로 상점 페이지에서 크리스탈이 먼저 표시되는 것을 선호하는 사용자가 있고, 반면에 상자가 먼저 표시되는 것을 선호하는 사용자도 있다는 것을 알고 있었습니다.

이에 대해 Rockbite는 다음과 같은 가정을 세웠습니다. “한 번도 구매를 하지 않은 사용자의 경우 우선 크리스탈을 구매할 것이다. 이를 통해 상자나 다른 아이템을 구매할 수 있다.” 타당해 보입니다. 크리스탈이 없는 사용자에게 상자는 아무런 의미가 없을테니까요. 이 가정을 기반으로 Rockbite는 다음과 같은 로직을 구성했습니다.

Firebase 예측을 통해 이 후 돈을 사용할 것으로 예측되는 사용자는 상점 최상단에 상자 아이템을 배치하고 크리스탈을 그 아래 배치했습니다. 이를 통해 전체 수익이 약 25% 증가했습니다.
Figure 7. Screen for Predicted Spenders

마찬가지로 돈을 지불하지 않을 것으로 예상되는 사용자 그룹을 대상으로는 크리스탈을 상점 페이지 최상단에 표시했습니다. 앞의 결과와 마찬가지로 이 경우에는 해당 그룹의 구매가 약 24% 증가했습니다.

Figure 8. Screen for Predicted Non-spenders

적절한 실험 설계와 이를 통한 수익 증대는 Firebase 예측 기능과 Firebase A/B 테스팅 기능을 결합하여 구현할 수 있었습니다. 아이템 배치 위치에 대한 적절한 가설을 세우고, 이를 예측된 사용자 그룹에 적용하고, 실험 결과를 통제 그룹 비교해 쉽게 비교할 수 있습니다.

Concrete Software
인 앱 구매와 광고를 모두 활용하는 앱이 많이 있습니다. Concrete Software는 앱을 통한 수익을 높이고 동시에 사용자 경험을 향상 시키고 싶었습니다. 이를 위해 앱 내에서 아이템을 직접 구매하거나 구매할 것 같은 사용자에게는 광고를 표시하지 않기로 했습니다. Firebase 예측 기능을 통해 사용자 그룹을 새롭게 만들고, 해당 사용자들에게는 전면 광고가 표시되지 않도록 앱을 업데이트 했습니다. 이 후 결과를 확인해보니, 해당 유저들의 앱 내 구매를 통한 수익이 21% 증가했습니다.

알림 사용하기

Firebase 알림 기능을 사용하는 경우, 알림 작성화면에서 Firebase 예측 결과를 활용해 사용자 그룹을 타겟팅 할 수 있습니다. 이때, 위험 허용 범위도 변경 가능합니다.

Figure 9. Targeting Predicted users with a notification.

Firebase 알림으로 전송된 알림 메시지를 앱에서 수신하기 위해서는, Firebase Cloud Messaging SDK를 사용해야 합니다. 각 플랫폼 별 보다 자세한 내용은 공식 개발자 문서를 참고하면 됩니다.


사용자 정의 이벤트를 기반으로 예측 만들기

기본으로 제공되는 예측 기능은 매우 유용합니다. 다만, 여러분의 앱에서 사용자 이탈이 혹은 앱 내 구매만큼 중요한 이벤트가 있을 수도 있습니다. 이런 경우, Firebase 예측 기능을 사용해 사용자 정의 이벤트를 기반으로 예측 모델을 만들 수도 있습니다.

예를 들어, 여러분의 앱에서 새로운 게임 스테이지를 구매할 수 있는 기능이 있다면, 해당 구매는 주요한 사용자 전환 (Conversion)으로 불 수 있습니다. 이 경우, 해당 전환에 대한 이벤트 (예를들어 purchase_level)를 정의할 수 있습니다. 이 후, 예측 메뉴에서 ‘예측 만들기' 버튼을 선택합니다. 예측 하고 싶은 이벤트 (purchase_level)을 선택하고, 일주일내에 해당 이벤트를 발생시킬 것으로 예상되는 사용자 혹은 예상되지 않는 사용자를 지정해서 설정할 수 있습니다. 아래 그림은 새로운 게임 레벨을 구매할 것으로 예상되는 사용자를 예측하기 위한 예측 카드 설정 화면 입니다.

Figure 10. Creating a Purchase level prediction

시간이 지나면, 예측 결과가 만들어집니다. 이 후에는 기본적으로 제공되는 예측과 마찬가지로 해당 예측 결과를 기반으로 사용자를 타겟팅해 활용할 수 있습니다.

Figure 11. Custom prediction

예측 결과, 약 3%의 사용자가 새로운 레벨을 구매할 것으로 예측되었습니다. 해당 사용자들의 구매를 촉진하기 위해 약간의 넛지를 줄 필요가 있을 수도 있겠네요. 예를 들어, 게임 내 아이템 같은 것 말이조, 혹은, 반대로 새로운 스테이지를 구매하지 않을 것으로 예상되는 사용자를 대상으로 별도의 프로모션을 진행해볼 수도 있을 것 입니다.

유용한 팁

각각의 앱마다 특징이 다를 수 있습니다. 그런 만큼 예측 기능을 활용하는 방법도 앱 마다 달라져야 합니다. 다만, 예측 기능을 활용하면서 알게된 몇 가지 팁을 공유드립니다.

  1. 가능한 빨리 기본 예측 기능을 활용해보세요. 적용하기 쉽고 무료입니다. 지금 바로 예측 기능을 활성화 하고 데이터를 확인해보시기 바랍니다. 예측 결과를 기반으로 즉시 액션을 취할 수도 있지만, 대략적인 수치를 확인하는 것 만으로도 여러분의 앱의 향후 성적에 대해 그리고 사용자들이 앱을 얼마나 잘 사용하고 있는지에 관한 의미있는 통찰을 얻을 수 있습니다. 
  2. 이탈자나 구매자로 예측되는 사용자를 대상으로 앱 사용 경험을 지금 바로 변경할 필요는 없지만, 사용자 행동을 상세히 분석하는데 사용할 수 있습니다. 예를들어 원격 구성 기능을 활용해 각각의 예측 사용자 그룹마다 서로 다른 값을 부여하고, 이를 기반으로 앱 이벤트 데이터를 나누어 살펴볼 수 있습니다. 앱을 이탈할 것으로 예상되는 사용자가 어떤 패턴으로 게임 스테이지를 클리어하고 있는지, 아니면 어디서 어려움을 겪고 있는지 등등을 확인하고, 주요 이탈 지점을 확인할 수도 있습니다. 이를 기반으로 앞으로는 앱 이탈율이 줄어들 수 있게 앱을 개선할 수도 있겠죠? 
  3. Firebase A/B 테스팅 기능을 함께 사용할 수 있습니다. 위에서 사례로 언급된 게임에서 매우 효과적으로 활용되었습니다. 이탈자 방지를 위해 세운 가설을 모든 사용자에게 바로 적용하기 보다는 A/B 테스팅을 통해 결과를 검증하고, 효과가 검증된 방법만을 점진적으로 사용자에게 적용할 수 있습니다. 
  4. 사용자 정의 이벤트를 활용할 수 있습니다. 사용자 정의 이벤트가 너무 적으며 의미있는 결과를 얻기 힘들 수 있습니다. 그리고 그 반대도 마찬가지 입니다. 항상 반복하고 반복하고 또 반복해야 합니다. 새로운 것을 시도하는 것을 두려워하지 말고, 불필요하다고 생각되면 과감히 정리할 필요가 있습니다.


마무리

이 블로그 포스팅에서는 Firebase 예측 기능을 소개하고 어떻게 ML 기반으로 사용자 행동을 예측할 수 있는지, 그리고 이를 어떻게 활용할 수 있는지 살펴보았습니다. 또한, 사용자 정의 이벤트를 기반으로 예측 그룹을 만들고 예측된 결과를 기반으로 앱 지표를 개선한 몇몇 사례를 살펴보았습니다. Firebase 예측에 관해 더 자세히 알고 싶은 분들은 아래의 공식 개발자 문서를 추가로 참고하시기 바랍니다.
https://firebase.google.com/products/predictions/