آموزش Keras : تنظیم دقیق با استفاده از مدل های از پیش آموزش دیده

در دو پست قبلی ، نحوه استفاده از مدل های از پیش آموزش دیده و نحوه استخراج ویژگی ها از آن ها برای آموزش مدلی به منظور انجام وظایف متفاوت را یاد گرفتیم. در این آموزش ، قصد داریم به نحوه ی تنظیم دقیق یک مدل از پیش آموزش دیده ، برای کاری متفاوت از آنچه در ابتدا برای آن آموزش دیده است بپردازیم.

ما سعی خواهیم کرد مسئله کلاسه بندی کدو تنبل ، هندوانه و گوجه فرنگی را که در پست قبلی هم مورد بحث قرار دادیم ، بهبود ببخشیم. برای این منظور از داده های مشابه استفاده خواهیم کرد.

منظور از تنظیم دقیق یک شبکه چیست؟

ما قبلاً اهمیت استفاده از شبکه های از پیش آموزش دیده را در مقاله قبلی خود توضیح دادیم. به طور خلاصه ، وقتی شبکه ای را از ابتدا آموزش می دهیم ، با دو محدودیت زیر روبرو می شویم :

  • مجموعه داده عظیمی مورد نیاز است : از آنجا که شبکه دارای میلیون ها پارامتر است ، برای به دست آوردن مجموعه بهینه پارامترها ، باید داده های زیادی داشته باشیم.
  • قدرت محاسباتی زیادی مورد نیاز است : حتی اگر داده های زیادی در اختیار داشته باشیم ، به طور کلی فرآیند آموزش نیاز به تکرارهای متعدد دارد و بر منابع محاسباتی تأثیر می گذارد.

وظیفه تنظیم دقیق یک شبکه این است که پارامترهای یک شبکه از پیش آموزش دیده را تغییر دهد تا با کار جدید سازگار شود. همانطور که در اینجا توضیح داده شد ، لایه های اولیه ویژگی های بسیار کلی را می آموزند و با پیش رفتن در شبکه ، لایه ها تمایل دارند الگو های بیشتری را برای وظیفه ای که در آن آموزش می بینند، بیاموزند. بنابراین ، برای تنظیم دقیق ، می خواهیم لایه های اولیه را ثابت و دست نخورده نگه داریم ( یا اصطلاحاً آن ها را فریز کنیم ) و لایه های بعدی را برای کار خود مجددا آموزش دهیم.

بنابراین ، تنظیم دقیق از هر دو محدودیتی که در بالا بحث شد جلوگیری می کند.

  • میزان داده های مورد نیاز برای آموزش به دو دلیل زیاد نیست. اول، ما کل شبکه را آموزش نمی دهیم. دوم، قسمتی که در حال آموزش است از ابتدا آموزش داده نشده است.
  • از آنجا که پارامتر هایی که باید به روزرسانی شوند کمتر هستند ، زمان مورد نیاز نیز کمتر خواهد بود.

تنظیم دقیق در Keras

اجازه دهید بدون هیچ گونه اتلاف وقت مستقیماً وارد کد نویسی شویم. ما از همان داده هایی که در پست قبلی استفاده کردیم استفاده خواهیم کرد. اگر GPU دارید می توانید از مجموعه داده بزرگتری استفاده کنید، زیرا آموزش مجموعه داده بزرگ روی CPU ، یک فرآیند بسیار زمان بر است. ما از مدل VGG برای تنظیم دقیق استفاده می کنیم.

بارگذاری مدل از پیش آموزش دیده

ابتدا ، یک مدل VGG را بدون لایه بالایی (که از لایه های کاملاً متصل تشکیل شده است) بارگذاری می کنیم.

from tensorflow.keras.applications import vgg16

# Init the VGG model 
vgg_conv = vgg16.VGG16(weights='imagenet', include_top=False, input_shape=(image_size, image_size, 3))

 

ثابت نگه داشتن لایه های مورد نیاز

در کراس ، هر لایه دارای پارامتری به نام ” قابل آموزش ” یا “ trainable ” است. برای فریز کردن وزن های یک لایه خاص ، باید این پارامتر را بر روی False قرار دهیم ، که نشان می دهد این لایه نباید آموزش داده شود. ما برای هر لایه ای را که می خواهیم آموزش دهیم این تنظیمات را اعمال می کنیم.

# Freeze all the layers
for layer in vgg_conv.layers[:]:
    layer.trainable = False

# Check the trainable status of the individual layers
for layer in vgg_conv.layers:
    print(layer, layer.trainable)
پارامتر خروجی قابل آموزش

ایجاد یک مدل جدید

حالا که پارامترهای قابل آموزش شبکه اصلی خود را تنظیم کردیم ، می خواهیم یک کلاسه بند در بالای قسمت کانولوشنی اضافه کنیم. به سادگی می توانیم یک لایه کاملاً متصل و سپس یک لایه softmax با ۳ خروجی اضافه می کنیم. که این کار به صورت زیر انجام می شود :

# Create the model
model = Sequential()

# Add the vgg convolutional base model
model.add(vgg_conv)

# Add new layers
model.add(Flatten())
model.add(Dense(1024, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(3, activation='softmax'))

# Show a summary of the model. Check the number of trainable parameters
model.summary()
خلاصه وضعیت مدل از پیش آموزش دیده

تنظیم داده افزایی

ما قبلاً داده ها را به دو قسمت آموزشی و اعتبار سنجی جدا کردیم و آن ها را در پوشه های “train ” و” validation ” نگه داشته ایم. همچنین می توانیم از ImageDataGenerator موجود در Keras برای خواندن مستقیم تصاویر بصورت دسته ای ، از این پوشه ها و انجام اختیاری داده افزایی استفاده کنیم. ما داده افزایی را بصورت جداگانه برای داده های پوشه های آموزش و اعتبار سنجی اعمال خواهیم کرد.

# Load the normalized images
train_datagen = ImageDataGenerator(rescale=1./255)
validation_datagen = ImageDataGenerator(rescale=1./255)

# Change the batchsize according to your system RAM
train_batchsize = 100
val_batchsize = 10

# Data generator for training data
train_generator = train_datagen.flow_from_directory(
        train_dir,
        target_size=(image_size, image_size),
        batch_size=train_batchsize,
        class_mode='categorical')

# Data generator for validation data
validation_generator = validation_datagen.flow_from_directory(
        validation_dir,
        target_size=(image_size, image_size),
        batch_size=val_batchsize,
        class_mode='categorical',
        shuffle=False)

آموزش مدل

تا به این مرحله ، ما مدل را ایجاد کرده و داده ها را برای آموزش مرتب کردیم. بنابراین ، حالا باید آموزش را شروع کنیم و عملکرد آن را بررسی کنیم. به علاوه، باید بهینه ساز و نرخ یادگیری را مشخص کرده و آموزش را با استفاده از تابع ()model.fit شروع کنیم. درنهایت، پس از پایان آموزش ، مدل را ذخیره می کنیم.

# Configure the model for training
model.compile(loss='categorical_crossentropy',
              optimizer=optimizers.RMSprop(lr=1e-4),
              metrics=['acc'])

# Train the model
history = model.fit(
      train_generator,
      steps_per_epoch=
         train_generator.samples/train_generator.batch_size,
      epochs=20,
      validation_data=validation_generator, 
      validation_steps=
         validation_generator.samples/validation_generator.batch_size,
      verbose=1)

بررسی عملکرد

ما با رویکرد یادگیری انتقالی که در مقاله قبلی مورد بحث قرار گرفت ، دقت ۹۰ درصدی را بدست آوردیم، اما در اینجا به دقت بسیار خوب ۹۸ درصدی رسیدیم.

اجازه دهید منحنی های زیان و دقت را با استفاده از تابع visualize_results (history) مشاهده کنیم :

# Utility function for plotting of the model results
def visualize_results(history):
    # Plot the accuracy and loss curves
    acc = history.history['acc']
    val_acc = history.history['val_acc']
    loss = history.history['loss']
    val_loss = history.history['val_loss']

    epochs = range(len(acc))

    plt.plot(epochs, acc, 'b', label='Training acc')
    plt.plot(epochs, val_acc, 'r', label='Validation acc')
    plt.title('Training and validation accuracy')
    plt.legend()

    plt.figure()

    plt.plot(epochs, loss, 'b', label='Training loss')
    plt.plot(epochs, val_loss, 'r', label='Validation loss')
    plt.title('Training and validation loss')
    plt.legend()

    plt.show()


# Run the function to illustrate accuracy and loss
visualize_results(history)

خروجی ها به شرح زیر است :

نمودار دقت و ضرر آموزش و اعتبار سنجی

همچنین ، اجازه دهید خطاهایی را که دریافت کرده ایم را به صورت بصری مشاهده کنیم. به منظور جلوگیری از تکرارهای اضافی کد در آزمایش های مختلف ، توابع obtain_errors و show_errors را معرفی می کنیم :

# Utility function for obtaining of the errors 
def obtain_errors(val_generator, predictions):
    # Get the filenames from the generator
    fnames = validation_generator.filenames

    # Get the ground truth from generator
    ground_truth = validation_generator.classes

    # Get the dictionary of classes
    label2index = validation_generator.class_indices

    # Obtain the list of the classes
    idx2label = list(label2index.keys())
    print("The list of classes: ", idx2label)

    # Get the class index
    predicted_classes = np.argmax(predictions, axis=1)

    errors = np.where(predicted_classes != ground_truth)[0]
    print("Number of errors = {}/{}".format(len(errors),validation_generator.samples))
    
    return idx2label, errors, fnames


# Utility function for visualization of the errors
def show_errors(idx2label, errors, predictions, fnames):
    # Show the errors
    for i in range(len(errors)):
        pred_class = np.argmax(predictions[errors[i]])
        pred_label = idx2label[pred_class]

        title = 'Original label:{}, Prediction :{}, confidence : {:.3f}'.format(
            fnames[errors[i]].split('/')[0],
            pred_label,
            predictions[errors[i]][pred_class])

        original = load_img('{}/{}'.format(validation_dir,fnames[errors[i]]))
        plt.figure(figsize=[7,7])
        plt.axis('off')
        plt.title(title)
        plt.imshow(original)
        plt.show()

بنابراین ، روند تحلیل خطا به صورت زیر است :

# Get the predictions from the model using the generator
predictions = model.predict(validation_generator, steps=validation_generator.samples/validation_generator.batch_size,verbose=1)

# Run the function to get the list of classes and errors
idx2label, errors, fnames = obtain_errors(validation_generator, predictions)

# Run the function to illustrate the error cases
show_errors(idx2label, errors, predictions, fnames)

در ادامه چند نمونه خروجی را بررسی می کنیم :

دقت شناسایی و میزان خطا بعد از تنظیم دقیق مدل

آزمایش ها

خب ما ۳ آزمایش انجام دادیم تا تاثیر تنظیم دقیق و داده افزایی را مشاهده کنیم. مجموعه اعتبار سنجی را مانند پست قبلی بصورت ۵۰ تصویر در هر کلاس نگه داشتیم.

  1. ثابت نگه داشتن همه لایه ها و همچنین یادگیری کلاسه بند : مشابه یادگیری انتقالی است. تعداد خطاها ۱۵ مورد از ۱۵۰ تصویر بود که مشابه مواردی است که در پست قبلی دریافت کردیم.
  2. آموزش ۳ لایه کانولوشنی آخر : ما ۹ خطا از ۱۵۰ مورد دریافت کردیم.
  3. آموزش ۳ لایه کانولوشنی آخر با داده افزایی : تعداد خطاها به ۳ از مورد مورد۱۵۰ کاهش می یابد.

امیدوارم این مقاله براس شما مفید بوده باشد. سعی کنید آزمایش های بیشتری انجام دهید و نتایج خود را در قسمت نظرات با ما به اشتراک بگذارید.

بیشتر بخوانید :

منبع Learn OpenCV

درباره‌ی امیر اقتدائی

همچنین ببینید

آیا می خواهید در زمینه یادگیری ماشین استخدام شوید؟

آیا می خواهید در زمینه یادگیری ماشین استخدام شوید؟

مسیر های شغلی زیادی در حوزه یادگیری ماشین وجود دارد، اما از کجا بفهمیم که …

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *