স্থানান্তর শিখন এবং সূক্ষ্ম-সুরকরণ

TensorFlow.org এ দেখুন Google Colab-এ চালান GitHub-এ উৎস দেখুন নোটবুক ডাউনলোড করুন

সেটআপ

import numpy as np
import tensorflow as tf
from tensorflow import keras

ভূমিকা

স্থানান্তর শেখার এক সমস্যা উপর শিখেছি বৈশিষ্ট্য গ্রহণ, এবং একটি নতুন, একই সমস্যা তাদের ওঠানামা নিয়ে গঠিত। উদাহরণস্বরূপ, একটি মডেলের বৈশিষ্ট্য যা রেকুন শনাক্ত করতে শিখেছে তানুকিস শনাক্ত করার জন্য একটি মডেলকে কিক-স্টার্ট করতে উপযোগী হতে পারে।

ট্রান্সফার লার্নিং সাধারণত এমন কাজগুলির জন্য করা হয় যেখানে আপনার ডেটাসেটে স্ক্র্যাচ থেকে একটি পূর্ণ-স্কেল মডেল প্রশিক্ষণের জন্য খুব কম ডেটা থাকে।

গভীর শিক্ষার পরিপ্রেক্ষিতে স্থানান্তর শিক্ষার সবচেয়ে সাধারণ অবতার হল নিম্নলিখিত কর্মপ্রবাহ:

  1. পূর্বে প্রশিক্ষিত মডেল থেকে স্তর নিন।
  2. তাদের হিমায়িত করুন, যাতে ভবিষ্যতের প্রশিক্ষণ রাউন্ডের সময় তাদের মধ্যে থাকা যেকোন তথ্য নষ্ট না হয়।
  3. হিমায়িত স্তরগুলির উপরে কিছু নতুন, প্রশিক্ষণযোগ্য স্তর যুক্ত করুন। তারা একটি নতুন ডেটাসেটে পুরানো বৈশিষ্ট্যগুলিকে ভবিষ্যদ্বাণীতে পরিণত করতে শিখবে।
  4. আপনার ডেটাসেটে নতুন স্তরগুলিকে প্রশিক্ষণ দিন।

শেষ, ঐচ্ছিক পদক্ষেপ, ফাইন টিউনিং, সমগ্র মডেল আপনি উপরে প্রাপ্ত (অথবা এটা অংশ) unfreezing নিয়ে গঠিত যা, এবং একটি খুব কম লার্নিং হার নতুন তথ্য তে এটি পুনরায় প্রশিক্ষণ দিচ্ছেন। নতুন ডেটাতে পূর্বপ্রশিক্ষিত বৈশিষ্ট্যগুলিকে ক্রমবর্ধমানভাবে অভিযোজিত করে এটি সম্ভাব্য অর্থপূর্ণ উন্নতি অর্জন করতে পারে।

প্রথমত, আমরা Keras ওভার যেতে হবে trainable যা সর্বাধিক স্থানান্তর শেখার & ফাইন টিউনিং কর্মপ্রবাহ ভিত্তি বিস্তারিতভাবে এপিআই,।

তারপরে, আমরা ইমেজনেট ডেটাসেটে পূর্বপ্রশিক্ষিত একটি মডেল গ্রহণ করে এবং কাগল "বিড়াল বনাম কুকুর" শ্রেণীবিভাগ ডেটাসেটে এটিকে পুনরায় প্রশিক্ষণ দিয়ে সাধারণ কর্মপ্রবাহ প্রদর্শন করব।

এই থেকে অভিযোজিত হয় পাইথন সঙ্গে গভীর শিক্ষা এবং 2016 ব্লগ পোস্টে "খুব সামান্য তথ্য ব্যবহার করে শক্তিশালী ইমেজ শ্রেণীবিন্যাস মডেল বিল্ডিং"

ঠাণ্ডা স্তর: বুঝতে trainable অ্যাট্রিবিউট

স্তর এবং মডেলের তিনটি ওজন বৈশিষ্ট্য আছে:

  • weights স্তরের সব ওজন ভেরিয়েবল তালিকা রয়েছে।
  • trainable_weights ঐ যে হালনাগাদ করা বোঝানো হয় (গ্রেডিয়েন্ট বংশদ্ভুত মাধ্যমে) প্রশিক্ষণের সময় হ্রাস কমান তালিকা।
  • non_trainable_weights ঐ যে প্রশিক্ষণ দেওয়া বোঝানো হয় না তাদের তালিকা করা হয়। সাধারণত তারা ফরোয়ার্ড পাস সময় মডেল দ্বারা আপডেট করা হয়.

উদাহরণ: Dense স্তর 2 trainable ওজন আছে (কার্নেল ও পক্ষপাত)

layer = keras.layers.Dense(3)
layer.build((None, 4))  # Create the weights

print("weights:", len(layer.weights))
print("trainable_weights:", len(layer.trainable_weights))
print("non_trainable_weights:", len(layer.non_trainable_weights))
weights: 2
trainable_weights: 2
non_trainable_weights: 0

সাধারণভাবে, সমস্ত ওজনই প্রশিক্ষণযোগ্য ওজন। শুধুমাত্র বিল্ট-ইন স্তর আছে অ trainable ওজন হয় BatchNormalization স্তর। এটি প্রশিক্ষণের সময় এর ইনপুটগুলির গড় এবং তারতম্যের ট্র্যাক রাখতে অ-প্রশিক্ষণযোগ্য ওজন ব্যবহার করে। কিভাবে, আপনার নিজস্ব স্তর অ trainable ওজন ব্যবহার করে তা দেখতে জানতে স্ক্র্যাচ থেকে নতুন স্তর লেখা গাইড

উদাহরণ: BatchNormalization স্তর 2 trainable ওজন এবং 2 অ trainable ওজন হয়েছে

layer = keras.layers.BatchNormalization()
layer.build((None, 4))  # Create the weights

print("weights:", len(layer.weights))
print("trainable_weights:", len(layer.trainable_weights))
print("non_trainable_weights:", len(layer.non_trainable_weights))
weights: 4
trainable_weights: 2
non_trainable_weights: 2

স্তরসমূহ & মডেল একটি বুলিয়ান অ্যাট্রিবিউট বৈশিষ্ট্য trainable । এর মান পরিবর্তন করা যেতে পারে। সেট layer.trainable করার False অ trainable করার trainable থেকে সব লেয়ারটির ওজন প্যাচসমূহ। এটাকে বলা হয় "জমাকৃত" স্তর: একটি হিমায়িত স্তর রাজ্যের প্রশিক্ষণের সময় আপডেট করা হবে না (হয় যখন সঙ্গে প্রশিক্ষণ fit() অথবা যখন উপর নির্ভর কোনো কাস্টম লুপ সঙ্গে প্রশিক্ষণ trainable_weights গ্রেডিয়েন্ট আপডেট প্রয়োগ করতে)।

উদাহরণ: সেটিং trainable করার False

layer = keras.layers.Dense(3)
layer.build((None, 4))  # Create the weights
layer.trainable = False  # Freeze the layer

print("weights:", len(layer.weights))
print("trainable_weights:", len(layer.trainable_weights))
print("non_trainable_weights:", len(layer.non_trainable_weights))
weights: 2
trainable_weights: 0
non_trainable_weights: 2

যখন একটি প্রশিক্ষণযোগ্য ওজন অ-প্রশিক্ষণযোগ্য হয়ে যায়, তখন প্রশিক্ষণের সময় এর মান আর আপডেট করা হয় না।

# Make a model with 2 layers
layer1 = keras.layers.Dense(3, activation="relu")
layer2 = keras.layers.Dense(3, activation="sigmoid")
model = keras.Sequential([keras.Input(shape=(3,)), layer1, layer2])

# Freeze the first layer
layer1.trainable = False

# Keep a copy of the weights of layer1 for later reference
initial_layer1_weights_values = layer1.get_weights()

# Train the model
model.compile(optimizer="adam", loss="mse")
model.fit(np.random.random((2, 3)), np.random.random((2, 3)))

# Check that the weights of layer1 have not changed during training
final_layer1_weights_values = layer1.get_weights()
np.testing.assert_allclose(
    initial_layer1_weights_values[0], final_layer1_weights_values[0]
)
np.testing.assert_allclose(
    initial_layer1_weights_values[1], final_layer1_weights_values[1]
)
1/1 [==============================] - 1s 640ms/step - loss: 0.0945

গুলান না layer.trainable আর্গুমেন্ট সহ অ্যাট্রিবিউট training মধ্যে layer.__call__() (যা কিনা তা নিয়ন্ত্রণ করে লেয়ার অনুমান মোড অথবা প্রশিক্ষণ মোডে তার ফরওয়ার্ড পাস চালানো উচিত)। আরো তথ্যের জন্য, দেখুন Keras প্রায়শই জিজ্ঞাসিত প্রশ্নাবলী

এর recursive সেটিং trainable অ্যাট্রিবিউট

আপনি সেট করেন তাহলে trainable = False একটি মডেল বা sublayers যে কোনো স্তরে, সব শিশুদের স্তর পাশাপাশি অ trainable হয়ে।

উদাহরণ:

inner_model = keras.Sequential(
    [
        keras.Input(shape=(3,)),
        keras.layers.Dense(3, activation="relu"),
        keras.layers.Dense(3, activation="relu"),
    ]
)

model = keras.Sequential(
    [keras.Input(shape=(3,)), inner_model, keras.layers.Dense(3, activation="sigmoid"),]
)

model.trainable = False  # Freeze the outer model

assert inner_model.trainable == False  # All layers in `model` are now frozen
assert inner_model.layers[0].trainable == False  # `trainable` is propagated recursively

সাধারণ ট্রান্সফার-লার্নিং ওয়ার্কফ্লো

এটি আমাদের কেরাসে কীভাবে একটি সাধারণ ট্রান্সফার লার্নিং ওয়ার্কফ্লো বাস্তবায়ন করা যেতে পারে তার দিকে নিয়ে যায়:

  1. একটি বেস মডেল ইনস্ট্যান্ট করুন এবং এতে প্রাক-প্রশিক্ষিত ওজন লোড করুন।
  2. সেটিং দ্বারা বেস মডেল সব স্তরগুলির ফ্রিজ trainable = False
  3. বেস মডেল থেকে এক (বা একাধিক) স্তরের আউটপুটের উপরে একটি নতুন মডেল তৈরি করুন।
  4. আপনার নতুন ডেটাসেটে আপনার নতুন মডেলকে প্রশিক্ষণ দিন।

মনে রাখবেন যে একটি বিকল্প, আরও হালকা কর্মপ্রবাহও হতে পারে:

  1. একটি বেস মডেল ইনস্ট্যান্ট করুন এবং এতে প্রাক-প্রশিক্ষিত ওজন লোড করুন।
  2. এটির মাধ্যমে আপনার নতুন ডেটাসেট চালান এবং বেস মডেল থেকে এক (বা একাধিক) স্তরের আউটপুট রেকর্ড করুন। এই বৈশিষ্ট্যটি নিষ্কাশন বলা হয়।
  3. একটি নতুন, ছোট মডেলের জন্য ইনপুট ডেটা হিসাবে সেই আউটপুটটি ব্যবহার করুন।

সেই দ্বিতীয় কর্মপ্রবাহের একটি মূল সুবিধা হল যে আপনি প্রশিক্ষণের যুগে একবারের পরিবর্তে আপনার ডেটাতে শুধুমাত্র একবার বেস মডেল চালান। তাই এটি অনেক দ্রুত এবং সস্তা।

সেই দ্বিতীয় ওয়ার্কফ্লোতে একটি সমস্যা, যদিও, এটি আপনাকে প্রশিক্ষণের সময় আপনার নতুন মডেলের ইনপুট ডেটা গতিশীলভাবে পরিবর্তন করার অনুমতি দেয় না, উদাহরণস্বরূপ, ডেটা বৃদ্ধি করার সময় এটি প্রয়োজনীয়। ট্রান্সফার লার্নিং সাধারণত কাজের জন্য ব্যবহৃত হয় যখন আপনার নতুন ডেটাসেটে স্ক্র্যাচ থেকে একটি পূর্ণ-স্কেল মডেলকে প্রশিক্ষণ দেওয়ার জন্য খুব কম ডেটা থাকে এবং এই ধরনের পরিস্থিতিতে ডেটা বৃদ্ধি করা খুবই গুরুত্বপূর্ণ। সুতরাং নিম্নলিখিতটিতে, আমরা প্রথম ওয়ার্কফ্লোতে ফোকাস করব।

কেরাসে প্রথম ওয়ার্কফ্লো কেমন দেখায় তা এখানে:

প্রথমত, প্রাক-প্রশিক্ষিত ওজন সহ একটি বেস মডেল ইনস্ট্যান্ট করুন।

base_model = keras.applications.Xception(
    weights='imagenet',  # Load weights pre-trained on ImageNet.
    input_shape=(150, 150, 3),
    include_top=False)  # Do not include the ImageNet classifier at the top.

তারপর, বেস মডেল হিমায়িত।

base_model.trainable = False

উপরে একটি নতুন মডেল তৈরি করুন।

inputs = keras.Input(shape=(150, 150, 3))
# We make sure that the base_model is running in inference mode here,
# by passing `training=False`. This is important for fine-tuning, as you will
# learn in a few paragraphs.
x = base_model(inputs, training=False)
# Convert features of shape `base_model.output_shape[1:]` to vectors
x = keras.layers.GlobalAveragePooling2D()(x)
# A Dense classifier with a single unit (binary classification)
outputs = keras.layers.Dense(1)(x)
model = keras.Model(inputs, outputs)

নতুন ডেটাতে মডেলকে প্রশিক্ষণ দিন।

model.compile(optimizer=keras.optimizers.Adam(),
              loss=keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=[keras.metrics.BinaryAccuracy()])
model.fit(new_dataset, epochs=20, callbacks=..., validation_data=...)

ফাইন-টিউনিং

একবার আপনার মডেলটি নতুন ডেটাতে একত্রিত হয়ে গেলে, আপনি বেস মডেলের সমস্ত বা কিছু অংশ আনফ্রিজ করার চেষ্টা করতে পারেন এবং খুব কম শেখার হারের সাথে সম্পূর্ণ মডেলটিকে এন্ড-টু-এন্ড পুনরায় প্রশিক্ষণ দিতে পারেন।

এটি একটি ঐচ্ছিক শেষ ধাপ যা আপনাকে ক্রমবর্ধমান উন্নতি দিতে পারে। এটি সম্ভাব্যভাবে দ্রুত ওভারফিটিং হতে পারে -- মনে রাখবেন।

এটা তোলে পর হিমায়িত স্তর সঙ্গে মডেল অভিসৃতি প্রশিক্ষিত করা হয়েছে শুধুমাত্র এই পদক্ষেপ করতে গুরুত্বপূর্ণ। আপনি যদি এলোমেলোভাবে-প্রশিক্ষণযোগ্য স্তরগুলিকে প্রশিক্ষণযোগ্য স্তরগুলির সাথে মিশ্রিত করেন যা প্রাক-প্রশিক্ষিত বৈশিষ্ট্যগুলি ধারণ করে, তবে এলোমেলোভাবে-শুরু করা স্তরগুলি প্রশিক্ষণের সময় খুব বড় গ্রেডিয়েন্ট আপডেটের কারণ হবে, যা আপনার প্রাক-প্রশিক্ষিত বৈশিষ্ট্যগুলিকে ধ্বংস করবে।

এই পর্যায়ে খুব কম শেখার হার ব্যবহার করাও গুরুত্বপূর্ণ, কারণ আপনি প্রশিক্ষণের প্রথম রাউন্ডের তুলনায় অনেক বড় মডেল প্রশিক্ষণ দিচ্ছেন, একটি ডেটাসেটে যা সাধারণত খুব ছোট। ফলস্বরূপ, আপনি যদি বড় ওজনের আপডেটগুলি প্রয়োগ করেন তবে আপনি খুব দ্রুত ওভারফিটিং হওয়ার ঝুঁকিতে রয়েছেন। এখানে, আপনি শুধুমাত্র ক্রমবর্ধমান উপায়ে পূর্বপ্রশিক্ষিত ওজনগুলিকে পুনরায় মানানসই করতে চান।

সম্পূর্ণ বেস মডেলের সূক্ষ্ম-টিউনিং কীভাবে বাস্তবায়ন করা যায় তা হল:

# Unfreeze the base model
base_model.trainable = True

# It's important to recompile your model after you make any changes
# to the `trainable` attribute of any inner layer, so that your changes
# are take into account
model.compile(optimizer=keras.optimizers.Adam(1e-5),  # Very low learning rate
              loss=keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=[keras.metrics.BinaryAccuracy()])

# Train end-to-end. Be careful to stop before you overfit!
model.fit(new_dataset, epochs=10, callbacks=..., validation_data=...)

সম্পর্কিত গুরুত্বপূর্ণ নোট compile() এবং trainable

কলিং compile() একটি মডেল বোঝানো হয় যে মডেল আচরণকে "বরফে পরিণত করা"। এর অর্থ হলো trainable সময় মডেল কম্পাইল করা হয় এ অ্যাট্রিবিউট মূল্যবোধ, মডেলটির জীবনকাল সর্বত্র সংরক্ষিত করা উচিত, যতক্ষণ না compile আবার বলা হয়। তাই, যদি আপনার কোন পরিবর্তন trainable মান, নিশ্চিত করুন কল করতে compile() আবার আপনার মডেল জন্য আপনার পরিবর্তনগুলি বিবেচনায় নেয়া হবে।

সম্পর্কে গুরুত্বপূর্ণ নোট BatchNormalization স্তর

অনেক ইমেজ মডেল ধারণ BatchNormalization স্তর। সেই স্তরটি প্রতিটি কল্পনাযোগ্য গণনায় একটি বিশেষ ক্ষেত্রে। এখানে কয়েকটি বিষয় মাথায় রাখতে হবে।

  • BatchNormalization 2 অ trainable ওজন যে প্রশিক্ষণের সময় আপডেট রয়েছে। এই ভেরিয়েবলগুলি ইনপুটগুলির গড় এবং বৈচিত্র ট্র্যাক করে।
  • যখন আপনি সেট bn_layer.trainable = False , BatchNormalization স্তর অনুমান মোডে চালানো হবে, এবং তার গড় & ভ্যারিয়েন্স পরিসংখ্যান আপডেট করবে না। এই সাধারণভাবে অন্যান্য স্তর, যেমন জন্য কেস নয় ওজন trainability & অনুমান / প্রশিক্ষণ মোড দুই লম্ব ধারণা । কিন্তু দুই ক্ষেত্রে বাঁধা BatchNormalization স্তর।
  • যখন আপনি একটি মডেল যা ধারণ করে unfreeze BatchNormalization অর্ডার ফাইন টিউনিং কাজ করার জন্য স্তরগুলির, আপনি রাখা উচিত BatchNormalization ক্ষণস্থায়ী দ্বারা অনুমান মোডে স্তর training=False যখন বেস মডেল কলিং। অন্যথায় অ-প্রশিক্ষণযোগ্য ওজনগুলিতে প্রয়োগ করা আপডেটগুলি হঠাৎ করে মডেলটি যা শিখেছে তা ধ্বংস করবে।

আপনি এই গাইডের শেষে এন্ড-টু-এন্ড উদাহরণে এই প্যাটার্নটি কার্যকরভাবে দেখতে পাবেন।

একটি কাস্টম প্রশিক্ষণ লুপের সাহায্যে শেখা এবং সূক্ষ্ম-টিউনিং স্থানান্তর করুন

পরিবর্তে এমন fit() , আপনি আপনার নিজের নিম্নস্তরের প্রশিক্ষণ লুপ ব্যবহার করছেন, কর্মপ্রবাহ থাকার বিষয়টি মতেই মূলত একই। আপনি সতর্কতা অবলম্বন করা উচিত একমাত্র একাউন্টে তালিকা নেওয়া model.trainable_weights যখন গ্রেডিয়েন্ট আপডেট প্রয়োগ:

# Create base model
base_model = keras.applications.Xception(
    weights='imagenet',
    input_shape=(150, 150, 3),
    include_top=False)
# Freeze base model
base_model.trainable = False

# Create new model on top.
inputs = keras.Input(shape=(150, 150, 3))
x = base_model(inputs, training=False)
x = keras.layers.GlobalAveragePooling2D()(x)
outputs = keras.layers.Dense(1)(x)
model = keras.Model(inputs, outputs)

loss_fn = keras.losses.BinaryCrossentropy(from_logits=True)
optimizer = keras.optimizers.Adam()

# Iterate over the batches of a dataset.
for inputs, targets in new_dataset:
    # Open a GradientTape.
    with tf.GradientTape() as tape:
        # Forward pass.
        predictions = model(inputs)
        # Compute the loss value for this batch.
        loss_value = loss_fn(targets, predictions)

    # Get gradients of loss wrt the *trainable* weights.
    gradients = tape.gradient(loss_value, model.trainable_weights)
    # Update the weights of the model.
    optimizer.apply_gradients(zip(gradients, model.trainable_weights))

সূক্ষ্ম টিউনিং জন্য অনুরূপভাবে.

একটি এন্ড-টু-এন্ড উদাহরণ: একটি বিড়াল বনাম কুকুর ডেটাসেটে একটি চিত্র শ্রেণিবিন্যাসের মডেলকে ফাইন-টিউনিং

এই ধারণাগুলিকে দৃঢ় করার জন্য, আসুন আপনাকে একটি কংক্রিট এন্ড-টু-এন্ড ট্রান্সফার লার্নিং এবং ফাইন-টিউনিং উদাহরণের মাধ্যমে নিয়ে যাই। আমরা ইমেজনেটে ​​পূর্ব-প্রশিক্ষিত এক্সসেপশন মডেলটি লোড করব এবং এটি কাগল "বিড়াল বনাম কুকুর" শ্রেণীবিভাগ ডেটাসেটে ব্যবহার করব।

তথ্য পাওয়া যাচ্ছে

প্রথমে, আসুন TFDS ব্যবহার করে বিড়াল বনাম কুকুর ডেটাসেট নিয়ে আসি। আপনি আপনার নিজের ডেটা সেটটি থাকে, তাহলে আপনি সম্ভবত ইউটিলিটি ব্যবহার করতে চাইবেন tf.keras.preprocessing.image_dataset_from_directory অনুরূপ লেবেল ডেটা সেটটি বর্গ-নির্দিষ্ট ফোল্ডারে দায়ের ডিস্কে ইমেজ একটি সেট থেকে বস্তু তৈরি করতে।

খুব ছোট ডেটাসেটের সাথে কাজ করার সময় ট্রান্সফার লার্নিং সবচেয়ে কার্যকর। আমাদের ডেটাসেট ছোট রাখতে, আমরা প্রশিক্ষণের জন্য 40% মূল প্রশিক্ষণ ডেটা (25,000 ছবি) ব্যবহার করব, 10% যাচাইকরণের জন্য এবং 10% পরীক্ষার জন্য।

import tensorflow_datasets as tfds

tfds.disable_progress_bar()

train_ds, validation_ds, test_ds = tfds.load(
    "cats_vs_dogs",
    # Reserve 10% for validation and 10% for test
    split=["train[:40%]", "train[40%:50%]", "train[50%:60%]"],
    as_supervised=True,  # Include labels
)

print("Number of training samples: %d" % tf.data.experimental.cardinality(train_ds))
print(
    "Number of validation samples: %d" % tf.data.experimental.cardinality(validation_ds)
)
print("Number of test samples: %d" % tf.data.experimental.cardinality(test_ds))
Number of training samples: 9305
Number of validation samples: 2326
Number of test samples: 2326

প্রশিক্ষণ ডেটাসেটে এই প্রথম 9টি ছবি -- যেমন আপনি দেখতে পাচ্ছেন, সেগুলি বিভিন্ন আকারের।

import matplotlib.pyplot as plt

plt.figure(figsize=(10, 10))
for i, (image, label) in enumerate(train_ds.take(9)):
    ax = plt.subplot(3, 3, i + 1)
    plt.imshow(image)
    plt.title(int(label))
    plt.axis("off")

png

আমরা আরও দেখতে পাচ্ছি যে লেবেল 1 হল "কুকুর" এবং লেবেল 0 হল "বিড়াল"।

ডেটা স্ট্যান্ডার্ডাইজ করা

আমাদের কাঁচা ছবি বিভিন্ন আকার আছে. উপরন্তু, প্রতিটি পিক্সেল 0 থেকে 255 (RGB স্তরের মান) এর মধ্যে 3টি পূর্ণসংখ্যার মান নিয়ে গঠিত। এটি একটি নিউরাল নেটওয়ার্ক খাওয়ানোর জন্য উপযুক্ত নয়। আমাদের 2টি জিনিস করতে হবে:

  • একটি স্থির চিত্র আকারে মানক করুন। আমরা 150x150 বাছাই করি।
  • স্বাভাবিক পিক্সেল মানের মধ্যে -1 এবং 1 আমরা একটি ব্যবহার করে এই চেষ্টা করবো Normalization মডেল নিজেই অংশ হিসেবে স্তর।

সাধারণভাবে, এমন মডেলগুলি তৈরি করা একটি ভাল অভ্যাস যা ইনপুট হিসাবে কাঁচা ডেটা গ্রহণ করে, এমন মডেলগুলির বিপরীতে যা ইতিমধ্যে-প্রি-প্রসেসড ডেটা গ্রহণ করে। কারণ হল, যদি আপনার মডেল প্রি-প্রসেসড ডেটা আশা করে, যে কোনো সময় আপনি আপনার মডেলটি অন্য কোথাও ব্যবহার করার জন্য রপ্তানি করেন (একটি ওয়েব ব্রাউজারে, একটি মোবাইল অ্যাপে), আপনাকে ঠিক একই প্রিপ্রসেসিং পাইপলাইনটি পুনরায় প্রয়োগ করতে হবে। এই খুব দ্রুত পায় খুব চতুর. সুতরাং মডেলটিকে আঘাত করার আগে আমাদের সর্বনিম্ন সম্ভাব্য পরিমাণ প্রিপ্রসেসিং করা উচিত।

এখানে, আমরা ডেটা পাইপলাইনে চিত্রের আকার পরিবর্তন করব (কারণ একটি গভীর নিউরাল নেটওয়ার্ক শুধুমাত্র ডেটার সংলগ্ন ব্যাচগুলিকে প্রক্রিয়া করতে পারে), এবং আমরা যখন এটি তৈরি করব তখন আমরা মডেলের অংশ হিসাবে ইনপুট মান স্কেলিং করব।

আসুন চিত্রগুলিকে 150x150 এ আকার পরিবর্তন করি:

size = (150, 150)

train_ds = train_ds.map(lambda x, y: (tf.image.resize(x, size), y))
validation_ds = validation_ds.map(lambda x, y: (tf.image.resize(x, size), y))
test_ds = test_ds.map(lambda x, y: (tf.image.resize(x, size), y))

এছাড়াও, আসুন ডেটা ব্যাচ করি এবং লোডিং গতি অপ্টিমাইজ করতে ক্যাশিং এবং প্রিফেচিং ব্যবহার করি।

batch_size = 32

train_ds = train_ds.cache().batch(batch_size).prefetch(buffer_size=10)
validation_ds = validation_ds.cache().batch(batch_size).prefetch(buffer_size=10)
test_ds = test_ds.cache().batch(batch_size).prefetch(buffer_size=10)

র্যান্ডম ডেটা পরিবর্ধন ব্যবহার করে

যখন আপনার কাছে একটি বড় ইমেজ ডেটাসেট না থাকে, তখন ট্রেনিং ইমেজে এলোমেলো অথচ বাস্তবসম্মত রূপান্তর প্রয়োগ করে কৃত্রিমভাবে নমুনা বৈচিত্র্য প্রবর্তন করা একটি ভালো অভ্যাস, যেমন এলোমেলো অনুভূমিক ফ্লিপিং বা ছোট এলোমেলো ঘূর্ণন। এটি ওভারফিটিং কমানোর সময় প্রশিক্ষণের ডেটার বিভিন্ন দিকের মডেলটিকে প্রকাশ করতে সহায়তা করে।

from tensorflow import keras
from tensorflow.keras import layers

data_augmentation = keras.Sequential(
    [layers.RandomFlip("horizontal"), layers.RandomRotation(0.1),]
)

বিভিন্ন এলোমেলো রূপান্তরের পরে প্রথম ব্যাচের প্রথম চিত্রটি কেমন হবে তা কল্পনা করা যাক:

import numpy as np

for images, labels in train_ds.take(1):
    plt.figure(figsize=(10, 10))
    first_image = images[0]
    for i in range(9):
        ax = plt.subplot(3, 3, i + 1)
        augmented_image = data_augmentation(
            tf.expand_dims(first_image, 0), training=True
        )
        plt.imshow(augmented_image[0].numpy().astype("int32"))
        plt.title(int(labels[0]))
        plt.axis("off")
2021-09-01 18:45:34.772284: 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.

png

একটি মডেল তৈরি করুন

এখন আসুন একটি মডেল তৈরি করি যা আমরা পূর্বে ব্যাখ্যা করা ব্লুপ্রিন্ট অনুসরণ করে।

মনে রাখবেন যে:

  • আমরা একটি যোগ Rescaling স্কেল ইনপুট মান স্তর (প্রথমদিকে মধ্যে [0, 255] থেকে রেঞ্জ) [-1, 1] পরিসীমা।
  • আমরা একটি যোগ Dropout নিয়মিতকরণ জন্য শ্রেণীবিভাগ স্তরের ার পূর্বে ের স্তর,।
  • আমরা পাস করতে ভুলবেন না training=False যাতে এটি, অনুমান মোডে সঞ্চালিত হয়, যাতে batchnorm পরিসংখ্যান আপডেট না হওয়ার পরও ফাইন টিউনিং জন্য বেস মডেল unfreeze যখন বেস মডেল কলিং।
base_model = keras.applications.Xception(
    weights="imagenet",  # Load weights pre-trained on ImageNet.
    input_shape=(150, 150, 3),
    include_top=False,
)  # Do not include the ImageNet classifier at the top.

# Freeze the base_model
base_model.trainable = False

# Create new model on top
inputs = keras.Input(shape=(150, 150, 3))
x = data_augmentation(inputs)  # Apply random data augmentation

# Pre-trained Xception weights requires that input be scaled
# from (0, 255) to a range of (-1., +1.), the rescaling layer
# outputs: `(inputs * scale) + offset`
scale_layer = keras.layers.Rescaling(scale=1 / 127.5, offset=-1)
x = scale_layer(x)

# The base model contains batchnorm layers. We want to keep them in inference mode
# when we unfreeze the base model for fine-tuning, so we make sure that the
# base_model is running in inference mode here.
x = base_model(x, training=False)
x = keras.layers.GlobalAveragePooling2D()(x)
x = keras.layers.Dropout(0.2)(x)  # Regularize with dropout
outputs = keras.layers.Dense(1)(x)
model = keras.Model(inputs, outputs)

model.summary()
Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/xception/xception_weights_tf_dim_ordering_tf_kernels_notop.h5
83689472/83683744 [==============================] - 2s 0us/step
83697664/83683744 [==============================] - 2s 0us/step
Model: "model"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_5 (InputLayer)         [(None, 150, 150, 3)]     0         
_________________________________________________________________
sequential_3 (Sequential)    (None, 150, 150, 3)       0         
_________________________________________________________________
rescaling (Rescaling)        (None, 150, 150, 3)       0         
_________________________________________________________________
xception (Functional)        (None, 5, 5, 2048)        20861480  
_________________________________________________________________
global_average_pooling2d (Gl (None, 2048)              0         
_________________________________________________________________
dropout (Dropout)            (None, 2048)              0         
_________________________________________________________________
dense_7 (Dense)              (None, 1)                 2049      
=================================================================
Total params: 20,863,529
Trainable params: 2,049
Non-trainable params: 20,861,480
_________________________________________________________________

উপরের স্তরটি প্রশিক্ষণ দিন

model.compile(
    optimizer=keras.optimizers.Adam(),
    loss=keras.losses.BinaryCrossentropy(from_logits=True),
    metrics=[keras.metrics.BinaryAccuracy()],
)

epochs = 20
model.fit(train_ds, epochs=epochs, validation_data=validation_ds)
Epoch 1/20
151/291 [==============>...............] - ETA: 3s - loss: 0.1979 - binary_accuracy: 0.9096
Corrupt JPEG data: 65 extraneous bytes before marker 0xd9
268/291 [==========================>...] - ETA: 1s - loss: 0.1663 - binary_accuracy: 0.9269
Corrupt JPEG data: 239 extraneous bytes before marker 0xd9
282/291 [============================>.] - ETA: 0s - loss: 0.1628 - binary_accuracy: 0.9284
Corrupt JPEG data: 1153 extraneous bytes before marker 0xd9
Corrupt JPEG data: 228 extraneous bytes before marker 0xd9
291/291 [==============================] - ETA: 0s - loss: 0.1620 - binary_accuracy: 0.9286
Corrupt JPEG data: 2226 extraneous bytes before marker 0xd9
291/291 [==============================] - 29s 63ms/step - loss: 0.1620 - binary_accuracy: 0.9286 - val_loss: 0.0814 - val_binary_accuracy: 0.9686
Epoch 2/20
291/291 [==============================] - 8s 29ms/step - loss: 0.1178 - binary_accuracy: 0.9511 - val_loss: 0.0785 - val_binary_accuracy: 0.9695
Epoch 3/20
291/291 [==============================] - 9s 30ms/step - loss: 0.1121 - binary_accuracy: 0.9536 - val_loss: 0.0748 - val_binary_accuracy: 0.9712
Epoch 4/20
291/291 [==============================] - 9s 29ms/step - loss: 0.1082 - binary_accuracy: 0.9554 - val_loss: 0.0754 - val_binary_accuracy: 0.9703
Epoch 5/20
291/291 [==============================] - 8s 29ms/step - loss: 0.1034 - binary_accuracy: 0.9570 - val_loss: 0.0721 - val_binary_accuracy: 0.9725
Epoch 6/20
291/291 [==============================] - 8s 29ms/step - loss: 0.0975 - binary_accuracy: 0.9602 - val_loss: 0.0748 - val_binary_accuracy: 0.9699
Epoch 7/20
291/291 [==============================] - 9s 29ms/step - loss: 0.0989 - binary_accuracy: 0.9595 - val_loss: 0.0732 - val_binary_accuracy: 0.9716
Epoch 8/20
291/291 [==============================] - 8s 29ms/step - loss: 0.1027 - binary_accuracy: 0.9566 - val_loss: 0.0787 - val_binary_accuracy: 0.9678
Epoch 9/20
291/291 [==============================] - 8s 29ms/step - loss: 0.0959 - binary_accuracy: 0.9614 - val_loss: 0.0734 - val_binary_accuracy: 0.9729
Epoch 10/20
291/291 [==============================] - 8s 29ms/step - loss: 0.0995 - binary_accuracy: 0.9588 - val_loss: 0.0717 - val_binary_accuracy: 0.9721
Epoch 11/20
291/291 [==============================] - 8s 29ms/step - loss: 0.0957 - binary_accuracy: 0.9612 - val_loss: 0.0731 - val_binary_accuracy: 0.9725
Epoch 12/20
291/291 [==============================] - 8s 29ms/step - loss: 0.0936 - binary_accuracy: 0.9622 - val_loss: 0.0751 - val_binary_accuracy: 0.9716
Epoch 13/20
291/291 [==============================] - 8s 29ms/step - loss: 0.0965 - binary_accuracy: 0.9610 - val_loss: 0.0821 - val_binary_accuracy: 0.9695
Epoch 14/20
291/291 [==============================] - 8s 29ms/step - loss: 0.0939 - binary_accuracy: 0.9618 - val_loss: 0.0742 - val_binary_accuracy: 0.9712
Epoch 15/20
291/291 [==============================] - 8s 29ms/step - loss: 0.0974 - binary_accuracy: 0.9585 - val_loss: 0.0771 - val_binary_accuracy: 0.9712
Epoch 16/20
291/291 [==============================] - 8s 29ms/step - loss: 0.0947 - binary_accuracy: 0.9621 - val_loss: 0.0823 - val_binary_accuracy: 0.9699
Epoch 17/20
291/291 [==============================] - 8s 29ms/step - loss: 0.0947 - binary_accuracy: 0.9625 - val_loss: 0.0718 - val_binary_accuracy: 0.9708
Epoch 18/20
291/291 [==============================] - 8s 29ms/step - loss: 0.0928 - binary_accuracy: 0.9616 - val_loss: 0.0738 - val_binary_accuracy: 0.9716
Epoch 19/20
291/291 [==============================] - 8s 29ms/step - loss: 0.0922 - binary_accuracy: 0.9644 - val_loss: 0.0743 - val_binary_accuracy: 0.9716
Epoch 20/20
291/291 [==============================] - 8s 29ms/step - loss: 0.0885 - binary_accuracy: 0.9635 - val_loss: 0.0745 - val_binary_accuracy: 0.9695
<keras.callbacks.History at 0x7f849a3b2950>

পুরো মডেলের সূক্ষ্ম টিউনিং একটি রাউন্ড করুন

অবশেষে, আসুন বেস মডেলটি আনফ্রিজ করি এবং কম শেখার হারের সাথে সম্পূর্ণ মডেলটিকে এন্ড-টু-এন্ড ট্রেনিং করি।

গুরুত্বপূর্ণভাবে, যদিও বেস মডেল trainable হয়ে, এটি এখনও অনুমান মোডে চালানো হয় যেহেতু আমরা পাস training=False যখন এটি কলিং যখন আমরা মডেল নির্মিত। এর মানে হল যে ভিতরে থাকা ব্যাচ স্বাভাবিককরণ স্তরগুলি তাদের ব্যাচের পরিসংখ্যান আপডেট করবে না। যদি তারা তা করে তবে তারা এখন পর্যন্ত মডেল দ্বারা শেখা উপস্থাপনাকে ধ্বংস করবে।

# Unfreeze the base_model. Note that it keeps running in inference mode
# since we passed `training=False` when calling it. This means that
# the batchnorm layers will not update their batch statistics.
# This prevents the batchnorm layers from undoing all the training
# we've done so far.
base_model.trainable = True
model.summary()

model.compile(
    optimizer=keras.optimizers.Adam(1e-5),  # Low learning rate
    loss=keras.losses.BinaryCrossentropy(from_logits=True),
    metrics=[keras.metrics.BinaryAccuracy()],
)

epochs = 10
model.fit(train_ds, epochs=epochs, validation_data=validation_ds)
Model: "model"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_5 (InputLayer)         [(None, 150, 150, 3)]     0         
_________________________________________________________________
sequential_3 (Sequential)    (None, 150, 150, 3)       0         
_________________________________________________________________
rescaling (Rescaling)        (None, 150, 150, 3)       0         
_________________________________________________________________
xception (Functional)        (None, 5, 5, 2048)        20861480  
_________________________________________________________________
global_average_pooling2d (Gl (None, 2048)              0         
_________________________________________________________________
dropout (Dropout)            (None, 2048)              0         
_________________________________________________________________
dense_7 (Dense)              (None, 1)                 2049      
=================================================================
Total params: 20,863,529
Trainable params: 20,809,001
Non-trainable params: 54,528
_________________________________________________________________
Epoch 1/10
291/291 [==============================] - 43s 131ms/step - loss: 0.0802 - binary_accuracy: 0.9692 - val_loss: 0.0580 - val_binary_accuracy: 0.9764
Epoch 2/10
291/291 [==============================] - 37s 128ms/step - loss: 0.0542 - binary_accuracy: 0.9792 - val_loss: 0.0529 - val_binary_accuracy: 0.9764
Epoch 3/10
291/291 [==============================] - 37s 128ms/step - loss: 0.0400 - binary_accuracy: 0.9832 - val_loss: 0.0510 - val_binary_accuracy: 0.9798
Epoch 4/10
291/291 [==============================] - 37s 128ms/step - loss: 0.0313 - binary_accuracy: 0.9879 - val_loss: 0.0505 - val_binary_accuracy: 0.9819
Epoch 5/10
291/291 [==============================] - 37s 128ms/step - loss: 0.0272 - binary_accuracy: 0.9904 - val_loss: 0.0485 - val_binary_accuracy: 0.9807
Epoch 6/10
291/291 [==============================] - 37s 128ms/step - loss: 0.0284 - binary_accuracy: 0.9901 - val_loss: 0.0497 - val_binary_accuracy: 0.9824
Epoch 7/10
291/291 [==============================] - 37s 127ms/step - loss: 0.0198 - binary_accuracy: 0.9937 - val_loss: 0.0530 - val_binary_accuracy: 0.9802
Epoch 8/10
291/291 [==============================] - 37s 127ms/step - loss: 0.0173 - binary_accuracy: 0.9930 - val_loss: 0.0572 - val_binary_accuracy: 0.9819
Epoch 9/10
291/291 [==============================] - 37s 127ms/step - loss: 0.0113 - binary_accuracy: 0.9958 - val_loss: 0.0555 - val_binary_accuracy: 0.9837
Epoch 10/10
291/291 [==============================] - 37s 127ms/step - loss: 0.0091 - binary_accuracy: 0.9966 - val_loss: 0.0596 - val_binary_accuracy: 0.9832
<keras.callbacks.History at 0x7f83982d4cd0>

10টি যুগের পরে, ফাইন-টিউনিং আমাদের এখানে একটি চমৎকার উন্নতি লাভ করে।