ホーム » Keras » TensorFlow 2.0 Alpha : Tutorials : ML 基本 :- 映画レビューでテキスト分類

TensorFlow 2.0 Alpha : Tutorials : ML 基本 :- 映画レビューでテキスト分類

TensorFlow 2.0 Alpha : Beginner Tutorials : ML 基本 :- 映画レビューでテキスト分類 (翻訳/解説)

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

* 本ページは、TensorFlow の本家サイトの TF 2.0 Alpha – Beginner Tutorials – ML basics の以下のページを翻訳した上で
適宜、補足説明したものです:

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

 

 

ML 基本 :- 映画レビューでテキスト分類

このノートブックは (映画) レビューのテキストを使用して映画レビューを肯定的か否定的として分類します。これは二値 — あるいは 2 クラス — 分類の例で、重要で広く利用可能な種類の機械学習問題です。

私達は IMDB データセット を使用します、これは Internet Movie Database からの 50,000 映画レビューのテキストを含みます。これらは訓練のための 25,000 レビューとテストのための 25,000 レビューに分割されます。訓練とテストセットは均等です、つまりそれらがポジティブとネガティブ・レビューの同じ数を含むことを意味します。

この notebook は tf.keras を使用します、TensorFlow でモデルを構築して訓練するための高位 API です。tf.keras を使用したより進んだテキスト分類チュートリアルについては、MLCC テキスト分類ガイド を見てください。

from __future__ import absolute_import, division, print_function

!pip install -q tensorflow==2.0.0-alpha0
import tensorflow as tf
from tensorflow import keras

import numpy as np

print(tf.__version__)
2.0.0-alpha0

 

IMDB データセットをダウンロードする

IMDB データセットは TensorFlow でパッケージ化されています。それは既にレビュー (単語のシークエンス) が数字のシークエンスに変換されるように前処理されていて、そこでは各整数は辞書の特定の単語を表しています。

次のコードは IMDB データセットを貴方のマシンにダウンロードします (あるいは既にそれをダウンロードしているのであればキャッシュされたコピーを使用します) :

imdb = keras.datasets.imdb

(train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000)
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/imdb.npz
17465344/17464789 [==============================] - 0s 0us/step

引数 num_words=10000 は訓練データにおいて最も頻度高く出現する top 10,000 の単語を保持します。データのサイズを管理可能に保つために稀な単語は捨てられます。

 

データを調査する

データのフォーマットを理解するために少し時間をつかいましょう。データセットは前処理されています : 各サンプルは映画レビューの単語を表わす数字の配列です。各ラベルは 0 か 1 の整数値で、そこでは 0 は否定的なレビューで、1 は肯定的なレビューです。

print("Training entries: {}, labels: {}".format(len(train_data), len(train_labels)))
Training entries: 25000, labels: 25000

レビューのテキストは整数に変換され、そこでは各整数は辞書の特定の単語を表します。最初のレビューがどのように見えるかがここにあります :

print(train_data[0])
[1, 14, 22, 16, 43, 530, 973, 1622, 1385, 65, 458, 4468, 66, 3941, 4, 173, 36, 256, 5, 25, 100, 43, 838, 112, 50, 670, 2, 9, 35, 480, 284, 5, 150, 4, 172, 112, 167, 2, 336, 385, 39, 4, 172, 4536, 1111, 17, 546, 38, 13, 447, 4, 192, 50, 16, 6, 147, 2025, 19, 14, 22, 4, 1920, 4613, 469, 4, 22, 71, 87, 12, 16, 43, 530, 38, 76, 15, 13, 1247, 4, 22, 17, 515, 17, 12, 16, 626, 18, 2, 5, 62, 386, 12, 8, 316, 8, 106, 5, 4, 2223, 5244, 16, 480, 66, 3785, 33, 4, 130, 12, 16, 38, 619, 5, 25, 124, 51, 36, 135, 48, 25, 1415, 33, 6, 22, 12, 215, 28, 77, 52, 5, 14, 407, 16, 82, 2, 8, 4, 107, 117, 5952, 15, 256, 4, 2, 7, 3766, 5, 723, 36, 71, 43, 530, 476, 26, 400, 317, 46, 7, 4, 2, 1029, 13, 104, 88, 4, 381, 15, 297, 98, 32, 2071, 56, 26, 141, 6, 194, 7486, 18, 4, 226, 22, 21, 134, 476, 26, 480, 5, 144, 30, 5535, 18, 51, 36, 28, 224, 92, 25, 104, 4, 226, 65, 16, 38, 1334, 88, 12, 16, 283, 5, 16, 4472, 113, 103, 32, 15, 16, 5345, 19, 178, 32]

映画レビューは異なる長さかもしれません。下のコードは最初と 2 番目のレビューの単語の数を示します。ニューラルネットワークへの入力は同じ長さでなければなりませんので、これを後で解決する必要があります。

len(train_data[0]), len(train_data[1])
(218, 189)

 

整数を単語に変換し戻す

整数をどのようにテキストに変換し戻すかを知ることは有用かもしれません。ここで、整数から文字列へのマッピングを含む辞書オブジェクトに問い合わせるためのヘルパー関数を作成します :

# A dictionary mapping words to an integer index
word_index = imdb.get_word_index()

# The first indices are reserved
word_index = {k:(v+3) for k,v in word_index.items()} 
word_index[""] = 0
word_index[""] = 1
word_index[""] = 2  # unknown
word_index[""] = 3

reverse_word_index = dict([(value, key) for (key, value) in word_index.items()])

def decode_review(text):
    return ' '.join([reverse_word_index.get(i, '?') for i in text])
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/imdb_word_index.json
1646592/1641221 [==============================] - 0s 0us/step

今では最初のレビューのテキストを表示するために decode_review 関数を使用することができます :

decode_review(train_data[0])
"<START> this film was just brilliant casting location scenery story direction everyone's really suited the part they played and you could just imagine being there robert <UNK> is an amazing actor and now the same being director <UNK> father came from the same scottish island as myself so i loved the fact there was a real connection with this film the witty remarks throughout the film were great it was just brilliant so much that i bought the film as soon as it was released for <UNK> and would recommend it to everyone to watch and the fly fishing was amazing really cried at the end it was so sad and you know what they say if you cry at a film it must have been good and this definitely was also <UNK> to the two little boy's that played the <UNK> of norman and paul they were just brilliant children are often left out of the <> list i think because the stars that play them all grown up are such a big profile for the whole film but these children are amazing and should be praised for what they have done don't you think the whole story was so lovely because it was true and was someone's life after all that was shared with us all"

 

データを準備する

レビュー — 整数の配列 — はニューラルネットワークに供給される前に tensor に変換されなければなりません。この変換は 2 つの方法で成されます :

  • 配列を単語の出現を示す 0 と 1 のベクトルに変換します、one-hot エンコーディングに類似しています。例えば、シークエンス [3, 5] は、(1 である) インデックス 3 と 5 を除いて総てゼロの 10,000 次元ベクトルになるでしょう。それから、これをネットワークの最初の層 — Dense 層 — にします、これは浮動小数点ベクトルデータを処理できます。けれども、このアプローチはメモリ集約的で、num_words * num_reviews サイズ行列を必要とします。
  • 代わりに、配列をそれらが総て同じ長さを持つようにパッドすることもできます、それから shape num_examples * max_length の整数 tensor を作成します。この shape をネットワークの最初の層として扱う埋め込み層を使用できます。

このチュートリアルでは、2 番目のアプローチを使用します。

映画レビューは同じ長さでなければならないので、長さを標準化するために pad_sequences 関数を使用します :

train_data = keras.preprocessing.sequence.pad_sequences(train_data,
                                                        value=word_index[""],
                                                        padding='post',
                                                        maxlen=256)

test_data = keras.preprocessing.sequence.pad_sequences(test_data,
                                                       value=word_index[""],
                                                       padding='post',
                                                       maxlen=256)

さてサンプルの長さを見てみましょう :

len(train_data[0]), len(train_data[1])
(256, 256)

そして (今はパッドされた) 最初のレビューを調査します :

print(train_data[0])
[   1   14   22   16   43  530  973 1622 1385   65  458 4468   66 3941
    4  173   36  256    5   25  100   43  838  112   50  670    2    9
   35  480  284    5  150    4  172  112  167    2  336  385   39    4
  172 4536 1111   17  546   38   13  447    4  192   50   16    6  147
 2025   19   14   22    4 1920 4613  469    4   22   71   87   12   16
   43  530   38   76   15   13 1247    4   22   17  515   17   12   16
  626   18    2    5   62  386   12    8  316    8  106    5    4 2223
 5244   16  480   66 3785   33    4  130   12   16   38  619    5   25
  124   51   36  135   48   25 1415   33    6   22   12  215   28   77
   52    5   14  407   16   82    2    8    4  107  117 5952   15  256
    4    2    7 3766    5  723   36   71   43  530  476   26  400  317
   46    7    4    2 1029   13  104   88    4  381   15  297   98   32
 2071   56   26  141    6  194 7486   18    4  226   22   21  134  476
   26  480    5  144   30 5535   18   51   36   28  224   92   25  104
    4  226   65   16   38 1334   88   12   16  283    5   16 4472  113
  103   32   15   16 5345   19  178   32    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0]

 

モデルを構築する

ニューラルネットワークは層をスタックすることにより作成されます — これは 2 つの主要なアーキテクチャ的な決定を必要とします :

  • モデルで幾つの層を使用するか?
  • 各層のために幾つの隠れユニットを使用するか?

このサンプルでは、入力データは単語インデックスの配列から成ります。予測するラベルは 0 か 1 です。この問題に対するモデルを構築しましょう :

# input shape is the vocabulary count used for the movie reviews (10,000 words)
vocab_size = 10000

model = keras.Sequential()
model.add(keras.layers.Embedding(vocab_size, 16))
model.add(keras.layers.GlobalAveragePooling1D())
model.add(keras.layers.Dense(16, activation='relu'))
model.add(keras.layers.Dense(1, activation='sigmoid'))

model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding (Embedding)        (None, None, 16)          160000    
_________________________________________________________________
global_average_pooling1d (Gl (None, 16)                0         
_________________________________________________________________
dense (Dense)                (None, 16)                272       
_________________________________________________________________
dense_1 (Dense)              (None, 1)                 17        
=================================================================
Total params: 160,289
Trainable params: 160,289
Non-trainable params: 0
_________________________________________________________________

分類器を構築するために層はシーケンシャルにスタックされます :

  1. 最初の層は Embedding 層です。この層は整数エンコードされた語彙を取って各単語インデックスのための埋め込みベクトルを検索します。これらのベクトルはモデルが訓練されるときに学習されます。ベクトルは出力配列に次元を追加します。結果としての次元は (batch, sequence, embedding) です。
  2. 次に、GlobalAveragePooling1D 層は各サンプルについて sequence 次元に渡り平均することにより固定長出力ベクトルを返します。これは可能な最も単純な方法でモデルが可変長の入力を扱うことを可能にします。
  3. この固定長出力ベクトルは 16 隠れユニットを持つ完全結合 (Dense) 層を通してパイプされます。
  4. 最後の層は単一の出力ノードに密に接続されています。sigmoid 活性化関数を使用し、この値は 0 と 1 の間の浮動小数点で、確率、または確信レベルを表します。

 

隠れユニット

上のモデルは入力と出力の間に、2 つの中間層あるいは「隠れ」層を持ちます。出力 (ユニット、ノード、またはニューロン) の数は層のための具象空間の次元です。換言すれば、内部表現を学習するときにネットワークが許容される自由度の総量です。

モデルがより多くの隠れユニット (より高い次元の表現空間) and/or より多くの層を持てば、ネットワークはより複雑な表現を学習できます。けれども、それはネットワークをより計算的に高価にして望まないパターンを学習することに繋がるかもしれません — このパターンは訓練データ上の性能を改良しますがテストデータ上ではそうではないものです。これは overfitting と呼ばれ、後でそれを調査します。

 

損失関数と optimizer

モデルは訓練のために損失関数と optimizer を必要とします。これは二値分類問題でモデルは確率を出力します (sigmoid 活性を持つシングルユニット層) ので、binary_crossentropy 損失関数を使用します。

これは損失関数のための唯一の選択ではありません、例えば、mean_squared_error を選択できるでしょう。しかし、一般的に、binary_crossentropy は確率を扱うためにはより良いです — それは確率分布間、あるいは私達のケースでは、正解の分布と予測の間の「距離」を測ります。

後で、回帰問題 (例えば、家の価格を予測する) を調べているときに、mean squared error と呼ばれるもう一つの損失関数をどのように使用するかを見ます。

さて、optimizer と損失関数を使用するためにモデルを configure します :

model.compile(optimizer='adam',
              loss='binary_crossentropy',
              metrics=['accuracy'])

 

検証セットを作成する

訓練時、モデルの精度をそれが前に見ていないデータ上でチェックすることを望みます。元の訓練データから 10,000 サンプルを分離することによって検証セットを作成します。(テストセットを何故今使わないのでしょう?目標は訓練データのみを使用してモデルを開発して調整することですから、テストデータは精度を評価するためだけに一度だけ使用します。)

x_val = train_data[:10000]
partial_x_train = train_data[10000:]

y_val = train_labels[:10000]
partial_y_train = train_labels[10000:]

 

モデルを訓練する

モデルを 512 サンプルのミニバッチで 40 エポック訓練します。これは x_train と y_train tensor の総てのサンプルに渡る 40 iteration (反復) です。訓練の間、検証セットからの 10,000 サンプル上でモデルの損失と精度を監視します :

history = model.fit(partial_x_train,
                    partial_y_train,
                    epochs=40,
                    batch_size=512,
                    validation_data=(x_val, y_val),
                    verbose=1)
Train on 15000 samples, validate on 10000 samples
Epoch 1/40
15000/15000 [==============================] - 1s 71us/sample - loss: 0.6923 - accuracy: 0.5915 - val_loss: 0.6907 - val_accuracy: 0.7308
Epoch 2/40
15000/15000 [==============================] - 1s 59us/sample - loss: 0.6880 - accuracy: 0.7417 - val_loss: 0.6851 - val_accuracy: 0.7471
Epoch 3/40
15000/15000 [==============================] - 1s 59us/sample - loss: 0.6794 - accuracy: 0.7533 - val_loss: 0.6742 - val_accuracy: 0.7330
Epoch 4/40
15000/15000 [==============================] - 1s 59us/sample - loss: 0.6643 - accuracy: 0.7613 - val_loss: 0.6564 - val_accuracy: 0.7254
Epoch 5/40
15000/15000 [==============================] - 1s 58us/sample - loss: 0.6408 - accuracy: 0.7765 - val_loss: 0.6312 - val_accuracy: 0.7571
Epoch 6/40
15000/15000 [==============================] - 1s 55us/sample - loss: 0.6097 - accuracy: 0.7941 - val_loss: 0.6000 - val_accuracy: 0.7910
Epoch 7/40
15000/15000 [==============================] - 1s 55us/sample - loss: 0.5727 - accuracy: 0.8119 - val_loss: 0.5641 - val_accuracy: 0.7990
Epoch 8/40
15000/15000 [==============================] - 1s 59us/sample - loss: 0.5328 - accuracy: 0.8303 - val_loss: 0.5279 - val_accuracy: 0.8178
Epoch 9/40
15000/15000 [==============================] - 1s 57us/sample - loss: 0.4926 - accuracy: 0.8463 - val_loss: 0.4922 - val_accuracy: 0.8288
Epoch 10/40
15000/15000 [==============================] - 1s 58us/sample - loss: 0.4542 - accuracy: 0.8590 - val_loss: 0.4599 - val_accuracy: 0.8371
Epoch 11/40
15000/15000 [==============================] - 1s 56us/sample - loss: 0.4195 - accuracy: 0.8669 - val_loss: 0.4312 - val_accuracy: 0.8470
Epoch 12/40
15000/15000 [==============================] - 1s 56us/sample - loss: 0.3887 - accuracy: 0.8759 - val_loss: 0.4075 - val_accuracy: 0.8536
Epoch 13/40
15000/15000 [==============================] - 1s 58us/sample - loss: 0.3626 - accuracy: 0.8838 - val_loss: 0.3859 - val_accuracy: 0.8594
Epoch 14/40
15000/15000 [==============================] - 1s 56us/sample - loss: 0.3389 - accuracy: 0.8897 - val_loss: 0.3693 - val_accuracy: 0.8631
Epoch 15/40
15000/15000 [==============================] - 1s 56us/sample - loss: 0.3192 - accuracy: 0.8933 - val_loss: 0.3551 - val_accuracy: 0.8673
Epoch 16/40
15000/15000 [==============================] - 1s 55us/sample - loss: 0.3014 - accuracy: 0.8997 - val_loss: 0.3433 - val_accuracy: 0.8701
Epoch 17/40
15000/15000 [==============================] - 1s 55us/sample - loss: 0.2854 - accuracy: 0.9041 - val_loss: 0.3334 - val_accuracy: 0.8705
Epoch 18/40
15000/15000 [==============================] - 1s 56us/sample - loss: 0.2713 - accuracy: 0.9089 - val_loss: 0.3244 - val_accuracy: 0.8761
Epoch 19/40
15000/15000 [==============================] - 1s 55us/sample - loss: 0.2587 - accuracy: 0.9110 - val_loss: 0.3169 - val_accuracy: 0.8768
Epoch 20/40
15000/15000 [==============================] - 1s 55us/sample - loss: 0.2472 - accuracy: 0.9160 - val_loss: 0.3114 - val_accuracy: 0.8762
Epoch 21/40
15000/15000 [==============================] - 1s 55us/sample - loss: 0.2361 - accuracy: 0.9194 - val_loss: 0.3063 - val_accuracy: 0.8769
Epoch 22/40
15000/15000 [==============================] - 1s 57us/sample - loss: 0.2266 - accuracy: 0.9219 - val_loss: 0.3014 - val_accuracy: 0.8812
Epoch 23/40
15000/15000 [==============================] - 1s 55us/sample - loss: 0.2169 - accuracy: 0.9257 - val_loss: 0.2986 - val_accuracy: 0.8802
Epoch 24/40
15000/15000 [==============================] - 1s 57us/sample - loss: 0.2083 - accuracy: 0.9283 - val_loss: 0.2943 - val_accuracy: 0.8819
Epoch 25/40
15000/15000 [==============================] - 1s 54us/sample - loss: 0.1994 - accuracy: 0.9327 - val_loss: 0.2913 - val_accuracy: 0.8825
Epoch 26/40
15000/15000 [==============================] - 1s 55us/sample - loss: 0.1914 - accuracy: 0.9354 - val_loss: 0.2899 - val_accuracy: 0.8815
Epoch 27/40
15000/15000 [==============================] - 1s 55us/sample - loss: 0.1839 - accuracy: 0.9387 - val_loss: 0.2880 - val_accuracy: 0.8832
Epoch 28/40
15000/15000 [==============================] - 1s 55us/sample - loss: 0.1767 - accuracy: 0.9428 - val_loss: 0.2863 - val_accuracy: 0.8838
Epoch 29/40
15000/15000 [==============================] - 1s 55us/sample - loss: 0.1706 - accuracy: 0.9443 - val_loss: 0.2869 - val_accuracy: 0.8826
Epoch 30/40
15000/15000 [==============================] - 1s 56us/sample - loss: 0.1642 - accuracy: 0.9472 - val_loss: 0.2851 - val_accuracy: 0.8839
Epoch 31/40
15000/15000 [==============================] - 1s 59us/sample - loss: 0.1578 - accuracy: 0.9505 - val_loss: 0.2847 - val_accuracy: 0.8855
Epoch 32/40
15000/15000 [==============================] - 1s 56us/sample - loss: 0.1519 - accuracy: 0.9531 - val_loss: 0.2850 - val_accuracy: 0.8855
Epoch 33/40
15000/15000 [==============================] - 1s 58us/sample - loss: 0.1463 - accuracy: 0.9545 - val_loss: 0.2860 - val_accuracy: 0.8836
Epoch 34/40
15000/15000 [==============================] - 1s 57us/sample - loss: 0.1413 - accuracy: 0.9572 - val_loss: 0.2863 - val_accuracy: 0.8858
Epoch 35/40
15000/15000 [==============================] - 1s 55us/sample - loss: 0.1368 - accuracy: 0.9586 - val_loss: 0.2879 - val_accuracy: 0.8863
Epoch 36/40
15000/15000 [==============================] - 1s 57us/sample - loss: 0.1317 - accuracy: 0.9608 - val_loss: 0.2888 - val_accuracy: 0.8865
Epoch 37/40
15000/15000 [==============================] - 1s 55us/sample - loss: 0.1270 - accuracy: 0.9629 - val_loss: 0.2901 - val_accuracy: 0.8859
Epoch 38/40
15000/15000 [==============================] - 1s 55us/sample - loss: 0.1226 - accuracy: 0.9652 - val_loss: 0.2923 - val_accuracy: 0.8848
Epoch 39/40
15000/15000 [==============================] - 1s 57us/sample - loss: 0.1189 - accuracy: 0.9657 - val_loss: 0.2939 - val_accuracy: 0.8838
Epoch 40/40
15000/15000 [==============================] - 1s 55us/sample - loss: 0.1147 - accuracy: 0.9679 - val_loss: 0.2955 - val_accuracy: 0.8850

 

モデルを評価する

そしてモデルどのように遂行するか見ましょう。2 つの値が返されます。損失 (エラーを表わす数字です、より低ければより良いです)、そして精度です。

results = model.evaluate(test_data, test_labels)

print(results)
25000/25000 [==============================] - 1s 45us/sample - loss: 0.3145 - accuracy: 0.8742
[0.3145076360368729, 0.87424]

このかなり素朴なアプローチは約 87 % の精度を得ます。より進んだアプローチでは、モデルは 95 % に近づくはずです。

 

時間とともに精度と損失のグラフを作成する

model.fit() は History オブジェクトを返します、これは訓練の間に発生した総てを持つ辞書を含みます :

history_dict = history.history
history_dict.keys()
dict_keys(['val_accuracy', 'accuracy', 'loss', 'val_loss'])

4 つのエントリがあります: 訓練と検証の間に各々監視されたメトリックのために一つ (ずつ) です。比較のために訓練と検証精度に加えて、訓練と検証損失をプロットするためにこれらを使用することができます :

import matplotlib.pyplot as plt

acc = history_dict['accuracy']
val_acc = history_dict['val_accuracy']
loss = history_dict['loss']
val_loss = history_dict['val_loss']

epochs = range(1, len(acc) + 1)

# "bo" is for "blue dot"
plt.plot(epochs, loss, 'bo', label='Training loss')
# b is for "solid blue line"
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()

plt.show()
<Figure size 640x480 with 1 Axes>
plt.clf()   # clear figure

plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()

plt.show()

このプロットでは、点線は訓練損失と精度を表し、そして実線は検証損失と精度です。

訓練損失は各エポックとともに減少して訓練精度は各エポックで増加することに気がつくでしょう。これは勾配降下最適化を使用するときに期待されるものです — それは総ての反復で望まれる量を最小化するはずです。

これは検証損失と精度については当てはまりません — それらは約 20 エポック後に最大になるようです。これは overfitting の例です : モデルは、それが前に決して見ていないデータ上よりも訓練データ上でより上手く遂行します。このポイント後、モデルは過剰に最適化されてテストデータに一般化されない訓練データに固有の表現を学習します。

この特定のケースのためには、単純に 20 程度のエポック後に訓練を停止することで overfitting を回避できるでしょう。後で、これを callback で自動的にどのように行なうかを見るでしょう。

 

以上



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