Mô hình đào tạo

Hướng dẫn này giả sử bạn đã đọc hướng dẫn về mô hình và lớp .

Trong TensorFlow.js có hai cách để đào tạo mô hình học máy:

  1. sử dụng API Lớp với LayersModel.fit() hoặc LayersModel.fitDataset() .
  2. sử dụng API lõi với Optimizer.minimize() .

Đầu tiên, chúng ta sẽ xem xét API Lớp, đây là API cấp cao hơn để xây dựng và đào tạo các mô hình. Sau đó, chúng tôi sẽ trình bày cách đào tạo mô hình tương tự bằng API lõi.

Giới thiệu

Mô hình học máy là một hàm có các tham số có thể học được để ánh xạ đầu vào tới đầu ra mong muốn. Các tham số tối ưu thu được bằng cách huấn luyện mô hình trên dữ liệu.

Việc đào tạo bao gồm một số bước:

  • Lấy một loạt dữ liệu vào mô hình.
  • Yêu cầu người mẫu đưa ra dự đoán.
  • So sánh dự đoán đó với giá trị "đúng".
  • Quyết định mức độ thay đổi của từng tham số để mô hình có thể đưa ra dự đoán tốt hơn trong tương lai cho lô đó.

Một mô hình được đào tạo tốt sẽ cung cấp ánh xạ chính xác từ đầu vào đến đầu ra mong muốn.

Thông số mô hình

Hãy xác định mô hình 2 lớp đơn giản bằng API Lớp:

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

Về cơ bản, các mô hình có các tham số (thường được gọi là trọng số ) có thể học được bằng cách huấn luyện trên dữ liệu. Hãy in tên của các trọng lượng liên quan đến mô hình này và hình dạng của chúng:

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

Chúng tôi nhận được kết quả đầu ra sau:

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

Tổng cộng có 4 trọng lượng, 2 trọng lượng cho mỗi lớp dày đặc. Điều này được mong đợi vì các lớp dày đặc biểu thị một hàm ánh xạ tenxơ đầu vào x với tenxơ đầu ra y thông qua phương trình y = Ax + b trong đó A (hạt nhân) và b (độ lệch) là các tham số của lớp dày đặc.

LƯU Ý: Theo mặc định, các lớp dày đặc bao gồm độ lệch, nhưng bạn có thể loại trừ nó bằng cách chỉ định {useBias: false} trong các tùy chọn khi tạo lớp dày đặc.

model.summary() là một phương pháp hữu ích nếu bạn muốn có cái nhìn tổng quan về mô hình của mình và xem tổng số tham số:

Lớp (loại) Hình dạng đầu ra Thông số #
dày đặc_Dense1 (Dày đặc) [không, 32] 25120
dày đặc_Dense2 (Dày đặc) [không,10] 330
Tổng thông số: 25450
Thông số có thể đào tạo: 25450
Thông số không thể đào tạo: 0

Mỗi trọng số trong mô hình được phụ trợ bởi một đối tượng Variable . Trong TensorFlow.js, Variable là một Tensor dấu phẩy động với một phương thức assign() được sử dụng để cập nhật các giá trị của nó. API Lớp tự động khởi tạo trọng số bằng cách sử dụng các phương pháp hay nhất. Để minh họa, chúng ta có thể ghi đè các trọng số bằng cách gọi assign() trên các biến cơ bản:

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

Trình tối ưu hóa, mất mát và số liệu

Trước khi thực hiện bất kỳ khóa đào tạo nào, bạn cần quyết định ba điều:

  1. Một trình tối ưu hóa . Công việc của trình tối ưu hóa là quyết định mức độ thay đổi của từng tham số trong mô hình dựa trên dự đoán mô hình hiện tại. Khi sử dụng API Lớp, bạn có thể cung cấp mã nhận dạng chuỗi của trình tối ưu hóa hiện có (chẳng hạn như 'sgd' hoặc 'adam' ) hoặc một phiên bản của lớp Trình Optimizer .
  2. Một hàm mất mát . Một mục tiêu mà mô hình sẽ cố gắng giảm thiểu. Mục tiêu của nó là đưa ra một con số duy nhất cho mức độ "sai" của dự đoán của mô hình. Sự mất mát được tính toán trên mỗi lô dữ liệu để mô hình có thể cập nhật trọng số của nó. Khi sử dụng API Lớp, bạn có thể cung cấp mã định danh chuỗi của hàm mất mát hiện có (chẳng hạn như 'categoricalCrossentropy' ) hoặc bất kỳ hàm nào nhận giá trị dự đoán và giá trị thực rồi trả về giá trị mất mát. Xem danh sách các khoản lỗ hiện có trong tài liệu API của chúng tôi.
  3. Danh sách các số liệu. Tương tự như tổn thất, số liệu tính toán một con số duy nhất, tóm tắt mức độ hoạt động của mô hình của chúng tôi. Các số liệu thường được tính toán trên toàn bộ dữ liệu vào cuối mỗi kỷ nguyên. Ít nhất, chúng ta muốn theo dõi xem tổn thất của mình có giảm dần theo thời gian hay không. Tuy nhiên, chúng tôi thường muốn một số liệu thân thiện với con người hơn, chẳng hạn như độ chính xác. Khi sử dụng API Lớp, bạn có thể cung cấp mã nhận dạng chuỗi của số liệu hiện có (chẳng hạn như 'accuracy' ) hoặc bất kỳ hàm nào nhận giá trị dự đoán và giá trị thực rồi trả về điểm. Xem danh sách các số liệu có sẵn trong tài liệu API của chúng tôi.

Khi bạn đã quyết định, hãy biên dịch LayersModel bằng cách gọi model.compile() với các tùy chọn được cung cấp:

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

Trong quá trình biên dịch, mô hình sẽ thực hiện một số xác nhận để đảm bảo rằng các tùy chọn bạn chọn tương thích với nhau.

Đào tạo

Có hai cách để huấn luyện LayersModel :

  • Sử dụng model.fit() và cung cấp dữ liệu dưới dạng một tensor lớn.
  • Sử dụng model.fitDataset() và cung cấp dữ liệu thông qua đối tượng Dataset .

model.fit()

Nếu tập dữ liệu của bạn vừa với bộ nhớ chính và có sẵn dưới dạng một tenxơ đơn, bạn có thể huấn luyện một mô hình bằng cách gọi phương thức 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);
 });

Tóm lại, model.fit() có thể giúp ích rất nhiều cho chúng ta:

  • Chia dữ liệu thành một tập huấn luyện và tập xác thực, đồng thời sử dụng tập hợp xác thực để đo lường tiến độ trong quá trình đào tạo.
  • Xáo trộn dữ liệu nhưng chỉ sau khi phân chia. Để an toàn, bạn nên xáo trộn trước dữ liệu trước khi chuyển nó tới fit() .
  • Chia tensor dữ liệu lớn thành các tensor nhỏ hơn có kích thước batchSize.
  • Gọi optimizer.minimize() trong khi tính toán tổn thất của mô hình đối với lô dữ liệu.
  • Nó có thể thông báo cho bạn khi bắt đầu và kết thúc mỗi kỷ nguyên hoặc đợt. Trong trường hợp của chúng tôi, chúng tôi được thông báo vào cuối mỗi đợt bằng tùy chọn callbacks.onBatchEnd . Các tùy chọn khác bao gồm: onTrainBegin , onTrainEnd , onEpochBegin , onEpochEndonBatchBegin .
  • Nó nhường chỗ cho luồng chính để đảm bảo rằng các tác vụ xếp hàng đợi trong vòng lặp sự kiện JS có thể được xử lý kịp thời.

Để biết thêm thông tin, hãy xem tài liệu của fit() . Lưu ý rằng nếu chọn sử dụng API lõi, bạn sẽ phải tự mình triển khai logic này.

model.fitDataset()

Nếu dữ liệu của bạn không hoàn toàn nằm gọn trong bộ nhớ hoặc đang được truyền trực tuyến, bạn có thể huấn luyện một mô hình bằng cách gọi fitDataset() , mô hình này nhận một đối tượng Dataset . Đây là mã đào tạo tương tự nhưng có tập dữ liệu bao bọc hàm tạo:

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);
});

Để biết thêm thông tin về tập dữ liệu, hãy xem tài liệu của model.fitDataset() .

Dự đoán dữ liệu mới

Khi mô hình đã được huấn luyện, bạn có thể gọi model.predict() để đưa ra dự đoán về dữ liệu chưa nhìn thấy:

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

API cốt lõi

Trước đó, chúng tôi đã đề cập rằng có hai cách để đào tạo mô hình học máy trong TensorFlow.js.

Nguyên tắc chung là trước tiên hãy thử sử dụng API Lớp vì nó được mô hình hóa theo API Keras được áp dụng tốt. API Lớp cũng cung cấp nhiều giải pháp sẵn có khác nhau như khởi tạo trọng lượng, tuần tự hóa mô hình, đào tạo giám sát, tính di động và kiểm tra an toàn.

Bạn có thể muốn sử dụng API lõi bất cứ khi nào:

  • Bạn cần sự linh hoạt hoặc kiểm soát tối đa.
  • Và bạn không cần tuần tự hóa hoặc có thể triển khai logic tuần tự hóa của riêng mình.

Để biết thêm thông tin về API này, hãy đọc phần "API cốt lõi" trong hướng dẫn Mô hình và Lớp .

Mô hình tương tự như trên được viết bằng API lõi trông như thế này:

// 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);
}

Ngoài API Lớp, API Dữ liệu cũng hoạt động liền mạch với API lõi. Hãy sử dụng lại tập dữ liệu mà chúng ta đã xác định trước đó trong phần model.fitDataset() , phần này thực hiện chức năng xáo trộn và phân nhóm cho chúng ta:

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);

Hãy đào tạo mô hình:

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);
}

Đoạn mã trên là công thức tiêu chuẩn khi đào tạo một mô hình bằng API lõi:

  • Lặp lại số kỷ nguyên.
  • Trong mỗi kỷ nguyên, lặp lại các lô dữ liệu của bạn. Khi sử dụng Dataset , dataset.forEachAsync() là một cách thuận tiện để lặp lại các lô của bạn.
  • Đối với mỗi lô, hãy gọi optimizer.minimize(f) , thực thi f và giảm thiểu đầu ra của nó bằng cách tính toán độ dốc đối với bốn biến mà chúng tôi đã xác định trước đó.
  • f tính toán tổn thất. Nó gọi một trong các hàm mất được xác định trước bằng cách sử dụng dự đoán của mô hình và giá trị thực.