یادگیری بدون نظارت (Unsupervised Learning)
همانطور که پیشتر بحث شده بود، یکی از حوزه های یادگیری ماشین، یادگیری بدون نظارت است که در آن دادهها برچسب ندارند. در یادگیری بدون نظارت هدف اصلی، یادگیری ساختار دادهها میباشد.
از کاربرد های یادگیری بدون نظارت میتوان به موارد زیر اشاره کرد:
• الگوریتم PCA یا Principle Component Analysis که برای کاهش ابعاد به کار میرود.
• روش K-means Clustering که برای دستهبندی دادهها با توجه به معیارهای مشخص استفاده میشود.
• از خودرمز نگارها یا Autorncoder ها برای یادگیری ویژگی و به دست آوردن Representation از دادهها استفاده میشود.
• برآورد چگالی داده یا Density Estimation که از آن برای یادگیری ساختار و توزیع آماری حاکم بر دادهها استفاده میشود.
مدلهای مولد (Generative Models)
مدلهای مولد بیشتر در حوزه یادگیری بدون نظارت بررسی میشوند و در این نوع مدلها به طور کلی ما یک مجموعه داده داریم که نمونه های آموزش ما را شامل میشوند که به این صورت نشان میدهیم:
(Training data ~ P_data (x
یک سری نمونههایی داریم که به وسیله مدل تولید میشوند و آنها به این صورت نشان میدهیم:
(Generated samples ~ P_model (x
که قصد داریم مدل یاد بگیرد که (P_model (x به (P_data (x شبیه شود که در نتیجه هرچه این مسئله بهتر روی دهد، نمونههای واقعیتری تولید خواهد شد.
مدلهای مولد به طور کلی به مسئله برآورد چگالی میپردازند که در این مدلها توابع برآورد چگالی به صورت صریح یا ضمنی تعریف میشوند.
کاربردهای مدل های مولد
• تولید نمونههای واقعی برای کارهای هنری، بهبود شدید وضوح تصاویر(Super Resolution) و رنگی کردن تصاویر سیاه و سفید(Colorization) و …
• تولید نمونه برای استفاده در یادگیری تقویتی(Reinforcement Learning) یا به منظور جبران تعداد کم نمونهها در زمانی که اندازه مجموعه داده کوچک است.
• به دست آوردن یک بردار ویژگی به منظور استفاده به عنوان یک ویژگی عمومی از دادهها
دستهبندی مدلهای مولد
برآورد درستنمایی بیشینه:
به طور کلی همه مدلهای مولد بر اساس برآورد درستنمایی بیشینه یا Maximum Likelihood Estimation کار میکنند. در علم آمار برآورد حداکثر درستنمایی یا MLE روشی است برای برآورد کردن پارامترهای یک مدل آماری. وقتی بر مجموعهای از دادهها عملیاتی انجام میشود یک مدل آماری به دست میآید آنگاه حداکثر درستنمایی میتواند تخمینی از پارامترهای مدل ارائه دهد. روش حداکثر درستنمایی به بسیاری از روشهای شناخته شده تخمین آماری شباهت دارد. فرض کنید برای شخصی اطلاعات مربوط به قد زرافههای ماده بالغ موجود در یک جمعیت مهم باشد و این شخص به خاطر محدودیت هزینه یا زمان نتواند قد تک تک این زرافهها را اندازه بگیرد، این شخص تنها میداند که این طول قدها از توزیع نرمال پیروی میکنند ولی میانگین و واریانس توزیع را نمیداند حال با استفاده از روش درستنمایی بیشینه و با در دست داشتن اطلاعات مربوط به نمونهای محدود از جمعیت میتواند تخمینی از میانگین و واریانس این توزیع بدست آورد. برآورد درست نمایی بیشینه این کار را به این ترتیب انجام میدهد که واریانس و میانگین را مجهول در نظر میگیرد آنگاه مقادیری را به آنها نسبت میدهد که با توجه به اطلاعات موجود محتملترین حالت باشد. در حالت کلی روش MLE در مورد یک مجموعه مشخص از دادهها عبارت است از نسبت دادن مقادیری به پارامترهای مدل که در نتیجه آن توزیعی تولید شود که بیشترین احتمال را به دادههای مشاهده شده نسبت دهد (یعنی مقادیری از پارامتر که تابع درستنمایی را حداکثر کند). MLE یک ساز و کار مشخص را برای تخمین ارائه میدهد که در مورد توزیع نرمال و بسیاری توزیعهای دیگر بهطور خوش تعریف عمل میکند. با این حال در بعضی موارد مشکلاتی پیش میآید از قبیل اینکه برآوردگرهای حداکثر درستنمایی نامناسب اند یا اصلاً وجود ندارند.
مدلهای مولد بر اساس برآورد چگالی کار میکنند و در این مدلها بر اساس اینکه تابع برآورد چگالیشان به چه صورت تعریف میشوند به دو نوع تقسیم میشوند. برخی از این مدلها تابع برآورد چگالی آنها به صورت صریح تعریف میشود. مانند VAEs ، PixelRNN ، PixelCNN و …
همینطور مدلهایی مانند(Generative Adversarial Networks(GANs از جمله مدلهایی به شمار میروند که تابع برآورد چگالی آنها به صورت صریح تعریف نمیشود بلکه به صورت ضمنی تعریف میشود.
مدل های PixelRNN و PixelCNN
این نوع از مدلهای مولد تابع برآورد چگالیشان به صورت صریح و به شکل زیر تعریف میشوند:
این تابع احتمال i امین پیکسل بر اساس اینکه احتمال پیکسلهای تولید شده قبلی داده شده باشند، محاسبه می کند. نحوه تولید در این مدلها سطر به سطر و پیکسل به پیکسل میباشد و این اتفاق برای هر سه کانال رنگی میتواند بیافتد.
این مدلها بر اساس روشهای آمار و احتمالی مانند احتمال شرطی و در نظر گرفتن توزیعهای نرمال یا گاوسی به عنوان مدلهای احتمالاتی تعداد کل پیکسلهای یک عکس را به صورت حاصل ضرب توزیعهای شرطی مختلف بیان میکنند.
چون در این مدلها پیکسلها به طور طولانی به هم وابستگی دارند و از طرفی شبکههای بازگشتی هم در این موضوع خوب عمل میکنند، از این شبکه ها استفاده میشود. از مزایای این مدلها میتوان به تولید نمونههای قابل قبول اشاره کرد ولی از معایب این مدلها این است که چون تولید در مدل به صورت ترتیبی میباشد، مدت زمان زیادی میبرد تا نمونه تولید کنند. در مدل PixelCNN هم تابع برآورد چگالی به همین گونه است ولی به جای شبکههای بازگشتی از شبکههای کانولوشنی استفاده میشود و در جزییات کمی متفاوت است که در اینجا بیشتر بحث نمیشود.
شبکههای مولد تخاصمی (Generative Adversarial Networks)
این شبکهها در سال 2014 توسط یان گودفلو ارائه شد و الان جزء تکنیک های state-of-the-art در انواع مدل های تولیدکننده به شمار میروند و پیشرفت ها و نتایج چشمگیری داشته اند.
هدف ما این است که از یک توزیع پیچیده و با ابعاد بالا که مربوط نمونههای آموزش ما است نمونه تولید کنیم و برای این کار راه مستقیمی وجود ندارد. به جای آن از یک توزیع ساده مانند نویز تصادفی شروع میکنیم و تبدیلاتی را یاد میگیریم که آن توزیع ساده را به توزیع مورد نظر ما تبدیل کند. اما چطور؟! معمولا برای یاد گرفتن تبدیلات یا توابع پیچیده از شبکه عصبی استفاده میکنیم و در اینجا هم از این روش استفاده میکنیم.
در این مدل، دو بازیکن داریم که یکی از آنها شبکه تمییزدهنده(Discriminator) و دیگری شبکه تولیدکننده(Generator) هست که مانند کاراگاه و جاعل عمل میکنند. به این گونه که Generator سعی میکند نمونههای واقعیتر تولید کند و Discriminator تلاش میکند نمونههای واقعی را از نمونههای تولیدشده توسط Generator تشخیص دهد و با رقابت این دو شبکه، مدل ما آموزش میبیند.
در واقع رقابت این دو شبکه مانند یک بازی minimax است که سود هر بازیکن در ضرر بازیکن مقابل است و تابع objective در این مدلها به صورت زیر تعریف میشود:
عبارت اول برای زمانی است که نمونه از توزیع دادههای آموزش است و در اینجا فقط Discriminator نقش دارد و با تاثیر 1 قرار دادن این عبارت(چون از مجموعه آموزش آمده)تلاش میکند این تابع را ماکزیمم کند و در واقع اینکه نمونه از نمونههای آموزش باشد، بهترین سناریو برای Discriminator است و در عبارت دوم Discriminator برای ماکزیمم کردن تابع objective برای خودش، سعی میکند برای عبارت دوم تاثیر 0 قائل شود چون از توزیع دادههای تولید شده توسط Generator است. به این صورت که ورودی یک بردار نویز به Generator داده میشود و این شبکه نمونه را تولید میکند و خروجی Generator به شبکه Discriminator داده میشود.
شبکه Generator سعی بر این دارد که این تابع objective را مینیمایز کند به این صورت که تلاش میکند برای عبارت دوم که خروجی خودش را به Discriminator میدهد تاثیر 1 قائل شود(انگار به نحوی Discriminator را گول میزند که نمونهای که تولید کرده از نمونههای واقعی است). همچینین واضح است که شبکه Generator فقط در این عبارت تابع objective نقش دارد.
نحوه آموزش شبکههای مولد تخاصمی (GANs Training)
در آموزش این مدلها، وزنهای هر دو شبکه به صورت تصادفی مقداردهی اولیه میشوند و هر دو شبکه در رقابت با هم آموزش میبینند. در ابتدا یک بچ(batch) از نمونههای مجموعه آموزش و یک بچ هم از خروجی شبکه Generator گرفته میشود و به وسیله آن، وزنهای شبکه Discriminator به روز میشوند. بعد از آن وزن های شبکه Discriminator قفل میشوند و این دفعه یک بچ از خروجی Generator گرفته میشود و به Discriminator داده میشود و Discriminator با پس انتشار گرادیانها وزنهای شبکه Generator را به روز میکند و این روند ادامه پیدا میکند.
این که تا کجا ادامه پیدا میکند یا چطور و بعد از چند قدم شبکه Generator همگرا میشود و … از موضوعات قابل بحث است و جای بررسی و تحقیق دارد.
معماری کانولوشنی در GAN ها
(Deep Convolutional Generative Adversarial Networks(DCGAN
شبکه مولد(Generator)
در این شبکه برخلاف شبکه های کانولوشنی عمیق در انتها از لایه های تمام متصل(Fully-connected) استفاده نمیشود و فقط در ابتدا یک بردار مثلا 100 تایی نویز وجود دارد که بعد از وصل شدن به یک لایه FC و reshape شدن از لایههای کانولوشن ترنسپوز استفاده میشود تا به سایز عکسی که میخواهیم تولید کنیم برسیم(که در واقع سایز ورودی شبکه Discriminator هم هست). در این شبکه معمولا از لایه pooling استفاده نمیشود. همینطور در این شبکه معمولا از لایه batch normalization استفاده میشود و در همه لایه ها تابع فعالساز relu یا leaky relu مورد استفاده قرار میگیرد به جز لایه آخر که tanh میباشد. تابع leakly relu برخلاف relu در مقادیر منفی، مقدار دارد که مقدار آن وابسته به پارامتر آن است. در ادامه کدهایی از پیادهسازی این معماری در فریمورک کراس(Keras) را میبینیم.
پیاده سازی Generator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
def generator(img_shape, z_dim): model = Sequential() # Reshape input into 7x7x256 tensor via a fully connected layer model.add(Dense(256 * 7 * 7, input_dim=z_dim)) model.add(Reshape((7, 7, 256))) # Transposed convolution layer, from 7x7x256 into 14x14x128 tensor model.add(Conv2DTranspose( 128, kernel_size=3, strides=2, padding='same')) # Batch normalization model.add(BatchNormalization()) # Leaky ReLU model.add(LeakyReLU(alpha=0.01)) # Transposed convolution layer, from 14x14x128 to 14x14x64 tensor model.add(Conv2DTranspose( 64, kernel_size=3, strides=1, padding='same')) # Batch normalization model.add(BatchNormalization()) # Leaky ReLU model.add(LeakyReLU(alpha=0.01)) # Transposed convolution layer, from 14x14x64 to 28x28x1 tensor model.add(Conv2DTranspose( 1, kernel_size=3, strides=2, padding='same')) # Tanh activation model.add(Activation('tanh')) z = Input(shape=(z_dim,)) img = model(z) return Model(z, img) |
شبکه تمییز دهنده(Discriminator)
این شبکه به عنوان ورودی یک عکس میگیرد و از لایههای کانولوشنی با stride استفاده میکند. در این شبکهها هم معمولا از pooling استفاده نمیشود و همینطور لایه batch normalization مورد استفاده قرار میگیرد. همچنین در لایه آخر این شبکه یک نورون با تابع activation، سیگموید وجود دارد که برای تشخیص real یا fake بودن تصویر ورودی است.
پیاده سازی Discriminator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
def discriminator(img_shape): model = Sequential() # Convolutional layer, from 28x28x1 into 14x14x32 tensor model.add(Conv2D(32, kernel_size=3, strides=2, input_shape=img_shape, padding='same')) # Leaky ReLU model.add(LeakyReLU(alpha=0.01)) # Convolutional layer, from 14x14x32 into 7x7x64 tensor model.add(Conv2D(64, kernel_size=3, strides=2, input_shape=img_shape, padding='same')) # Batch normalization model.add(BatchNormalization()) # Leaky ReLU model.add(LeakyReLU(alpha=0.01)) # Convolutional layer, from 7x7x64 tensor into 3x3x128 tensor model.add(Conv2D(128, kernel_size=3, strides=2, input_shape=img_shape, padding='same')) # Batch normalization model.add(BatchNormalization()) # Leaky ReLU model.add(LeakyReLU(alpha=0.01)) # Flatten the tensor and apply sigmoid activation function model.add(Flatten()) model.add(Dense(1, activation='sigmoid')) img = Input(shape=img_shape) prediction = model(img) return Model(img, prediction) |
ساخت مدل GAN
در اینجا همانطور که میبینید بعد مشخص کردن نوع تابع خطا و بهینهساز، مدل GAN ساخته میشود که این مدل به عنوان ورودی بردار 100تایی میگیرد و خروجی آن همان خروجی Discriminator است که مشخص میکند عکس ورودی از دیتاهای آموزش است یا به وسیله Generator تولید شده است.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# Build and compile the Discriminator discriminator = discriminator(img_shape) discriminator.compile(loss='binary_crossentropy', optimizer=Adam(), metrics=['accuracy']) # Build the Generator generator = generator(img_shape, z_dim) # Generated image to be used as input z = Input(shape=(100,)) img = generator(z) # Keep Discriminator’s parameters constant during Generator training discriminator.trainable = False # The Discriminator’s prediction prediction = discriminator(img) # Combined GAN model to train the Generator combined = Model(z, prediction) combined.compile(loss='binary_crossentropy', optimizer=Adam()) |
حلقه آموزش GAN
طبق موادی که پیشتر در نحوه آموزش این گونه شبکهها توضیح داده شد، هر دو شبکه Generator و Discriminator با هم آموزش میبینند.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
losses = [] accuracies = [] def train(iterations, batch_size, sample_interval): # Load the HODA dataset X_train = hoda_dataset() # Rescale -1 to 1 X_train = X_train / 127.5 - 1. X_train = np.expand_dims(X_train, axis=3) # Labels for real and fake examples real = np.ones((batch_size, 1)) fake = np.zeros((batch_size, 1)) for iteration in range(iterations): # ------------------------- # Train the Discriminator # ------------------------- # Select a random batch of real images idx = np.random.randint(0, X_train.shape[0], batch_size) imgs = X_train[idx] # Generate a batch of fake images z = np.random.normal(0, 1, (batch_size, 100)) gen_imgs = generator.predict(z) # Discriminator loss d_loss_real = discriminator.train_on_batch(imgs, real) d_loss_fake = discriminator.train_on_batch(gen_imgs, fake) d_loss = 0.5 * np.add(d_loss_real, d_loss_fake) # --------------------- # Train the Generator # --------------------- # Generate a batch of fake images z = np.random.normal(0, 1, (batch_size, 100)) gen_imgs = generator.predict(z) # Generator loss g_loss = combined.train_on_batch(z, real) if iteration % sample_interval == 0: # Output training progress print ("%d [D loss: %f, acc.: %.2f%%] [G loss: %f]" % (iteration, d_loss[0], 100*d_loss[1], g_loss)) # Save losses and accuracies so they can be plotted after training losses.append((d_loss[0], g_loss)) accuracies.append(100*d_loss[1]) # Output generated image samples sample_images(iteration) |
منابع
برآورد درستنمایی بیشینه – ویکی پدیا فارسی
کورس CS231n دانشگاه استنفورد – مدلهای مولد
شبکه های اجتماعی