Lưu ngày! Google I / O hoạt động trở lại từ ngày 18 đến 20 tháng 5 Đăng ký ngay
Trang này được dịch bởi Cloud Translation API.
Switch to English

Các 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. bằng cách sử dụng API lớp với LayersModel.fit() hoặc LayersModel.fitDataset() .
  2. sử dụng Core API với Optimizer.minimize() .

Đầu tiên, chúng ta sẽ xem xét API Lớp, là một 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ẽ chỉ ra cách đào tạo cùng một mô hình bằng cách sử dụng Core API.

Giới thiệu

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

Đà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ị "true".
  • Quyết định mức độ thay đổi 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 một á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ột mô hình 2 lớp đơn giản bằng cách sử dụ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'}),
 ]
});

Bên dưới, các mô hình có các tham số (thường được gọi là trọng lượng ) có thể học được bằng cách đào tạo trên dữ liệu. Hãy in tên của các quả cân có 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ả 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 trên mỗi lớp dày đặc. Điều này được mong đợi vì các lớp dày đặc đại diện cho một hàm ánh xạ tensor đầu vào x với tensor đầu ra y thông qua phương trình y = Ax + b trong đó A (nhân) và b (thiên vị) 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 một sai 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 một lớp dày đặc.

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

Lớp (loại) Đầu ra hình dạng Thông số #
dầy đặc_Dense1 (Mật độ) [null, 32] 25120
dầy đặc_Dense2 (Dày đặc) [null, 10] 330
Tổng số tham số: 25450
Thông số có thể huấn luyện: 25450
Các 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, một Variable là một Tensor dấu phẩy động với một phương thức bổ sung là 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 các trọng số bằng cách sử dụng các phương pháp hay nhất. Để chứng minh, chúng ta có thể ghi đè các trọng số bằng cách gọi lệnh 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 từng tham số trong mô hình, dựa trên dự đoán của mô hình hiện tại. Khi sử dụng API Lớp, bạn có thể cung cấp số 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 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 một 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ị đúng và trả về lỗ. 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 chỉ số. Tương tự như tổn thất, các chỉ số tính toán một con số, tóm tắt mức độ hoạt động của mô hình của chúng tôi. Các chỉ số 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 tôi muốn theo dõi rằng khoản lỗ của chúng tôi đang giảm dần theo thời gian. 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 một chỉ số 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ị đúng và trả về điểm. Xem danh sách các chỉ số 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 để đào tạo một 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 phù hợp với bộ nhớ chính và có sẵn dưới dạng một tensor duy nhất, bạn có thể đào tạo 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);
 });

Dưới mui xe, model.fit() có thể làm được nhiều điều cho chúng ta:

  • Tách dữ liệu thành một tập hợp đào tạo và 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 tách. Để an toàn, bạn nên xáo trộn trước dữ liệu trước khi chuyển nó vào fit() .
  • Tách tensor dữ liệu lớn thành tensor nhỏ hơn của kích thước batchSize.
  • Gọi optimizer.minimize() trong khi tính toán sự mất mát của mô hình liên quan đến 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 cách sử dụng tùy chọn callbacks.onBatchEnd . Các tùy chọn khác bao gồm: onTrainBegin , onTrainEnd , onEpochBegin , onEpochEndonBatchBegin .
  • Nó dẫn đến luồng chính để đảm bảo rằng các tác vụ được 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 bạn chọn sử dụng Core API, bạn sẽ phải tự triển khai logic này.

model.fitDataset ()

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

Sau khi mô hình đã được đào tạo, bạn có thể gọi model.predict() để đưa ra dự đoán trên dữ liệu chưa 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ột mô hình học máy trong TensorFlow.js.

Nguyên tắc chung là cố gắng sử dụng API Lớp trước, vì nó được mô phỏng theo API Keras được chấp nhận tốt. API Lớp cũng cung cấp các giải pháp 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 Core API 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 bạn.

Để 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 về Mô hình và Lớp .

Mô hình tương tự như trên được viết bằng Core API trông giống như sau:

// 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 xáo trộn và phân lô 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 chuẩn khi đào tạo một mô hình với Core API:

  • Lặp lại số lượng kỷ nguyên.
  • Trong mỗi kỷ nguyên, hãy 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 qua 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 gradient liên quan đến bốn biến mà chúng ta đã xác định trước đó.
  • f tính toán khoản lỗ. Nó gọi một trong những hàm tổn thấ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.