オンライン会話は、ビデオゲームから電気通信に至るまで、現代の生活に遍在しています。 これにより、オンライン会話データの量が指数関数的に増加し、チャットボットや自然言語生成(NLG)モデルなどの最先端の自然言語処理(NLP)システムの開発に役立っています。 時間の経過とともに、テキスト分析のためのさまざまなNLP手法も進化してきました。 これには、広範な機械学習(ML)の専門知識を必要とせずに、API呼び出しを使用してアプリケーションに統合できるフルマネージドサービスの要件が必要です。 AWSは、次のような事前トレーニング済みのAWSAIサービスを提供します Amazon Comprehend、分類、テキストの要約、エンティティの認識などを含むNLPのユースケースを効果的に処理して、テキストから洞察を収集できます。
さらに、オンラインでの会話は、従来とは異なる言語の使用という広範な現象を引き起こしました。 従来のNLP手法は、さまざまなプラットフォーム内に存在する絶えず進化するドメイン固有の語彙、および偶然または敵対的な攻撃の形式としての適切な英語からの単語の大幅な語彙の逸脱のために、このテキストデータでパフォーマンスが低下することがよくあります。
この投稿では、AWSで利用可能なツールとサービスを使用したオンライン会話のテキスト分類のための複数のMLアプローチについて説明します。
前提条件
このユースケースを深く掘り下げる前に、次の前提条件を完了してください。
- セットアップ AWSアカウント & IAMユーザーを作成する.
- セットアップ AWSCLI & AWSSDK.
- (オプション)を設定します Cloud9IDE環境.
データセット
この投稿では、 毒性分類データセットのジグソー意図しないバイアス、オンライン会話における毒性の分類の特定の問題のベンチマーク。 データセットは、毒性ラベルに加えて、わいせつ、アイデンティティ攻撃、侮辱、脅迫、性的に露骨なものなどのいくつかのサブグループ属性を提供します。 ラベルは小数値として提供されます。これは、特定のテキストに属性が適用されていると信じている人間のアノテーターの割合を表しますが、全員一致になることはめったにありません。 バイナリラベル(たとえば、毒性または非毒性)を生成するために、0.5のしきい値が小数値に適用され、しきい値より大きい値のコメントは、そのラベルのポジティブクラスとして扱われます。
サブワードの埋め込みとRNN
最初のモデリングアプローチでは、サブワード埋め込みとリカレントニューラルネットワーク(RNN)の組み合わせを使用して、テキスト分類モデルをトレーニングします。 サブワード埋め込みはによって導入されました Bojanowskietal。 2017年 以前の単語レベルの埋め込み方法の改善として。 従来のWord2Vecスキップグラムモデルは、ターゲット単語のコンテキストを最適に予測する静的ベクトル表現を学習するようにトレーニングされています。 一方、サブワードモデルは、各ターゲット単語を、単語を構成する文字n-gramのバッグとして表します。n-gramは、n個の連続する文字のセットで構成されます。 この方法により、埋め込みモデルは、コーパス内の関連する単語の基本的な形態をより適切に表すことができ、新しい語彙外(OOV)単語の埋め込みを計算することもできます。 これは、オンライン会話のコンテキストで特に重要です。これは、ユーザーが単語のスペルを間違えることが多く(場合によっては意図的に検出を回避するため)、一般的なトレーニングコーパスではキャプチャされない可能性のある独自の絶えず進化する語彙を使用する問題空間です。
アマゾンセージメーカー 組み込みのドメイン固有テキストデータの独自のコーパスで、教師なしサブワード埋め込みモデルを簡単にトレーニングおよび最適化できます。 BlazingTextアルゴリズム。 次のようなオンラインテキストの大規模なデータセットでトレーニングされた既存の汎用モデルをダウンロードすることもできます。 fastTextから直接入手できる英語モデル。 SageMakerノートブックインスタンスから、以下を実行して、事前にトレーニングされたfastTextモデルをダウンロードします。
!wget -O vectors.zip https://dl.fbaipublicfiles.com/fasttext/vectors-english/crawl-300d-2M-subword.zip
BlazingTextを使用して独自の埋め込みをトレーニングした場合でも、事前にトレーニングしたモデルをダウンロードした場合でも、結果はzip形式のモデルバイナリになり、gensimライブラリで使用して、特定のターゲット単語をその構成サブワードに基づくベクターとして埋め込むことができます。
# Imports
import os
from zipfile import ZipFile
from gensim.models.fasttext import load_facebook_vectors # Unzip the model binary into 'dir_path'
with ZipFile('vectors.zip', 'r') as zipObj: zipObj.extractall(path=<dir_path_name>) # Load embedding model into memory
embed_model = load_facebook_vectors(os.path.join(<dir_path_name>, 'vectors.bin')) # Compute embedding vector for 'word'
word_embedding = embed_model[word]
テキストの特定のセグメントを前処理した後、このアプローチを使用して、構成する単語ごとに(スペースで区切られた)ベクトル表現を生成できます。 次に、SageMakerとPyTorchなどの深層学習フレームワークを使用して、バイナリまたはマルチラベル分類の目的でカスタマイズされたRNNをトレーニングし、ラベル付きのトレーニング例に基づいて、テキストが毒性であるかどうか、および毒性の特定のサブタイプを予測します。
前処理されたテキストをにアップロードするには Amazon シンプル ストレージ サービス (Amazon S3)、次のコードを使用します。
import boto3
s3 = boto3.client('s3') bucket = <bucket_name>
prefix = <prefix_name> s3.upload_file('train.pkl', bucket, os.path.join(prefix, 'train/train.pkl'))
s3.upload_file('valid.pkl', bucket, os.path.join(prefix, 'valid/valid.pkl'))
s3.upload_file('test.pkl', bucket, os.path.join(prefix, 'test/test.pkl'))
SageMakerでスケーラブルなマルチGPUモデルトレーニングを開始するには、次のコードを入力します。
import sagemaker
sess = sagemaker.Session()
role = iam.get_role(RoleName= ‘AmazonSageMakerFullAccess’)['Role']['Arn'] from sagemaker.pytorch import PyTorch # hyperparameters, which are passed into the training job
hyperparameters = { 'epochs': 20, # Maximum number of epochs to train model 'train-batch-size': 128, # Training batch size (No. sentences) 'eval-batch-size': 1024, # Evaluation batch size (No. sentences) 'embed-size': 300, # Vector dimension of word embeddings (Must match embedding model) 'lstm-hidden-size': 200, # Number of neurons in LSTM hidden layer 'lstm-num-layers': 2, # Number of stacked LSTM layers 'proj-size': 100, # Number of neurons in intermediate projection layer 'num-targets': len(<list_of_label_names>), # Number of targets for classification 'class-weight': ' '.join([str(c) for c in <list_of_weights_per_class>]), # Weight to apply to each target during training 'total-length':<max_number_of_words_per_sentence>, 'metric-for-best-model': 'ap_score_weighted', # Metric on which to select the best model
} # create the Estimator
pytorch_estimator = PyTorch( entry_point='train.py', source_dir=<source_dir_path>, instance_type=<train_instance_type>, volume_size=200, instance_count=1, role=role, framework_version='1.6.0’, py_version='py36', hyperparameters=hyperparameters, metric_definitions=[ {'Name': 'validation:accuracy', 'Regex': 'eval_accuracy = (.*?);'}, {'Name': 'validation:f1-micro', 'Regex': 'eval_f1_score_micro = (.*?);'}, {'Name': 'validation:f1-macro', 'Regex': 'eval_f1_score_macro = (.*?);'}, {'Name': 'validation:f1-weighted', 'Regex': 'eval_f1_score_weighted = (.*?);'}, {'Name': 'validation:ap-micro', 'Regex': 'eval_ap_score_micro = (.*?);'}, {'Name': 'validation:ap-macro', 'Regex': 'eval_ap_score_macro = (.*?);'}, {'Name': 'validation:ap-weighted', 'Regex': 'eval_ap_score_weighted = (.*?);'}, {'Name': 'validation:auc-micro', 'Regex': 'eval_auc_score_micro = (.*?);'}, {'Name': 'validation:auc-macro', 'Regex': 'eval_auc_score_macro = (.*?);'}, {'Name': 'validation:auc-weighted', 'Regex': 'eval_auc_score_weighted = (.*?);'} ]
) pytorch_estimator.fit( { 'train': 's3://<bucket_name>/<prefix_name>/train', 'valid': 's3://<bucket_name>/<prefix_name>/valid', 'test': 's3://<bucket_name>/<prefix_name>/test' }
)
中で 、によって使用されるPyTorchデータセットを定義します train.py
モデルのトレーニングと評価のためにテキストデータを準備するには:
def pad_matrix(m: torch.Tensor, max_len: int =100)-> tuple[int, torch.Tensor] : """Pads an embedding matrix to a specified maximum length.""" if m.ndim == 1: m = m.reshape(1, -1) mask = np.ones_like(m) if m.shape[0] > max_len: m = m[:max_len, :] mask = mask[:max_len, :] else: m = np.pad(m, ((0, max_len - m.shape[0]), (0,0))) mask = np.pad(mask, ((0, max_len - mask.shape[0]), (0,0))) return m, mask class EmbeddingDataset(Dataset: torch.utils.data.Dataset): """PyTorch dataset representing pretrained sentence embeddings, masks, and labels.""" def __init__(self, text: str, labels: int, max_len: int=100): self.text = text self.labels = labels self.max_len = max_len def __len__(self) -> int: return len(self.labels) def __getitem__(self, idx: int) -> dict: e = embed_line(self.text[idx]) length = e.shape[0] m, mask = pad_matrix(e, max_len=self.max_len) item = {} item['embeddings'] = torch.from_numpy(m) item['mask'] = torch.from_numpy(mask) item['labels'] = torch.tensor(self.labels[idx]) if length > self.max_len: item['lengths'] = torch.tensor(self.max_len) else: item['lengths'] = torch.tensor(length) return item
このコードは、 vectors.zip
fastTextまたはBlazingTextの埋め込みを含むファイルはに保存されます .
さらに、事前にトレーニングされたfastTextモデルをライブのSageMakerエンドポイントに簡単にデプロイして、関連する単語レベルのタスクで使用する埋め込みベクトルをその場で計算できます。 以下を参照してください GitHubの例 のガイドをご参照ください。
抱きしめる顔のトランスフォーマー
XNUMX番目のモデリングアプローチでは、論文で紹介したトランスフォーマーの使用法に移行します 注意はあなたが必要とするすべてです。 トランスフォーマーは、入力と出力の間にグローバルな依存関係を描画するための自己注意メカニズムに依存することにより、RNNの落とし穴を意図的に回避するように設計された深層学習モデルです。 Transformerモデルアーキテクチャは、大幅に優れた並列化を可能にし、比較的短いトレーニング時間で高いパフォーマンスを実現できます。
論文で紹介されたTransformers、BERTの成功に基づいて構築 BERT:言語理解のためのディープ双方向トランスフォーマーの事前トレーニング、言語表現のための双方向の事前トレーニングを追加しました。 クローズタスクに触発されたBERTは、マスクされた言語モデリング(MLM)で事前にトレーニングされており、モデルはランダムにマスクされたトークンの元の単語を復元することを学習します。 BERTモデルは、次の文の予測(NSP)タスクでも事前にトレーニングされており、2018つの文が正しい読み順であるかどうかを予測します。 XNUMX年の登場以来、BERTとそのバリエーションは、テキスト分類タスクで広く使用されてきました。
私たちのソリューションは、論文で紹介されたRoBERTaとして知られるBERTのバリアントを使用しています RoBERTa:ロバストに最適化されたBERT事前トレーニングアプローチ。 RoBERTaは、最適化されたハイパーパラメータの使用、動的ランダムマスキング、NSPタスクの削除など、10倍大きいコーパスでモデルをより長くトレーニングするなど、最適化されたモデルトレーニングによって、さまざまな自然言語タスクでのBERTパフォーマンスをさらに向上させます。
RoBERTaベースのモデルは フェイストランスフォーマーを抱き締める ライブラリ。これは、さまざまなNLPタスク用のあらゆる種類の最先端のTransformerモデルの高品質な実装を提供する人気のあるオープンソースのPythonフレームワークです。 HuggingFaceはAWSと提携しています SageMakerでTransformerモデルを簡単にトレーニングしてデプロイできるようにします。 この機能は、 顔を抱き締めるAWSディープラーニングコンテナの画像、Transformers、Tokenizers、およびDatasetsライブラリが含まれ、モデルのトレーニングと推論のためにSageMakerとの統合が最適化されています。
私たちの実装では、Hugging Face TransformersフレームワークからRoBERTaアーキテクチャバックボーンを継承し、SageMakerを使用して、RoBERToxと呼ばれる独自のテキスト分類モデルをトレーニングおよびデプロイします。 RoBERToxは、で導入されたバイトペアエンコーディング(BPE)を使用します。 サブワード単位を持つレアワードのニューラル機械翻訳、入力テキストをサブワード表現にトークン化します。 次に、モデルとトークナイザーをJigsawデータまたは任意の大規模なドメイン固有のコーパス(特定のゲームのチャットログなど)でトレーニングし、カスタマイズされたテキスト分類に使用できます。 次のコードでカスタム分類モデルクラスを定義します。
class RoBERToxForSequenceClassification(CustomLossMixIn, RobertaPreTrainedModel): _keys_to_ignore_on_load_missing = [r"position_ids"] def __init__(self, config: PretrainedConfig, *inputs, **kwargs): """Initialize the RoBERToxForSequenceClassification instance Parameters ---------- config : PretrainedConfig num_labels : Optional[int] if not None, overwrite the default classification head in pretrained model. mode : Optional[str] 'MULTI_CLASS', 'MULTI_LABEL' or "REGRESSION". Used to determine loss class_weight : Optional[List[float]] If not None, add class weight to BCEWithLogitsLoss or CrossEntropyLoss """ super().__init__(config, *inputs, **kwargs) # Define model architecture self.roberta = RobertaModel(self.config, add_pooling_layer=False) self.classifier = RobertaClassificationHead(self.config) self.init_weights() @modeling_roberta.add_start_docstrings_to_model_forward( modeling_roberta.ROBERTA_INPUTS_DOCSTRING.format("batch_size, sequence_length") ) @modeling_roberta.add_code_sample_docstrings( tokenizer_class=modeling_roberta._TOKENIZER_FOR_DOC, checkpoint=modeling_roberta._CHECKPOINT_FOR_DOC, output_type=SequenceClassifierOutput, config_class=modeling_roberta._CONFIG_FOR_DOC, ) def forward( self, input_ids: torch.Tensor = None, attention_mask: torch.Tensor = None, token_type_ids: torch.Tensor = None, position_ids: torch.Tensor =None, head_mask: torch.Tensor =None, inputs_embeds: torch.Tensor =None, labels: torch.Tensor =None, output_attentions: torch.Tensor =None, output_hidden_states: torch.Tensor =None, return_dict: bool =None, sample_weights: torch.Tensor =None, ) -> : dict: """Forward pass to return loss, logits, ... Returns -------- output : SequenceClassifierOutput has those keys: loss, logits, hidden states, attentions """ return_dict = return_dict or self.config.use_return_dict outputs = self.roberta( input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids, position_ids=position_ids, head_mask=head_mask, inputs_embeds=inputs_embeds, output_attentions=output_attentions, output_hidden_states=output_hidden_states, return_dict=return_dict, ) sequence_output = outputs[0] # [CLS] embedding logits = self.classifier(sequence_output) loss = self.compute_loss(logits, labels, sample_weights=sample_weights) if not return_dict: output = (logits,) + outputs[2:] return ((loss,) + output) if loss is not None else output return SequenceClassifierOutput( loss=loss, logits=logits, hidden_states=outputs.hidden_states, attentions=outputs.attentions, ) def compute_loss(self, logits: torch.Tensor, labels: torch.Tensor, sample_weights: Optional[torch.Tensor] = None) -> torch.FloatTensor: return super().compute_loss(logits, labels, sample_weights)
トレーニングの前に、Hugging Faceのデータセットライブラリを使用してテキストデータとラベルを準備し、その結果をAmazonS3にアップロードします。
from datasets import Dataset
import multiprocessing data_train = Dataset.from_pandas(df_train)
… tokenizer = <instantiated_huggingface_tokenizer> def preprocess_function(examples: examples) -> torch.Tensor: result = tokenizer(examples["text"], padding="max_length", max_length=128, truncation=True) return result num_proc = multiprocessing.cpu_count()
print("Number of CPUs =", num_proc) data_train = data_train.map( preprocess_function, batched=True, load_from_cache_file=False, num_proc=num_proc
)
… import botocore
from datasets.filesystems import S3FileSystem s3_session = botocore.session.Session() # create S3FileSystem instance with s3_session
s3 = S3FileSystem(session=s3_session) # saves encoded_dataset to your s3 bucket
data_train.save_to_disk(f's3://<bucket_name>/<prefix_name>/train', fs=s3)
…
RNNと同様の方法でモデルのトレーニングを開始します。
import sagemaker
sess = sagemaker.Session()
role = sagemaker.get_execution_role()
from sagemaker.huggingface import HuggingFace # hyperparameters, which are passed into the training job
hyperparameters = { 'model-name': <huggingface_base_model_name>, 'epochs': 10, 'train-batch-size': 32, 'eval-batch-size': 64, 'num-labels': len(<list_of_label_names>), 'class-weight': ' '.join([str(c) for c in <list_of_class_weights>]), 'metric-for-best-model': 'ap_score_weighted', 'save-total-limit': 1,
} # create the Estimator
huggingface_estimator = HuggingFace( entry_point='train.py', source_dir=<source_dir_path>, instance_type=<train_instance_type>, instance_count=1, role=role, transformers_version='4.6.1', pytorch_version='1.7.1', py_version='py36', hyperparameters=hyperparameters, metric_definitions=[ {'Name': 'validation:accuracy', 'Regex': 'eval_accuracy = (.*?);'}, {'Name': 'validation:f1-micro', 'Regex': 'eval_f1_score_micro = (.*?);'}, {'Name': 'validation:f1-macro', 'Regex': 'eval_f1_score_macro = (.*?);'}, {'Name': 'validation:f1-weighted', 'Regex': 'eval_f1_score_weighted = (.*?);'}, {'Name': 'validation:ap-micro', 'Regex': 'eval_ap_score_micro = (.*?);'}, {'Name': 'validation:ap-macro', 'Regex': 'eval_ap_score_macro = (.*?);'}, {'Name': 'validation:ap-weighted', 'Regex': 'eval_ap_score_weighted = (.*?);'}, {'Name': 'validation:auc-micro', 'Regex': 'eval_auc_score_micro = (.*?);'}, {'Name': 'validation:auc-macro', 'Regex': 'eval_auc_score_macro = (.*?);'}, {'Name': 'validation:auc-weighted', 'Regex': 'eval_auc_score_weighted = (.*?);'} ]
) huggingface_estimator.fit( { 'train': 's3://<bucket_name>/<prefix_name>/train', 'valid': 's3://<bucket_name>/<prefix_name>/valid', 'test': 's3://<bucket_name>/<prefix_name>/test'
)
最後に、次のPythonコードスニペットは、JSONリクエストのリアルタイムテキスト分類のためにライブSageMakerエンドポイントを介してRoBERToxを提供するプロセスを示しています。
from sagemaker.huggingface import HuggingFaceModel
from sagemaker import get_execution_role
from sagemaker.predictor import Predictor
from sagemaker.serializers import JSONSerializer
from sagemaker.deserializers import JSONDeserializer class Classifier(Predictor): def __init__(self, endpoint_name, sagemaker_session): super().__init__(endpoint_name, sagemaker_session, serializer=JSONSerializer(), deserializer=JSONDeserializer()) hf_model = HuggingFaceModel( role=get_execution_role(), model_data=<s3_model_and_tokenizer.tar.gz>, entry_point="inference.py", transformers_version="4.6.1", pytorch_version="1.7.1", py_version="py36", predictor_cls=Classifier
) predictor = hf_model.deploy(instance_type=<deploy_instance_type>, initial_instance_count=1)
モデルのパフォーマンスの評価:ジグソーの意図しないバイアスデータセット
次の表には、毒性検出KaggleコンペティションのJigsawUnintendedBiasからのデータでトレーニングおよび評価されたモデルのパフォーマンスメトリックが含まれています。 XNUMXつの異なるが相互に関連するタスクのモデルをトレーニングしました。
- バイナリケース –モデルは、完全なトレーニングデータセットでトレーニングされ、
toxicity
ラベルのみ
- きめの細かいケース –対象となるトレーニングデータのサブセット
toxicity>=0.5
他の毒性サブタイプラベルを予測するために使用されました(obscene
, threat
, insult
, identity_attack
, sexual_explicit
)
- マルチタスクの場合 –完全なトレーニングデータセットを使用して、XNUMXつのラベルすべてを同時に予測しました
ジグソーが提供するフラクショナルラベルを使用して、これら0.5つのタスクのそれぞれについてRNNモデルとRoBERTaモデルをトレーニングしました。これは、ラベルがテキストに適していると考えたアノテーターの割合に対応し、バイナリラベルとネットワーク内のクラスの重みを組み合わせたものです。損失関数。 バイナリラベリングスキームでは、利用可能なラベルごとに比率を1にしきい値処理し(ラベル> = 0.5の場合は0、それ以外の場合はXNUMX)、モデル損失関数はトレーニングデータセット内の各バイナリラベルの相対比率に基づいて重み付けされました。 すべての場合において、分数ラベルを直接使用すると最高のパフォーマンスが得られることがわかりました。これは、アノテーター間の一致度に固有の情報の付加価値を示しています。
0.5つのモデルメトリックを表示します。各分類しきい値で達成された精度値の加重平均を計算することによって適合率-再現率曲線の要約を提供する平均精度(AP)と、受信者動作特性曲線(AUC)の下の領域です。 、これは、真陽性率と偽陽性率に関して分類しきい値全体でモデルのパフォーマンスを集計します。 テストセット内の特定のテキストインスタンスの真のクラスは、真の比率が1以上であるかどうかに対応することに注意してください(ラベル> = 0.5の場合は0、それ以外の場合はXNUMX)。
. |
サブワード埋め込み+RNN |
ロベルタ |
. |
分数ラベル |
バイナリラベル+クラスの重み付け |
分数ラベル |
バイナリラベル+クラスの重み付け |
バイナリ |
AP = 0.746、 AUC = 0.966 |
AP = 0.730、AUC = 0.963 |
AP = 0.758、AUC = 0.966 |
AP = 0.747、AUC = 0.963 |
きめ細かい |
AP = 0.906、AUC = 0.909 |
AP = 0.850、AUC = 0.851 |
AP = 0.913、AUC = 0.913 |
AP = 0.911、AUC = 0.912 |
マルチタスク |
AP = 0.721、 AUC = 0.972 |
AP = 0.535、AUC = 0.907 |
AP = 0.740、AUC = 0.972 |
AP = 0.711、AUC = 0.961 |
まとめ
この投稿では、AWSMLサービスを使用したオンライン会話のXNUMXつのテキスト分類アプローチを紹介しました。 これらのソリューションは、オンライン通信プラットフォーム全体で一般化できます。ゲームなどの業界では、有害なコンテンツを検出する機能が向上することで特にメリットが得られる可能性があります。 今後の投稿では、AWSアカウントにモデルをシームレスにデプロイするためのエンドツーエンドのアーキテクチャについてさらに説明する予定です。
製品やプロセスでのMLの使用を加速するためにサポートが必要な場合は、 Amazon MLソリューションラボ.
著者について
ライアンブランド は、Amazon Machine Learning SolutionsLabのデータサイエンティストです。 彼は、ヘルスケアとライフサイエンスの問題に機械学習を適用する特定の経験があり、自由な時間には、歴史とサイエンスフィクションを読むことを楽しんでいます。
スーラヴ・バベシュ Amazon MLSolutionsLabのデータサイエンティストです。 彼は、さまざまな業界のAWS顧客向けにAI/MLソリューションを開発しています。 彼の専門は自然言語処理(NLP)であり、ディープラーニングに情熱を注いでいます。 仕事以外では、本を読んだり旅行したりするのが好きです。
劉通周 は、Amazon MLSolutionsLabの応用科学者です。 彼は、さまざまな業界のAWS顧客向けに特注のAI/MLソリューションを構築しています。 彼は自然言語処理(NLP)を専門としており、マルチモーダルディープラーニングに情熱を注いでいます。 彼は叙情的なテノールであり、仕事以外でオペラを歌うことを楽しんでいます。
シア・ゴラミ アマゾンMLソリューションラボのシニアデータサイエンティストであり、さまざまな業界の顧客向けにAI/MLソリューションを構築しています。 彼は自然言語処理(NLP)とディープラーニングに情熱を注いでいます。 仕事以外では、Siaは自然の中で過ごしたりテニスをしたりすることを楽しんでいます。
ダニエルホロウィッツ 応用AIサイエンスマネージャーです。 彼は、Amazon ML Solutions Labの科学者チームを率いて、顧客の問題を解決し、MLでクラウドの採用を推進しています。