คู่มือนี้ถือว่าคุณได้อ่านคำแนะนำ เกี่ยวกับโมเดลและเลเยอร์ แล้ว
ใน TensorFlow.js มีสองวิธีในการฝึกโมเดลแมชชีนเลิร์นนิง:
- ใช้ Layers API กับ
LayersModel.fit()
หรือLayersModel.fitDataset()
- ใช้ 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);
});
เครื่องมือเพิ่มประสิทธิภาพ การสูญเสีย และการวัด
ก่อนที่คุณจะทำการฝึกอบรม คุณต้องตัดสินใจสามสิ่ง:
- เครื่องมือเพิ่มประสิทธิภาพ งานของเครื่องมือเพิ่มประสิทธิภาพคือการตัดสินใจว่าจะเปลี่ยนแปลงแต่ละพารามิเตอร์ในแบบจำลองมากน้อยเพียงใด โดยพิจารณาจากการคาดการณ์ของแบบจำลองปัจจุบัน เมื่อใช้ Layers API คุณสามารถระบุตัวระบุสตริงของเครื่องมือเพิ่มประสิทธิภาพที่มีอยู่ (เช่น
'sgd'
หรือ'adam'
) หรืออินสแตนซ์ของคลาสOptimizer
ได้ - ฟังก์ชันการสูญเสีย วัตถุประสงค์ที่โมเดลจะพยายามย่อให้เล็กสุด เป้าหมายคือการให้ตัวเลขเพียงตัวเดียวสำหรับการคาดการณ์ของแบบจำลองว่า "ผิดแค่ไหน" การสูญเสียจะถูกคำนวณจากข้อมูลทุกชุดเพื่อให้แบบจำลองสามารถอัปเดตน้ำหนักได้ เมื่อใช้ Layers API คุณสามารถระบุตัวระบุสตริงของฟังก์ชันการสูญเสียที่มีอยู่ (เช่น
'categoricalCrossentropy'
) หรือฟังก์ชันใดๆ ที่รับค่าที่คาดการณ์และเป็นค่าจริงและส่งกลับค่าที่สูญเสียไป ดู รายการการสูญเสียที่มีอยู่ ในเอกสาร API ของเรา - รายการเมตริก เช่นเดียวกับการสูญเสีย หน่วยเมตริกจะคำนวณตัวเลขตัวเดียว โดยสรุปว่าแบบจำลองของเราทำงานได้ดีเพียงใด โดยทั่วไปการวัดจะคำนวณจากข้อมูลทั้งหมดในตอนท้ายของแต่ละยุค อย่างน้อยที่สุด เราต้องการติดตามดูว่าการสูญเสียของเราลดลงเมื่อเวลาผ่านไป อย่างไรก็ตาม เรามักต้องการเมตริกที่เป็นมิตรต่อมนุษย์มากขึ้น เช่น ความแม่นยำ เมื่อใช้ 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
คำนวณการสูญเสีย โดยเรียกหนึ่งในฟังก์ชันการสูญเสียที่กำหนดไว้ล่วงหน้าโดยใช้การทำนายแบบจำลองและค่าจริง