โมเดลการฝึกอบรม

คู่มือนี้ถือว่าคุณได้อ่านคำแนะนำ เกี่ยวกับโมเดลและเลเยอร์ แล้ว

ใน TensorFlow.js มีสองวิธีในการฝึกโมเดลแมชชีนเลิร์นนิง:

  1. ใช้ Layers API กับ LayersModel.fit() หรือ LayersModel.fitDataset()
  2. ใช้ Core API กับ Optimizer.minimize()

อันดับแรก เราจะดูที่ Layers API ซึ่งเป็น API ระดับที่สูงกว่าสำหรับการสร้างและการฝึกอบรมโมเดล จากนั้น เราจะแสดงวิธีฝึกโมเดลเดียวกันโดยใช้ Core API

การแนะนำ

โมเดล การเรียนรู้ของเครื่องคือฟังก์ชันที่มีพารามิเตอร์ที่สามารถเรียนรู้ได้ซึ่งจับคู่อินพุตกับเอาต์พุตที่ต้องการ พารามิเตอร์ที่เหมาะสมที่สุดได้มาจากการฝึกฝนโมเดลเกี่ยวกับข้อมูล

การฝึกอบรมประกอบด้วยหลายขั้นตอน:

  • รับ ชุด ข้อมูลไปยังโมเดล
  • การขอให้แบบจำลองทำนาย
  • การเปรียบเทียบคำทำนายนั้นกับค่า "จริง"
  • การตัดสินใจว่าจะเปลี่ยนแปลงแต่ละพารามิเตอร์มากน้อยเพียงใด เพื่อให้แบบจำลองสามารถคาดการณ์ได้ดีขึ้นในอนาคตสำหรับชุดงานนั้น

โมเดลที่ได้รับการฝึกอบรมมาอย่างดีจะให้การแมปที่แม่นยำตั้งแต่อินพุตไปยังเอาต์พุตที่ต้องการ

พารามิเตอร์โมเดล

มากำหนดโมเดล 2 เลเยอร์อย่างง่ายโดยใช้ Layers API:

const model = tf.sequential({
 layers: [
   tf.layers.dense({inputShape: [784], units: 32, activation: 'relu'}),
   tf.layers.dense({units: 10, activation: 'softmax'}),
 ]
});

ภายใต้ประทุน โมเดลมีพารามิเตอร์ (มักเรียกว่า Weights ) ที่สามารถเรียนรู้ได้จากการฝึกข้อมูล มาพิมพ์ชื่อของตุ้มน้ำหนักที่เกี่ยวข้องกับแบบจำลองนี้และรูปร่าง:

model.weights.forEach(w => {
 console.log(w.name, w.shape);
});

เราได้รับผลลัพธ์ดังต่อไปนี้:

> dense_Dense1/kernel [784, 32]
> dense_Dense1/bias [32]
> dense_Dense2/kernel [32, 10]
> dense_Dense2/bias [10]

มีทั้งหมด 4 ตุ้มน้ำหนัก 2 ตุ้มน้ำหนักต่อชั้นหนาแน่น สิ่งนี้คาดหวังได้เนื่องจากชั้นที่หนาแน่นเป็นตัวแทนของฟังก์ชันที่แมปเทนเซอร์อินพุต x กับเทนเซอร์เอาท์พุต y ผ่านสมการ y = Ax + b โดยที่ A (เคอร์เนล) และ b (อคติ) เป็นพารามิเตอร์ของชั้นหนาแน่น

หมายเหตุ: ตามค่าเริ่มต้น เลเยอร์หนาแน่นจะรวมอคติด้วย แต่คุณสามารถยกเว้นได้โดยการระบุ {useBias: false} ในตัวเลือกเมื่อสร้างเลเยอร์หนาแน่น

model.summary() เป็นวิธีการที่มีประโยชน์หากคุณต้องการดูภาพรวมของโมเดลของคุณและดูจำนวนพารามิเตอร์ทั้งหมด:

ชั้น (ชนิด) รูปร่างเอาท์พุต พารามิเตอร์ #
หนาแน่น_Dense1 (หนาแน่น) [ว่าง,32] 25120
หนาแน่น_Dense2 (หนาแน่น) [null,10] 330
พารามิเตอร์ทั้งหมด: 25450
พารามิเตอร์ที่ฝึกได้: 25450
พารามิเตอร์ที่ไม่สามารถฝึกได้: 0

น้ำหนักแต่ละรายการในโมเดลจะได้รับแบ็กเอนด์โดย Variable ตัวแปร ใน TensorFlow.js Variable คือ Tensor จุดลอยตัวที่มีเมธอดเพิ่มเติม 1 รายการ assign() ที่ใช้สำหรับการอัปเดตค่าของมัน Layers API จะเริ่มต้นน้ำหนักโดยอัตโนมัติโดยใช้แนวทางปฏิบัติที่ดีที่สุด เพื่อประโยชน์ในการสาธิต เราสามารถเขียนทับน้ำหนักโดยการเรียก assign() บนตัวแปรพื้นฐาน:

model.weights.forEach(w => {
  const newVals = tf.randomNormal(w.shape);
  // w.val is an instance of tf.Variable
  w.val.assign(newVals);
});

เครื่องมือเพิ่มประสิทธิภาพ การสูญเสีย และการวัด

ก่อนที่คุณจะทำการฝึกอบรม คุณต้องตัดสินใจสามสิ่ง:

  1. เครื่องมือเพิ่มประสิทธิภาพ งานของเครื่องมือเพิ่มประสิทธิภาพคือการตัดสินใจว่าจะเปลี่ยนแปลงแต่ละพารามิเตอร์ในแบบจำลองมากน้อยเพียงใด โดยพิจารณาจากการคาดการณ์ของแบบจำลองปัจจุบัน เมื่อใช้ Layers API คุณสามารถระบุตัวระบุสตริงของเครื่องมือเพิ่มประสิทธิภาพที่มีอยู่ (เช่น 'sgd' หรือ 'adam' ) หรืออินสแตนซ์ของคลาส Optimizer ได้
  2. ฟังก์ชันการสูญเสีย วัตถุประสงค์ที่โมเดลจะพยายามย่อให้เล็กสุด เป้าหมายคือการให้ตัวเลขเพียงตัวเดียวสำหรับการคาดการณ์ของแบบจำลองว่า "ผิดแค่ไหน" การสูญเสียจะถูกคำนวณจากข้อมูลทุกชุดเพื่อให้แบบจำลองสามารถอัปเดตน้ำหนักได้ เมื่อใช้ Layers API คุณสามารถระบุตัวระบุสตริงของฟังก์ชันการสูญเสียที่มีอยู่ (เช่น 'categoricalCrossentropy' ) หรือฟังก์ชันใดๆ ที่รับค่าที่คาดการณ์และเป็นค่าจริงและส่งกลับค่าที่สูญเสียไป ดู รายการการสูญเสียที่มีอยู่ ในเอกสาร API ของเรา
  3. รายการเมตริก เช่นเดียวกับการสูญเสีย หน่วยเมตริกจะคำนวณตัวเลขตัวเดียว โดยสรุปว่าแบบจำลองของเราทำงานได้ดีเพียงใด โดยทั่วไปการวัดจะคำนวณจากข้อมูลทั้งหมดในตอนท้ายของแต่ละยุค อย่างน้อยที่สุด เราต้องการติดตามดูว่าการสูญเสียของเราลดลงเมื่อเวลาผ่านไป อย่างไรก็ตาม เรามักต้องการเมตริกที่เป็นมิตรต่อมนุษย์มากขึ้น เช่น ความแม่นยำ เมื่อใช้ Layers API คุณสามารถระบุตัวระบุสตริงของเมตริกที่มีอยู่ (เช่น 'accuracy' ) หรือฟังก์ชันใดๆ ที่รับค่าที่คาดการณ์และเป็นค่าจริงและส่งกลับคะแนน ดู รายการตัววัดที่มีอยู่ ในเอกสาร API ของเรา

เมื่อคุณตัดสินใจแล้ว ให้คอมไพล์ LayersModel โดยการเรียก model.compile() พร้อมด้วยตัวเลือกที่มีให้:

model.compile({
  optimizer: 'sgd',
  loss: 'categoricalCrossentropy',
  metrics: ['accuracy']
});

ในระหว่างการรวบรวม โมเดลจะทำการตรวจสอบเพื่อให้แน่ใจว่าตัวเลือกที่คุณเลือกเข้ากันได้

การฝึกอบรม

มีสองวิธีในการฝึก LayersModel :

  • การใช้ model.fit() และให้ข้อมูลเป็นเทนเซอร์ขนาดใหญ่ตัวเดียว
  • การใช้ model.fitDataset() และการให้ข้อมูลผ่านวัตถุ Dataset

รุ่น.พอดี()

หากชุดข้อมูลของคุณพอดีกับหน่วยความจำหลัก และพร้อมใช้งานเป็นเทนเซอร์ตัวเดียว คุณสามารถฝึกโมเดลได้โดยการเรียกเมธอด fit() ดังนี้

// Generate dummy data.
const data = tf.randomNormal([100, 784]);
const labels = tf.randomUniform([100, 10]);

function onBatchEnd(batch, logs) {
  console.log('Accuracy', logs.acc);
}

// Train for 5 epochs with batch size of 32.
model.fit(data, labels, {
   epochs: 5,
   batchSize: 32,
   callbacks: {onBatchEnd}
 }).then(info => {
   console.log('Final accuracy', info.history.acc);
 });

ภายใต้ประทุน model.fit() สามารถทำอะไรให้เราได้มากมาย:

  • แยกข้อมูลออกเป็นชุดรถไฟและชุดตรวจสอบ และใช้ชุดตรวจสอบเพื่อวัดความคืบหน้าระหว่างการฝึกอบรม
  • สับเปลี่ยนข้อมูลแต่หลังจากแยกแล้วเท่านั้น เพื่อความปลอดภัย คุณควรสับเปลี่ยนข้อมูลล่วงหน้าก่อนที่จะส่งต่อให้ fit()
  • แยกเทนเซอร์ข้อมูลขนาดใหญ่ออกเป็นเทนเซอร์ขนาดเล็กที่มีขนาด batchSize.
  • เรียก optimizer.minimize() ขณะคำนวณการสูญเสียของโมเดลโดยสัมพันธ์กับชุดข้อมูล
  • สามารถแจ้งให้คุณทราบเมื่อเริ่มต้นและสิ้นสุดแต่ละยุคหรือแบทช์ ในกรณีของเรา เราได้รับแจ้งเมื่อสิ้นสุดทุกชุดโดยใช้ตัวเลือก callbacks.onBatchEnd ตัวเลือกอื่นๆ ได้แก่: onTrainBegin , onTrainEnd , onEpochBegin , onEpochEnd และ onBatchBegin
  • ส่งผลให้เธรดหลักเพื่อให้แน่ใจว่างานที่อยู่ในคิวในลูปเหตุการณ์ JS สามารถจัดการได้ทันเวลา

สำหรับข้อมูลเพิ่มเติม โปรดดู เอกสารประกอบ ของ fit() โปรดทราบว่าหากคุณเลือกใช้ Core API คุณจะต้องนำตรรกะนี้ไปใช้ด้วยตนเอง

รุ่น.fitDataset()

หากข้อมูลของคุณไม่พอดีกับหน่วยความจำทั้งหมดหรือกำลังสตรีมอยู่ คุณสามารถฝึกโมเดลได้โดยการเรียก fitDataset() ซึ่งรับออบเจ็กต์ Dataset นี่คือโค้ดการฝึกอบรมเดียวกัน แต่มีชุดข้อมูลที่ล้อมรอบฟังก์ชันตัวสร้าง:

function* data() {
 for (let i = 0; i < 100; i++) {
   // Generate one sample at a time.
   yield tf.randomNormal([784]);
 }
}

function* labels() {
 for (let i = 0; i < 100; i++) {
   // Generate one sample at a time.
   yield tf.randomUniform([10]);
 }
}

const xs = tf.data.generator(data);
const ys = tf.data.generator(labels);
// We zip the data and labels together, shuffle and batch 32 samples at a time.
const ds = tf.data.zip({xs, ys}).shuffle(100 /* bufferSize */).batch(32);

// Train the model for 5 epochs.
model.fitDataset(ds, {epochs: 5}).then(info => {
 console.log('Accuracy', info.history.acc);
});

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับชุดข้อมูล โปรดดู เอกสารประกอบ ของ model.fitDataset()

การคาดการณ์ข้อมูลใหม่

เมื่อโมเดลได้รับการฝึกอบรมแล้ว คุณสามารถเรียก model.predict() เพื่อคาดการณ์ข้อมูลที่มองไม่เห็นได้:

// Predict 3 random samples.
const prediction = model.predict(tf.randomNormal([3, 784]));
prediction.print();

คอร์ API

ก่อนหน้านี้ เราได้กล่าวไว้ว่ามีสองวิธีในการฝึกโมเดลแมชชีนเลิร์นนิงใน TensorFlow.js

หลักการทั่วไปคือพยายามใช้ Layers API ก่อน เนื่องจากมีการสร้างแบบจำลองตาม Keras API ที่นำมาใช้อย่างดี Layers API ยังนำเสนอโซลูชันที่มีอยู่ทั่วไปมากมาย เช่น การเริ่มต้นน้ำหนัก การทำให้เป็นอนุกรมของโมเดล การฝึกอบรมการตรวจสอบ ความสะดวกในการพกพา และการตรวจสอบความปลอดภัย

คุณอาจต้องการใช้ Core API ทุกครั้ง:

  • คุณต้องการความยืดหยุ่นหรือการควบคุมสูงสุด
  • และคุณไม่จำเป็นต้องทำให้เป็นอนุกรม หรือใช้ตรรกะการทำให้เป็นอนุกรมของคุณเองได้

หากต้องการข้อมูลเพิ่มเติมเกี่ยวกับ API นี้ โปรดอ่านส่วน "Core API" ในคู่มือ โมเดลและเลเยอร์

โมเดลเดียวกันกับที่เขียนไว้ข้างต้นโดยใช้ Core API มีลักษณะดังนี้:

// The weights and biases for the two dense layers.
const w1 = tf.variable(tf.randomNormal([784, 32]));
const b1 = tf.variable(tf.randomNormal([32]));
const w2 = tf.variable(tf.randomNormal([32, 10]));
const b2 = tf.variable(tf.randomNormal([10]));

function model(x) {
  return x.matMul(w1).add(b1).relu().matMul(w2).add(b2);
}

นอกจาก Layers API แล้ว Data API ยังทำงานร่วมกับ Core API ได้อย่างราบรื่น ลองใช้ชุดข้อมูลที่เรากำหนดไว้ก่อนหน้านี้ในส่วน model.fitDataset() ซึ่งทำการสับและแบทช์ให้เรา:

const xs = tf.data.generator(data);
const ys = tf.data.generator(labels);
// Zip the data and labels together, shuffle and batch 32 samples at a time.
const ds = tf.data.zip({xs, ys}).shuffle(100 /* bufferSize */).batch(32);

มาฝึกโมเดลกันเถอะ:

const optimizer = tf.train.sgd(0.1 /* learningRate */);
// Train for 5 epochs.
for (let epoch = 0; epoch < 5; epoch++) {
  await ds.forEachAsync(({xs, ys}) => {
    optimizer.minimize(() => {
      const predYs = model(xs);
      const loss = tf.losses.softmaxCrossEntropy(ys, predYs);
      loss.data().then(l => console.log('Loss', l));
      return loss;
    });
  });
  console.log('Epoch', epoch);
}

โค้ดด้านบนเป็นสูตรมาตรฐานเมื่อฝึกโมเดลด้วย Core API:

  • วนซ้ำจำนวนยุค
  • ภายในแต่ละยุค ให้วนซ้ำชุดข้อมูลของคุณ เมื่อใช้ Dataset dataset.forEachAsync() เป็นวิธีที่สะดวกในการวนซ้ำแบตช์ของคุณ
  • สำหรับแต่ละแบตช์ ให้เรียก optimizer.minimize(f) ซึ่งดำเนินการ f และลดเอาต์พุตให้เหลือน้อยที่สุดโดยการคำนวณการไล่ระดับสีตามตัวแปรสี่ตัวที่เรากำหนดไว้ก่อนหน้านี้
  • f คำนวณการสูญเสีย โดยเรียกหนึ่งในฟังก์ชันการสูญเสียที่กำหนดไว้ล่วงหน้าโดยใช้การทำนายแบบจำลองและค่าจริง