機械学習の時代
世の中は AI 全盛で、どんどん便利になっています。
会社でも、研修で AI 関連のものが増えてきています。
ここは、時代に取り残されないように、機械学習をさらっと予習しておきましょう。
機械学習の環境を作る
まずは、tensorflow のインストールです。
tensorflow の読み方ですが、"テンサーフロー"、"テンソルフロー" のどちらでもいいようです。
私は tensor だけだったら、"テンソル" と読んでます。
tensorflow を 公式ドキュメント に沿ってインストールしましょう。
まずは、Python 開発環境の構築です。
Python をインストールしていない場合は、インストールが必要です。
私の Python の Version は 3.9.9でした。
Python 3.9.9
そして、Visual Studio 2015、2017、2019、および 2022用 Microsoft Visual C++ 再頒布可能パッケージ をインストールします。
ここ から、VC_redist.x86.exe と VC_redist.x64.exe をダウンロードして、ダブルクリックでインストール完了させます。
次は、Python の仮想環境の作成です。
コマンドプロンプトを起動し、以下のコマンドで、 Python 仮想環境を作成し、有効化します。
公式ドキュメントに書かれていますが、ここにも載せておきます。
$ .\venv\Scripts\activate
仮想環境で、pip をインストールします。
(venv) $ pip list # show packages installed within the virtual environment
仮想環境の Python の Version は、仮想環境作成時に使った Python のバージョンになっています。
Python 3.9.9
最後に、tensorflow のインストールです。
仮想環境下で、tensorflow をインストールして、検証しましょう。ちょっと時間がかかります。
(venv) $ python -c "import tensorflow as tf;print(tf.reduce_sum(tf.random.normal([1000, 1000])))"
機械学習してみる
データセットの取得
環境は整ったので、あとは機械学習するのみです。
このチュートリアル 通りに、mnist と呼ばれる手書き数字の画像分類をやってみます。
データセットを取得し、学習データとテストデータに分類します。
x が画像、y がラベルなので、y は 0-9 の数字です。
import tensorflow as tf
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
print('len(x_train): {}' .format(len(x_train)))
print('type(x_train): {}' .format(type(x_train)))
print('x_train.shape: {}' .format(x_train.shape))
# len(x_train): 60000
# type(x_train):
# x_train.shape: (60000, 28, 28)
print('len(x_test): {}' .format(len(x_test)))
print('type(x_test): {}' .format(type(x_test)))
print('x_test.shape: {}' .format(x_test.shape))
# len(x_test): 10000
# type(x_test):
# x_test.shape: (10000, 28, 28)
print('len(y_train): {}' .format(len(y_train)))
print('type(y_train): {}' .format(type(y_train)))
print('y_train.shape: {}' .format(y_train.shape))
# len(y_train): 60000
# type(y_train):
# y_train.shape: (60000,)
print('len(y_test): {}' .format(len(y_test)))
print('type(y_test): {}' .format(type(y_test)))
print('y_test.shape: {}' .format(y_test.shape))
# len(y_test): 10000
# type(y_test):
# y_test.shape: (10000,)
GPU が搭載されていない PC で実行すると、cuda の dll が見つからないエラーが出ますが、問題ないので、気にしないでください。
mnist が 28x28 の白黒画像で、60,000枚の学習データと10,000枚のテストデータで構成されていることがわかりました。
何枚か画像にしてみましょう。
import matplotlib.pyplot as plt
from PIL import Image
rows = 2
cols = 4
fig, axes = plt.subplots(rows, cols, figsize=(6, 4))
for r in range(rows):
for c in range(cols):
img = Image.fromarray(x_train[r*cols+c])
axes[r][c].imshow(img, cmap='gray')
axes[r][c].axis('off') # 軸目盛りを消す。
filename = 'mnist_{}x{}_{}.png' \
.format(rows, cols, datetime.now().strftime('%Y%m%d'))
file_path = os.path.join(os.getcwd(), filename)
fig.savefig(file_path)
モデルの構築と学習
Sequential モデルでネットワーク層を構築します。
https://keras.io/ja/getting-started/sequential-model-guide/
最後の層は、Dense で出力の次元を 10クラス とし、さらに活性化関数 softmax で、入力画像がどのクラスに所属するかの確率をそれぞれ出力し、すべての出力の合計が1となるようにします。
損失関数の from_logits=False にしているのは、モデルの出力が logits テンソルではなく、softmax 出力だからです。
ロジットの説明は こちら をご覧ください。
DeepL で翻訳すると、
分類モデルが生成する生の(正規化されていない)予測値のベクトルで、通常、正規化関数に渡される。モデルがマルチクラス分類問題を解く場合、ロジットは通常ソフトマックス関数への入力となる。 とのことです。
model = tf.keras.models.Sequential([
tf.keras.layers.Flatten(input_shape=(28, 28)),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(10, activation='softmax')
])
# 損失関数
loss_fn = tf.keras.losses.SparseCategoricalCrossentropy(
from_logits=False)
# compileで、損失・メトリック、オプティマイザを指定する。
model.compile(
optimizer='adam',
loss=loss_fn,
metrics=['accuracy'],
)
# 学習
history = model.fit(
x_train,
y_train,
validation_split=0.2,
epochs=10,
batch_size=32,
verbose=1,
)
コマンドラインに、学習の進捗具合が出力されます。
1500/1500 [==============================] - 3s 2ms/step - loss: 2.8785 - accuracy: 0.7364 - val_loss: 0.5680 - val_accuracy: 0.8658
Epoch 2/10
1500/1500 [==============================] - 3s 2ms/step - loss: 0.6532 - accuracy: 0.8314 - val_loss: 0.4682 - val_accuracy: 0.9018
Epoch 3/10
1500/1500 [==============================] - 3s 2ms/step - loss: 0.5234 - accuracy: 0.8605 - val_loss: 0.3451 - val_accuracy: 0.9185
学習曲線を描いてみます。
Epoch が進むにつれて、損失が収束していることがわかります。
# 学習の可視化
plt.plot(history.history['accuracy'])
plt.plot(history.history['val_accuracy'])
plt.title('Model accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='upper left')
filename = 'accuracy_curve_{}.png' .format(datetime.now().strftime('%Y%m%d'))
file_path = os.path.join(os.getcwd(), filename)
plt.savefig(file_path)
plt.clf()
plt.close()
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('Model loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='upper left')
filename = 'loss_curve_{}.png' .format(datetime.now().strftime('%Y%m%d'))
file_path = os.path.join(os.getcwd(), filename)
plt.savefig(file_path)
plt.clf()
plt.close()
モデルの評価
学習に使用していないテストデータを使って、学習済みモデルが画像分類が正しくできてるか、評価します。
# 学習に使用していないテストデータで評価する。
results = model.evaluate(x_test, y_test, verbose=2)
print('Test loss: {:.6f} Test accuracy: {:.6f}'
.format(results[0], results[1]))
Test loss: 0.261413 Test accuracy: 0.941500
94% くらいの精度が出ていることがわかりました。
いくつかのテストデータの、予測値と実際のラベルを見てみましょう。
# 予測
predictions = model.predict(x_test[:3])
# 指数表記にせず、小数点以下の桁数を指定する。
np.set_printoptions(suppress=True, precision=2)
print(predictions)
print(y_test[:3])
予測は 10クラス の内、0 から 9 になる確率がそれぞれ出力されています。
y_test ラベルは、x_test 画像の正解の数字です。
確率が最も高い数字と、正解の数字が合っていることがわかります。
以上が、機械学習の環境構築と、簡単な学習例となります。
機械学習の実装は難しいということはなく、モジュールを使って、簡単に作れることを感じていただけたと思います。