Makine Öğrenimi ile CAPTCHA Sistemi Nasıl Kırılır?

by admin
0 comment

Completely Automated Public Turing Test to Tell Computers and Humans Apart’ın kısaltması olan CAPTCHA, insanları botlardan ayırmaya yardımcı olan ve sitenizi kötü niyetli kişilerden kurtaran devrim niteliğinde bir teknolojidir. Ancak bu teknoloji yaşını göstermeye başladı. Captcha’nın sağlam bir sistem olması gerekiyordu, ancak yapay zeka onu neredeyse işe yaramaz hale getiriyor. Bir Captcha’yı kırmak için eğitmemiz gereken bir makine öğrenimi modeline ihtiyacımız var. Eğitildikten sonra, tek gereken modele istediğiniz CAPTCHA’yı vermek ve onun da sizin için çözmesi.

Bu makalede, makine öğrenimi yardımıyla bir CAPTCHA sisteminin nasıl kırılabileceğini keşfedeceğiz. Sürecin tamamını ayrıntılı olarak tartışacağız. Ayrıca, bu yaklaşımın sınırlamalarını ve bu girişimde bulunurken göz önünde bulundurulması gereken etik ve ahlaki konuları da paylaşacağız. CAPTCHA’yı kırmaktaki amacımızın kendimizi eğitmek ve sistemin insan olmayanları filtreleme konusundaki yetersizliğini vurgulamak olması gerektiği unutulmamalıdır. Ancak CAPTCHA’lar siteleri kötü niyetli saldırılardan koruyan şeylerdir ve interneti etkili bir şekilde korumaktadırlar. Dolayısıyla, web sitelerinde CAPTCHA’ları izinsiz kırmak için bot kullanmak en iyi ihtimalle etik değildir ve bulunduğunuz yere bağlı olarak yasa dışıdır.

Bir Veri Kümesinin Toplanması

Verilerin toplanması, bir Makine Öğrenimi Modelinin eğitilmesinde ilk ve temel adımdır. Burada da durum farklı değildir. İlk olarak, çok sayıda CAPTCHA görüntüsü içeren bir veri kümesi bulmamız gerekir. Modelin kendisine verilen herhangi bir CAPTCHA’yı çözebilmesini sağlamak için veri kümesinin çeşitli olması gerekir.CAPTCHA görüntülerinin toplanması o kadar kolay bir iş değildir. Veri kümelerini elde etmek için yasal bir yol bulmak oldukça karmaşık bir süreçtir ve bunları web sitelerinden kazımak istiyorsanız, bunu izinsiz yapmanın yasa dışı olabileceği ve aynı zamanda etik olmadığı konusunda bilgilendirilmelisiniz. Bu nedenle, açık kaynaklı veri setlerini kullanmaya başvurmamız gerekiyor.

Kullanılabilecek bir veri kümesi Kaggle’dan küçük bir Veri Kümesidir. Captcha’lar hakkında bilgi edinmek için yeterlidir.

Veri kümesi, resim ve etiketlerin bulunduğu bir klasördür. Sadece yolu belirtmeniz gerekir ve bu kadar basittir.

Görüntülerin Ön İşlemden Geçirilmesi

# Path to the Dataset
direc = Path("ML\samples")

dir_img = sorted(list(map(str, list(direc.glob("*.png")))))
img_labels = [img.split(os.path.sep)[-1].split(".png")[0] for img in dir_img]
char_img = set(char for label in img_labels for char in label)
char_img = sorted(list(char_img))


print("Number of dir_img found: ", len(dir_img))
print("Number of img_labels found: ", len(img_labels))
print("Number of unique char_img: ", len(char_img))
print("Characters present: ", char_img)


# Batch Size of Traning and Validation
batch_size = 16


# Setting dimensions of the image
img_width = 200
img_height = 50


# Setting downsampling factor
downsample_factor = 4


# Setting the Maximum Length
max_length = max([len(label) for label in img_labels])


# Char to integers
char_to_num = layers.StringLookup(
    vocabulary=list(char_img), mask_token=None
)


# Integers to original chaecters
num_to_char = layers.StringLookup(
    vocabulary=char_to_num.get_vocabulary(), mask_token=None, invert=True
)

import os
import numpy as np
import matplotlib.pyplot as plt
from pathlib import Path
from collections import Counter
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
def data_split(dir_img, img_labels, train_size=0.9, shuffle=True):
    # Get the total size of the dataset
    size = len(dir_img)
    # Create an indices array and shuffle it if required
    indices = np.arange(size)
    if shuffle:
        np.random.shuffle(indices)
    # Calculate the size of training samples
    train_samples = int(size * train_size)
    # Split data into training and validation sets
    x_train, y_train = dir_img[indices[:train_samples]], img_labels[indices[:train_samples]]
    x_valid, y_valid = dir_img[indices[train_samples:]], img_labels[indices[train_samples:]]
    return x_train, x_valid, y_train, y_valid




# Split data into training and validation sets
x_train, x_valid, y_train, y_valid = data_split(np.array(dir_img), np.array(img_labels))
def encode_sample(img_path, label):
    # Read the image
    img = tf.io.read_file(img_path)
    # Converting the image to grayscale
    img = tf.io.decode_png(img, channels=1)
    img = tf.image.convert_image_dtype(img, tf.float32)
    # Resizing to the desired size
    img = tf.image.resize(img, [img_height, img_width])
    # Transposing the image
    img = tf.transpose(img, perm=[1, 0, 2])
    # Mapping image label to numbers
    label = char_to_num(tf.strings.unicode_split(label, input_encoding="UTF-8"))
    
    return {"image": img, "label": label}
# Creating training dataset
dataset_train = tf.data.Dataset.from_tensor_slices((x_train, y_train))
dataset_train = (
    dataset_train.map(
        encode_sample, num_parallel_calls=tf.data.AUTOTUNE
    )
    .batch(batch_size)
    .prefetch(buffer_size=tf.data.AUTOTUNE)
)


# Creating validation dataset
val_data = tf.data.Dataset.from_tensor_slices((x_valid, y_valid))
val_data = (
    val_data.map(
        encode_sample, num_parallel_calls=tf.data.AUTOTUNE
    )
    .batch(batch_size)
    .prefetch(buffer_size=tf.data.AUTOTUNE)
)


# Visualizing some training data
_, ax = plt.subplots(4, 4, figsize=(10, 5))
for batch in dataset_train.take(1):
    dir_img = batch["image"]
    img_labels = batch["label"]
    for i in range(16):
        img = (dir_img[i] * 255).numpy().astype("uint8")
        label = tf.strings.reduce_join(num_to_char(img_labels[i])).numpy().decode("utf-8")
        ax[i // 4, i % 4].imshow(img[:, :, 0].T, cmap="gray")
        ax[i // 4, i % 4].set_title(label)
        ax[i // 4, i % 4].axis("off")
plt.show()
# CTC loss calculation
class LayerCTC(layers.Layer):
    def __init__(self, name=None):
        super().__init__(name=name)
        self.loss_fn = keras.backend.ctc_batch_cost


    def call(self, y_true, y_pred):
        # Compute the training-time loss value
        batch_len = tf.cast(tf.shape(y_true)[0], dtype="int64")
        input_length = tf.cast(tf.shape(y_pred)[1], dtype="int64")
        label_length = tf.cast(tf.shape(y_true)[1], dtype="int64")


        input_length = input_length * tf.ones(shape=(batch_len, 1), dtype="int64")
        label_length = label_length * tf.ones(shape=(batch_len, 1), dtype="int64")


        loss = self.loss_fn(y_true, y_pred, input_length, label_length)
        self.add_loss(loss)


        # Return Computed predictions
        return y_pred


def model_build():
    # Define the inputs to the model
    input_img = layers.Input(
        shape=(img_width, img_height, 1), name="image", dtype="float32"
    )
    img_labels = layers.Input(name="label", shape=(None,), dtype="float32")


    # First convolutional block
    x = layers.Conv2D(
        32,
        (3, 3),
        activation="relu",
        kernel_initializer="he_normal",
        padding="same",
        name="Conv1",
    )(input_img)
    x = layers.MaxPooling2D((2, 2), name="pool1")(x)


    # Second convolutional block
    x = layers.Conv2D(
        64,
        (3, 3),
        activation="relu",
        kernel_initializer="he_normal",
        padding="same",
        name="Conv2",
    )(x)
    x = layers.MaxPooling2D((2, 2), name="pool2")(x)


    # Reshaping the output before passing to RNN
    new_shape = ((img_width // 4), (img_height // 4) * 64)
    x = layers.Reshape(target_shape=new_shape, name="reshape")(x)
    x = layers.Dense(64, activation="relu", name="dense1")(x)
    x = layers.Dropout(0.2)(x)


    #RNNs
    x = layers.Bidirectional(layers.LSTM(128, return_sequences=True, dropout=0.25))(x)
    x = layers.Bidirectional(layers.LSTM(64, return_sequences=True, dropout=0.25))(x)


    # Output layer
    x = layers.Dense(
        len(char_to_num.get_vocabulary()) + 1, activation="softmax", name="dense2"
    )(x)


    #Calculate CTC loss at each step
    output = LayerCTC(name="ctc_loss")(img_labels, x)


    # Defining the model
    model = keras.models.Model(
        inputs=[input_img, img_labels], outputs=output, name="ocr_model_v1"
    )
    opt = keras.optimizers.Adam()


    # Compile the model
    model.compile(optimizer=opt)


    return model




# Build the model
model = model_build()
model.summary()


# Early Stopping Parameters and EPOCH
epochs = 100
early_stopping_patience = 10


early_stopping = keras.callbacks.EarlyStopping(
    monitor="val_loss", patience=early_stopping_patience, restore_best_weights=True
)


# Training the model
history = model.fit(
    dataset_train,
    validation_data=val_data,
    epochs=epochs,
    callbacks=[early_stopping],
)
# Get the Model
prediction_model = keras.models.Model(
    model.get_layer(name="image").input, model.get_layer(name="dense2").output
)
prediction_model.summary()


def decode_batch_predictions(pred):
    input_len = np.ones(pred.shape[0]) * pred.shape[1]
results = keras.backend.ctc_decode(pred, input_length=input_len, greedy=True)[0][0][
        :, :max_length
    ]
    output_text = []
    for res in results:
        res = tf.strings.reduce_join(num_to_char(res)).numpy().decode("utf-8")
        output_text.append(res)
    return output_text


# Check the validation on a few samples
for batch in val_data.take(1):
    batch_images = batch["image"]
    batch_labels = batch["label"]


    preds = prediction_model.predict(batch_images)
    pred_texts = decode_batch_predictions(preds)


    orig_texts = []
    for label in batch_labels:
        label = tf.strings.reduce_join(num_to_char(label)).numpy().decode("utf-8")
        orig_texts.append(label)


    _, ax = plt.subplots(4, 4, figsize=(15, 5))
    for i in range(len(pred_texts)):
        img = (batch_images[i, :, :, 0] * 255).numpy().astype(np.uint8)
        img = img.T
        title = f"Prediction: {pred_texts[i]}"
        ax[i // 4, i % 4].imshow(img, cmap="gray")
        ax[i // 4, i % 4].set_title(title)
        ax[i // 4, i % 4].axis("off")
plt.show()

Makine öğrenimi modelinin eğitimi

Ön işlemeden sonra zor kısım gelir, CAPTCHA’yı kırmak için çeşitli makine öğrenimi algoritmaları ve teknikleri kullanabiliriz. Konvolüsyonel Sinir Ağları (CNN’ler) ve Tekrarlayan Sinir Ağları (RNN’ler) CAPTCHA’yı kırmak için kullanılabilir. CNN’ler görüntü tanıma için mükemmel bir eşleşme ve görüntüleri tanırken çok etkiliyken, RNN’ler sıralı verileri çok yetkin bir şekilde işleyebilir ve ses tabanlı CAPTCHA gibi şeyler için uygundur. Önceden işlenmiş görüntüler Makine Öğrenimi modeline beslenebilir. Model, akıllı matematik kullanarak sağlanan görüntülerdeki örüntüleri tanımaya başlayacak ve ağırlıklarını ve önyargılarını ayarlayarak öğrenecektir.

Ancak bir engel var. CAPTCHA görüntüleri oldukça değişkendir ve bu da Makine Öğrenimi modelleri için örüntü bulmayı oldukça zorlaştırır. Bu nedenle, test verilerini daha değişken hale getirmek için veri artırımı kullanılmalıdır. Bu döndürme, ölçekleme ve çevirme yoluyla yapılabilir. Ancak veri artırmadan önce, verileri biri eğitim diğeri test için olmak üzere iki parçaya ayırmamız gerekir. Bu şekilde, modelimizin ne kadar doğru olduğunu daha sonra belirleyebiliriz. TensorFlow gibi kütüphaneler, çok çeşitli uygulamalar için istediğiniz CNN’leri oluşturmanıza yardımcı olabilir, bu nedenle bu kullanım için geçerli bir seçimdir.

Şimdi eğitim verilerinden bazı görüntüler çizelim.

Çıktı:

Modelin bir örneğini oluşturduktan sonra şimdi modelin özetini ve bu modelde kullanılan parametre sayısını yazdıralım.

Çıktı:

Model: "ocr_model_v1"
__________________________________________________________________________________________________
 Layer (type)                   Output Shape         Param #     Connected to                     
==================================================================================================
 image (InputLayer)             [(None, 200, 50, 1)  0           []                               
                                ]                                                                 
                                                                                                  
 Conv1 (Conv2D)                 (None, 200, 50, 32)  320         ['image[0][0]']                  
                                                                                                  
 pool1 (MaxPooling2D)           (None, 100, 25, 32)  0           ['Conv1[0][0]']                  
                                                                                                  
 Conv2 (Conv2D)                 (None, 100, 25, 64)  18496       ['pool1[0][0]']                  
                                                                                                  
 pool2 (MaxPooling2D)           (None, 50, 12, 64)   0           ['Conv2[0][0]']                  
                                                                                                  
 reshape (Reshape)              (None, 50, 768)      0           ['pool2[0][0]']                  
                                                                                                  
 dense1 (Dense)                 (None, 50, 64)       49216       ['reshape[0][0]']                
                                                                                                  
 dropout (Dropout)              (None, 50, 64)       0           ['dense1[0][0]']                 
                                                                                                  
 bidirectional (Bidirectional)  (None, 50, 256)      197632      ['dropout[0][0]']                
                                                                                                  
 bidirectional_1 (Bidirectional  (None, 50, 128)     164352      ['bidirectional[0][0]']          
 )                                                                                                
                                                                                                  
 label (InputLayer)             [(None, None)]       0           []                               
                                                                                                  
 dense2 (Dense)                 (None, 50, 21)       2709        ['bidirectional_1[0][0]']        
                                                                                                  
 ctc_loss (LayerCTC)            (None, 50, 21)       0           ['label[0][0]',                  
                                                                  'dense2[0][0]']                 
                                                                                                  
==================================================================================================
Total params: 432,725
Trainable params: 432,725
Non-trainable params: 0
__________________________________________________________________________________________________

Şimdi modeli eğitmeye hazırız. Modeli 100 epok için ve bazı erken durdurma yöntemleriyle birlikte eğiteceğiz, böylece model veriye aşırı uymayacak.

# Early Stopping Parameters and EPOCH
epochs = 100
early_stopping_patience = 10


early_stopping = keras.callbacks.EarlyStopping(
	monitor="val_loss",
	patience=early_stopping_patience,
	restore_best_weights=True
)

# Training the model
history = model.fit(
	dataset_train,
	validation_data=val_data,
	epochs=epochs,
	callbacks=[early_stopping],
)

Çıktı:

Epoch 80/100
59/59 [==============================] - 2s 36ms/step - loss: 1.7622 - val_loss: 7.1511
Epoch 81/100
59/59 [==============================] - 2s 35ms/step - loss: 1.7216 - val_loss: 7.0523
Epoch 82/100
59/59 [==============================] - 3s 47ms/step - loss: 1.5814 - val_loss: 7.1403
Epoch 83/100
59/59 [==============================] - 2s 37ms/step - loss: 1.6464 - val_loss: 7.0921
Epoch 84/100
59/59 [==============================] - 2s 35ms/step - loss: 1.6113 - val_loss: 7.1740
Epoch 85/100
59/59 [==============================] - 2s 35ms/step - loss: 1.5529 - val_loss: 7.1272
Epoch 86/100
59/59 [==============================] - 2s 39ms/step - loss: 1.5346 - val_loss: 7.0750

Makine Öğrenimi Modelinin Test Edilmesi

Modelin CAPTCHA sistemini kırabildiğinden emin olmak için performansını test etmek çok önemlidir. Ancak onu eğitmek için kullandığımız görüntüleri kullanamayız. Bu yüzden, bir önceki adımda kullanmadığımız görüntüleri kullanacağız. Modelimizin ne kadar iyi olduğunu belirlemek için çeşitli metrikler kullanılır. Bunlar F1 Puanı, doğruluk, geri çağırma, kesinlik vb.

  • F1 Puanı: F1 Puanı, bir modelin ne kadar iyi olduğunu anlamak için kullanılan bir metriktir. Doğruluk ve geri çağırmanın bir fonksiyonudur ve 0-1 arasında değişir.
  • Doğruluk: Doğruluk, doğru tahmin ile toplam tahminler arasındaki orandır.
  • Geri Çağırma: Geri çağırma, belirli bir sınıfa ait tüm veri noktalarını ne kadar doğru tanımlayabildiğini belirtir.
  • Kesinlik: Kesinlik, model tarafından yapılan doğru tahminlerin sayısı ile pozitif tahminlerin sayısı arasındaki orandır.

En iyi çabalarımıza rağmen, bir yapay zeka modeli asla tam olarak doğru olmayacaktır. Dolayısıyla, modelin her zaman etkili olacağına güvenemeyiz. Bunun nedeni kısmen Makine Öğreniminin CAPTCHA hizmetlerinin sunucularında da CAPTCHA sistemini kırma girişimlerini tespit etmek ve engellemek için kullanılıyor olmasıdır. Sadece bu da değil, CAPTCHA’lar yeni CAPTCHA türleri sundukları için Makine Öğrenimi modelleri için CAPTCHA’ları anlamak da zorlaşıyor. Şimdi modelin ne kadar iyi çalıştığını bilmenin zamanı geldi.

# Get the Model
prediction_model = keras.models.Model(
	model.get_layer(name="image").input,
	model.get_layer(name="dense2").output
)
prediction_model.summary()


def decode_batch_predictions(pred):
	input_len = np.ones(pred.shape[0]) * pred.shape[1]
	results = keras.backend.ctc_decode(pred,
									input_length=input_len,
									greedy=True)[0][0][
		:, :max_length
	]
	output_text = []
	for res in results:
		res = tf.strings.reduce_join(num_to_char(res))\
		.numpy().decode("utf-8")
		output_text.append(res)
	return output_text

Captcha kodlarında bulunan metni tahmin etmek için yine eğitilmiş modeli kullanıyoruz.

# Check the validation on a few samples
for batch in val_data.take(1):
	batch_images = batch["image"]
	batch_labels = batch["label"]


	preds = prediction_model.predict(batch_images)
	pred_texts = decode_batch_predictions(preds)


	orig_texts = []
	for label in batch_labels:
		label = tf.strings.reduce_join(num_to_char(label))\
		.numpy().decode("utf-8")
		orig_texts.append(label)


	_, ax = plt.subplots(4, 4, figsize=(15, 5))
	for i in range(len(pred_texts)):
		img = (batch_images[i, :, :, 0] * 255).\
		numpy().astype(np.uint8)
		img = img.T
		title = f"Prediction: {pred_texts[i]}"
		ax[i // 4, i % 4].imshow(img, cmap="gray")
		ax[i // 4, i % 4].set_title(title)
		ax[i // 4, i % 4].axis("off")
plt.show()

Çıktı:

Çekişmeli Örnekler Oluşturma

n Layman’s terms, Adversarial Examples, yalnızca bir sinir ağının kafasını karıştırmak amacıyla oluşturulan girdiler anlamına gelir. Bu girdiler, çözülmesi zor CAPTCHA’lara maruz kaldığı için modelin performansını artırır. Muhalif örnekler oluşturmak için birkaç adım izlememiz gerekiyor:

1.Hedef Modelin Seçilmesi
2.Veri Kümesi Seçimi
3.Amaç fonksiyonunun tanımlanması
4.Çekişmeli Nesil
Dolayısıyla, adımlara göre, bir hedef model seçilir ve modelin orijinal olarak eğitildiği veri kümesini seçeriz. Daha sonra amaç fonksiyonu, çıktının gerçek çıktıdan ne kadar farklı olduğunu belirler. Bu, düşman oluşturma sürecine yardımcı olur. Daha sonra, düşman oluşturmak için çok sayıda teknik kullanabiliriz. Bunlar arasında Jacobian Based Saliency Map (JBSM), Fast Gradient Sign Method (FGSM) ve çok daha fazlası bulunmaktadır. Adversarial oluşturulduktan sonra, modeliniz geliştirilmeye hazırdır. Bu adversarial örnekleri oluşturmak için yine TensorFlow kullanılabilir ve bunları oldukça kolay bir şekilde oluşturabilirsiniz.

Sonuç

Sonuç olarak, bir CAPTCHA sistemi makine öğrenimi kullanılarak kırılabilir. Sadece kalıpları tanımlamak için bir makine öğrenimi modeli eğitmek gerekir ve bu model sizin için karakterleri tanıyabilir. Bu makale boyunca, bir Makine öğrenimi modelini çözmek için gerekli adımları tartıştık. Her adımı yineledik ve modelimizi eğittik, ayarladık ve optimize ettik. Model, görülmemiş kalıpları tanımlayabiliyor ve daha önce hiç görmediği CAPTCHA’ları çözebiliyor. Modelin ne kadar doğru olduğunu kontrol etmek için prosedürler de uyguladık. Zamanla CAPTCHA da evrim geçiriyor. Çeşitli CAPTCHA sistemleri kendilerini otomatik saldırılara karşı korumak için önlemler almaya başladı bile. Bizim amacımız bu önlemleri geliştirmek ve herkes için güvenli bir ortam yaratmak olmalıdır. 🙂

You may also like

Leave a Comment