ดูบน TensorFlow.org | ทำงานใน Google Colab | ดูบน GitHub | ดาวน์โหลดโน๊ตบุ๊ค | ดูรุ่น TF Hub |
TensorFlow Hub เป็นพื้นที่เก็บข้อมูลของโมเดล TensorFlow ที่ผ่านการฝึกอบรมล่วงหน้า
บทช่วยสอนนี้สาธิตวิธี:
- ใช้โมเดลจาก TensorFlow Hub กับ
tf.keras
- ใช้แบบจำลองการจัดประเภทรูปภาพจาก TensorFlow Hub
- ทำการเรียนรู้การถ่ายโอนอย่างง่ายเพื่อปรับแต่งโมเดลสำหรับคลาสรูปภาพของคุณเอง
ติดตั้ง
import numpy as np
import time
import PIL.Image as Image
import matplotlib.pylab as plt
import tensorflow as tf
import tensorflow_hub as hub
import datetime
%load_ext tensorboard
ตัวแยกประเภท ImageNet
คุณจะเริ่มต้นด้วยการใช้แบบจำลองลักษณนามที่ได้รับการฝึกอบรมล่วงหน้าบนชุดข้อมูลเปรียบเทียบของ ImageNet โดยไม่ต้องมีการฝึกหัดขั้นต้น!
ดาวน์โหลดลักษณนาม
เลือกโมเดลก่อนการฝึกอบรม MobileNetV2 จาก TensorFlow Hub และห่อเป็นเลเยอร์ Keras ด้วย hub.KerasLayer
โมเดลตัวแยกประเภทรูปภาพที่เข้ากันได้ จาก TensorFlow Hub จะทำงานที่นี่ รวมถึงตัวอย่างที่มีให้ในรายการดรอปดาวน์ด้านล่าง
mobilenet_v2 ="https://tfhub.dev/google/tf2-preview/mobilenet_v2/classification/4"
inception_v3 = "https://tfhub.dev/google/imagenet/inception_v3/classification/5"
classifier_model = mobilenet_v2
IMAGE_SHAPE = (224, 224)
classifier = tf.keras.Sequential([
hub.KerasLayer(classifier_model, input_shape=IMAGE_SHAPE+(3,))
])
เรียกใช้บนภาพเดียว
ดาวน์โหลดรูปภาพเดียวเพื่อลองใช้โมเดลบน:
grace_hopper = tf.keras.utils.get_file('image.jpg','https://storage.googleapis.com/download.tensorflow.org/example_images/grace_hopper.jpg')
grace_hopper = Image.open(grace_hopper).resize(IMAGE_SHAPE)
grace_hopper
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/grace_hopper.jpg 65536/61306 [================================] - 0s 0us/step 73728/61306 [====================================] - 0s 0us/step
grace_hopper = np.array(grace_hopper)/255.0
grace_hopper.shape
(224, 224, 3)
เพิ่มมิติแบตช์ (ด้วย np.newaxis
) และส่งภาพไปยังโมเดล:
result = classifier.predict(grace_hopper[np.newaxis, ...])
result.shape
(1, 1001)
ผลลัพธ์ที่ได้คือเวกเตอร์องค์ประกอบ 1001 ของล็อก ซึ่งให้คะแนนความน่าจะเป็นของแต่ละคลาสสำหรับรูปภาพ
ID ระดับบนสุดสามารถพบได้ด้วย tf.math.argmax
:
predicted_class = tf.math.argmax(result[0], axis=-1)
predicted_class
<tf.Tensor: shape=(), dtype=int64, numpy=653>
ถอดรหัสคำทำนาย
นำ predicted_class
ID (เช่น 653
) และดึงป้ายกำกับชุดข้อมูล ImageNet เพื่อถอดรหัสการคาดคะเน:
labels_path = tf.keras.utils.get_file('ImageNetLabels.txt','https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt')
imagenet_labels = np.array(open(labels_path).read().splitlines())
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt 16384/10484 [==============================================] - 0s 0us/step 24576/10484 [======================================================================] - 0s 0us/step
plt.imshow(grace_hopper)
plt.axis('off')
predicted_class_name = imagenet_labels[predicted_class]
_ = plt.title("Prediction: " + predicted_class_name.title())
การเรียนรู้การถ่ายโอนอย่างง่าย
แต่ถ้าคุณต้องการสร้างตัวแยกประเภทแบบกำหนดเองโดยใช้ชุดข้อมูลของคุณเองที่มีคลาสที่ไม่รวมอยู่ในชุดข้อมูล ImageNet ดั้งเดิม (ที่โมเดลที่ผ่านการฝึกอบรมล่วงหน้าได้รับการฝึกอบรม)
ในการทำเช่นนั้น คุณสามารถ:
- เลือกรุ่นก่อนการฝึกอบรมจาก TensorFlow Hub; และ
- ฝึกเลเยอร์บนสุด (สุดท้าย) อีกครั้งเพื่อจดจำคลาสจากชุดข้อมูลที่คุณกำหนดเอง
ชุดข้อมูล
ในตัวอย่างนี้ คุณจะใช้ชุดข้อมูลดอกไม้ TensorFlow:
data_root = tf.keras.utils.get_file(
'flower_photos',
'https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz',
untar=True)
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz 228818944/228813984 [==============================] - 7s 0us/step 228827136/228813984 [==============================] - 7s 0us/step
ขั้นแรก โหลดข้อมูลนี้ลงในโมเดลโดยใช้ข้อมูลภาพนอกดิสก์ด้วย tf.keras.utils.image_dataset_from_directory
ซึ่งจะสร้าง tf.data.Dataset
:
batch_size = 32
img_height = 224
img_width = 224
train_ds = tf.keras.utils.image_dataset_from_directory(
str(data_root),
validation_split=0.2,
subset="training",
seed=123,
image_size=(img_height, img_width),
batch_size=batch_size
)
val_ds = tf.keras.utils.image_dataset_from_directory(
str(data_root),
validation_split=0.2,
subset="validation",
seed=123,
image_size=(img_height, img_width),
batch_size=batch_size
)
Found 3670 files belonging to 5 classes. Using 2936 files for training. Found 3670 files belonging to 5 classes. Using 734 files for validation.
ชุดข้อมูลดอกไม้มีห้าคลาส:
class_names = np.array(train_ds.class_names)
print(class_names)
['daisy' 'dandelion' 'roses' 'sunflowers' 'tulips']
ประการที่สอง เนื่องจากหลักการของ TensorFlow Hub สำหรับโมเดลรูปภาพคือการคาดหวังอินพุตแบบลอยในช่วง [0, 1]
ให้ใช้ tf.keras.layers.Rescaling
เลเยอร์การประมวลผลล่วงหน้าเพื่อให้ได้สิ่งนี้
normalization_layer = tf.keras.layers.Rescaling(1./255)
train_ds = train_ds.map(lambda x, y: (normalization_layer(x), y)) # Where x—images, y—labels.
val_ds = val_ds.map(lambda x, y: (normalization_layer(x), y)) # Where x—images, y—labels.
ประการที่สาม เสร็จสิ้นขั้นตอนอินพุตโดยใช้การดึงข้อมูลล่วงหน้าที่บัฟเฟอร์ด้วย Dataset.prefetch
เพื่อให้คุณสามารถส่งข้อมูลจากดิสก์โดยไม่มีปัญหาการบล็อก I/O
นี่คือวิธี tf.data
ที่สำคัญที่สุดบางส่วนที่คุณควรใช้เมื่อโหลดข้อมูล ผู้อ่านที่สนใจสามารถเรียนรู้เพิ่มเติมเกี่ยวกับพวกเขา รวมถึงวิธีการแคชข้อมูลไปยังดิสก์และเทคนิคอื่นๆ ในคู่มือ tf.data API ประสิทธิภาพ ที่ดีขึ้น
AUTOTUNE = tf.data.AUTOTUNE
train_ds = train_ds.cache().prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)
for image_batch, labels_batch in train_ds:
print(image_batch.shape)
print(labels_batch.shape)
break
(32, 224, 224, 3) (32,) 2022-01-26 05:06:19.465331: W tensorflow/core/kernels/data/cache_dataset_ops.cc:768] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.
เรียกใช้ตัวแยกประเภทบนชุดของรูปภาพ
ตอนนี้ เรียกใช้ตัวแยกประเภทในชุดรูปภาพ:
result_batch = classifier.predict(train_ds)
predicted_class_names = imagenet_labels[tf.math.argmax(result_batch, axis=-1)]
predicted_class_names
array(['daisy', 'coral fungus', 'rapeseed', ..., 'daisy', 'daisy', 'birdhouse'], dtype='<U30')
ตรวจสอบว่าการคาดคะเนเหล่านี้สอดคล้องกับภาพอย่างไร:
plt.figure(figsize=(10,9))
plt.subplots_adjust(hspace=0.5)
for n in range(30):
plt.subplot(6,5,n+1)
plt.imshow(image_batch[n])
plt.title(predicted_class_names[n])
plt.axis('off')
_ = plt.suptitle("ImageNet predictions")
ผลลัพธ์ยังห่างไกลจากความสมบูรณ์แบบ แต่สมเหตุสมผลเมื่อพิจารณาว่าสิ่งเหล่านี้ไม่ใช่ชั้นเรียนที่นางแบบได้รับการฝึกอบรมมา (ยกเว้น "เดซี่")
ดาวน์โหลดโมเดลหัวขาด
TensorFlow Hub ยังจำหน่ายโมเดลที่ไม่มีเลเยอร์การจัดหมวดหมู่บนสุด สิ่งเหล่านี้สามารถใช้เพื่อทำการถ่ายโอนการเรียนรู้ได้อย่างง่ายดาย
เลือกรุ่นก่อนการฝึกอบรม MobileNetV2 จาก TensorFlow Hub โมเดลเวกเตอร์ฟีเจอร์รูปภาพที่เข้ากันได้ จาก TensorFlow Hub จะทำงานที่นี่ รวมถึงตัวอย่างจากเมนูแบบเลื่อนลง
mobilenet_v2 = "https://tfhub.dev/google/tf2-preview/mobilenet_v2/feature_vector/4"
inception_v3 = "https://tfhub.dev/google/tf2-preview/inception_v3/feature_vector/4"
feature_extractor_model = mobilenet_v2
สร้างตัวแยกคุณลักษณะโดยห่อโมเดลที่ฝึกไว้ล่วงหน้าเป็นเลเยอร์ Keras ด้วย hub.KerasLayer
ใช้อาร์กิวเมนต์ trainable=False
เพื่อตรึงตัวแปร เพื่อให้การฝึกอบรมแก้ไขเฉพาะเลเยอร์ตัวแยกประเภทใหม่:
feature_extractor_layer = hub.KerasLayer(
feature_extractor_model,
input_shape=(224, 224, 3),
trainable=False)
ตัวแยกคุณลักษณะจะคืนค่าเวกเตอร์ที่ยาว 1280 สำหรับแต่ละรูปภาพ (ขนาดแบทช์รูปภาพยังคงอยู่ที่ 32 ในตัวอย่างนี้):
feature_batch = feature_extractor_layer(image_batch)
print(feature_batch.shape)
(32, 1280)ตัวยึดตำแหน่ง32
แนบหัวการจำแนกประเภท
ในการทำให้โมเดลสมบูรณ์ ให้ห่อเลเยอร์ตัวแยกคุณลักษณะในโมเดล tf.keras.Sequential
และเพิ่มเลเยอร์ที่เชื่อมต่ออย่างสมบูรณ์สำหรับการจัดประเภท:
num_classes = len(class_names)
model = tf.keras.Sequential([
feature_extractor_layer,
tf.keras.layers.Dense(num_classes)
])
model.summary()
Model: "sequential_1" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= keras_layer_1 (KerasLayer) (None, 1280) 2257984 dense (Dense) (None, 5) 6405 ================================================================= Total params: 2,264,389 Trainable params: 6,405 Non-trainable params: 2,257,984 _________________________________________________________________
predictions = model(image_batch)
predictions.shape
TensorShape([32, 5])
ฝึกโมเดล
ใช้ Model.compile
เพื่อกำหนดค่ากระบวนการฝึกอบรมและเพิ่มการเรียกกลับ tf.keras.callbacks.TensorBoard
เพื่อสร้างและจัดเก็บบันทึก:
model.compile(
optimizer=tf.keras.optimizers.Adam(),
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['acc'])
log_dir = "logs/fit/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
tensorboard_callback = tf.keras.callbacks.TensorBoard(
log_dir=log_dir,
histogram_freq=1) # Enable histogram computation for every epoch.
ตอนนี้ใช้วิธี Model.fit
เพื่อฝึกโมเดล
เพื่อให้ตัวอย่างนี้สั้น คุณจะฝึกอบรมเพียง 10 ยุค หากต้องการเห็นภาพความคืบหน้าการฝึกอบรมใน TensorBoard ในภายหลัง ให้สร้างและจัดเก็บบันทึกการเรียกกลับของ TensorBoard
NUM_EPOCHS = 10
history = model.fit(train_ds,
validation_data=val_ds,
epochs=NUM_EPOCHS,
callbacks=tensorboard_callback)
Epoch 1/10 92/92 [==============================] - 7s 42ms/step - loss: 0.7904 - acc: 0.7210 - val_loss: 0.4592 - val_acc: 0.8515 Epoch 2/10 92/92 [==============================] - 3s 33ms/step - loss: 0.3850 - acc: 0.8713 - val_loss: 0.3694 - val_acc: 0.8787 Epoch 3/10 92/92 [==============================] - 3s 33ms/step - loss: 0.3027 - acc: 0.9057 - val_loss: 0.3367 - val_acc: 0.8856 Epoch 4/10 92/92 [==============================] - 3s 33ms/step - loss: 0.2524 - acc: 0.9237 - val_loss: 0.3210 - val_acc: 0.8869 Epoch 5/10 92/92 [==============================] - 3s 33ms/step - loss: 0.2164 - acc: 0.9373 - val_loss: 0.3124 - val_acc: 0.8896 Epoch 6/10 92/92 [==============================] - 3s 33ms/step - loss: 0.1888 - acc: 0.9469 - val_loss: 0.3070 - val_acc: 0.8937 Epoch 7/10 92/92 [==============================] - 3s 33ms/step - loss: 0.1668 - acc: 0.9550 - val_loss: 0.3032 - val_acc: 0.9005 Epoch 8/10 92/92 [==============================] - 3s 33ms/step - loss: 0.1487 - acc: 0.9619 - val_loss: 0.3004 - val_acc: 0.9005 Epoch 9/10 92/92 [==============================] - 3s 33ms/step - loss: 0.1335 - acc: 0.9687 - val_loss: 0.2981 - val_acc: 0.9019 Epoch 10/10 92/92 [==============================] - 3s 33ms/step - loss: 0.1206 - acc: 0.9748 - val_loss: 0.2964 - val_acc: 0.9046
เริ่ม TensorBoard เพื่อดูว่าเมตริกเปลี่ยนแปลงไปอย่างไรในแต่ละยุคและเพื่อติดตามค่าสเกลาร์อื่นๆ:
%tensorboard --logdir logs/fit
ตรวจสอบคำทำนาย
รับรายชื่อคลาสที่เรียงลำดับจากการทำนายแบบจำลอง:
predicted_batch = model.predict(image_batch)
predicted_id = tf.math.argmax(predicted_batch, axis=-1)
predicted_label_batch = class_names[predicted_id]
print(predicted_label_batch)
['roses' 'dandelion' 'tulips' 'sunflowers' 'dandelion' 'roses' 'dandelion' 'roses' 'tulips' 'dandelion' 'tulips' 'tulips' 'sunflowers' 'tulips' 'dandelion' 'roses' 'daisy' 'tulips' 'dandelion' 'dandelion' 'dandelion' 'tulips' 'sunflowers' 'roses' 'sunflowers' 'dandelion' 'tulips' 'roses' 'roses' 'sunflowers' 'tulips' 'sunflowers']ตัวยึดตำแหน่ง43
พล็อตการทำนายแบบจำลอง:
plt.figure(figsize=(10,9))
plt.subplots_adjust(hspace=0.5)
for n in range(30):
plt.subplot(6,5,n+1)
plt.imshow(image_batch[n])
plt.title(predicted_label_batch[n].title())
plt.axis('off')
_ = plt.suptitle("Model predictions")
ส่งออกและโหลดโมเดลของคุณใหม่
ตอนนี้ คุณได้ฝึกโมเดลแล้ว ให้ส่งออกเป็น SavedModel เพื่อนำกลับมาใช้ใหม่ในภายหลัง
t = time.time()
export_path = "/tmp/saved_models/{}".format(int(t))
model.save(export_path)
export_path
2022-01-26 05:07:03.429901: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them. INFO:tensorflow:Assets written to: /tmp/saved_models/1643173621/assets INFO:tensorflow:Assets written to: /tmp/saved_models/1643173621/assets '/tmp/saved_models/1643173621'ตัวยึดตำแหน่ง46
ยืนยันว่าคุณสามารถโหลด SavedModel ใหม่ได้ และโมเดลสามารถแสดงผลลัพธ์เดียวกันได้:
reloaded = tf.keras.models.load_model(export_path)
result_batch = model.predict(image_batch)
reloaded_result_batch = reloaded.predict(image_batch)
abs(reloaded_result_batch - result_batch).max()
0.0
reloaded_predicted_id = tf.math.argmax(reloaded_result_batch, axis=-1)
reloaded_predicted_label_batch = class_names[reloaded_predicted_id]
print(reloaded_predicted_label_batch)
ตัวยึดตำแหน่ง51['roses' 'dandelion' 'tulips' 'sunflowers' 'dandelion' 'roses' 'dandelion' 'roses' 'tulips' 'dandelion' 'tulips' 'tulips' 'sunflowers' 'tulips' 'dandelion' 'roses' 'daisy' 'tulips' 'dandelion' 'dandelion' 'dandelion' 'tulips' 'sunflowers' 'roses' 'sunflowers' 'dandelion' 'tulips' 'roses' 'roses' 'sunflowers' 'tulips' 'sunflowers']
plt.figure(figsize=(10,9))
plt.subplots_adjust(hspace=0.5)
for n in range(30):
plt.subplot(6,5,n+1)
plt.imshow(image_batch[n])
plt.title(reloaded_predicted_label_batch[n].title())
plt.axis('off')
_ = plt.suptitle("Model predictions")
ขั้นตอนถัดไป
คุณสามารถใช้ SavedModel เพื่อโหลดสำหรับการอนุมานหรือแปลงเป็น โมเดล TensorFlow Lite (สำหรับการเรียนรู้ของเครื่องในอุปกรณ์) หรือโมเดล TensorFlow.js (สำหรับการเรียนรู้ของเครื่องใน JavaScript)
ค้นพบบทช่วย สอนเพิ่มเติม เพื่อเรียนรู้วิธีใช้โมเดลที่ได้รับการฝึกอบรมล่วงหน้าจาก TensorFlow Hub ในงานด้านรูปภาพ ข้อความ เสียง และวิดีโอ