1. บทนำ
ใน Codelab นี้ คุณจะได้ฝึกโมเดลให้ทำการคาดคะเนจากข้อมูลตัวเลขที่อธิบายชุดรถยนต์
แบบฝึกหัดนี้จะสาธิตขั้นตอนที่เกิดขึ้นบ่อยในการฝึกโมเดลประเภทต่างๆ แต่จะใช้ชุดข้อมูลขนาดเล็กและโมเดลง่ายๆ (ตื้น) เป้าหมายหลักคือการช่วยให้คุณคุ้นเคยกับคำศัพท์พื้นฐาน แนวคิด และไวยากรณ์เกี่ยวกับโมเดลการฝึกด้วย TensorFlow.js ตลอดจนการเตรียมความพร้อมเพื่อการสำรวจและเรียนรู้เพิ่มเติม
เนื่องจากเรากำลังฝึกโมเดลให้คาดการณ์จำนวนต่อเนื่อง งานนี้จึงอาจเรียกว่างานการถดถอยในบางครั้ง เราจะฝึกโมเดลด้วยการแสดงตัวอย่างอินพุตหลายๆ อย่างพร้อมกับเอาต์พุตที่ถูกต้อง ซึ่งเรียกว่าการเรียนรู้แบบมีการควบคุมดูแล
สิ่งที่คุณจะสร้าง
คุณจะได้สร้างหน้าเว็บที่ใช้ TensorFlow.js เพื่อฝึกโมเดลในเบราว์เซอร์ ระบุ "แรงม้า" สำหรับรถยนต์ โมเดลนี้จะเรียนรู้การคาดการณ์ "ไมล์ต่อแกลลอน" (MPG)
ในการดำเนินการนี้ คุณจะ:
- โหลดข้อมูลและเตรียมพร้อมสำหรับการฝึก
- กำหนดสถาปัตยกรรมของโมเดล
- ฝึกโมเดลและตรวจสอบประสิทธิภาพขณะฝึก
- ประเมินโมเดลที่ฝึกโดยทำการคาดการณ์
สิ่งที่คุณจะได้เรียนรู้
- แนวทางปฏิบัติแนะนำในการเตรียมข้อมูลสำหรับแมชชีนเลิร์นนิง รวมถึงการสับเปลี่ยนและการแปลงข้อมูลให้เป็นมาตรฐาน
- ไวยากรณ์ TensorFlow.js สำหรับการสร้างโมเดลโดยใช้ tf.layers API
- วิธีตรวจสอบการฝึกทำงานในเบราว์เซอร์โดยใช้ไลบรารี tfjs-vis
สิ่งที่ต้องมี
- Chrome เวอร์ชันล่าสุด หรือเบราว์เซอร์ที่ทันสมัยอื่นๆ
- เครื่องมือแก้ไขข้อความ ซึ่งจะทำงานในเครื่องหรือบนเว็บผ่านบางอย่าง เช่น Codepen หรือ Glitch
- ความรู้เกี่ยวกับ HTML, CSS, JavaScript และเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome (หรือเครื่องมือสำหรับนักพัฒนาเว็บในเบราว์เซอร์ที่คุณต้องการ)
- ความเข้าใจในแนวคิดระดับสูงเกี่ยวกับโครงข่ายระบบประสาทเทียม หากต้องการข้อมูลเบื้องต้นหรือทบทวนความรู้ โปรดดูวิดีโอนี้โดย 3blue1brown หรือวิดีโอเกี่ยวกับการเรียนรู้เชิงลึกใน JavaScript โดย Ashi Krishnan
2. ตั้งค่า
สร้างหน้า HTML และรวม JavaScript
คัดลอกโค้ดต่อไปนี้ลงในไฟล์ HTML ชื่อ
index.html
<!DOCTYPE html>
<html>
<head>
<title>TensorFlow.js Tutorial</title>
<!-- Import TensorFlow.js -->
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@2.0.0/dist/tf.min.js"></script>
<!-- Import tfjs-vis -->
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-vis@1.0.2/dist/tfjs-vis.umd.min.js"></script>
</head>
<body>
<!-- Import the main script file -->
<script src="script.js"></script>
</body>
</html>
สร้างไฟล์ JavaScript สำหรับโค้ด
- ในโฟลเดอร์เดียวกับไฟล์ HTML ด้านบน ให้สร้างไฟล์ชื่อ script.js และวางโค้ดต่อไปนี้ลงในไฟล์
console.log('Hello TensorFlow');
ทดสอบเลย
ตอนนี้คุณได้สร้างไฟล์ HTML และ JavaScript แล้ว โปรดทดสอบ เปิดไฟล์ index.html ในเบราว์เซอร์และเปิดคอนโซล Devtools
หากทุกอย่างทำงานเป็นปกติ ควรสร้างตัวแปรร่วม 2 ตัวและพร้อมใช้งานในคอนโซลเครื่องมือสำหรับนักพัฒนาเว็บ
tf
เป็นการอ้างอิงไปยังไลบรารี TensorFlow.jstfvis
เป็นการอ้างอิงไปยังไลบรารี tfjs-vis
เปิดเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ของเบราว์เซอร์ คุณควรเห็นข้อความระบุว่า Hello TensorFlow
ในเอาต์พุตของคอนโซล ถ้าใช่ คุณก็พร้อมที่จะทำขั้นตอนต่อไปแล้ว
3. โหลด จัดรูปแบบ และแสดงข้อมูลอินพุตเป็นภาพ
ในขั้นแรก เราจะปล่อยให้เราโหลด จัดรูปแบบ และแสดงภาพข้อมูลที่ต้องการฝึกโมเดล
เราจะโหลด "รถยนต์" จากไฟล์ JSON ซึ่งเราโฮสต์ให้กับคุณ ซึ่งมีฟีเจอร์ต่างๆ มากมายเกี่ยวกับรถยนต์แต่ละคัน สำหรับบทแนะนำนี้ เราต้องการแยกข้อมูลเกี่ยวกับแรงม้าและไมล์ต่อแกลลอนเท่านั้น
เพิ่มโค้ดต่อไปนี้ลงใน
script.js
ไฟล์
/**
* Get the car data reduced to just the variables we are interested
* and cleaned of missing data.
*/
async function getData() {
const carsDataResponse = await fetch('https://storage.googleapis.com/tfjs-tutorials/carsData.json');
const carsData = await carsDataResponse.json();
const cleaned = carsData.map(car => ({
mpg: car.Miles_per_Gallon,
horsepower: car.Horsepower,
}))
.filter(car => (car.mpg != null && car.horsepower != null));
return cleaned;
}
การดำเนินการนี้จะนำรายการที่ไม่มีการกำหนดจำนวนไมล์ต่อแกลลอนหรือแรงม้าระบุไว้ออกด้วย ลองมาพล็อตข้อมูลนี้ในแผนภูมิกระจายเพื่อดูลักษณะการแสดงผลด้วย
เพิ่มโค้ดต่อไปนี้ไว้ที่ด้านล่างของ
script.js
ไฟล์
async function run() {
// Load and plot the original input data that we are going to train on.
const data = await getData();
const values = data.map(d => ({
x: d.horsepower,
y: d.mpg,
}));
tfvis.render.scatterplot(
{name: 'Horsepower v MPG'},
{values},
{
xLabel: 'Horsepower',
yLabel: 'MPG',
height: 300
}
);
// More code will be added below
}
document.addEventListener('DOMContentLoaded', run);
เมื่อรีเฟรชหน้า คุณจะเห็นแผงข้อมูลดังกล่าวทางด้านซ้ายมือของหน้าซึ่งมีแผนภูมิกระจายของข้อมูล ซึ่งควรมีหน้าตาเช่นนี้
แผงนี้เรียกว่า Visor ซึ่งให้บริการโดย tfjs-vis ซึ่งช่วยให้แสดงการแสดงภาพข้อมูลได้สะดวก
โดยทั่วไปแล้ว เมื่อทำงานกับข้อมูล เราขอแนะนำให้หาวิธีที่จะตรวจสอบข้อมูลของคุณและทำความสะอาดข้อมูลตามความจำเป็น ในกรณีนี้ เราต้องนำบางรายการออกจาก carsData
ซึ่งมีข้อมูลไม่ครบทุกช่อง การแสดงภาพข้อมูลช่วยให้เรารู้ได้ว่าข้อมูลนั้นมีโครงสร้างที่โมเดลเรียนรู้ได้หรือไม่
เราจะเห็นจากแผนภาพด้านบนว่ามีความสัมพันธ์ทางลบระหว่างแรงม้ากับ MPG เช่น เมื่อแรงม้าเพิ่มขึ้น โดยทั่วไปแล้วรถยนต์จะได้รับไมล์ต่อแกลลอนน้อยลง
วางแนวคิดเกี่ยวกับงาน
ข้อมูลที่ป้อนของเราจะมีลักษณะดังนี้
...
{
"mpg":15,
"horsepower":165,
},
{
"mpg":18,
"horsepower":150,
},
{
"mpg":16,
"horsepower":150,
},
...
เป้าหมายของเราคือการฝึกโมเดลที่ใช้ตัวเลขเดียวแรงม้า และเรียนรู้ที่จะคาดการณ์จำนวน 1 จำนวนไมล์ต่อแกลลอน โปรดทราบว่าการแมปแบบหนึ่งต่อหนึ่งจะมีความสำคัญสำหรับส่วนถัดไป
เราจะป้อนตัวอย่างเหล่านี้ ซึ่งได้แก่ แรงม้า และ MPG ไปยังโครงข่ายระบบประสาทเทียมที่จะเรียนรู้จากตัวอย่างเหล่านี้ถึงสูตร (หรือฟังก์ชัน) เพื่อคาดการณ์ MPG ตามแรงม้า การเรียนรู้จากตัวอย่างที่เรามีคำตอบที่ถูกต้องนี้เรียกว่าการเรียนรู้ภายใต้การควบคุมดูแล
4. กำหนดสถาปัตยกรรมโมเดล
ในส่วนนี้ เราจะเขียนโค้ดเพื่ออธิบายสถาปัตยกรรมโมเดล สถาปัตยกรรมโมเดลเป็นเพียงการพูดให้เข้าใจง่ายๆ ว่า "โมเดลจะเรียกใช้ฟังก์ชันใดเมื่อโมเดลกำลังทำงาน" หรืออีกทางเลือกหนึ่งคือ "โมเดลของเราจะใช้อัลกอริทึมใดในการคำนวณคำตอบ"
โมเดล ML คืออัลกอริทึมที่รับอินพุตและสร้างเอาต์พุต เมื่อใช้โครงข่ายประสาท อัลกอริทึมคือชุดของเลเยอร์เซลล์ประสาทที่มี "น้ำหนัก" (ตัวเลข) ควบคุมเอาต์พุต กระบวนการฝึกจะเรียนรู้ค่าที่เหมาะสำหรับการยกน้ำหนักเหล่านั้น
เพิ่มฟังก์ชันต่อไปนี้ลงใน
script.js
เพื่อระบุสถาปัตยกรรมโมเดล
function createModel() {
// Create a sequential model
const model = tf.sequential();
// Add a single input layer
model.add(tf.layers.dense({inputShape: [1], units: 1, useBias: true}));
// Add an output layer
model.add(tf.layers.dense({units: 1, useBias: true}));
return model;
}
นี่คือรูปแบบที่ง่ายที่สุดรูปแบบหนึ่งที่เรากำหนดได้ใน tensorflow.js เราจะอธิบายรายละเอียดทีละบรรทัด
สร้างอินสแตนซ์โมเดล
const model = tf.sequential();
การดำเนินการนี้จะสร้างอินสแตนซ์ออบเจ็กต์ tf.Model
โมเดลนี้คือ sequential
เนื่องจากอินพุตจะไหลลงสู่เอาต์พุตโดยตรง โมเดลประเภทอื่นๆ อาจมีสาขา หรือแม้กระทั่งอินพุตและเอาต์พุตหลายรายการ แต่ในหลายกรณี โมเดลของคุณจะเป็นแบบเรียงตามลำดับ นอกจากนี้ โมเดลตามลำดับยังมี API ที่ใช้งานได้ง่ายกว่า
เพิ่มเลเยอร์
model.add(tf.layers.dense({inputShape: [1], units: 1, useBias: true}));
ซึ่งจะเพิ่มเลเยอร์อินพุตลงในเครือข่ายของเรา ซึ่งจะเชื่อมต่อกับเลเยอร์ dense
ที่มีหน่วยที่ซ่อนอยู่ 1 หน่วยโดยอัตโนมัติ เลเยอร์ dense
เป็นเลเยอร์ประเภทหนึ่งที่คูณอินพุตของเลเยอร์ด้วยเมทริกซ์ (เรียกว่าน้ำหนัก) แล้วเพิ่มตัวเลข (เรียกว่า อคติ) ลงในผลลัพธ์ เนื่องจากนี่เป็นชั้นแรกของเครือข่าย เราจึงต้องกำหนด inputShape
ของเรา inputShape
คือ [1]
เนื่องจากเรามีหมายเลข 1
เป็นข้อมูล (แรงม้าของรถคันหนึ่งๆ)
units
จะกำหนดขนาดของเมทริกซ์น้ำหนักในเลเยอร์ การตั้งค่าเป็น 1 ในที่นี้หมายความว่าเรามีน้ำหนัก 1 สำหรับฟีเจอร์อินพุตแต่ละรายการของข้อมูล
model.add(tf.layers.dense({units: 1}));
โค้ดด้านบนจะสร้างเลเยอร์เอาต์พุตของเรา เราตั้งค่า units
เป็น 1
เพราะเราต้องการเอาต์พุต 1
หมายเลข
สร้างอินสแตนซ์
เพิ่มโค้ดต่อไปนี้ลงใน
run
ฟังก์ชันที่เรากำหนดไว้ก่อนหน้านี้
// Create the model
const model = createModel();
tfvis.show.modelSummary({name: 'Model Summary'}, model);
ซึ่งจะเป็นการสร้างอินสแตนซ์ของโมเดลและแสดงข้อมูลสรุปของเลเยอร์บนหน้าเว็บ
5. เตรียมข้อมูลสำหรับการฝึก
เราจำเป็นต้องแปลงข้อมูลเป็น tensor เพื่อได้รับประโยชน์ด้านประสิทธิภาพของ TensorFlow.js ที่ทำให้การฝึกโมเดลแมชชีนเลิร์นนิงทำได้จริง นอกจากนี้เราจะดำเนินการเปลี่ยนรูปแบบข้อมูลอีกหลายรูปแบบซึ่งเป็นแนวทางปฏิบัติแนะนำ อันได้แก่ การสับเปลี่ยน และ การทำให้เป็นมาตรฐาน
เพิ่มโค้ดต่อไปนี้ลงใน
script.js
ไฟล์
/**
* Convert the input data to tensors that we can use for machine
* learning. We will also do the important best practices of _shuffling_
* the data and _normalizing_ the data
* MPG on the y-axis.
*/
function convertToTensor(data) {
// Wrapping these calculations in a tidy will dispose any
// intermediate tensors.
return tf.tidy(() => {
// Step 1. Shuffle the data
tf.util.shuffle(data);
// Step 2. Convert data to Tensor
const inputs = data.map(d => d.horsepower)
const labels = data.map(d => d.mpg);
const inputTensor = tf.tensor2d(inputs, [inputs.length, 1]);
const labelTensor = tf.tensor2d(labels, [labels.length, 1]);
//Step 3. Normalize the data to the range 0 - 1 using min-max scaling
const inputMax = inputTensor.max();
const inputMin = inputTensor.min();
const labelMax = labelTensor.max();
const labelMin = labelTensor.min();
const normalizedInputs = inputTensor.sub(inputMin).div(inputMax.sub(inputMin));
const normalizedLabels = labelTensor.sub(labelMin).div(labelMax.sub(labelMin));
return {
inputs: normalizedInputs,
labels: normalizedLabels,
// Return the min/max bounds so we can use them later.
inputMax,
inputMin,
labelMax,
labelMin,
}
});
}
เรามาดูรายละเอียดของสิ่งที่เกิดขึ้นกัน
สับเปลี่ยนข้อมูล
// Step 1. Shuffle the data
tf.util.shuffle(data);
ในที่นี้เราจะสุ่มลำดับของตัวอย่างที่เราจะฟีดไปยังอัลกอริทึมการฝึก การสับเปลี่ยนมีความสำคัญเนื่องจากโดยปกติแล้ว ในระหว่างการฝึก ระบบจะแบ่งชุดข้อมูลออกเป็นเซตย่อยที่เล็กลง ซึ่งเรียกว่ากลุ่ม ซึ่งมีการฝึกโมเดลอยู่ การสุ่มช่วยให้แต่ละกลุ่มมีข้อมูลที่หลากหลายจากการกระจายข้อมูล การทำเช่นนั้นจะช่วยให้เราเข้าใจโมเดล:
- ไม่ได้เรียนรู้สิ่งต่างๆ ที่ขึ้นอยู่ลำดับการป้อนข้อมูลเพียงอย่างเดียว
- ไม่ไวต่อโครงสร้างในกลุ่มย่อย (เช่น หากรถเห็นเฉพาะรถยนต์แรงม้าสูงในช่วงครึ่งแรกของการฝึก ระบบก็อาจเรียนรู้ถึงความสัมพันธ์ที่ไม่เกี่ยวข้องกับส่วนที่เหลือของชุดข้อมูล)
แปลงเป็น Tensor
// Step 2. Convert data to Tensor
const inputs = data.map(d => d.horsepower)
const labels = data.map(d => d.mpg);
const inputTensor = tf.tensor2d(inputs, [inputs.length, 1]);
const labelTensor = tf.tensor2d(labels, [labels.length, 1]);
เราสร้างอาร์เรย์ 2 รายการ รายการหนึ่งเป็นตัวอย่างอินพุต (รายการแรงม้า) และอีกอาร์เรย์สำหรับค่าเอาต์พุตจริง (เรียกว่าป้ายกำกับในแมชชีนเลิร์นนิง)
จากนั้นเราจะแปลงข้อมูลแต่ละอาร์เรย์เป็น Tensor แบบ 2 มิติ Tensor จะมีรูปร่างเป็น [num_examples, num_features_per_example]
เรามีตัวอย่าง inputs.length
รายการและแต่ละตัวอย่างมีฟีเจอร์อินพุต 1
(แรงม้า)
ปรับข้อมูลให้เป็นมาตรฐาน
//Step 3. Normalize the data to the range 0 - 1 using min-max scaling
const inputMax = inputTensor.max();
const inputMin = inputTensor.min();
const labelMax = labelTensor.max();
const labelMin = labelTensor.min();
const normalizedInputs = inputTensor.sub(inputMin).div(inputMax.sub(inputMin));
const normalizedLabels = labelTensor.sub(labelMin).div(labelMax.sub(labelMin));
ต่อไปเราจะทำแนวทางปฏิบัติแนะนำอีกอย่างสำหรับการฝึกแมชชีนเลิร์นนิง เราทำให้ข้อมูลเป็นมาตรฐาน ในที่นี้เราจะปรับข้อมูลให้เป็นมาตรฐานในช่วงตัวเลข 0-1
โดยใช้ การปรับขนาดต่ำสุด การทำให้เป็นมาตรฐานเป็นสิ่งสำคัญเนื่องจากภายในของโมเดลแมชชีนเลิร์นนิงจำนวนมากที่คุณจะสร้างด้วย tensorflow.js จะได้รับการออกแบบมาให้ทำงานกับตัวเลขที่ไม่ใหญ่เกินไป ช่วงทั่วไปในการปรับข้อมูลให้เป็นมาตรฐานเพื่อรวม 0 to 1
หรือ -1 to 1
คุณจะฝึกโมเดลให้ประสบความสำเร็จได้มากขึ้นหากคุณเริ่มปรับข้อมูลให้เป็นปกติในระดับที่สมเหตุสมผล
ส่งคืนข้อมูลและขอบเขตการปรับให้เป็นมาตรฐาน
return {
inputs: normalizedInputs,
labels: normalizedLabels,
// Return the min/max bounds so we can use them later.
inputMax,
inputMin,
labelMax,
labelMin,
}
เราต้องการเก็บค่าที่ใช้สําหรับการทําให้เป็นมาตรฐานระหว่างการฝึก เพื่อให้เราเลิกปรับเอาต์พุตให้เป็นมาตรฐานเพื่อนําผลลัพธ์กลับมาใช้ขนาดเดิม และช่วยให้เราทําให้ข้อมูลอินพุตในอนาคตเป็นมาตรฐานในลักษณะเดียวกันได้
6. ฝึกโมเดล
เมื่อสร้างอินสแตนซ์โมเดลและข้อมูลแสดงเป็น Tensor แล้ว เรามีทุกอย่างเตรียมไว้สำหรับการเริ่มกระบวนการฝึก
คัดลอกฟังก์ชันต่อไปนี้ไปยัง
script.js
ไฟล์
async function trainModel(model, inputs, labels) {
// Prepare the model for training.
model.compile({
optimizer: tf.train.adam(),
loss: tf.losses.meanSquaredError,
metrics: ['mse'],
});
const batchSize = 32;
const epochs = 50;
return await model.fit(inputs, labels, {
batchSize,
epochs,
shuffle: true,
callbacks: tfvis.show.fitCallbacks(
{ name: 'Training Performance' },
['loss', 'mse'],
{ height: 200, callbacks: ['onEpochEnd'] }
)
});
}
มาดูรายละเอียดกัน
เตรียมพร้อมสำหรับการฝึกอบรม
// Prepare the model for training.
model.compile({
optimizer: tf.train.adam(),
loss: tf.losses.meanSquaredError,
metrics: ['mse'],
});
เราต้อง "คอมไพล์" โมเดลก่อนที่จะทำการฝึก ในการดำเนินการดังกล่าว เราต้องระบุสิ่งที่สำคัญที่สุดหลายอย่างดังนี้
optimizer
: นี่คืออัลกอริทึมที่จะควบคุมการอัปเดตโมเดลตามที่เห็นตัวอย่าง ใน TensorFlow.js มีเครื่องมือเพิ่มประสิทธิภาพมากมายที่ใช้ได้ ในส่วนนี้เราได้เลือกเครื่องมือเพิ่มประสิทธิภาพ adam เนื่องจากมีประสิทธิภาพในทางปฏิบัติค่อนข้างมีประสิทธิภาพและไม่ต้องกำหนดค่าใดๆloss
: นี่คือฟังก์ชันที่จะบอกโมเดลว่ามีประสิทธิภาพเพียงใดในการเรียนรู้กลุ่มแต่ละกลุ่ม (ชุดย่อยของข้อมูล) ที่แสดง เราจะใช้meanSquaredError
เพื่อเปรียบเทียบการคาดคะเนที่สร้างโดยโมเดลกับค่าจริง
const batchSize = 32;
const epochs = 50;
ต่อไปเราจะเลือก {1/}{1/} และจำนวน Epoch ดังต่อไปนี้
batchSize
หมายถึงขนาดของชุดข้อมูลย่อยที่โมเดลจะเห็นในการฝึกซ้ำแต่ละครั้ง ขนาดกลุ่มทั่วไปมักจะอยู่ในช่วง 32-512 เนื่องจากยังไม่มีขนาดกลุ่มที่เหมาะสมสำหรับทุกโจทย์ และอยู่นอกเหนือขอบเขตของบทแนะนำนี้ในการอธิบายแรงจูงใจทางคณิตศาสตร์สำหรับชุดปัญหาขนาดต่างๆepochs
หมายถึงจำนวนครั้งที่โมเดลจะพิจารณาชุดข้อมูลทั้งหมดที่คุณให้ไว้ ในส่วนนี้เราจะทำซ้ำ 50 ครั้งผ่านชุดข้อมูล
เริ่มวงจรรถไฟ
return await model.fit(inputs, labels, {
batchSize,
epochs,
callbacks: tfvis.show.fitCallbacks(
{ name: 'Training Performance' },
['loss', 'mse'],
{ height: 200, callbacks: ['onEpochEnd'] }
)
});
model.fit
คือฟังก์ชันที่เราเรียกใช้เพื่อเริ่มลูปการฝึก ฟังก์ชันนี้ทำงานไม่พร้อมกัน เราจึงให้คำมั่นสัญญาที่แจ้งไว้เพื่อให้ผู้โทรระบุได้ว่าการฝึกเสร็จสมบูรณ์เมื่อใด
เราจะส่งต่อ Callback บางส่วนไปยัง model.fit
เพื่อติดตามความคืบหน้าในการฝึก เราใช้ tfvis.show.fitCallbacks
เพื่อสร้างฟังก์ชันที่พล็อตแผนภูมิสำหรับ "ภาวะขาดทุน" และ "mse" ที่เราระบุไว้ก่อนหน้านี้
นำข้อมูลทุกอย่างมารวมกัน
ตอนนี้เราต้องเรียกฟังก์ชันที่ได้กำหนดไว้จากฟังก์ชัน run
เพิ่มโค้ดต่อไปนี้ไว้ที่ด้านล่างของ
run
ฟังก์ชัน
// Convert the data to a form we can use for training.
const tensorData = convertToTensor(data);
const {inputs, labels} = tensorData;
// Train the model
await trainModel(model, inputs, labels);
console.log('Done Training');
เมื่อคุณรีเฟรชหน้าเว็บ แล้วคุณจะเห็นกราฟต่อไปนี้ที่อัปเดตหลังจากนั้น 2-3 วินาที
ซึ่งสร้างโดย Callback ที่เราสร้างไว้ก่อนหน้านี้ โดยจะแสดง Loss และ mse โดยเฉลี่ยจากชุดข้อมูลทั้งหมด เมื่อสิ้นสุดแต่ละ Epoch
เมื่อฝึกโมเดล เราต้องการเห็นการสูญเสียลดลง ในกรณีนี้ เนื่องจากเมตริกของเราเป็นการวัดข้อผิดพลาด เราจึงต้องการเห็นข้อผิดพลาดที่ลดลงด้วยเช่นกัน
7. คาดการณ์
เมื่อโมเดลได้รับการฝึกแล้ว เราก็ต้องทำการคาดการณ์ มาประเมินโมเดลโดยดูว่าโมเดลคาดการณ์อะไรไว้สำหรับช่วงแรงม้าต่ำถึงสูงที่เท่ากัน
เพิ่มฟังก์ชันต่อไปนี้ลงในไฟล์ Script.js
function testModel(model, inputData, normalizationData) {
const {inputMax, inputMin, labelMin, labelMax} = normalizationData;
// Generate predictions for a uniform range of numbers between 0 and 1;
// We un-normalize the data by doing the inverse of the min-max scaling
// that we did earlier.
const [xs, preds] = tf.tidy(() => {
const xsNorm = tf.linspace(0, 1, 100);
const predictions = model.predict(xsNorm.reshape([100, 1]));
const unNormXs = xsNorm
.mul(inputMax.sub(inputMin))
.add(inputMin);
const unNormPreds = predictions
.mul(labelMax.sub(labelMin))
.add(labelMin);
// Un-normalize the data
return [unNormXs.dataSync(), unNormPreds.dataSync()];
});
const predictedPoints = Array.from(xs).map((val, i) => {
return {x: val, y: preds[i]}
});
const originalPoints = inputData.map(d => ({
x: d.horsepower, y: d.mpg,
}));
tfvis.render.scatterplot(
{name: 'Model Predictions vs Original Data'},
{values: [originalPoints, predictedPoints], series: ['original', 'predicted']},
{
xLabel: 'Horsepower',
yLabel: 'MPG',
height: 300
}
);
}
สิ่งที่ควรสังเกตเห็นในฟังก์ชันข้างต้น
const xsNorm = tf.linspace(0, 1, 100);
const predictions = model.predict(xsNorm.reshape([100, 1]));
เราสร้าง "ตัวอย่าง" ใหม่ 100 รายการ เพื่อป้อนให้กับโมเดล Model.predict คือวิธีที่เราป้อนตัวอย่างเหล่านั้นลงในโมเดล โปรดทราบว่าจะต้องมีรูปร่างคล้ายกับ ([num_examples, num_features_per_example]
) เหมือนเวลาที่เราฝึก
// Un-normalize the data
const unNormXs = xsNorm
.mul(inputMax.sub(inputMin))
.add(inputMin);
const unNormPreds = predictions
.mul(labelMax.sub(labelMin))
.add(labelMin);
ในการคืนค่าข้อมูลกลับไปยังช่วงเดิม (แทนที่จะเป็น 0-1) เราจะใช้ค่าที่คํานวณได้ขณะทําให้เป็นมาตรฐาน แต่เพียงกลับด้านการดําเนินการเท่านั้น
return [unNormXs.dataSync(), unNormPreds.dataSync()];
.dataSync()
คือวิธีที่เราสามารถใช้เพื่อรับ typedarray
ของค่าที่จัดเก็บไว้ใน Tensor ซึ่งจะทำให้เราประมวลผลค่าเหล่านั้นใน JavaScript ปกติได้ นี่เป็นเมธอด .data()
เวอร์ชันซิงโครนัส ซึ่งโดยทั่วไปเราแนะนำให้ใช้
ขั้นตอนสุดท้าย เราใช้ tfjs-vis เพื่อพล็อตข้อมูลเดิมและการคาดการณ์จากโมเดล
เพิ่มโค้ดต่อไปนี้ลงใน
run
ฟังก์ชัน
// Make some predictions using the model and compare them to the
// original data
testModel(model, data, tensorData);
รีเฟรชหน้าเว็บ และคุณควรเห็นข้อมูลต่อไปนี้เมื่อโมเดลสิ้นสุดการฝึก
ยินดีด้วย คุณเพิ่งฝึกโมเดลแมชชีนเลิร์นนิงแบบง่าย ในปัจจุบัน เครื่องมือนี้จะทำสิ่งที่เรียกว่าการถดถอยเชิงเส้นและพยายามจัดแนวเส้นให้ตรงกับแนวโน้มที่ปรากฏในข้อมูลอินพุต
8. สรุปประเด็นสำคัญ
ขั้นตอนในการฝึกโมเดลแมชชีนเลิร์นนิงมีดังนี้
กำหนดงานของคุณ
- ปัญหานี้เป็นปัญหาการถดถอยหรือปัญหาการจำแนกประเภท
- โดยจะทำกับการเรียนรู้ที่มีการควบคุมดูแลหรือการเรียนรู้ที่ไม่มีการควบคุมดูแลได้ไหม
- ข้อมูลอินพุตมีรูปร่างอย่างไร ข้อมูลเอาต์พุตควรมีลักษณะอย่างไร
เตรียมข้อมูลของคุณ:
- ทำความสะอาดข้อมูลและตรวจสอบรูปแบบด้วยตนเอง หากเป็นไปได้
- สับเปลี่ยนข้อมูลก่อนนำไปใช้ฝึก
- ปรับข้อมูลให้เป็นมาตรฐานในช่วงที่สมเหตุสมผลสำหรับโครงข่ายระบบประสาทเทียม โดยทั่วไป 0-1 หรือ -1-1 จะเป็นช่วงที่ดีสำหรับข้อมูลตัวเลข
- แปลงข้อมูลเป็น Tensor
สร้างและเรียกใช้โมเดลโดยทำดังนี้
- กำหนดโมเดลโดยใช้
tf.sequential
หรือtf.model
แล้วเพิ่มเลเยอร์ลงในโมเดลโดยใช้tf.layers.*
- เลือกเครื่องมือเพิ่มประสิทธิภาพ ( adam ก็เป็นตัวเลือกที่ดี) และพารามิเตอร์ เช่น ขนาดกลุ่มและจำนวน Epoch
- เลือกฟังก์ชันการสูญเสียที่เหมาะกับปัญหา และเมตริกความแม่นยำเพื่อช่วยในการประเมินความคืบหน้า
meanSquaredError
เป็นฟังก์ชันการสูญเสียผู้ใช้ที่พบได้ทั่วไปสำหรับปัญหาการถดถอย - ตรวจสอบการฝึกเพื่อดูว่าการสูญเสียลดลงหรือไม่
ประเมินโมเดล
- เลือกเมตริกการประเมินสำหรับโมเดลที่คุณตรวจสอบได้ขณะฝึก เมื่อฝึกฝนแล้ว ให้ลองคาดการณ์การทดสอบเพื่อให้เข้าใจถึงคุณภาพของการคาดการณ์
9. เครดิตเพิ่มเติม: สิ่งที่น่าลอง
- การทดสอบเปลี่ยนจำนวน Epoch ต้องการจำนวน Epoch เท่าไรก่อนที่กราฟจะค่อยๆ แตก
- ทดสอบโดยเพิ่มจำนวนหน่วยในเลเยอร์ที่ซ่อนอยู่
- ทดสอบด้วยการเพิ่มเลเยอร์ที่ซ่อนอยู่ระหว่างเลเยอร์ที่ซ่อนอยู่รายการแรกที่เราเพิ่มเข้าไปกับเลเยอร์เอาต์พุตสุดท้าย โค้ดสำหรับเลเยอร์เพิ่มเติมเหล่านี้ควรมีลักษณะดังนี้
model.add(tf.layers.dense({units: 50, activation: 'sigmoid'}));
สิ่งใหม่ๆ ที่สำคัญที่สุดเกี่ยวกับเลเยอร์ที่ซ่อนอยู่เหล่านี้คือเลเยอร์ที่มีฟังก์ชันเปิดใช้งานแบบไม่เป็นเชิงเส้น ซึ่งในกรณีนี้การเปิดใช้งาน sigmoid หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับฟังก์ชันการเปิดใช้งาน โปรดอ่านบทความนี้
ดูว่าคุณสามารถทำให้โมเดลสร้างเอาต์พุตเหมือนในรูปภาพด้านล่างได้ไหม