ホーム » Kubeflow » Kubeflow 1.0 : コンポーネント : TensorFlow 訓練 (TFJob)

Kubeflow 1.0 : コンポーネント : TensorFlow 訓練 (TFJob)

Kubeflow 1.0 : コンポーネント : TensorFlow 訓練 (TFJob) (翻訳/解説)

翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 04/10/2020 (1.0)

* 本ページは、Kubeflow の以下のページを翻訳した上で適宜、補足説明したものです:

* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

コンポーネント : TensorFlow 訓練 (TFJob)

このページは TensorFlow で機械学習モデルを訓練するための TFJob を記述します。

 

TFJob とは何でしょう?

TFJob は Kubernetes 上で TensorFlow 訓練ジョブを実行するために利用できる Kubernetes カスタム・リソース です。TFJob の Kubeflow 実装は tf-operator にあります。

TFJob は下の一つのような YAML 表現を持つリソースです (貴方自身の訓練コードのためのコンテナ・イメージとコマンドを使用するために編集します) :

apiVersion: kubeflow.org/v1
kind: TFJob
metadata:
  generateName: tfjob
  namespace: your-user-namespace
spec:
  tfReplicaSpecs:
    PS:
      replicas: 1
      restartPolicy: OnFailure
      template:
        spec:
          containers:
          - name: tensorflow
            image: gcr.io/your-project/your-image
            command:
              - python
              - -m
              - trainer.task
              - --batch_size=32
              - --training_steps=1000
    Worker:
      replicas: 3
      restartPolicy: OnFailure
      template:
        spec:
          containers:
          - name: tensorflow
            image: gcr.io/your-project/your-image
            command:
              - python
              - -m
              - trainer.task
              - --batch_size=32
              - --training_steps=1000

GKE ベースで Kubeflow インストールを行なったときに自動的に作成される GCP クレデンシャルのような、クレデンシャル secret への TFJob ポッド・アクセスを与えることを望む場合、このように secret をマウントして使用できます :

apiVersion: kubeflow.org/v1
kind: TFJob
metadata:
  generateName: tfjob
  namespace: your-user-namespace
spec:
  tfReplicaSpecs:
    PS:
      replicas: 1
      restartPolicy: OnFailure
      template:
        spec:
          containers:
          - name: tensorflow
            image: gcr.io/your-project/your-image
            command:
              - python
              - -m
              - trainer.task
              - --batch_size=32
              - --training_steps=1000
            env:
            - name: GOOGLE_APPLICATION_CREDENTIALS
              value: "/etc/secrets/user-gcp-sa.json"
            volumeMounts:
            - name: sa
              mountPath: "/etc/secrets"
              readOnly: true
          volumes:
          - name: sa
            secret:
              secretName: user-gcp-sa
    Worker:
      replicas: 1
      restartPolicy: OnFailure
      template:
        spec:
          containers:
          - name: tensorflow
            image: gcr.io/your-project/your-image
            command:
              - python
              - -m
              - trainer.task
              - --batch_size=32
              - --training_steps=1000
            env:
            - name: GOOGLE_APPLICATION_CREDENTIALS
              value: "/etc/secrets/user-gcp-sa.json"
            volumeMounts:
            - name: sa
              mountPath: "/etc/secrets"
              readOnly: true
          volumes:
          - name: sa
            secret:
              secretName: user-gcp-sa

Kubernetes リソースに馴染みがないのであれば、ページ Understanding Kubernetes オブジェクト を参照してください。

TFJob を 組込みコントローラ と違わせるものは TFJob spec は 分散 TensorFlow 訓練ジョブ を管理するために設計されていることです。

分散 TensorFlow ジョブは典型的には以下のプロセスの 0 またそれ以上を含みます :

  • Chief : chief はモデルをチェックポイントするように訓練の編成とタスクの遂行の責任を負います。
  • Ps : ps はパラメータ・サーバです ; これらのサーバはモデルパラメータのための分散データストアを提供します。
  • Worker : ワーカーはモデルを訓練する実際の作業を行ないます。ある場合には、ワーカー 0 はまた chief として動作するかもしれません。
  • Evaluator : 評価器はモデルが訓練されるとき評価メトリクスを計算するために使用できます。

TFJob spec のフィールド tfReplicaSpecs は (上でリストされた) レプリカのタイプからそのレプリカのための TFReplicaSpec へのマップを含みます。TFReplicaSpec は 3 フィールドから成ります :

  • replicas この TFJob のために起動するこのタイプのレプリカ数。
  • template 各レプリカのために作成するポッドを記述する PodTemplateSpec
    • ポッドは tensorflow という名前のコンテナを含まなければなりません
  • restartPolicy ポッドがそれらが exit するとき再開始されるか否かを決定します。許可される値は次のようなものです :
    • Always はポッドが常に再開始されることを意味します。このポリシーはパラメータサーバのために良いです、何故ならばそれらは決して exit せずに failure イベントでは常に再開始されるべきであるためです。
    • OnFailure はポッドが failure により exit する場合に再開始されることを意味します。
      • 非ゼロは failure を示すコードです。
      • 0 の exit コードは成功を示しそしてポッドは再開始されません。
      • このポリシーは chief と worker のために良いです。
    • ExitCode は再開始動作は次のように tensorflow コンテナの exit コードに依拠していることを意味します。
      • Exit コード 0 はプロセスは成功的に完了し再開始されません。
      • 以下の exit コードはパーマネントエラーを示しそしてコンテナは再開始されません :
        • 1: 一般エラー
        • 2: misuse of shell builtins
        • 126: command invoked cannot execute
        • 127: command not found
        • 128: invalid argument to exit
        • 139: container terminated by SIGSEGV (invalid memory reference)
      • 以下の exit コードは再試行可能なエラーを示しそしてコンテナは再開始されます :
        • 130: container terminated by SIGINT (keyboard Control-C)
        • 137: container received a SIGKILL
        • 143: container received a SIGTERM
      • Exit コード 138 は SIGUSR1 に対応してユーザ指定再試行可能なエラーのために予約されています。
      • 他の exit コードは未定義で動作について保証はありません。

      exit コードのバックグラウンド情報については、termination シグナルへの GNU ガイドLinux ドキュメント・プロジェクト を見てください。

    • Never は停止するポッドは決して再開始されないことを意味します。このポリシーは滅多に使用されないはずです、何故ならば Kubernetes はどのような数の理由 (e.g. ノードが不安定になる) でもポッドを停止しそしてこれはジョブがリカバーされることを回避するからです。

 

クイックスタート

TensorFlow 訓練ジョブを投入する

Note: 訓練ジョブを投入する前に、kubeflow を貴方のクラスタに配備する べきでした。それを行なうことで訓練ジョブを投入するとき TFJob カスタム・リソース が利用可能であることを確かなものにします。

 

MNist サンプルを実行する

Kubeflow は単純な MNist モデル を実行するために適した サンプル とともに配布されています。

git clone https://github.com/kubeflow/tf-operator
cd tf-operator/examples/v1/mnist_with_summaries
# Deploy the event volume
kubectl apply -f tfevent-volume
# Submit the TFJob
kubectl apply -f tf_job_mnist.yaml

ジョブを監視する (下の詳細ガイド を見てください) :

kubectl -n kubeflow get tfjob mnist -o yaml

それを削除する :

kubectl -n kubeflow delete tfjob mnist

 

TFJob をカスタマイズする

典型的には TFJob yaml ファイルの次の値を変更できます :

  1. イメージを貴方のコードを含む docker イメージを指すように変更する
  2. レプリカの数とタイプを変更する
  3. 各リソースに割り当てられたリソース (リクエストと制限) を変更する
  4. 任意の環境変数を設定する
    • 例えば、GCS or S3 のようなデータストアと通信するために様々な環境変数を configure する必要があるかもしれません
  5. ストレージのために PV を使用することを望む場合 PV を装着する。

 

GPU を使用する

貴方のクラスタは GPU を利用するために configure されなければなりません。

GPU を装着するには GPU を含むべきレプリカのコンテナ上の GPU リソースを指定します ; 例えば :

apiVersion: "kubeflow.org/v1"
kind: "TFJob"
metadata:
  name: "tf-smoke-gpu"
spec:
  tfReplicaSpecs:
    PS:
      replicas: 1
      template:
        metadata:
          creationTimestamp: null
        spec:
          containers:
          - args:
            - python
            - tf_cnn_benchmarks.py
            - --batch_size=32
            - --model=resnet50
            - --variable_update=parameter_server
            - --flush_stdout=true
            - --num_gpus=1
            - --local_parameter_device=cpu
            - --device=cpu
            - --data_format=NHWC
            image: gcr.io/kubeflow/tf-benchmarks-cpu:v20171202-bdab599-dirty-284af3
            name: tensorflow
            ports:
            - containerPort: 2222
              name: tfjob-port
            resources:
              limits:
                cpu: '1'
            workingDir: /opt/tf-benchmarks/scripts/tf_cnn_benchmarks
          restartPolicy: OnFailure
    Worker:
      replicas: 1
      template:
        metadata:
          creationTimestamp: null
        spec:
          containers:
          - args:
            - python
            - tf_cnn_benchmarks.py
            - --batch_size=32
            - --model=resnet50
            - --variable_update=parameter_server
            - --flush_stdout=true
            - --num_gpus=1
            - --local_parameter_device=cpu
            - --device=gpu
            - --data_format=NHWC
            image: gcr.io/kubeflow/tf-benchmarks-gpu:v20171202-bdab599-dirty-284af3
            name: tensorflow
            ports:
            - containerPort: 2222
              name: tfjob-port
            resources:
              limits:
                nvidia.com/gpu: 1
            workingDir: /opt/tf-benchmarks/scripts/tf_cnn_benchmarks
          restartPolicy: OnFailure

GPU を利用するための TensorFlow の 手順 に従ってください。

 

貴方のジョブを監視する

貴方のジョブのステータスを得るには :

kubectl get -o yaml tfjobs ${JOB}

ここのサンプル・ジョブのためのサンプル出力があります :

apiVersion: kubeflow.org/v1
kind: TFJob
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"kubeflow.org/v1","kind":"TFJob","metadata":{"annotations":{},"name":"mnist","namespace":"kubeflow"},"spec":{"cleanPodPolicy":"None","tfReplicaSpecs":{"Worker":{"replicas":1,"restartPolicy":"Never","template":{"spec":{"containers":[{"command":["python","/var/tf_mnist/mnist_with_summaries.py","--log_dir=/train","--learning_rate=0.01","--batch_size=150"],"image":"gcr.io/kubeflow-ci/tf-mnist-with-summaries:1.0","name":"tensorflow","volumeMounts":[{"mountPath":"/train","name":"training"}]}],"volumes":[{"name":"training","persistentVolumeClaim":{"claimName":"tfevent-volume"}}]}}}}}}
  creationTimestamp: "2019-07-16T02:44:38Z"
  generation: 1
  name: mnist
  namespace: your-user-namespace
  resourceVersion: "10429537"
  selfLink: /apis/kubeflow.org/v1/namespaces/kubeflow/tfjobs/mnist
  uid: a77b9fb4-a773-11e9-91fe-42010a960094
spec:
  cleanPodPolicy: None
  tfReplicaSpecs:
    Worker:
      replicas: 1
      restartPolicy: Never
      template:
        spec:
          containers:
          - command:
            - python
            - /var/tf_mnist/mnist_with_summaries.py
            - --log_dir=/train
            - --learning_rate=0.01
            - --batch_size=150
            image: gcr.io/kubeflow-ci/tf-mnist-with-summaries:1.0
            name: tensorflow
            volumeMounts:
            - mountPath: /train
              name: training
          volumes:
          - name: training
            persistentVolumeClaim:
              claimName: tfevent-volume
status:
  completionTime: "2019-07-16T02:45:23Z"
  conditions:
  - lastTransitionTime: "2019-07-16T02:44:38Z"
    lastUpdateTime: "2019-07-16T02:44:38Z"
    message: TFJob mnist is created.
    reason: TFJobCreated
    status: "True"
    type: Created
  - lastTransitionTime: "2019-07-16T02:45:20Z"
    lastUpdateTime: "2019-07-16T02:45:20Z"
    message: TFJob mnist is running.
    reason: TFJobRunning
    status: "True"
    type: Running
  replicaStatuses:
    Worker:
      running: 1
  startTime: "2019-07-16T02:44:38Z"

 

条件

TFJob は TFJobStatus を持ち、これは TFJobConditions の配列を持ちます、それを通して TFJob は通過または非通過しました。TFJobCondition の各要素は 6 つの可能なフィールドを持ちます :

  • lastUpdateTime フィールドはこの条件が更新された最後の時間を提供します。
  • lastTransitionTime フィールドは条件が一つのステータスから他に遷移した最後の時間を提供します。
  • message フィールドは遷移についての詳細を示す可読なメッセージです。
  • reason フィールドは条件の最後の遷移のための一意、1 単語、CamelCase な理由です。
  • status フィールドは可能な値 “True”, “False” と “Unknown” を持つ文字列です。
  • type フィールドは以下の可能な値を持つ文字列です :
    • TFJobCreated は tfjob がシステムにより受け取られたことを意味しますが、ポッド/サービスの一つまたはそれ以上がまだ開始されていません。
    • TFJobRunning はこの TFJob の総てのサブリソース (e.g. サービス/ポッド) が成功的にスケジュールされて起動されてジョブが実行されていることを意味します。
    • TFJobRestarting はこの TFJob の一つまたはそれ以上のサブリソース (e.g. サービス/ポッド) が問題を持ち再開始されていることを意味します。
    • TFJobSucceeded はジョブが成功的に完了したことを意味します。
    • TFJobFailed はジョブが失敗したことを意味します。

ジョブの成功と失敗は次のように決定されます :

  • ジョブが chief 成功か失敗を持つかは chief のステータスにより決定されます。
  • ジョブが chief でない成功か失敗を持つかはワーカーにより決定されます。
  • 両者の場合、TFJob は監視されているプロセスが exit コード 0 で抜ける場合に成功します。
  • 非ゼロ exit コードの場合動作はレプリカのための restartPolicy により決定されます。
  • restartPolicy が再開始を許容する場合にはプロセスは単に再開始されて TFJob は実行し続けます。
    • restartPolicy ExitCode については動作は exit コード依存です。
    • restartPolicy が再開始を許容しない場合、非ゼロ exit コードはパーマネント失敗と考えられてジョブは失敗とマークされます。

 

tfReplicaStatuses

tfReplicaStatuses は与えられた状態にある各レプリカのためのポッドの数を示すマップを提供します。3 つの可能な状態があります :

  • Active は現在実行中のポッドの数です。
  • Succeeded は成功的に完了したポッドの数です。
  • Failed はエラーで完了したポッドの数です。

 

イベント

実行の間、TFJob はポッドとサービスの作成/削除のような発生したことを示すためにイベントを出力します。Kubernetes はデフォルトでは 1 時間よりも古いイベントは保持しません。ジョブのための最近のイベントを見るには次を実行します :

kubectl describe tfjobs ${JOB}

これは次のような出力を生成します :

Name:         mnist
Namespace:    kubeflow
Labels:       
Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                {"apiVersion":"kubeflow.org/v1","kind":"TFJob","metadata":{"annotations":{},"name":"mnist","namespace":"kubeflow"},"spec":{"cleanPodPolicy...
API Version:  kubeflow.org/v1
Kind:         TFJob
Metadata:
  Creation Timestamp:  2019-07-16T02:44:38Z
  Generation:          1
  Resource Version:    10429537
  Self Link:           /apis/kubeflow.org/v1/namespaces/kubeflow/tfjobs/mnist
  UID:                 a77b9fb4-a773-11e9-91fe-42010a960094
Spec:
  Clean Pod Policy:  None
  Tf Replica Specs:
    Worker:
      Replicas:        1
      Restart Policy:  Never
      Template:
        Spec:
          Containers:
            Command:
              python
              /var/tf_mnist/mnist_with_summaries.py
              --log_dir=/train
              --learning_rate=0.01
              --batch_size=150
            Image:  gcr.io/kubeflow-ci/tf-mnist-with-summaries:1.0
            Name:   tensorflow
            Volume Mounts:
              Mount Path:  /train
              Name:        training
          Volumes:
            Name:  training
            Persistent Volume Claim:
              Claim Name:  tfevent-volume
Status:
  Completion Time:  2019-07-16T02:45:23Z
  Conditions:
    Last Transition Time:  2019-07-16T02:44:38Z
    Last Update Time:      2019-07-16T02:44:38Z
    Message:               TFJob mnist is created.
    Reason:                TFJobCreated
    Status:                True
    Type:                  Created
    Last Transition Time:  2019-07-16T02:45:20Z
    Last Update Time:      2019-07-16T02:45:20Z
    Message:               TFJob mnist is running.
    Reason:                TFJobRunning
    Status:                True
    Type:                  Running
  Replica Statuses:
    Worker:
      Running:  1
  Start Time:  2019-07-16T02:44:38Z
Events:
  Type    Reason                   Age    From         Message
  ----    ------                   ----   ----         -------
  Normal  SuccessfulCreatePod      8m6s   tf-operator  Created pod: mnist-worker-0
  Normal  SuccessfulCreateService  8m6s   tf-operator  Created service: mnist-worker-0

ここでイベントはポッドとサービスが成功的に作成されたことを示します。

 

TensorFlow ログ

ロギングは標準的な K8s ロギング実践に従います。

削除 されなかった任意のポッドのための標準的な出力/エラーを得るために kubectl を使用できます。

最初に関心のあるレプリカのためのジョブ・コントローラにより作成されたポッドを見つけます。ポッドは次のように名前付けられます :

${JOBNAME}-${REPLICA-TYPE}-${INDEX}

ひとたびポッドを特定すれば、kubectl を使用してログを得ることができます。

kubectl logs ${PODNAME}

TFJob spec の CleanPodPolicy はジョブが停止したときポッドの削除を制御します。ポリシーは以下の値の一つであり得ます :

  • Running はジョブが完了したとき依然として実行しているポッド (e.g. パラメータサーバ) だけが直ちに削除されます ; 完了したポッドはログが保存されるように削除されません。これはデフォルト値です。
  • All ポリシーはジョブが終了したとき総てのポッド、完了したポッドさえも直ちに削除されることを意味します。
  • None ポリシーはジョブが完了したときポッドは削除されないことを意味します。

貴方のクラスタが Kubernetes クラスタ・ロギング を活用するならばログも更なる解析のために適切なデータストアに送られるかもしれません。

 

GKE 上の Stackdriver

Stackdriver を使用してログを得る上での手順については ロギングと監視 へのガイドを見てください。

ロギングと監視 へのガイドで説明されているように、ポッドラベルに基づいて特定のレプリカのためのログを取得することができます。

Stackdriver UI を使用して次のような問い合わせを使用できます :

resource.type="k8s_container"
resource.labels.cluster_name="${CLUSTER}"
metadata.userLabels.tf_job_name="${JOB_NAME}"
metadata.userLabels.tf-replica-type="${TYPE}"
metadata.userLabels.tf-replica-index="${INDEX}"

代わりに gcloud を使用して :

QUERY="resource.type=\"k8s_container\" "
QUERY="${QUERY} resource.labels.cluster_name=\"${CLUSTER}\" "
QUERY="${QUERY} metadata.userLabels.tf_job_name=\"${JOB_NAME}\" "
QUERY="${QUERY} metadata.userLabels.tf-replica-type=\"${TYPE}\" "
QUERY="${QUERY} metadata.userLabels.tf-replica-index=\"${INDEX}\" "
gcloud --project=${PROJECT} logging read  \
     --freshness=24h \
     --order asc  ${QUERY}

 

トラブルシューティング

ここに貴方のジョブのトラブルシュートをするために従うべき幾つかのステップがあります。

  1. ステータスは貴方のジョブのために存在していますか? 次のコマンドを実行してください :
    kubectl -n ${USER_NAMESPACE} get tfjobs -o yaml ${JOB_NAME}
    
    • USER_NAMESPACE は貴方のユーザプロフィールのために作成された名前空間です。
    • 結果としての出力が貴方のジョブのためのステータスを含まない場合、これは典型的にはジョブ spec が不正であることを示しています。
    • TFJob spec が不正であれば tf operator ログにログメッセージがあるはずです :
        kubectl -n ${KUBEFLOW_NAMESPACE} logs `kubectl get pods --selector=name=tf-job-operator -o jsonpath='{.items[0].metadata.name}'` 
        

      • KUBEFLOW_NAMESPACE は TFJob 演算子を配備した名前空間です。

     

  2. ポッドが作成されたかを見るために貴方のジョブのためのイベントを確認します。
    • イベントを得るために幾つかの方法があります ; ジョブが 1 時間未満であれば次を行なうことができます :
        kubectl -n ${USER_NAMESPACE} describe tfjobs -o yaml ${JOB_NAME}
        
    • 出力のボトムはジョブにより出力されたイベントのリストを含むはずです ; e.g.
      Events:
      Type     Reason                          Age                From         Message
      ----     ------                          ----               ----         -------
      Warning  SettedPodTemplateRestartPolicy  19s (x2 over 19s)  tf-operator  Restart policy in pod template will be overwritten by restart policy in replica spec
      Normal   SuccessfulCreatePod             19s                tf-operator  Created pod: tfjob2-worker-0
      Normal   SuccessfulCreateService         19s                tf-operator  Created service: tfjob2-worker-0
      Normal   SuccessfulCreatePod             19s                tf-operator  Created pod: tfjob2-ps-0
      Normal   SuccessfulCreateService         19s                tf-operator  Created service: tfjob2-ps-0
      
    • Kubernetes は 1 時間 の間イベントを保存するだけです (kubernetes/kubernetes#52521 参照)
      • 貴方のクラスタ・セットアップに依拠してイベントは外部ストレージに存続してより長い期間アクセス可能かもしれません。
      • GKE 上ではイベントは stackdriver で存続されて前のセクションの手順を使用してアクセスできます。
    • ポッドとサービスが作成されなければこれは TFJob が処理されていないことを提示します ; 一般的な原因は :
      • TFJob spec が不正である (上を見てください)
      • TFJob 演算子が動作していない

     

  3. ポッドのためのイベントをそれらがスケジュールされたかを確実にするためにクリックします。
    • イベントを得るために幾つかの方法があります ; ポッドが 1 時間未満であれば次を行なうことができます :
        kubectl -n ${USER_NAMESPACE} describe pods ${POD_NAME}
        
    • 出力のボトムは次のようなイベントを含むはずです :
      Events:
      Type    Reason                 Age   From                                                  Message
      ----    ------                 ----  ----                                                  -------
      Normal  Scheduled              18s   default-scheduler                                     Successfully assigned tfjob2-ps-0 to gke-jl-kf-v0-2-2-default-pool-347936c1-1qkt
      Normal  SuccessfulMountVolume  17s   kubelet, gke-jl-kf-v0-2-2-default-pool-347936c1-1qkt  MountVolume.SetUp succeeded for volume "default-token-h8rnv"
      Normal  Pulled                 17s   kubelet, gke-jl-kf-v0-2-2-default-pool-347936c1-1qkt  Container image "gcr.io/kubeflow/tf-benchmarks-cpu:v20171202-bdab599-dirty-284af3" already present on machine
      Normal  Created                17s   kubelet, gke-jl-kf-v0-2-2-default-pool-347936c1-1qkt  Created container
      Normal  Started                16s   kubelet, gke-jl-kf-v0-2-2-default-pool-347936c1-1qkt  Started container
      
    • コンテナを開始から妨げられる幾つかの一般的な問題は :
      • ポッドをスケジュールするために不十分なリソース
      • ポッドが存在しないか利用不可能なボリューム (or secret) をマウントしようとする
      • docker イメージが存在しないかアクセスできない (e.g. パーミッション問題により)
  4. コンテナが開始される場合 ; 前のセクションの手順に従ってコンテナのログを確認してください。
 

以上






AI導入支援 #2 ウェビナー

スモールスタートを可能としたAI導入支援   Vol.2
[無料 WEB セミナー] [詳細]
「画像認識 AI PoC スターターパック」の紹介
既に AI 技術を実ビジネスで活用し、成果を上げている日本企業も多く存在しており、競争優位なビジネスを展開しております。
しかしながら AI を導入したくとも PoC (概念実証) だけでも高額な費用がかかり取組めていない企業も少なくないようです。A I導入時には欠かせない PoC を手軽にしかも短期間で認知度を確認可能とするサービの紹介と共に、AI 技術の特性と具体的な導入プロセスに加え運用時のポイントについても解説いたします。
日時:2021年10月13日(水)
会場:WEBセミナー
共催:クラスキャット、日本FLOW(株)
後援:働き方改革推進コンソーシアム
参加費: 無料 (事前登録制)
人工知能開発支援
◆ クラスキャットは 人工知能研究開発支援 サービスを提供しています :
  • テクニカルコンサルティングサービス
  • 実証実験 (プロトタイプ構築)
  • アプリケーションへの実装
  • 人工知能研修サービス
◆ お問合せ先 ◆
(株)クラスキャット
セールス・インフォメーション
E-Mail:sales-info@classcat.com