X10 উপস্থাপন করা হচ্ছে

%install '.package(url: "https://github.com/tensorflow/swift-models", .branch("tensorflow-0.12"))' Datasets ImageClassificationModels
print("\u{001B}[2J")


TensorFlow.org এ দেখুন Google Colab-এ চালান GitHub-এ উৎস দেখুন

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

X10 টেনসর লাইব্রেরি টেনসরফ্লো-এর জন্য সুইফটে একটি উচ্চ-পারফরম্যান্স ব্যাকএন্ড যোগ করে, টেনসর ট্রেসিং এবং XLA কম্পাইলার ব্যবহার করে। এই টিউটোরিয়ালটি X10 এর সাথে পরিচয় করিয়ে দেবে এবং GPUs বা TPU-তে চালানোর জন্য একটি প্রশিক্ষণ লুপ আপডেট করার প্রক্রিয়ার মাধ্যমে আপনাকে গাইড করবে।

আগ্রহী বনাম X10 টেনসর

TensorFlow-এর জন্য Swift-এ ত্বরিত গণনাগুলি Tensor প্রকারের মাধ্যমে সঞ্চালিত হয়। টেনসর বিভিন্ন ধরনের অপারেশনে অংশগ্রহণ করতে পারে এবং মেশিন লার্নিং মডেলের মৌলিক বিল্ডিং ব্লক।

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

import TensorFlow
import Foundation
let eagerTensor1 = Tensor([0.0, 1.0, 2.0])
let eagerTensor2 = Tensor([1.5, 2.5, 3.5])
let eagerTensorSum = eagerTensor1 + eagerTensor2
print(eagerTensorSum)
[1.5, 3.5, 5.5]

print(eagerTensor1.device)
Device(kind: .CPU, ordinal: 0, backend: .TF_EAGER)

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

একটি টেনসর তৈরি করার সময়, একটি বিকল্প নির্দিষ্ট করে ডিফল্ট এজার মোড ডিভাইসটি ওভাররাইড করা যেতে পারে। এইভাবে আপনি X10 ব্যাকএন্ড ব্যবহার করে গণনা সম্পাদন করতে অপ্ট-ইন করেন।

let x10Tensor1 = Tensor([0.0, 1.0, 2.0], on: Device.defaultXLA)
let x10Tensor2 = Tensor([1.5, 2.5, 3.5], on: Device.defaultXLA)
let x10TensorSum = x10Tensor1 + x10Tensor2
print(x10TensorSum)
[1.5, 3.5, 5.5]

print(x10Tensor1.device)
Device(kind: .CPU, ordinal: 0, backend: .XLA)

আপনি যদি এটি একটি GPU-সক্ষম উদাহরণে চালাচ্ছেন, তাহলে আপনার X10 টেনসরের ডিভাইসে তালিকাভুক্ত এক্সিলারেটরটি দেখতে হবে। আগ্রহী সম্পাদনের বিপরীতে, আপনি যদি এটি টিপিইউ-সক্ষম দৃষ্টান্তে চালান তবে আপনার এখন দেখতে হবে যে গণনাগুলি সেই ডিভাইসটি ব্যবহার করছে। টেনসরফ্লো-এর জন্য সুইফট-এর মধ্যে আপনি কীভাবে TPU-এর সুবিধা গ্রহণ করেন তা হল X10।

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

ডিফল্ট আগ্রহী এবং XLA ডিভাইসগুলির বাইরে, আপনি একটি ডিভাইসে নির্দিষ্ট হার্ডওয়্যার এবং ব্যাকএন্ড লক্ষ্যগুলি প্রদান করতে পারেন:

// let tpu1 = Device(kind: .TPU, ordinal: 1, backend: .XLA)
// let tpuTensor1 = Tensor([0.0, 1.0, 2.0], on: tpu1)

একটি আগ্রহী-মোড মডেল প্রশিক্ষণ

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

প্রথমে, আমরা MNIST ডেটাসেট সেট আপ এবং ডাউনলোড করব।

import Datasets

let epochCount = 5
let batchSize = 128
let dataset = MNIST(batchSize: batchSize)
Loading resource: train-images-idx3-ubyte
File does not exist locally at expected path: /home/kbuilder/.cache/swift-models/datasets/MNIST/train-images-idx3-ubyte and must be fetched
Fetching URL: https://storage.googleapis.com/cvdf-datasets/mnist/train-images-idx3-ubyte.gz...
Archive saved to: /home/kbuilder/.cache/swift-models/datasets/MNIST
Loading resource: train-labels-idx1-ubyte
File does not exist locally at expected path: /home/kbuilder/.cache/swift-models/datasets/MNIST/train-labels-idx1-ubyte and must be fetched
Fetching URL: https://storage.googleapis.com/cvdf-datasets/mnist/train-labels-idx1-ubyte.gz...
Archive saved to: /home/kbuilder/.cache/swift-models/datasets/MNIST
Loading resource: t10k-images-idx3-ubyte
File does not exist locally at expected path: /home/kbuilder/.cache/swift-models/datasets/MNIST/t10k-images-idx3-ubyte and must be fetched
Fetching URL: https://storage.googleapis.com/cvdf-datasets/mnist/t10k-images-idx3-ubyte.gz...
Archive saved to: /home/kbuilder/.cache/swift-models/datasets/MNIST
Loading resource: t10k-labels-idx1-ubyte
File does not exist locally at expected path: /home/kbuilder/.cache/swift-models/datasets/MNIST/t10k-labels-idx1-ubyte and must be fetched
Fetching URL: https://storage.googleapis.com/cvdf-datasets/mnist/t10k-labels-idx1-ubyte.gz...
Archive saved to: /home/kbuilder/.cache/swift-models/datasets/MNIST

এর পরে, আমরা মডেল এবং অপ্টিমাইজার কনফিগার করব।

import ImageClassificationModels

var eagerModel = LeNet()
var eagerOptimizer = SGD(for: eagerModel, learningRate: 0.1)

এখন, আমরা মৌলিক অগ্রগতি ট্র্যাকিং এবং রিপোর্টিং বাস্তবায়ন করব। সমস্ত মধ্যবর্তী পরিসংখ্যান একই ডিভাইসে টেনসর হিসাবে রাখা হয় যেখানে প্রশিক্ষণ চালানো হয় এবং শুধুমাত্র রিপোর্টিংয়ের সময় scalarized() বলা হয়। X10 ব্যবহার করার সময় এটি পরে বিশেষভাবে গুরুত্বপূর্ণ হবে, কারণ এটি অলস টেনসরের অপ্রয়োজনীয় বস্তুগতকরণ এড়ায়।

struct Statistics {
    var correctGuessCount = Tensor<Int32>(0, on: Device.default)
    var totalGuessCount = Tensor<Int32>(0, on: Device.default)
    var totalLoss = Tensor<Float>(0, on: Device.default)
    var batches: Int = 0
    var accuracy: Float { 
        Float(correctGuessCount.scalarized()) / Float(totalGuessCount.scalarized()) * 100 
    } 
    var averageLoss: Float { totalLoss.scalarized() / Float(batches) }

    init(on device: Device = Device.default) {
        correctGuessCount = Tensor<Int32>(0, on: device)
        totalGuessCount = Tensor<Int32>(0, on: device)
        totalLoss = Tensor<Float>(0, on: device)
    }

    mutating func update(logits: Tensor<Float>, labels: Tensor<Int32>, loss: Tensor<Float>) {
        let correct = logits.argmax(squeezingAxis: 1) .== labels
        correctGuessCount += Tensor<Int32>(correct).sum()
        totalGuessCount += Int32(labels.shape[0])
        totalLoss += loss
        batches += 1
    }
}

অবশেষে, আমরা পাঁচটি যুগের জন্য একটি প্রশিক্ষণ লুপের মাধ্যমে মডেলটি চালাব।

print("Beginning training...")

for (epoch, batches) in dataset.training.prefix(epochCount).enumerated() {
    let start = Date()
    var trainStats = Statistics()
    var testStats = Statistics()

    Context.local.learningPhase = .training
    for batch in batches {
        let (images, labels) = (batch.data, batch.label)
        let 𝛁model = TensorFlow.gradient(at: eagerModel) { eagerModel -> Tensor<Float> in
            let ŷ = eagerModel(images)
            let loss = softmaxCrossEntropy(logits: ŷ, labels: labels)
            trainStats.update(logits: ŷ, labels: labels, loss: loss)
            return loss
        }
        eagerOptimizer.update(&eagerModel, along: 𝛁model)
    }

    Context.local.learningPhase = .inference
    for batch in dataset.validation {
        let (images, labels) = (batch.data, batch.label)
        let ŷ = eagerModel(images)
        let loss = softmaxCrossEntropy(logits: ŷ, labels: labels)
        testStats.update(logits: ŷ, labels: labels, loss: loss)
    }

    print(
        """
        [Epoch \(epoch)] \
        Training Loss: \(String(format: "%.3f", trainStats.averageLoss)), \
        Training Accuracy: \(trainStats.correctGuessCount)/\(trainStats.totalGuessCount) \
        (\(String(format: "%.1f", trainStats.accuracy))%), \
        Test Loss: \(String(format: "%.3f", testStats.averageLoss)), \
        Test Accuracy: \(testStats.correctGuessCount)/\(testStats.totalGuessCount) \
        (\(String(format: "%.1f", testStats.accuracy))%) \
        seconds per epoch: \(String(format: "%.1f", Date().timeIntervalSince(start)))
        """)
}
Beginning training...
[Epoch 0] Training Loss: 0.528, Training Accuracy: 50154/59904 (83.7%), Test Loss: 0.168, Test Accuracy: 9468/10000 (94.7%) seconds per epoch: 11.9
[Epoch 1] Training Loss: 0.133, Training Accuracy: 57488/59904 (96.0%), Test Loss: 0.107, Test Accuracy: 9659/10000 (96.6%) seconds per epoch: 11.7
[Epoch 2] Training Loss: 0.092, Training Accuracy: 58193/59904 (97.1%), Test Loss: 0.069, Test Accuracy: 9782/10000 (97.8%) seconds per epoch: 11.8
[Epoch 3] Training Loss: 0.071, Training Accuracy: 58577/59904 (97.8%), Test Loss: 0.066, Test Accuracy: 9794/10000 (97.9%) seconds per epoch: 11.8
[Epoch 4] Training Loss: 0.059, Training Accuracy: 58800/59904 (98.2%), Test Loss: 0.064, Test Accuracy: 9800/10000 (98.0%) seconds per epoch: 11.8

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

একটি X10 মডেল প্রশিক্ষণ

ডেটাসেট, মডেল এবং অপ্টিমাইজারগুলিতে টেনসর থাকে যেগুলি ডিফল্ট আগ্রহী এক্সিকিউশন ডিভাইসে আরম্ভ করা হয়। X10 এর সাথে কাজ করার জন্য, আমাদের এই টেনসরগুলিকে একটি X10 ডিভাইসে সরাতে হবে।

let device = Device.defaultXLA
print(device)
Device(kind: .CPU, ordinal: 0, backend: .XLA)

ডেটাসেটের জন্য, ট্রেনিং লুপে ব্যাচগুলি প্রসেস করার সময়ে আমরা তা করব, যাতে আমরা আগ্রহী এক্সিকিউশন মডেল থেকে ডেটাসেটটি পুনরায় ব্যবহার করতে পারি।

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

var x10Model = LeNet()
x10Model.move(to: device)

var x10Optimizer = SGD(for: x10Model, learningRate: 0.1)
x10Optimizer = SGD(copying: x10Optimizer, to: device)

প্রশিক্ষণ লুপের জন্য প্রয়োজনীয় পরিবর্তনগুলি কয়েকটি নির্দিষ্ট পয়েন্টে আসে। প্রথমত, আমাদের প্রশিক্ষণ ডেটার ব্যাচগুলিকে X10 ডিভাইসে নিয়ে যেতে হবে। প্রতিটি ব্যাচ পুনরুদ্ধার করা হলে এটি Tensor(copying:to:) এর মাধ্যমে করা হয়।

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

কোডের অনুপস্থিতিতে যা স্পষ্টভাবে একটি টেনসর থেকে একটি মান অনুরোধ করে (এগুলি সাধারণত .scalars বা .scalarized() কল হিসাবে আলাদা হয়), X10 সমস্ত লুপ পুনরাবৃত্তি একসাথে কম্পাইল করার চেষ্টা করবে। এটি প্রতিরোধ করার জন্য, এবং একটি নির্দিষ্ট বিন্দুতে ট্রেস কাটাতে, আমরা একটি সুস্পষ্ট LazyTensorBarrier() স্থাপন করি যখন অপ্টিমাইজার মডেলের ওজন আপডেট করে এবং যাচাইকরণের সময় ক্ষতি এবং নির্ভুলতা প্রাপ্ত হয়। এটি দুটি পুনঃব্যবহৃত চিহ্ন তৈরি করে: প্রশিক্ষণের লুপের প্রতিটি ধাপ এবং যাচাইকরণের সময় অনুমানের প্রতিটি ব্যাচ।

এই পরিবর্তনগুলি নিম্নলিখিত প্রশিক্ষণ লুপের ফলে।

print("Beginning training...")

for (epoch, batches) in dataset.training.prefix(epochCount).enumerated() {
    let start = Date()
    var trainStats = Statistics(on: device)
    var testStats = Statistics(on: device)

    Context.local.learningPhase = .training
    for batch in batches {
        let (eagerImages, eagerLabels) = (batch.data, batch.label)
        let images = Tensor(copying: eagerImages, to: device)
        let labels = Tensor(copying: eagerLabels, to: device)
        let 𝛁model = TensorFlow.gradient(at: x10Model) { x10Model -> Tensor<Float> in
            let ŷ = x10Model(images)
            let loss = softmaxCrossEntropy(logits: ŷ, labels: labels)
            trainStats.update(logits: ŷ, labels: labels, loss: loss)
            return loss
        }
        x10Optimizer.update(&x10Model, along: 𝛁model)
        LazyTensorBarrier()
    }

    Context.local.learningPhase = .inference
    for batch in dataset.validation {
        let (eagerImages, eagerLabels) = (batch.data, batch.label)
        let images = Tensor(copying: eagerImages, to: device)
        let labels = Tensor(copying: eagerLabels, to: device)
        let ŷ = x10Model(images)
        let loss = softmaxCrossEntropy(logits: ŷ, labels: labels)
        LazyTensorBarrier()
        testStats.update(logits: ŷ, labels: labels, loss: loss)
    }

    print(
        """
        [Epoch \(epoch)] \
        Training Loss: \(String(format: "%.3f", trainStats.averageLoss)), \
        Training Accuracy: \(trainStats.correctGuessCount)/\(trainStats.totalGuessCount) \
        (\(String(format: "%.1f", trainStats.accuracy))%), \
        Test Loss: \(String(format: "%.3f", testStats.averageLoss)), \
        Test Accuracy: \(testStats.correctGuessCount)/\(testStats.totalGuessCount) \
        (\(String(format: "%.1f", testStats.accuracy))%) \
        seconds per epoch: \(String(format: "%.1f", Date().timeIntervalSince(start)))
        """)
}
Beginning training...
[Epoch 0] Training Loss: 0.421, Training Accuracy: 51888/59904 (86.6%), Test Loss: 0.134, Test Accuracy: 9557/10000 (95.6%) seconds per epoch: 18.6
[Epoch 1] Training Loss: 0.117, Training Accuracy: 57733/59904 (96.4%), Test Loss: 0.085, Test Accuracy: 9735/10000 (97.3%) seconds per epoch: 14.9
[Epoch 2] Training Loss: 0.080, Training Accuracy: 58400/59904 (97.5%), Test Loss: 0.068, Test Accuracy: 9791/10000 (97.9%) seconds per epoch: 13.1
[Epoch 3] Training Loss: 0.064, Training Accuracy: 58684/59904 (98.0%), Test Loss: 0.056, Test Accuracy: 9804/10000 (98.0%) seconds per epoch: 13.5
[Epoch 4] Training Loss: 0.053, Training Accuracy: 58909/59904 (98.3%), Test Loss: 0.063, Test Accuracy: 9779/10000 (97.8%) seconds per epoch: 13.4

X10 ব্যাকএন্ড ব্যবহার করে মডেলের প্রশিক্ষণ একই পদ্ধতিতে এগিয়ে যাওয়া উচিত ছিল যেমনটি উদগ্রীব এক্সিকিউশন মডেল আগে করেছিল। আপনি হয়ত প্রথম ব্যাচের আগে এবং প্রথম যুগের শেষে বিলম্ব লক্ষ্য করেছেন, সেই পয়েন্টগুলিতে অনন্য ট্রেসগুলির ঠিক সময়ে সংকলনের কারণে। আপনি যদি একটি অ্যাক্সিলারেটর সংযুক্ত করে এটি চালাচ্ছেন, তাহলে আপনার সেই বিন্দুর পরে প্রশিক্ষণটি আগ্রহী মোডের চেয়ে দ্রুত এগিয়ে যাওয়া উচিত ছিল।

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

যেমনটি আগে বলা হয়েছে, X10 ব্যবহার করে এখন TPUs-এর সাথে কাজ করা কেবল সম্ভব নয়, সহজ করে তোলে, আপনার সুইফ্ট ফর টেনসরফ্লো মডেলের জন্য সেই পুরো শ্রেণীর এক্সিলারেটর আনলক করে।