WHAT IS TORCH.NN REALLY?
আমরা এই টিউটোরিয়ালটি স্ক্রিপ্ট নয়, একটি নোটবুক হিসাবে চালানোর পরামর্শ দিচ্ছি। নোটবুক (.ipynb) ফাইলটি ডাউনলোড করতে, পৃষ্ঠার উপরের লিঙ্কটি ক্লিক করুন।
পাইটর্চ আপনাকে স্নায়বিক নেটওয়ার্কগুলি তৈরি এবং প্রশিক্ষণে সহায়তা করার জন্য মার্শাল ডিজাইন করা মডিউল এবং ক্লাস টর্চ.এনএন , টর্চ.অপটিম , ডেটাসেট এবং ডেটা লডার সরবরাহ করে। তাদের সমস্যার সম্পূর্ণরূপে ব্যবহার করতে এবং আপনার সমস্যার জন্য তাদের কাস্টমাইজ করার জন্য, তারা সত্যিই কী করছে তা আপনাকে সত্যই বুঝতে হবে। এই বোঝাপড়াটি বিকাশের জন্য, আমরা প্রথমে এই মডেলগুলির কোনও বৈশিষ্ট্য ব্যবহার না করে এমএনআইএসটি ডেটা সেটে বেসিক নিউরাল নেট প্রশিক্ষণ করব; আমরা প্রাথমিকভাবে কেবলমাত্র সবচেয়ে বেসিক পাইটর্চ টেন্সর কার্যকারিতা ব্যবহার করব। এর পরে, আমরা বৃদ্ধিলাভ থেকে এক বৈশিষ্ট্য যোগ করা হবে
torch.nn
, torch.optim
, Dataset
, অথবা DataLoader
একটি সময়ে, ঠিক দেখাচ্ছে প্রতিটি টুকরা করে, এবং কীভাবে কোড পারেন আরও সংক্ষিপ্ত, অথবা আরও নমনীয় করতে কাজ করে।
এই টিউটোরিয়ালটি ধরে নিয়েছে যে আপনি ইতিমধ্যে পাইটর্চ ইনস্টল করেছেন এবং টেনসর ক্রিয়াকলাপগুলির সাথে পরিচিত। (যদি আপনি নম্পি অ্যারে অপারেশনগুলির সাথে পরিচিত হন তবে আপনি পাইটর্চ টেনসর অপারেশনগুলি এখানে প্রায় অভিন্ন ব্যবহার করেছেন)।
MNIST ডেটা সেটআপ
আমরা ক্লাসিক এমএনআইএসটি ডেটাসেট ব্যবহার করব , যা হাতে আঁকা অঙ্কগুলির কালো-সাদা চিত্র ধারণ করে (0 থেকে 9 এর মধ্যে)।
আমরা পাথগুলি (পাইথন 3 স্ট্যান্ডার্ড লাইব্রেরির অংশ) মোকাবেলার জন্য ব্যবহার করব , এবং অনুরোধগুলি ব্যবহার করে ডেটাসেটটি ডাউনলোড করব । আমরা কেবলমাত্র মডিউলগুলি ব্যবহার করার সময় আমদানি করব, যাতে আপনি প্রতিটি বিন্দুতে কী ব্যবহার করা হচ্ছে তা দেখতে পাবেন।
from pathlib import Path
import requests
DATA_PATH = Path("data")
PATH = DATA_PATH / "mnist"
PATH.mkdir(parents=True, exist_ok=True)
URL = "http://deeplearning.net/data/mnist/"
FILENAME = "mnist.pkl.gz"
if not (PATH / FILENAME).exists():
content = requests.get(URL + FILENAME).content
(PATH / FILENAME).open("wb").write(content)
এই ডেটাসেটটি অসাধারণ অ্যারে ফর্ম্যাটে রয়েছে এবং আঙ্কাল ব্যবহার করে সংরক্ষণ করা হয়েছে, ডেটা সিরিয়ালাইজ করার জন্য পাইথন-নির্দিষ্ট ফর্ম্যাট।
import pickle
import gzip
with gzip.open((PATH / FILENAME).as_posix(), "rb") as f:
((x_train, y_train), (x_valid, y_valid), _) = pickle.load(f, encoding="latin-1")
প্রতিটি চিত্র 28 x 28, এবং 784 (= 28x28) দৈর্ঘ্যের সমতল সারি হিসাবে সংরক্ষণ করা হচ্ছে। আসুন একবার দেখে নেওয়া যাক; আমাদের প্রথমে এটি 2 ডি আকারে রূপান্তর করা দরকার।
from matplotlib import pyplot
import numpy as np
pyplot.imshow(x_train[0].reshape((28, 28)), cmap="gray")
print(x_train.shape)

বাইরে:
(50000, 784)
পাইটর্চ
torch.tensor
নাম্বার অ্যারেগুলির পরিবর্তে ব্যবহার করে, তাই আমাদের আমাদের ডেটা রূপান্তর করতে হবে।import torch
x_train, y_train, x_valid, y_valid = map(
torch.tensor, (x_train, y_train, x_valid, y_valid)
)
n, c = x_train.shape
x_train, x_train.shape, y_train.min(), y_train.max()
print(x_train, y_train)
print(x_train.shape)
print(y_train.min(), y_train.max())
বাইরে:
tensor([[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
...,
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.]]) tensor([5, 0, 4, ..., 8, 4, 8])
torch.Size([50000, 784])
tensor(0) tensor(9)
স্ক্র্যাচ থেকে নিউরাল নেট (কোনও টর্চ.এনএন নেই)
প্রথমে পাইটর্চ টেনসর অপারেশন ব্যতীত আর কিছুই ব্যবহার করে একটি মডেল তৈরি করি। আমরা ধরে নিচ্ছি যে আপনি নিউরাল নেটওয়ার্কের বেসিকগুলির সাথে ইতিমধ্যে পরিচিত। (If you're not, you can learn them at course.fast.ai)
পাইটর্চ এলোমেলো বা শূন্য-ভরা টেনারগুলি তৈরি করার পদ্ধতি সরবরাহ করে, যা আমরা একটি সাধারণ রৈখিক মডেলের জন্য আমাদের ওজন এবং পক্ষপাত তৈরি করতে ব্যবহার করব। এগুলি কেবল নিয়মিত টেনারগুলির মধ্যে একটি বিশেষ বিশেষ সংযোজন সহ: আমরা পাইটর্চকে বলি যে তাদের গ্রেডিয়েন্টের প্রয়োজন require এটি পাইটর্চকে টেনসারে করা সমস্ত ক্রিয়াকলাপ রেকর্ড করে তোলে, যাতে এটি স্বয়ংক্রিয়ভাবে ব্যাক-প্রসারণের সময় গ্রেডিয়েন্টটি গণনা করতে পারে !
ওজনগুলির জন্য, আমরা সূচনাকরণের
requires_grad
পরে সেট করি , যেহেতু আমরা সেই পদক্ষেপটি গ্রেডিয়েন্টের অন্তর্ভুক্ত করতে চাই না। (নোট করুন যে পাইটর্চে একটি ট্রেইলিং _
ইঙ্গিত দেয় যে অপারেশনটি স্থানে করা হয়েছে))Note that a trailling _
in PyTorch signifies that the operation is performed in-place.)
বিঃদ্রঃ
We are initializing the weights here with Xavier initialisation (by multiplying with 1/sqrt(n)). আমরা এখানে ভারী জেভিয়ার ইনিশিয়ালাইজেশন দিয়ে শুরু করছি (1 / sqrt (n) দিয়ে গুণ করে)।
import math
weights = torch.randn(784, 10) / math.sqrt(784)
weights.requires_grad_()
bias = torch.zeros(10, requires_grad=True)
পাইটর্চের স্বয়ংক্রিয়ভাবে গ্রেডিয়েন্টগুলি গণনা করার ক্ষমতাকে ধন্যবাদ, আমরা মডেল হিসাবে কোনও মানক পাইথন ফাংশন (বা কলযোগ্য বস্তু) ব্যবহার করতে পারি! সুতরাং আসুন একটি সাধারণ লিনিয়ার মডেল তৈরি করতে কেবল একটি সরল ম্যাট্রিক্স গুণ এবং সম্প্রচারিত সংযোজন লিখি। আমাদের একটি অ্যাক্টিভেশন ফাংশনও প্রয়োজন, তাই আমরা লগ_সোফটম্যাক্স লিখব এবং এটি ব্যবহার করব । মনে রাখবেন: যদিও পাইটর্চ প্রচুর প্রাক-লিখিত ক্ষতি ফাংশন, অ্যাক্টিভেশন ফাংশন এবং আরও কিছু প্রদান করে, আপনি সহজেই প্লেইন পাইথন ব্যবহার করে নিজের লেখা লিখতে পারেন। পাইটর্চ এমনকি স্বয়ংক্রিয়ভাবে আপনার ফাংশনের জন্য দ্রুত জিপিইউ বা ভেক্টরাইজড সিপিইউ কোড তৈরি করবে।
def log_softmax(x):
return x - x.exp().sum(-1).log().unsqueeze(-1)
def model(xb):
return log_softmax(xb @ weights + bias)
উপরের দিকে,
@
বিন্দু পণ্য অপারেশন জন্য দাঁড়িয়েছে। আমরা আমাদের ফাংশনটিকে এক ব্যাচের ডেটাতে কল করব (এই ক্ষেত্রে, 64 টি চিত্র)। এটি একটি ফরোয়ার্ড পাস । নোট করুন যে আমাদের ভবিষ্যদ্বাণীগুলি এ পর্যায়ে এলোমেলো চেয়ে ভাল আর কিছু হতে পারে না, যেহেতু আমরা এলোমেলো ওজন দিয়ে শুরু করি।bs = 64 # batch size
xb = x_train[0:bs] # a mini-batch from x
preds = model(xb) # predictions
preds[0], preds.shape
print(preds[0], preds.shape)
বাইরে:
tensor([-2.5125, -2.3091, -2.0139, -1.8648, -2.7132, -2.5598, -2.3423, -1.8809,
-2.5860, -2.7542], grad_fn=) torch.Size([64, 10])
যেমনটি আপনি দেখতে পাচ্ছেন,
preds
সেন্সরটিতে কেবলমাত্র সেন্সর মানগুলিই নয়, তবে একটি গ্রেডিয়েন্ট ফাংশনও রয়েছে। আমরা এটি ব্যাকপ্রপ করতে পরে ব্যবহার করব।
আসুন ক্ষতির ফাংশন হিসাবে ব্যবহার করার জন্য নেতিবাচক লগ-সম্ভাবনা বাস্তবায়ন করি (আবার আমরা কেবল স্ট্যান্ডার্ড পাইথন ব্যবহার করতে পারি):
def nll(input, target):
return -input[range(target.shape[0]), target].mean()
loss_func = nll
আসুন আমরা আমাদের এলোমেলো মডেল দিয়ে আমাদের ক্ষতি যাচাই করে দেখি, যাতে আমরা পরে কোনও ব্যাকপ্রপ পাসের পরে উন্নতি করি কিনা তা দেখতে পারি।
yb = y_train[0:bs]
print(loss_func(preds, yb))
বাইরে:
tensor(2.3860, grad_fn=)
আসুন আমাদের মডেলের যথার্থতা গণনা করার জন্য একটি ফাংশনও বাস্তবায়ন করি। প্রতিটি পূর্বাভাসের জন্য, যদি সর্বাধিক মানযুক্ত সূচকটি লক্ষ্য মানের সাথে মেলে তবে ভবিষ্যদ্বাণীটি সঠিক ছিল।
def accuracy(out, yb):
preds = torch.argmax(out, dim=1)
return (preds == yb).float().mean()
আসুন আমাদের এলোমেলো মডেলের যথার্থতা যাচাই করি, যাতে আমরা দেখতে পারি যে আমাদের ক্ষতিটি উন্নতির সাথে সাথে আমাদের নির্ভুলতা আরও উন্নত হয় কিনা।
print(accuracy(preds, yb))
বাইরে:
tensor(0.1094)
আমরা এখন একটি প্রশিক্ষণ লুপ চালাতে পারি। প্রতিটি পুনরাবৃত্তির জন্য, আমরা করব:
- একটি মিনি ব্যাচের তথ্য নির্বাচন করুন (আকারের
bs
) - ভবিষ্যদ্বাণী করতে মডেলটি ব্যবহার করুন
- ক্ষতি গণনা
loss.backward()
মডেল গ্রেডিয়েন্ট, এই ক্ষেত্রে কোনো আপডেট,weights
এবংbias
।
ওজন এবং পক্ষপাতিত্ব আপডেট করার জন্য আমরা এখন এই গ্রেডিয়েন্টগুলি ব্যবহার করি। আমরা
torch.no_grad()
প্রসঙ্গ ব্যবস্থাপকের মধ্যে এটি করি, কারণ আমরা চাই না যে এই ক্রিয়াগুলি গ্রেডিয়েন্টের পরবর্তী গণনার জন্য রেকর্ড করা হোক। পাইটর্চের অটোগ্রাড কীভাবে এখানে অপারেশন রেকর্ড করে সে সম্পর্কে আপনি আরও পড়তে পারেন ।
তারপরে আমরা গ্রেডিয়েন্টগুলি শূন্যে সেট করি, যাতে আমরা পরবর্তী লুপের জন্য প্রস্তুত। অন্যথায়, আমাদের গ্রেডিয়েন্টগুলি ঘটেছে এমন সমস্ত ক্রিয়াকলাপের চলমান ট্যালি রেকর্ড করবে (অর্থাত্ ইতিমধ্যে সঞ্চিত যা কিছু রয়েছে তার পরিবর্তে তারা গ্রেডিয়েন্টগুলি
loss.backward()
যুক্ত করে)।
ডগা
আপনি পাইটর্চ কোডের মাধ্যমে পদক্ষেপে স্ট্যান্ডার্ড পাইথন ডিবাগারটি ব্যবহার করতে পারেন, আপনাকে প্রতিটি পদক্ষেপে বিভিন্ন পরিবর্তনশীল মান পরীক্ষা করতে সহায়তা করে। Uncomment
set_trace()
নিচে এটি ব্যবহার করে দেখতে।from IPython.core.debugger import set_trace
lr = 0.5 # learning rate
epochs = 2 # how many epochs to train for
for epoch in range(epochs):
for i in range((n - 1) // bs + 1):
# set_trace()
start_i = i * bs
end_i = start_i + bs
xb = x_train[start_i:end_i]
yb = y_train[start_i:end_i]
pred = model(xb)
loss = loss_func(pred, yb)
loss.backward()
with torch.no_grad():
weights -= weights.grad * lr
bias -= bias.grad * lr
weights.grad.zero_()
bias.grad.zero_()
এটি হ'ল: পুরোপুরি স্ক্র্যাচ থেকে আমরা একটি ন্যূনতম নিউরাল নেটওয়ার্ক তৈরি করেছি এবং প্রশিক্ষণ দিয়েছি (এই ক্ষেত্রে, একটি লজিস্টিক রিগ্রেশন, যেহেতু আমাদের কোনও গোপন স্তর নেই)!
আসুন আমরা ক্ষতি এবং নির্ভুলতা যাচাই করি এবং সেগুলির তুলনা করি যা আমরা আগে পেয়েছিলাম। আমরা আশা করি যে ক্ষয়টি হ্রাস পেয়েছে এবং যথাযথতা বৃদ্ধি পেয়েছে এবং তাদের রয়েছে।
print(loss_func(model(xb), yb), accuracy(model(xb), yb))
বাইরে:
tensor(0.0831, grad_fn=) tensor(1.)
Torch.nn.functional ব্যবহার করা হচ্ছে
আমরা এখন আমাদের কোডটি রিফ্যাক্টর করব, যাতে এটি আগের মতো একই কাজ করে, কেবলমাত্র পাইটর্চের
nn
ক্লাসগুলি আরও সংক্ষিপ্ত এবং নমনীয় করে তোলার জন্য আমরা সুবিধা নেওয়া শুরু করব । এখান থেকে প্রতিটি পদক্ষেপে আমাদের কোডগুলি এক বা একাধিক: সংক্ষিপ্ত, আরও বোধগম্য এবং / অথবা আরও নমনীয় করা উচিত।
প্রথম এবং সবচেয়ে সহজ পদক্ষেপ হ'ল তাদের হাতে লেখা লিখিত অ্যাক্টিভেশন এবং ক্ষতির ক্রিয়াকলাপগুলি
torch.nn.functional
(যা সাধারণত F
কনভেনশন দ্বারা নামস্থানে আমদানি করা হয় ) এর সাথে প্রতিস্থাপন করে আমাদের কোডকে ছোট করা । এই মডিউলটিতে torch.nn
গ্রন্থাগারের সমস্ত ফাংশন রয়েছে (যেখানে গ্রন্থাগারের অন্যান্য অংশে ক্লাস রয়েছে)। ক্ষতি এবং অ্যাক্টিভেশন ফাংশনগুলির বিস্তৃত পরিসরের পাশাপাশি আপনি স্নায়ু জাল তৈরির জন্য কিছু সুবিধাজনক ফাংশন যেমন পুলিং ফাংশনগুলিও পাবেন find (কনভলিউশন, রৈখিক স্তর ইত্যাদির জন্যও রয়েছে বিভিন্ন কার্যাদি, তবে আমরা দেখতে পাবো, সাধারণত গ্রন্থাগারের অন্যান্য অংশ ব্যবহার করে এগুলি আরও ভালভাবে পরিচালনা করা হয়))
আপনি যদি নেতিবাচক লগ সম্ভাবনা হ্রাস এবং লগ সফটম্যাক্স অ্যাক্টিভেশন ব্যবহার করে থাকেন তবে পাইটোর্চ একটি একক ফাংশন সরবরাহ করে
F.cross_entropy
যা দুটি সংযুক্ত করে। সুতরাং আমরা এমনকি আমাদের মডেল থেকে অ্যাক্টিভেশন ফাংশন অপসারণ করতে পারেন।import torch.nn.functional as F
loss_func = F.cross_entropy
def model(xb):
return xb @ weights + bias
মনে রাখবেন যে, আমরা আর কল
log_softmax
মধ্যে model
ফাংশন। আসুন আমরা নিশ্চিত করি যে আমাদের ক্ষতি এবং নির্ভুলতা আগের মতো একই:print(loss_func(model(xb), yb), accuracy(model(xb), yb))
বাইরে:
tensor(0.0831, grad_fn=) tensor(1.)
রিফেক্টর nn.Module ব্যবহার করে
পরবর্তী আপ, আমরা ব্যবহার করব
nn.Module
এবং nn.Parameter
একটা পরিষ্কার এবং আরো সংক্ষিপ্ত প্রশিক্ষণ লুপ জন্য। আমরা সাবক্লাস nn.Module
(যা নিজেই একটি শ্রেণি এবং রাষ্ট্রের উপর নজর রাখতে সক্ষম)। এই ক্ষেত্রে, আমরা একটি শ্রেণি তৈরি করতে চাই যা আমাদের ওজন, পক্ষপাত এবং সামনের পদক্ষেপের জন্য পদ্ধতি রাখে। আমরা ব্যবহার করব nn.Module
এমন কয়েকটি বৈশিষ্ট্য এবং পদ্ধতি রয়েছে (যেমন .parameters()
এবং .zero_grad()
)।
বিঃদ্রঃ
nn.Module
(বড় বড় এম) একটি পাইটর্চ নির্দিষ্ট ধারণা এবং এটি একটি শ্রেণি যা আমরা প্রচুর ব্যবহার করব। nn.Module
(লোয়ারকেস m
) মডিউলটির পাইথন ধারণার সাথে বিভ্রান্ত হওয়ার দরকার নেই , এটি পাইথন কোডের একটি ফাইল যা আমদানি করা যায়।from torch import nn
class Mnist_Logistic(nn.Module):
def __init__(self):
super().__init__()
self.weights = nn.Parameter(torch.randn(784, 10) / math.sqrt(784))
self.bias = nn.Parameter(torch.zeros(10))
def forward(self, xb):
return xb @ self.weights + self.bias
যেহেতু আমরা এখন কেবল কোনও ফাংশন ব্যবহার না করে কোনও অবজেক্ট ব্যবহার করছি, তাই প্রথমে আমাদের মডেলটি ইনস্ট্যান্ট করতে হবে:
model = Mnist_Logistic()
এখন আমরা আগের মতোই লোকসানটি গণনা করতে পারি। নোট করুন যে
nn.Module
বস্তুগুলি যেমন ফাংশন হিসাবে ব্যবহৃত হয় (যেমন তারা কলযোগ্য ) তবে পর্দার পিছনে পাই্টোর্চ আমাদের forward
পদ্ধতিটিকে স্বয়ংক্রিয়ভাবে কল করবে ।print(loss_func(model(xb), yb))
বাইরে:
tensor(2.2001, grad_fn=)
পূর্বে আমাদের প্রশিক্ষণ লুপের জন্য আমাদের প্রতিটি প্যারামিটারের জন্য মান অনুসারে মানগুলি আপডেট করতে হত এবং প্রতিটি প্যারামিটারের জন্য আলাদাভাবে গ্রেডগুলি শূন্য করে আলাদাভাবে করতে হত:
with torch.no_grad():
weights -= weights.grad * lr
bias -= bias.grad * lr
weights.grad.zero_()
bias.grad.zero_()
nn.Module
আমাদের কয়েকটি পরামিতি ভুলে যাওয়ার ত্রুটির জন্য এই পদক্ষেপগুলি আরও সংক্ষিপ্ত এবং কম প্রবণ করার জন্য এখন আমরা মডেল.পরিমিতি () এবং মডেল.জারো_গ্রাড () উভয়ই পাইটর্চ দ্বারা সংজ্ঞায়িত) এর সুবিধা নিতে পারি, বিশেষত যদি আমাদের একটি ছিল আরও জটিল মডেল:with torch.no_grad():
for p in model.parameters(): p -= p.grad * lr
model.zero_grad()
আমরা আমাদের ফাংশনটিতে আমাদের ছোট প্রশিক্ষণের লুপটি আবৃত করব
fit
যাতে আমরা এটি পরে আবার চালাতে পারি।def fit():
for epoch in range(epochs):
for i in range((n - 1) // bs + 1):
start_i = i * bs
end_i = start_i + bs
xb = x_train[start_i:end_i]
yb = y_train[start_i:end_i]
pred = model(xb)
loss = loss_func(pred, yb)
loss.backward()
with torch.no_grad():
for p in model.parameters():
p -= p.grad * lr
model.zero_grad()
fit()
আসুন ডাবল পরীক্ষা করে দেখুন যে আমাদের ক্ষতি কমেছে:
print(loss_func(model(xb), yb))
বাইরে:
tensor(0.0821, grad_fn=)
রিফেক্টর এনএন.লাইনার ব্যবহার করে
আমরা আমাদের কোডটি পুনরুদ্ধার করতে থাকি। ম্যানুয়ালি সংজ্ঞা দেওয়া এবং আরম্ভ
self.weights
এবং self.bias
, এবং গণনা করার পরিবর্তে আমরা এর পরিবর্তে পাইটারক ক্লাস nn.Linear একটি লিনিয়ার স্তর জন্য ব্যবহার করব , যা আমাদের জন্য সব কিছু করে। পাইটরঞ্চে অনেক ধরণের পূর্বনির্ধারিত স্তর রয়েছে যা আমাদের কোডকে ব্যাপকভাবে সরল করতে পারে এবং প্রায়শই এটি আরও দ্রুত করে তোলে।xb @ self.weights + self.bias
class Mnist_Logistic(nn.Module):
def __init__(self):
super().__init__()
self.lin = nn.Linear(784, 10)
def forward(self, xb):
return self.lin(xb)
আমরা আমাদের মডেলটি ইনস্ট্যান্ট করি এবং লোকসানটি আগের মতোই গণনা করি:
model = Mnist_Logistic()
print(loss_func(model(xb), yb))
বাইরে:
tensor(2.3749, grad_fn=)
আমরা এখনও
fit
আগের মতো আমাদের একই পদ্ধতি ব্যবহার করতে সক্ষম ।fit()
print(loss_func(model(xb), yb))
বাইরে:
tensor(0.0817, grad_fn=)
রিফ্যাক্টর অপ্টিম ব্যবহার করে
পাইটোর্কে বিভিন্ন অপ্টিমাইজেশন অ্যালগরিদম সহ একটি প্যাকেজ রয়েছে
torch.optim
,। আমরা step
প্রতিটি প্যারামিটার ম্যানুয়ালি আপডেট করার পরিবর্তে, আমাদের অপ্টিমাইজার থেকে পদ্ধতিটি একটি সামনের পদক্ষেপ নিতে পারি।
এটি আমাদের আগের ম্যানুয়ালি কোডেড অপটিমাইজেশন পদক্ষেপটি প্রতিস্থাপন করবে:
with torch.no_grad():
for p in model.parameters(): p -= p.grad * lr
model.zero_grad()
এবং পরিবর্তে কেবল ব্যবহার করুন:
opt.step()
opt.zero_grad()
(
optim.zero_grad()
গ্রেডিয়েন্টটি 0 এ পুনরায় সেট করে এবং পরবর্তী মিনিবাসের জন্য গ্রেডিয়েন্টটি গণনার আগে আমাদের এটি কল করা উচিত need)from torch import optim
আমরা আমাদের মডেল এবং অপ্টিমাইজার তৈরি করতে একটি সামান্য ফাংশন সংজ্ঞায়িত করব যাতে আমরা ভবিষ্যতে এটি পুনরায় ব্যবহার করতে পারি।
def get_model():
model = Mnist_Logistic()
return model, optim.SGD(model.parameters(), lr=lr)
model, opt = get_model()
print(loss_func(model(xb), yb))
for epoch in range(epochs):
for i in range((n - 1) // bs + 1):
start_i = i * bs
end_i = start_i + bs
xb = x_train[start_i:end_i]
yb = y_train[start_i:end_i]
pred = model(xb)
loss = loss_func(pred, yb)
loss.backward()
opt.step()
opt.zero_grad()
print(loss_func(model(xb), yb))
বাইরে:
tensor(2.2795, grad_fn=)
tensor(0.0813, grad_fn=)
ডেটাসেট ব্যবহার করে রিফ্যাক্টর
পাইটর্চের একটি বিমূর্ত ডেটাसेट ক্লাস রয়েছে। একটি ডেটাসেট এমন কোনও কিছু হতে পারে যা
__len__
ফাংশন (পাইথনের স্ট্যান্ডার্ড len
ফাংশন দ্বারা ডাকা হয় ) এবং এতে __getitem__
সূচকের উপায় হিসাবে একটি ফাংশন। এই টিউটোরিয়ালটিFacialLandmarkDataset
একটি সাবক্লাস হিসাবে একটি কাস্টম ক্লাস তৈরি করার একটি দুর্দান্ত উদাহরণ দিয়ে যায় Dataset
।
পাইটর্চের টেনসরড্যাটাসেট হ'ল একটি ডেটাসেট মোড়ানো টেনার । সূচকের দৈর্ঘ্য এবং উপায় নির্ধারণ করে এটি আমাদেরকে টেনসরের প্রথম মাত্রার সাথে পুনরাবৃত্তি, সূচক এবং স্লাইস করার একটি উপায়ও দেয়। এটি আমাদের প্রশিক্ষণের মতো একই লাইনে স্বতন্ত্র এবং নির্ভরশীল উভয় ভেরিয়েবলগুলি অ্যাক্সেস করা সহজ করবে।
from torch.utils.data import TensorDataset
উভয়
x_train
এবং y_train
একক একত্রিত হতে পারে TensorDataset
, যা পুনরাবৃত্তি এবং স্লাইস করা সহজ হবে।train_ds = TensorDataset(x_train, y_train)
পূর্বে, আমাদের আলাদাভাবে x এবং y মানের মিনিব্যাচগুলির মাধ্যমে পুনরাবৃত্তি করতে হয়েছিল:
xb = x_train[start_i:end_i]
yb = y_train[start_i:end_i]
এখন, আমরা একসাথে এই দুটি পদক্ষেপ করতে পারি:
xb,yb = train_ds[i*bs : i*bs+bs]
model, opt = get_model()
for epoch in range(epochs):
for i in range((n - 1) // bs + 1):
xb, yb = train_ds[i * bs: i * bs + bs]
pred = model(xb)
loss = loss_func(pred, yb)
loss.backward()
opt.step()
opt.zero_grad()
print(loss_func(model(xb), yb))
বাইরে:
tensor(0.0825, grad_fn=)
ডেটা লোডার ব্যবহার করে রিফ্যাক্টর
পাইটোরিচ
DataLoader
ব্যাচ পরিচালনার জন্য দায়বদ্ধ। আপনি যে DataLoader
কোনও একটি তৈরি করতে পারেন Dataset
। DataLoader
ব্যাচগুলির মাধ্যমে পুনরাবৃত্তি করা সহজ করে তোলে। ব্যবহার না করে , ডেটা লোডার আমাদের প্রতিটি মিনিবাস স্বয়ংক্রিয়ভাবে দেয়।train_ds[i*bs : i*bs+bs]
from torch.utils.data import DataLoader
train_ds = TensorDataset(x_train, y_train)
train_dl = DataLoader(train_ds, batch_size=bs)
পূর্বে, আমাদের লুপগুলি এই জাতীয় ব্যাচগুলিতে (এক্সবি, ইবি) পুনরাবৃত্তি হয়েছিল:
for i in range((n-1)//bs + 1):
xb,yb = train_ds[i*bs : i*bs+bs]
pred = model(xb)
এখন, আমাদের লুপটি অনেক ক্লিনার, যেমন (এক্সবি, ইবি) ডেটা লোডার থেকে স্বয়ংক্রিয়ভাবে লোড হয়:
for xb,yb in train_dl:
pred = model(xb)
model, opt = get_model()
for epoch in range(epochs):
for xb, yb in train_dl:
pred = model(xb)
loss = loss_func(pred, yb)
loss.backward()
opt.step()
opt.zero_grad()
print(loss_func(model(xb), yb))
বাইরে:
tensor(0.0823, grad_fn=)
Pytorch এর ধন্যবাদ
nn.Module
, nn.Parameter
, Dataset
, এবং DataLoader
, আমাদের প্রশিক্ষণ লুপ এখন নাটকীয়ভাবে ছোট এবং বুঝতে সহজ। আসুন এখন অনুশীলনে বর্ষণকারী মডেলগুলি তৈরি করতে প্রয়োজনীয় প্রাথমিক বৈশিষ্ট্যগুলি যুক্ত করার চেষ্টা করি।বৈধতা যুক্ত করুন
বিভাগ 1 এ, আমরা কেবল আমাদের প্রশিক্ষণের ডেটা ব্যবহারের জন্য একটি যুক্তিসঙ্গত প্রশিক্ষণ লুপটি পেতে চেষ্টা করছিলাম। বাস্তবে, আপনি কী পরিমাণে বেশি ফিট করছেন তা সনাক্ত করার জন্য আপনার সর্বদা একটি বৈধতা সেট থাকা উচিত ।
ব্যাচ এবং ওভারফিটের মধ্যে পারস্পরিক সম্পর্ক রোধ করতে প্রশিক্ষণের ডেটা বদলানো গুরুত্বপূর্ণ । অন্যদিকে, বৈধতা হ্রাস আমরা বৈধতা সেট পরিবর্তন বা না তা অভিন্ন হবে। যেহেতু বদলানো অতিরিক্ত সময় নেয় তাই বৈধতা ডেটা বদলে নেওয়া কোনও বোধগম্য নয়।
আমরা বৈধতা সেটের জন্য একটি ব্যাচের আকার ব্যবহার করব যা প্রশিক্ষণের জন্য দ্বিগুণ is এটি কারণ বৈধতা সেটটি ব্যাকপ্রসারণ প্রয়োজন হয় না এবং এইভাবে কম মেমরি লাগে (এটি গ্রেডিয়েন্টগুলি সঞ্চয় করার প্রয়োজন হয় না)। আমরা বৃহত্তর ব্যাচের আকার ব্যবহার করতে এবং ক্ষতির আরও দ্রুত গণনা করতে এর সুবিধা গ্রহণ করি।
train_ds = TensorDataset(x_train, y_train)
train_dl = DataLoader(train_ds, batch_size=bs, shuffle=True)
valid_ds = TensorDataset(x_valid, y_valid)
valid_dl = DataLoader(valid_ds, batch_size=bs * 2)
আমরা প্রতিটি যুগের শেষে বৈধতা হ্রাস গণনা এবং মুদ্রণ করব।
(উল্লেখ্য যে সবসময় আমরা কল
model.train()
প্রশিক্ষণ সামনে ও model.eval()
, অনুমান করার আগে কারণ এই যেমন স্তর দ্বারা ব্যবহার করা হয় nn.BatchNorm2d
এবং nn.Dropout
এই বিভিন্ন পর্যায়ক্রমে জন্য উপযুক্ত আচরণ নিশ্চিত করার।)model, opt = get_model()
for epoch in range(epochs):
model.train()
for xb, yb in train_dl:
pred = model(xb)
loss = loss_func(pred, yb)
loss.backward()
opt.step()
opt.zero_grad()
model.eval()
with torch.no_grad():
valid_loss = sum(loss_func(model(xb), yb) for xb, yb in valid_dl)
print(epoch, valid_loss / len(valid_dl))
বাইরে:
0 tensor(0.3039)
1 tensor(0.2842)
ফিট () এবং get_data () তৈরি করুন
আমরা এখন আমাদের নিজস্ব রিফ্যাক্টরিং করব। যেহেতু আমরা প্রশিক্ষণ সেট এবং বৈধতা সেট উভয়ের জন্য ক্ষতির গণনা করার জন্য একই ধরণের প্রক্রিয়াটি দ্বিগুণ করেছি, সুতরাং আসুন এটির নিজস্ব ফাংশন করুন
loss_batch
, যা একটি ব্যাচের ক্ষতির হিসাব করে।
আমরা প্রশিক্ষণের সেটটির জন্য একটি অপ্টিমাইজারটি পাস করি এবং ব্যাকপ্রপটি সম্পাদন করতে এটি ব্যবহার করি। বৈধতা সেট করার জন্য, আমরা কোনও অপ্টিমাইজার পাস করি না, সুতরাং পদ্ধতিটি ব্যাকপ্রপ সম্পাদন করে না।
def loss_batch(model, loss_func, xb, yb, opt=None):
loss = loss_func(model(xb), yb)
if opt is not None:
loss.backward()
opt.step()
opt.zero_grad()
return loss.item(), len(xb)
fit
আমাদের মডেলকে প্রশিক্ষণ দিতে এবং প্রতিটি যুগের জন্য প্রশিক্ষণ এবং বৈধতা ক্ষতির গণনা করার জন্য প্রয়োজনীয় ক্রিয়াকলাপ পরিচালনা করে।import numpy as np
def fit(epochs, model, loss_func, opt, train_dl, valid_dl):
for epoch in range(epochs):
model.train()
for xb, yb in train_dl:
loss_batch(model, loss_func, xb, yb, opt)
model.eval()
with torch.no_grad():
losses, nums = zip(
*[loss_batch(model, loss_func, xb, yb) for xb, yb in valid_dl]
)
val_loss = np.sum(np.multiply(losses, nums)) / np.sum(nums)
print(epoch, val_loss)
get_data
প্রশিক্ষণ এবং বৈধতা সেটগুলির জন্য ডেটালয়েডারগুলি প্রদান করে।def get_data(train_ds, valid_ds, bs):
return (
DataLoader(train_ds, batch_size=bs, shuffle=True),
DataLoader(valid_ds, batch_size=bs * 2),
)
এখন, আমাদের ডেটা লোডারগুলি অর্জন এবং মডেলটিকে ফিট করার পুরো প্রক্রিয়াটি 3 টি কোডের লাইনে চালানো যেতে পারে:
train_dl, valid_dl = get_data(train_ds, valid_ds, bs)
model, opt = get_model()
fit(epochs, model, loss_func, opt, train_dl, valid_dl)
বাইরে:
0 0.3368099178314209
1 0.28037907302379605
বিভিন্ন মডেলকে প্রশিক্ষণের জন্য আপনি এই বেসিক 3 লাইন কোডটি ব্যবহার করতে পারেন। আসুন দেখুন আমরা একটি কনভ্যুশনাল নিউরাল নেটওয়ার্ক (সিএনএন) প্রশিক্ষণের জন্য সেগুলি ব্যবহার করতে পারি কিনা!
সিএনএন-এ স্যুইচ করুন
আমরা এখন তিনটি কনভ্যুশনাল স্তর সহ আমাদের নিউরাল নেটওয়ার্ক তৈরি করতে যাচ্ছি। কারণ পূর্ববর্তী বিভাগের কোনও কার্যই মডেল ফর্ম সম্পর্কে কিছুই ধরে নেয় না, আমরা কোনও পরিবর্তন ছাড়াই সিএনএন প্রশিক্ষণে সেগুলি ব্যবহার করতে সক্ষম হব।
আমরা পাইওরচের পূর্বনির্ধারিত কনভ 2 ডি ক্লাসটি আমাদের কনভ্যুশনাল স্তর হিসাবে ব্যবহার করব । আমরা একটি সিএনএন সংজ্ঞায়িত 3 স্তর সহ। প্রতিটি সমঝোতা একটি RLU দ্বারা অনুসরণ করা হয়। শেষে, আমরা একটি গড় পুলিং করি। (নোটের
view
পাইটর্চের সংস্করণ এটি নোট করুন reshape
)class Mnist_CNN(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(1, 16, kernel_size=3, stride=2, padding=1)
self.conv2 = nn.Conv2d(16, 16, kernel_size=3, stride=2, padding=1)
self.conv3 = nn.Conv2d(16, 10, kernel_size=3, stride=2, padding=1)
def forward(self, xb):
xb = xb.view(-1, 1, 28, 28)
xb = F.relu(self.conv1(xb))
xb = F.relu(self.conv2(xb))
xb = F.relu(self.conv3(xb))
xb = F.avg_pool2d(xb, 4)
return xb.view(-1, xb.size(1))
lr = 0.1
গতিশীলতা স্টোকাস্টিক গ্রেডিয়েন্ট বংশোদ্ভূত একটি প্রকরণ যা পূর্ববর্তী আপডেটগুলি অ্যাকাউন্টেও গ্রহণ করে এবং সাধারণত দ্রুত প্রশিক্ষণের দিকে পরিচালিত করে।
model = Mnist_CNN()
opt = optim.SGD(model.parameters(), lr=lr, momentum=0.9)
fit(epochs, model, loss_func, opt, train_dl, valid_dl)
বাইরে:
0 0.3590330636262894
1 0.24007404916286468
nn.Sequential
torch.nn
আমাদের কোডটি সিক্যুয়েনশিয়াল করতে আমরা আরও সহজে ব্যবহারযোগ্য ক্লাস ব্যবহার করতে পারি । একটি Sequential
অবজেক্ট তার মধ্যে থাকা প্রতিটি মডিউলকে অনুক্রমিক পদ্ধতিতে চালায়। এটি আমাদের নিউরাল নেটওয়ার্ক লেখার একটি সহজ উপায়।
এর সুবিধা নিতে, আমাদের প্রদত্ত ফাংশন থেকে সহজেই একটি কাস্টম স্তর সংজ্ঞায়িত করতে সক্ষম হওয়া প্রয়োজন । উদাহরণস্বরূপ, পাইটর্চের একটি ভিউ স্তর নেই এবং আমাদের আমাদের নেটওয়ার্কের জন্য এটি তৈরি করতে হবে।
Lambda
এমন একটি স্তর তৈরি করবে যা আমরা তার সাথে নেটওয়ার্ক সংজ্ঞায়িত করার সময় ব্যবহার করতে পারি Sequential
।class Lambda(nn.Module):
def __init__(self, func):
super().__init__()
self.func = func
def forward(self, x):
return self.func(x)
def preprocess(x):
return x.view(-1, 1, 28, 28)
এর সাথে তৈরি মডেলটি
Sequential
হ'ল:model = nn.Sequential(
Lambda(preprocess),
nn.Conv2d(1, 16, kernel_size=3, stride=2, padding=1),
nn.ReLU(),
nn.Conv2d(16, 16, kernel_size=3, stride=2, padding=1),
nn.ReLU(),
nn.Conv2d(16, 10, kernel_size=3, stride=2, padding=1),
nn.ReLU(),
nn.AvgPool2d(4),
Lambda(lambda x: x.view(x.size(0), -1)),
)
opt = optim.SGD(model.parameters(), lr=lr, momentum=0.9)
fit(epochs, model, loss_func, opt, train_dl, valid_dl)
বাইরে:
0 0.340390869307518
1 0.2571977460026741
ডেটা লোডার মোড়ানো
- আমাদের সিএনএন মোটামুটি সংক্ষিপ্ত, তবে এটি কেবল এমএনআইস্টের সাথেই কাজ করে, কারণ:
- এটি ধরে নেয় যে ইনপুটটি একটি 28 * 28 দীর্ঘ ভেক্টর
- এটি ধরে নেওয়া হয় যে চূড়ান্ত সিএনএন গ্রিডের আকার 4 * 4 (যেহেতু এটি গড়
পুলিং কার্নেলের আকারটি আমরা ব্যবহার করি)
আসুন এই দুটি অনুমান থেকে মুক্তি পাবেন, সুতরাং আমাদের মডেল যে কোনও 2 ডি একক চ্যানেল চিত্রের সাথে কাজ করে। প্রথমত, আমরা প্রাথমিক ল্যাম্বদা স্তরটি সরিয়ে ফেলতে পারি তবে ডেটা প্রিপ্রোসেসিং জেনারেটরে স্থানান্তরিত করে:
def preprocess(x, y):
return x.view(-1, 1, 28, 28), y
class WrappedDataLoader:
def __init__(self, dl, func):
self.dl = dl
self.func = func
def __len__(self):
return len(self.dl)
def __iter__(self):
batches = iter(self.dl)
for b in batches:
yield (self.func(*b))
train_dl, valid_dl = get_data(train_ds, valid_ds, bs)
train_dl = WrappedDataLoader(train_dl, preprocess)
valid_dl = WrappedDataLoader(valid_dl, preprocess)
এর পরে, আমরা এর
nn.AvgPool2d
সাথে প্রতিস্থাপন করতে পারি nn.AdaptiveAvgPool2d
, যা আমাদের যে ইনপুট টেনসরটি চায় তার চেয়ে আমাদের আউটপুট টেনসর আকার নির্ধারণ করতে দেয়। ফলস্বরূপ, আমাদের মডেল যে কোনও আকারের ইনপুট নিয়ে কাজ করবে।model = nn.Sequential(
nn.Conv2d(1, 16, kernel_size=3, stride=2, padding=1),
nn.ReLU(),
nn.Conv2d(16, 16, kernel_size=3, stride=2, padding=1),
nn.ReLU(),
nn.Conv2d(16, 10, kernel_size=3, stride=2, padding=1),
nn.ReLU(),
nn.AdaptiveAvgPool2d(1),
Lambda(lambda x: x.view(x.size(0), -1)),
)
opt = optim.SGD(model.parameters(), lr=lr, momentum=0.9)
আসুন এটি ব্যবহার করে দেখুন:
fit(epochs, model, loss_func, opt, train_dl, valid_dl)
বাইরে:
0 0.44035838775634767
1 0.2957034994959831
আপনার জিপিইউ ব্যবহার করে
আপনি যদি CUDA- সক্ষম GPU- এ অ্যাক্সেস পাওয়ার মতো ভাগ্যবান হন (তবে আপনি বেশিরভাগ ক্লাউড সরবরাহকারীদের কাছ থেকে প্রায় $ 0.50 / ঘন্টা ভাড়া নিতে পারেন) আপনি নিজের কোডটি গতিতে ব্যবহার করতে পারেন। প্রথমে আপনার জিপিইউ পাইটোর্চে কাজ করছে তা পরীক্ষা করুন:
print(torch.cuda.is_available())
বাইরে:
True
এবং তারপরে একটি ডিভাইস অবজেক্ট তৈরি করুন:
dev = torch.device(
"cuda") if torch.cuda.is_available() else torch.device("cpu")
preprocess
জিপিইউতে ব্যাচগুলি সরানোর জন্য আপডেট করা যাক :def preprocess(x, y):
return x.view(-1, 1, 28, 28).to(dev), y.to(dev)
train_dl, valid_dl = get_data(train_ds, valid_ds, bs)
train_dl = WrappedDataLoader(train_dl, preprocess)
valid_dl = WrappedDataLoader(valid_dl, preprocess)
শেষ পর্যন্ত, আমরা আমাদের মডেলটি জিপিইউতে স্থানান্তর করতে পারি।
model.to(dev)
opt = optim.SGD(model.parameters(), lr=lr, momentum=0.9)
আপনার এখন এটি দ্রুত চালিত হওয়া উচিত:
fit(epochs, model, loss_func, opt, train_dl, valid_dl)
বাইরে:
0 0.2397482816696167
1 0.2180072937965393
সমাপ্তি চিন্তা
আমাদের কাছে এখন একটি সাধারণ ডেটা পাইপলাইন এবং প্রশিক্ষণ লুপ রয়েছে যা আপনি পাই্টোর্চ ব্যবহার করে বিভিন্ন ধরণের মডেল প্রশিক্ষণের জন্য ব্যবহার করতে পারেন। কোনও মডেল এখন কত সহজ প্রশিক্ষণ হতে পারে তা দেখতে, mnist_sample নমুনা নোটবুকটি একবার দেখুন।
অবশ্যই, আপনি যুক্ত করতে চান এমন অনেকগুলি বিষয় রয়েছে যেমন ডেটা বর্ধন, হাইপারপ্যারমিটার টিউনিং, নিরীক্ষণ প্রশিক্ষণ, স্থানান্তর শিখন এবং আরও অনেক কিছু। এই বৈশিষ্ট্যগুলি ফাস্টাই লাইব্রেরিতে পাওয়া যায় যা এই টিউটোরিয়ালে প্রদর্শিত একই নকশার পদ্ধতির ব্যবহার করে তৈরি করা হয়েছে, অনুশীলনকারীদের তাদের মডেলগুলি আরও এগিয়ে নিতে চাইলে একটি প্রাকৃতিক পরবর্তী পদক্ষেপ সরবরাহ করে।
আমরা এই টিউটোরিয়ালের শুরুতে প্রতিশ্রুত আমরা উদাহরণ প্রতিটি মাধ্যমে ব্যাখ্যা চাই
torch.nn
, torch.optim
, Dataset
, এবং DataLoader
। সুতরাং আসুন আমরা যা দেখেছি তার সংক্ষিপ্ত বিবরণ দাও:
- torch.nn
Module
: একটি কলযোগ্য তৈরি করে যা কোনও ফাংশনের মতো আচরণ করে, তবে এতে রাষ্ট্র (যেমন নিউরাল নেট স্তর ওজন )ও থাকতে পারে। এটি কীParameter
(গুলি) ধারণ করে এবং তাদের সমস্ত গ্রেডিয়েন্টকে শূন্য করতে পারে, ওজন আপডেটের জন্য তাদের মধ্য দিয়ে লুপ করতে পারে ইত্যাদি ItParameter
: টেনসারের একটি মোড়কModule
যা এটি বলে যে এর ওজন রয়েছে যা ব্যাকপ্রপের সময় আপডেট করার প্রয়োজন। প্রয়োজনীয়_গ্রাড বৈশিষ্ট্য সেট সহ কেবল টেনারগুলি আপডেট করা হয়functional
: একটি মডিউল (সাধারণতF
কনভেনশন দ্বারা নেমস্পেসে আমদানি করা হয় ) এতে অ্যাক্টিভেশন ফাংশন, ক্ষতির ফাংশন ইত্যাদি থাকে এবং পাশাপাশি স্তরগুলির অ-রাষ্ট্রীয় সংস্করণ যেমন কনভ্যুশনাল এবং লিনিয়ার স্তর রয়েছে।torch.optim
: যেমন অপ্টিমাইজার থাকেSGD
, যাParameter
পিছনের পদক্ষেপের সময় ওজন আপডেট করেDataset
: পাইওরচের সাথে ক্লাস সরবরাহ সহ a__len__
এবং a__getitem__
সহ অবজেক্টগুলির একটি বিমূর্ত ইন্টারফেসTensorDataset
DataLoader
: যে কোনও গ্রহণDataset
করে এবং একটি পুনরুক্তি তৈরি করে যা ডেটাগুলির ব্যাচগুলি ফিরিয়ে দেয়।
স্ক্রিপ্টের মোট চলমান সময়: (1 মিনিট 2.784 সেকেন্ড)
0 comments:
Post a Comment