Path: blob/master/site/ko/probability/examples/Distributed_Inference_with_JAX.ipynb
25118 views
Copyright 2020 The TensorFlow Probability Authors.
아파치 라이선스, 버전 2.0 (the "License")에 의거함;
JAX의 TensorFlow Probability(TFP)에 이제 분산된 수치적 컴퓨팅을 위한 도구가 있습니다. 수많은 가속기로 확장하기 위해, "단일-프로그램 다중-데이터" 패러다임(SPMD)을 사용하여 코드를 작성하는 것을 중심으로 도구가 구축됩니다.
이 노트북에서는, "SPMD으로 사고"하는 방법과 TPU 팟 또는 GPU의 클러스터와 같은 구성으로 확장하기 위해 새로운 TFP 추상화를 도입하는 내용을 다룹니다. 이 코드를 직접 실행하고 있다면, TPU 런타임을 선택합니다.
우선 최신 버전의 TFP, JAX 및 TF를 설치하겠습니다.
ERROR: tensorflow 2.4.1 has requirement gast==0.3.3, but you'll have gast 0.4.0 which is incompatible.
ERROR: tensorflow 2.4.1 has requirement grpcio~=1.32.0, but you'll have grpcio 1.34.1 which is incompatible.
ERROR: tensorflow 2.4.1 has requirement h5py~=2.10.0, but you'll have h5py 3.1.0 which is incompatible.
ERROR: google-colab 1.0.0 has requirement requests~=2.23.0, but you'll have requests 2.25.1 which is incompatible.
ERROR: datascience 0.10.6 has requirement folium==0.2.1, but you'll have folium 0.8.3 which is incompatible.
ERROR: albumentations 0.1.12 has requirement imgaug<0.2.7,>=0.2.5, but you'll have imgaug 0.2.9 which is incompatible.
ERROR: tf-nightly-cpu 2.6.0.dev20210401 has requirement numpy~=1.19.2, but you'll have numpy 1.20.2 which is incompatible.
ERROR: tensorflow 2.4.1 has requirement gast==0.3.3, but you'll have gast 0.4.0 which is incompatible.
ERROR: tensorflow 2.4.1 has requirement grpcio~=1.32.0, but you'll have grpcio 1.34.1 which is incompatible.
ERROR: tensorflow 2.4.1 has requirement h5py~=2.10.0, but you'll have h5py 3.1.0 which is incompatible.
ERROR: tensorflow 2.4.1 has requirement numpy~=1.19.2, but you'll have numpy 1.20.2 which is incompatible.
ERROR: google-colab 1.0.0 has requirement requests~=2.23.0, but you'll have requests 2.25.1 which is incompatible.
ERROR: datascience 0.10.6 has requirement folium==0.2.1, but you'll have folium 0.8.3 which is incompatible.
ERROR: albumentations 0.1.12 has requirement imgaug<0.2.7,>=0.2.5, but you'll have imgaug 0.2.9 which is incompatible.
몇몇 JAX 유틸리티와 함께 몇몇 일반 라이브러리를 가져오겠습니다.
또한 몇몇 유용한 TFP 에일리어스도 설정하겠습니다. 새로운 추상화는 현재 tfp.experimental.distribute
및 tfp.experimental.mcmc
에 제공됩니다.
노트북을 TPU에 연결하기 위해, JAX에서 다음 헬퍼를 사용합니다. 연결되었는지 확인하기 위해, 기기의 수를 프린트합니다. 이는 8이어야 합니다.
jax.pmap
에 대한 짧은 소개
TPU에 연결한 후, 8개 기기에 액세스했습니다. 하지만, JAX 코드를 열심히 실행할 때, JAX는 기본적으로 하나의 컴퓨팅에서만 실행됩니다.
여러 기기에 걸친 컴퓨팅을 하는 가장 간단한 방법은 각 기기가 맵의 인덱스 1개를 실행하도록 하는 함수를 매핑하는 것입니다. JAX는 jax.pmap
("병렬 맵") 함수를 여러 기기에 걸쳐 함수를 매핑하는 함수로 변환하는 변환을 제공합니다.
다음 예시에서, 크기가 8(사용 가능한 기기 수 일치를 위함)인 배열을 생성하고 5를 이에 추가하는 함수를 매핑합니다.
출력 행렬이 물리적으로 기기에 분할된 것을 나타내는 ShardedDeviceArray
유형을 반환받았습니다.
jax.pmap
는 의미론적으로 맵처럼 동작하지만, 동작을 수정하는 중요한 옵션이 몇 가지 있습니다. 기본적으로, pmap
는 매핑되고 있는 함수에 대한 모든 입력을 추정하지만, 이 동작을 in_axes
인수로 수정할 수 있습니다.
마찬가지로, pmap
에 대한 out_axes
인수가 모든 기기에 대한 값을 반환할지 여부를 결정합니다. out_axes
를 None
로 설정하는 중 자동으로 첫 번째 기기에 대한 값을 반환하기 때문에 기기에 대한 값이 동일하다는 확신이 있을 때에만 사용해야 합니다.
하고자 하는 작업을 매핑된 순수 함수로 쉽게 표현할 수 없다면 어떻게 될까요? 예를 들어, 매핑하고 있는 축 전체의 합을 컴퓨팅하고 싶다면 어떨까요? 더욱 흥미롭고 복잡한 분산 프로그램을 작성할 수 있도록 JAX는 모든 기기와 통신하는 함수인 "collectives"를 제공합니다. 실제 작동 방법에 대한 이해를 위해, SPMD를 소개하겠습니다.
SPMD란?
단일-프로그램 다중-데이터(SPMD)는 단일 프로그램(즉 동일한 코드)이 기기 간 동시에 실행되지만 실행 프로그램의 각각에 대한 입력은 다를 수 있는 동시 프로그래밍 모델입니다.
프로그램이 입력(예: x + 5
)의 단순한 함수인 경우, SPMD에서 프로그램을 실행하는 것은 그저 jax.pmap
로 이전에 했던 것과 같이 다른 데이터에 매핑하는 것입니다. 하지만, 그저 함수를 "매핑"하는 것 그 이상의 작업이 가능합니다. JAX는 기기 간 통신하는 함수인 "collectives"를 제공합니다.
예를 들어, 모든 기기의 수량의 합계를 내려고 할 수 있습니다. 그러기 전에, pmap
에서 매핑할 축에 이름을 할당해야 합니다. 그런 다음 lax.psum
("병렬 합계") 함수를 사용해 기기 간 합을 수행하여, 합계를 컴퓨팅할 명명된 축을 식별합니다.
psum
집합은 각 기기에 대한 x
값을 종합하며 맵 전체에 값을 동기화합니다. 각 기기의 out
은 28
입니다. 더 이상 단순한 "매핑"을 하지는 않지만, 집합을 이용하는 데 한계가 있을지라도 각 기기의 컴퓨팅이 다른 기기의 동일한 컴퓨팅과 상호 작용할 수 있는 SMPD 프로그램을 실행합니다. 이 시나리오에서, psum
가 값을 동기화할 것이기 때문에 out_axes = None
를 사용할 수 있습니다.
SPMD를 사용하여 TPU 구성의 모든 기기에서 동시에 실행되는 하나의 프로그램을 작성할 수 있습니다. 8개의 TPU 코어에 대해 기계 학습을 수행하는 데 사용되는 동일한 코드를 수백 개에서 수천 개의 코어를 가진 TPU 포드에서 사용할 수 있습니다! jax.pmap
및 SPMD에 관한 더욱 자세한 튜토리얼은 JAX 101 tutorial를 참조할 수 있습니다.
대규모 MCMC
이 노트북에서는, 베이지안을 위해 마르코프 연쇄 몬테카를로(MCMC) 메서드를 사용하는 데 중점을 둡니다. MCMC를 위해 많은 기기를 활용하는 방법이 있을 수 있지만, 이 노트북에서는 다음과 같은 두 가지에 집중합니다.
다른 기기에서 독립적인 마르코프 연쇄 실행. 이 경우는 상당히 단순하며 Vanilla TFP로 가능합니다.
Sharding a dataset across devices. 모든 기기에 데이터세트를 샤딩. 이 경우는 좀 더 복잡하고 최근 추가된 TFP 장치가 필요합니다.
독립적인 연쇄
MCMC를 사용하여 문제에 대한 베이지안 추론을 하고자 하며 여러 기기(예: 각 기기에서 2개)에서 병렬로 여러 연쇄를 실행하고자 한다고 가정해 봅시다. 이것은 전체 기기, 즉 집합이 필요 없는 기기 전체에 "매핑"할 수 있는 프로그램인 것으로 밝혀졌습니다. 각 프로그램이 서로 다른 마르코프 연쇄를 실행하도록 하기 위해 (동일한 것을 실행하는 것과 반대로), 각 기기에 무작위 시드에 대한 서로 다른 값을 전달합니다.
2D 가우시안 분포 샘플링의 장난감 문제에 이를 적용해 봅시다. TFP의 기존 MCMC 기능을 바로 사용할 수 있습니다. 일반적으로, 모든 기기에서 실행되는 것과 첫 번째 기기에서 실행되는 것을 더욱 명확하게 구분하기 위해 매핑된 함수의 내부에 로직의 대부분을 넣으려고 합니다.
run
함수는 스스로 상태 비저장 무작위 시드를 받아들입니다(상태 비저장 무작위가 어떻게 작동하는지 확인하려면, JAX의 TFP 노트북 또는 JAX 101 튜토리얼을 참조합니다). 다른 시드에 대해 run
을 매핑하면 여러 독립적인 마르코프 연쇄가 실행됩니다.
이제 각 기기에 해당하는 추가 축이 어떻게 있는지 알아봅니다. 차원을 재배열할 수 있으며 평평하게 하여 16개 연쇄에 대한 축을 얻을 수 있습니다.
많은 기기에서 독립적인 연쇄를 실행하는 경우, 이는 tfp.mcmc
를 사용하는 함수에 대해 pmap
-ing 을 사용하는 것만큼 쉬워 각 기기에 무작위 시드에 대한 다른 값을 전달합니다.
데이터 공유
MCMC를 수행하는 경우, 대상 분산은 종종 데이터세트에 조건을 적용하여 얻은 사후 분산이며, 각 관찰된 데이터에 대한 가능성을 합하여 비정규화된 로그 밀도를 컴퓨팅합니다.
매우 큰 데이터세트의 경우, 하나의 기기에서 하나의 연쇄를 실행하는 것조차 엄두가 나지 않을 만큼 비용이 많이 들 수 있습니다. 하지만, 여러 기기에 액세스하는 경우, 사용 가능한 컴퓨팅을 더욱 잘 활용하기 위해 기기 전체의 데이터세트를 분할할 수 있습니다.
샤딩된 데이터세트로 MCMC를 수행하려는 경우, 각 기기에서 컴퓨팅한 비정규화된 로그-밀도가 total, 즉 모든 데이터에 대한 밀도를 나타내는지 확인해야 합니다. 그렇지 않으면 각 기기는 올바르지 않은 대상 분포로 MCMC를 수행하게 될 것입니다. 이를 위해, TFP는 이제 "샤딩된" 로그 가능성을 컴퓨팅하고 이로 MCMC를 수행할 수 있는 새로운 툴(예: tfp.experimental.distribute
및 tfp.experimental.mcmc
)을 제공합니다.
샤딩된 분포
TFP가 이제 샤딩된 로그 가능성 컴퓨팅을 위해 제공하는 핵심 추상화는 Sharded
이며, 이는 분포를 입력으로 취하고 SPME 컨텍스트에서 실행될 때 특정 속성을 가지는 새로운 분포를 반환합니다. Sharded
는 tfp.experimental.distribute
에 있습니다.
직관적으로 Shared
분포는 장치 간에 "분할"된 랜덤 변수 집합에 해당합니다. 각 기기에서, 다른 샘플을 생성하며 개별적으로 다른 로그-밀도를 가질 수 있습니다. 또는, Sharded
분포는 플레이트 크기가 기기의 수인 그래픽 모델 용어의 "플레이트"에 해당합니다.
Sharded
분포 샘플링
각 기기에 동일한 시드를 사용하여 pmap
-ed 프로그램의 Normal
분포에서 샘플링하는 경우, 각 기기에 동일한 샘플을 얻게 됩니다. 다음 함수를 기기 간 동기화된 단일 무작위 함수 샘플링으로 간주할 수 있습니다.
tfed.Sharded
로 tfd.Normal(0., 1.)
를 래핑 하는 경우, 이제 논리적으로 8개의 다른 무작위 변수(각 기기에 하나)를 가기 때문에 동일한 시드에서 전달함에도 불구하고 각각의 변수에 대해 다른 샘플을 생성합니다.
단일 기기에 대한 이 분포의 동등한 표현은 8개의 독립적인 정규 샘플일 뿐입니다. 샘플 값이 다르더라도(tfed.Sharded
는 의사 난수 생성을 약간 다르게 함), 모두 동일한 분포를 나타냅니다.
Sharded
분포의 로그-밀도 가져오기
SPMD 컨텍스트에서 정규 분포 샘플의 로그-밀집을 컴퓨팅할 때 무슨 일이 일어나는지 확인합니다.
각 샘플은 각 장치에서 동일하므로 각 장치에서 동일한 밀도를 계산합니다. 직관적으로, 여기에는 단일 정규 분포 변수에 대한 하나의 분포만 있게 됩니다.
Sharded
분포를 사용하여, 8개의 무작위 변수에 대한 분포를 가지게 되어, 샘플 log_prob
를 컴퓨팅 하는 경우 기기 간의 개별 로그 밀집 각각에 대해 합계를 냅니다. 이 총 log_prob 값이 위에서 컴퓨팅 된 싱글톤 log_prob보다 크다는 것을 알 수 있습니다.
동등한 "샤딩되지 않은" 분포는 동일한 로그 밀도를 생성합니다.
Sharded
분포는 각 기기에서 sample
의 다른 값을 생성하지만, 각 기기에서 log_prob
에 대한 동일한 값을 얻습니다. 여기서 무슨 일이 일어나고 있습니까? Sharded
분포는 내부적으로 psum
를 수행하여 기기 간 log_prob
이 동기화되도록 합니다. 이러한 동작을 원하는 이유는 무엇입니까? 각 기기에 동일한 MCMC 연쇄를 실행하는 경우, 일부 무작위 변수가 기기 간 샤딩되더라도 target_log_prob
는 각 기기에서 동일해야 합니다.
또한, Sharded
분포는 기기 간 그래디언트가 정확하도록 보장하고, 변환 함수의 일부로서 로그-밀도 함수의 그래디언트를 취하는 HMC와 같은 알고리즘이 적절한 샘플을 생성하도록 합니다.
샤딩된 JointDistribution
JointDistribution
(JD)를 사용하여 여러 Sharded
무작위 변수로 모델을 생성할 수 있습니다. 유감스럽게도, Sharded
분포는 Vanilla tfd.JointDistribution
과 안전하게 사용할 수 없지만, tfp.experimental.distribute
는 Sharded
분포와 같이 동작하는 "패치된" JD를 내보내기 합니다.
이러한 샤딩된 JD는 Sharded
및 Vanilla TFP 분산을 구성 요소로 모두 가질 수 있습니다. 샤딩되지 않은 분포의 경우, 각 기기에서 동일한 샘플을 얻고, 샤딩된 분포의 경우, 다른 샘플을 얻습니다. 각 기기의 log_prob
역시 동기화됩니다.
Sharded
분포를 사용한 MCMC
MCMC의 컨텍스트 내 Sharded
분포에 대해 어떻게 생각하십니까? JointDistribution
로 표현될 수 있는 생성 모델이 있다면, 해당 모델의 일부 축을 선별하여 전체를 "샤딩"할 수 있습니다. 일반적으로, 모델의 하나의 무작위 변수는 관찰된 데이터에 해당하며, 기기 간 공유하고자 하는 큰 데이터세트가 있다면 데이터 지점과 관련된 변수도 샤딩되기를 원합니다. 또한 샤딩 중인 관찰과 일대일인 "로컬" 무작위 변수가 있을 수 있으므로 이러한 무작위 변수를 추가적으로 샤딩해야 합니다.
이 섹션에서 TFP MCMC를 사용한 Sharded
분포의 사용에 대한 예시를 다루겠습니다. 더욱 단순한 베이지안 로지스틱 회귀 예시를 사용하여 시작하고 distribute
라이브러리를 위한 몇몇 활용 사례를 시연하는 것을 목표로 행렬 인수 분해 예시를 사용하여 마무리할 것입니다.
예시: MNIST를 위한 베이지안 로지스틱 회귀
대규모 데이터세트에서 베이지안 로지스틱 회귀를 하고자 합니다. 모델에는 총 조인트 로그 밀도를 얻기 위한 회귀 가중치에 대한 이전 와 전체 데이터 에 대해 합산되는 가능성 가 있습니다. 데이터를 샤딩하는 경우, 모델의 관측된 무작위 변수 및 를 샤딩합니다.
MNIST 분류를 위해 다음 베이지안 로지스틱 회귀 모델을 사용합니다:
데이터세트를 사용하는 MNIST를 로드하겠습니다
Downloading and preparing dataset mnist/3.0.1 (download: 11.06 MiB, generated: 21.00 MiB, total: 32.06 MiB) to /root/tensorflow_datasets/mnist/3.0.1...
Dataset mnist downloaded and prepared to /root/tensorflow_datasets/mnist/3.0.1. Subsequent calls will reuse this data.
60,000개의 훈련 이미지가 있지만 8개의 사용 가능한 코어를 활용해서 8가지의 방식으로 분할하겠습니다. 이 편리한 shard
활용 함수를 사용하겠습니다.
계속 진행하기 전에, TPU의 정확도와 TPU가 HMC에 미치는 영향을 신속히 논의하겠습니다. PU는 속도를 위해 낮은 bfloat16
정확도를 사용해 행렬 곱셈을 수행합니다. bfloat16
행렬 곱셈은 종종 많은 딥 러닝 애플리케이션에는 충분하지만, HMC와 사용하는 경우, 낮은 정확성으로 인해 궤적이 분산되어 거부 반응이 유발될 수 있다는 것을 실증적으로 발견했습니다. 약간의 추가적인 컴퓨팅 비용으로 더욱 높은 정확도의 행렬 곱셈을 사용힐 수 있습니다.
행렬곱 정확도를 향상하기 위해, "tensorfloat32"
정확도로 jax.default_matmul_precision
데코레이터를 사용할 수 있습니다(더 높은 정확도의 경우 "float32"
정확도를 사용할 수 있습니다).
이제 무작위 시드 및 MNIST의 샤드를 포함하는 run
함수를 정의해 봅니다. 이 함수는 앞서 언급한 모델을 구현한 다음 단일 연쇄를 실행하기 위해 TFP의 Vanilla MCMC 기능을 사용합니다. 행렬 곱셈이 더욱 높은 정확성으로 실행되도록 jax.default_matmul_precision
데코레이터로 run
를 데코레이트할 것입니다. 아래의 특정 예시에서는 jnp.dot(images, w, precision=lax.Precision.HIGH)
를 사용할 수도 있습니다.
jax.pmap
는 JIT 컴파일을 포함하지만 컴파일된 함수는 첫 번째 호출 후에 캐시 됩니다. run
를 호출하고 출력을 무시하여 컴파일을 캐시 하겠습니다.
이제 실제 실행에 소요되는 시간을 확인하기 위해 run
을 다시 호출하겠습니다.
각각의 200,000개의 도약 단계를 수행 중이며, 각 단계는 전체 데이터세트에 대한 그래디언트를 컴퓨팅합니다. 8개의 코어에 대한 컴퓨팅을 분할하면 약 95초에 200,000개의 epoch 훈련, 초당 2,100개의 epoch 훈련과 동등하게 컴퓨팅할 수 있습니다!
각 샘플의 로그-밀도 및 각 샘플의 정확도를 표시해 봅시다.
샘플을 앙상블하는 경우, 베이지안 모델 평균을 컴퓨팅하여 성능을 개선할 수 있습니다.
베이지안 모델 평균은 정확도를 거의 1% 향상합니다!
예시: MovieLens 추천 시스템
사용자와 여러 영화에 대한 평점을 모은 MovieLens 추천 데이터세트를 사용하여 추론을 시도해 보겠습니다. 구체적으로 말하면, MovieLens를 은 사용자의 수이고 은 영화의 수인 watch matrix 로 나타낼 수 있습니다. ParseError: KaTeX parse error: Expected 'EOF', got '&' at position 3: N &̲gt; M일 것으로 예상합니다. 의 입력값은 사용자 이 영화 를 봤는지 표시하는 불리언입니다. MovieLens는 사용자 평점을 제공하지만 문제를 단순화하기 위해 무시하겠습니다.
우선, 데이터세트를 로드하겠습니다. 평점이 1백만이 넘는 버전을 사용하겠습니다.
Downloading and preparing dataset movielens/1m-ratings/0.1.0 (download: Unknown size, generated: Unknown size, total: Unknown size) to /root/tensorflow_datasets/movielens/1m-ratings/0.1.0...
Shuffling and writing examples to /root/tensorflow_datasets/movielens/1m-ratings/0.1.0.incompleteYKA3TG/movielens-train.tfrecord
Dataset movielens downloaded and prepared to /root/tensorflow_datasets/movielens/1m-ratings/0.1.0. Subsequent calls will reuse this data.
행렬 를 보기 위해 데이터세트를 약간 전처리하겠습니다.
간단한 확률적 행렬 인수 분해 모델을 사용하여 에 대한 생성 모델을 정의할 수 있습니다. 잠재 사용자 행렬 및 잠재 영화 행렬 를 추정합니다. 이 행렬을 곱하면 시청 행렬 에 대한 베르누이 로짓을 생성합니다. 또한 사용자 및 영화, and 에 대한 편향 벡터를 포함하겠습니다.
이것은 상당히 큰 행렬입니다. 6,040명의 사용자와 3,706개의 영화가 2천2백만 개가 넘는 입력값을 가진 행렬로 이어집니다. 이 모델을 샤딩하는 데 어떻게 접근해야 할까요? ParseError: KaTeX parse error: Expected 'EOF', got '&' at position 3: N &̲gt; M(사용자가 영화보다 많음)일 것이라 가정하면 사용자 축 전체에 걸쳐 시청 행렬을 샤딩하는 것이 의미가 있으며, 따라서 각 기기는 사용자의 하위 집합에 해당하는 시청 패트릭스 청크를 가지게 됩니다. 하지만 이전의 예시와는 다르게, 행렬은 각 사용자에 대한 임베딩이 있기 때문에 샤딩해야 하며, 따라서 각 기기는 의 샤드 및 의 샤드에 대한 책임이 있습니다. 반면에, 는 기기 전체에 샤딩되지 않으며 동기화됩니다.
run
을 작성하기 전에, 로컬 무작위 변수 를 샤딩하는 것과 관련된 추가적인 어려움에 대해 짧게 논의해 보겠습니다. HMC를 실행하는 경우, Vanilla tfp.mcmc.HamiltonianMonteCarlo
커널이 각 연쇄 상태의 요소에 대한 모멘텀을 샘플링할 것입니다. 이전에는, 샤딩되지 않은 무작위 변수들만이 해당 상태의 일부였으며 모멘텀은 각 기기에서 동일했습니다. 이제 샤딩된 가 있는 경우, 에 대한 동일한 모멘텀을 샘플링하는 동시에 에 대한 각 기기의 다른 모멘텀을 샘플링해야 합니다. 이를 해내기 위해서, Sharded
모멘텀 분산과 tfp.experimental.mcmc.PreconditionedHamiltonianMonteCarlo
를 사용할 수 있습니다. 예를 들어, HMC 커널에 샤딩 지표를 가져옴으로써 병렬 컴퓨팅을 계속 1등급으로 만들어 이를 단순화할 수 있습니다.
이를 다시 한 번 실행하여 컴파일된 run
을 캐시합니다.
이를 이제 컴파일 오버헤드 없이 다시 실행합니다.
3분 동안 10,000개의 도약 단계를 마친 것으로 보이므로, 초당 83개의 도약 단계를 마쳤습니다! 샘플의 허용 비율 및 로그 밀도를 표시해 보겠습니다.
이제 마르코프 연쇄에서 샘플을 얻었습니다. 이를 사용해 예측을 해보겠습니다. 우선, 구성 요소 각각을 추출해 봅시다. user_embeddings
및 user_bias
는 기기 간 분할되어 있으므로, ShardedArray
를 연결하여 이를 모두 획득해야 한다는 점을 잊지 마십시오. 반면, 모든 기기에서 movie_embeddings
및 movie_bias
는 동일하므로, 첫 번째 샤드에서 값을 선별할 수 있습니다. 정규 numpy
를 사용하여 TPU에서 값을 CPU에 다시 복사하겠습니다.
이러한 샘플에서 캡처된 불확실성을 활용하는 단순한 추천 시스템을 구축해 보겠습니다. 우선 시청 확률에 따른 영화의 순위를 매기는 함수를 작성하겠습니다.
이제 모든 샘플 및 각각을 순환하고, 사용자가 아직 시청하지 않은 상위 랭크된 영화를 선별하는 함수를 작성할 수 있습니다. 그런 다음 전체 샘플의 모든 추천된 영화 수를 볼 수 있습니다.
가장 많은 영화를 본 사용자 대 가장 적게 영화를 본 사용자를 살펴보겠습니다.
user_most
가 더 많이 시청할 것 같은 영화의 종류가 무엇인지에 대한 정보가 더 많다는 점을 고려하면 시스템이 user_least
보다 user_most
에 대한 확실성이 더 있길 바랍니다.
시청 선호도의 추가적인 불확실성을 반영하는 user_least
에 대한 추천에 더 많은 변수가 있다는 것을 확인할 수 있습니다.
추천 영화의 장르도 확인할 수 있습니다.
user_least
가 많은 영화를 보지 않았으며 코미디와 액션을 왜곡하는 주류 영화를 더 많이 추천받은 반면, user_most
는 영화를 더 많이 보았고 미스터리 및 범죄와 같은 틈새 장르를 추천받았습니다.