Share
Embed
Cloud Composerで組む機械学習パイプライン
Discovery DataScience Meet up (DsDS) #0 にて発表した内容に、スライドを幾つか追加したものになります。
https://scramble.connpass.com/event/171602/
2kyym
August 21, 2020
Transcript
45 slides
-
import datetime import logging from airflow.models import DAG from
airflow.operators.bash_operator import BashOperator from airflow.operators.python_operator import PythonOperator def greeting(): logging.info("Hello World!") DEFAULT_ARGS = { "start_date": datetime.datetime(2018, 1, 1), "retries": 5, } dag = DAG( dag_id="test_dag", schedule_interval=datetime.timedelta(days=1), default_args=DEFAULT_ARGS, ) hello_python = PythonOperator(task_id="hello", python_callable=greeting, dag=dag) goodbye_bash = BashOperator(task_id="bye", bash_command="echo Goodbye.", dag=dag) hello_python >> goodbye_bash ύΠϓϥΠϯ %BH ఆٛ ԋࢉࢠʢ0QFSBUPSʣ͔Β λεΫΛੜ λεΫ࣮ߦॱংΛఆٛ -
Variables w $PNQPTFSڥશମͰڞ༗͞ΕΔڥมͷΑ͏ͳͷɻ w ੩తͳΛ֨ೲ͓ͯ͘͠ɻҟͳΔ%BHͰಉ͡,FZΛΘͳ͍Α͏ҙɻ w ྫʛ($4ͷೖग़ྗύεɺ(,&ͷΫϥελ໊ɺ($3*NBHF%JHFTUͳͲ XCom (cross
communication) w %BH3VOͰͷΈڞ༗͞Εɺ͋ΔλεΫ͔ΒλεΫͱड͚͞ΕΔࣙॻɻ w 3VO͝ͱʹมΘΔΛ͢ɻ5BTL*OTUBODFΦϒδΣΫτ͔ΒࢀরͰ͖Δɻ w ྫʛֶशσʔλͷूܭظؒɺϑΝΠϧ໊ʹ͚ΔϋογϡͳͲ λεΫͷใͷ͠ํ -
def set_env_variables(c, key, value): c.run( f"gcloud --project {PROJECT} composer
environments run {COMPOSER_NAME} --location {LOCATION} \ variables -- -s {key} {value}" ) ) 7BSJBCMFͷՃ from airflow.models import Variable VALUE = Variable.get(key) 7BSJBCMFͷࢀর -
9$PN7BMVFͷՃྫ def create_args(**kwargs): execution_date = kwargs["execution_date"] preprocess_start_datetime = execution_date
- timedelta(days=PREPROCESS_DIFF) kwargs["ti"].xcom_push( key="preprocess_start_datetime", value=preprocess_start_datetime.strftime("%Y-%m-%dT%H:%M:%S"), ) create_args_task = PythonOperator( task_id="create_args", python_callable=create_args, dag=dag ) 1ZUIPO0QFSBPSͰͷ࣮ؔߦ࣌ɺՄมҾ͔Β࣮ߦ࣌λεΫΠϯελϯεΛࢀরͰ͖Δ ˞UJUBTLJOTUBODFͷུ UBTL@JOTUBODF YDPN@QVTI ࠷ॳͷλεΫͰ QVTI͓ͯ͘͠ -
NBJO@EBHQZ ڞ௨෦ΛΓग़͠ɺλεΫ͝ͱͷ0QFSBUPSϥούʔΛ࡞Δͱ͖ͬ͢Γ͢Δ create_args_task = PythonOperator( task_id="create_args", python_callable=create_args, dag=dag )
profiler_task = profiler_operator.create_operator(dag) preprocess_a_task = preprocess_operator.create_operator(dag, "a") preprocess_b_task = preprocess_operator.create_operator(dag, "b") train_task = train_operator.create_operator(dag) create_args_task >> profiler_task >> [ preprocess_a_task, preprocess_b_task, ] >> train_task def create_operator(dag, task_id, create_args_task_id): container_arguments = [ "--bucket_name", BUCKET_NAME, "preprocess", "--start_datetime", "{{ ti.xcom_pull(task_ids='" + create_args_task_id + "', key='preprocess_start_datetime') }}", "--bq_dataset_name", BQ_DATASET_NAME, "--gcs_path", GCS_PATH, ] operator = GKEPodOperator( task_id=task_id, project_id=PROJECT, location=CLUSTER_LOCATION, cluster_name=CLUSTER_NAME, namespace="default", image=IMAGE, arguments=container_arguments, dag=dag, ) return operator QSFQSPDFTT@PQFSBUPSQZ Import -
(,&1PE0QFSBUPSͰશ෦Δ ཧ༝ w .-ଆͷ࣮ͱύΠϓϥΠϯ࣮Λग़དྷΔ͚ͩಠཱ͍ͤͨ͞ w σʔλαΠΤϯςΟετਞʹύΠϓϥΠϯଆͷ࣮Λҙࣝͤͨ͘͞ͳ͍ w 1ZUIPO0QFSBUPSͷ੍ʢޙड़ʣɺ$PNQPTFSڥෳࡶͳॲཧʹෆ͖ ۩ମతʹ
w ผϦϙδτϦΛ࡞Γɺ.-ΞϧΰϦζϜͷ࣮ͦͪΒͰཧ͢Δ w લॲཧɺֶशɺͦͷଞࡉʑͨ͠ॲཧશͯ%PDLFSΠϝʔδʹด͡ࠐΊΔ w #JH2VFSZΛ͏߹ɺ42-ͱ+PCൃߦॲཧˢͷΠϝʔδʹด͡ࠐΊΔ w ੳɺ࣮ݧɺϩʔΧϧͰͷ։ൃΛߟྀͯ͜͠ͷํ๏͕ಘࡦ -
1ZUIPO0QFSBUPSͷ੍ PythonOperator w 1Z1*ύοέʔδΛඞཁͱ͠ͳ͍ൣғͷ؆୯ͳॲཧͳΒ͓ͦΒ͘࠷దղ w 7BSJBCMFTHFUTFUͰͷड͚͕͠ඇৗʹָɺ9$PN༰қʹ͑Δ w Ұํɺ1Z1*ύοέʔδΛඞཁͱ͢ΔॲཧͰ$PNQPTFSڥΛԚછ͢Δ w
"JSqPXͷύοέʔδґଘͱিಥ͢ΔͳͲɺ࠶ݱੑ͕ݫ͍͠ PythonVirtualenvOperator w ྑ͍ͱ͜औΓ͔ͱࢥ͍͖ѱ͍ͱ͜औΓͩͬͨ w 7BSJBCMFT9$PN͑ͣɺ͍উख(,&1PE0QFSBUPSҎԼ w ҰͭͷDBMMBCMFʹશͯΛ٧ΊࠐΉඞཁ͕͋Γɺඇৗʹ͍ͮΒ͍ -
(,&1PE0QFSBUPSͰશ෦Δ࣌ͷҙ σϝϦοτ w λεΫ࣮ߦ࣌ʹ7BSJBCMFT͕ίʔυ͔ΒࢀরͰ͖ͳ͍ w YDPN@QVTI YDPN@QVMM ͑ͳ͍ ղܾࡦ
w (,&1PE0QFSBUPSͰίϯςφҾ͔Βશͯͯ͠Δ w %PDLFSpMFͰHDMPVE4%,ͱLVCFDUMΛೖΕΕେମԿͰͰ͖Δ w ผڥͷݖݶ͕ඞཁͳ߹4FSWJDF"DDPVOU,FZpMFΛ҉߸Խͯ͢͠ -
ೖग़ྗύεूܭظؒͳͲશͯίϚϯυϥΠϯҾͰ੍ޚͰ͖ΔΑ͏ʹ͓ͯ͘͠ ˞ຊൃදͷൣғ֎͕ͩɺ1ZUIPO'JSF*OWPLF 'BCSJD Λ͏ͱָ container_arguments = [ “preprocess", "--bucket_name",
BUCKET_NAME, "--start_datetime", PREPROCESS_START_DATETIME, "--bq_dataset_name", BQ_DATASET_NAME, “—gcs_export_path", GCS_EXPORT_PATH, ] (,&1PE0QFSBUPSʹҾΛ͢ -
(,&1PE0QFSBUPSʹҾΛ͢ BUCKET_NAME = Variable.get("bucket_name") CLUSTER_NAME = Variable.get("cluster_name") CLUSTER_LOCATION =
Variable.get("cluster_location") IMAGE = f"gcr.io/{PROJECT}/test-image@{Variable.get('test_image_digest')}" BQ_PROFILE_DATASET_NAME = Variable.get("bq_dataset_name") ඞཁͳ7BSJBCMFTࣄલʹऔಘ͓ͯ͘͠ -
def create_operator(dag, task_id, create_args_task_id): container_arguments = [ “preprocess", "--bucket_name",
BUCKET_NAME, "--start_datetime", "{{ ti.xcom_pull(task_ids='" + create_args_task_id + "', key='preprocess_start_datetime') }}", "--bq_dataset_name", BQ_DATASET_NAME, "--gcs_path", GCS_PATH, ] operator = GKEPodOperator( task_id=task_id, project_id=PROJECT, location=CLUSTER_LOCATION, cluster_name=CLUSTER_NAME, namespace="default", image=IMAGE, arguments=container_arguments, dag=dag, ) return operator +JOKBςϯϓϨʔτͰ 9$PNΛࢀরͰ͖Δ BSHVNFOUTҾ ςϯϓϨʔτஔର ˞ׅހͰғͬͨจࣈྻ͕λεΫ࣮ߦલʹ ςϯϓϨʔτஔ͞ΕΔ -
.-ΞϧΰϦζϜͷߋ৽Λࣗಈө ඪ w .-ଆϦϙδτϦʹมߋ͕͋ͬͯɺύΠϓϥΠϯଆमਖ਼ෆཁͳঢ়ଶ͕ཧ w (,&1PE0QFSBUPSͰ࣮ߦ͞ΕΔΠϝʔδΛߋ৽͢Ε͍͍͚ͩɺͱ͍͏ঢ়ଶ ۩ମతʹ w .-ଆϦϙδτϦͷNBTUFSϒϥϯνʹϚʔδ͞Εͨࡍɺ$JSDMF$*ͰࣗಈϏϧυ
w Ϗϧυ͞Εͨ($3*NBHF%JHFTUΛHDMPVEDPNQPTFSWBSJBCMFTTFUͰઃఆ͢Δ w ࣍ճύΠϓϥΠϯ࣮ߦ࣌ʹউखʹߋ৽͕ө͞Ε͍ͯΔ w ίϚϯυϥΠϯҾมߋػೳՃ͕͋ͬͨࡍΉͳ͘ύΠϓϥΠϯΛमਖ਼ -
build_dev: docker: - image: google/cloud-sdk environment: GCP_PROJECT: dummy-gcp COMPOSER_NAME:
dummy-composer IMAGE_TAG: dummy-tag steps: - checkout - setup_remote_docker: docker_layer_caching: true - attach_workspace: at: . - run: name: build command: &build | TAG=gcr.io/${GCP_PROJECT}/test-image:${IMAGE_TAG} docker build -t ${TAG} -f images/runner/Dockerfile . docker push ${TAG} IMAGE_DIGEST=$(gcloud container images describe gcr.io/${GCP_PROJECT}/test-image: ${IMAGE_TAG} —format='value(image_summary.digest)') gcloud composer environments run ${COMPOSER_NAME} --location asia-northeast1 variables -- -s pipeline_image_digest ${IMAGE_DIGEST} .-ଆϦϙδτϦʹஔ͔Εͨ$JSDMF$*༻ͷDPOGJHZNM ($3*NBHF%JHFTUΛ 7BSJBCMFTʹొ -
ϞσϧͷධՁͱࣗಈσϓϩΠ ϞσϧͷࣗಈσϓϩΠ w ਪ༻ͷ*NBHF%JHFTUΛ࣋ͭ7BSJBCMFΛ্ॻ͖͢ΕΑ͍ w ͭ·Γɺ$JSDMF$*ͰσϓϩΠύΠϓϥΠϯ*NBHFΛߋ৽͍ͯͨ͠ͷͱຆͲಉ͡ w ࠷ޙஈͷλεΫͰ৽چϞσϧͷൺֱධՁͱ7BSJBCMFͷ্ॻ͖Λߦ͏ ϞσϧͷධՁ
w ৄࡉল͕͘ɺλΫγʔγϛϡϨʔλͰ࠷ऴతͳϞσϧධՁΛߦ͍ͬͯΔ w ৽ϞσϧͱطଘϞσϧͷ྆ํͰόονਪͱγϛϡϨʔγϣϯΛฒྻ࣮ߦ w Ϟσϧߋ৽ج४ʛ̎िؒ࿈ଓͰطଘϞσϧͷύϑΥʔϚϯεΛ্ճΔ͜ͱ