到目前为止,你一直使用numpy来构建神经网络。现在,我们将引导你使用深度学习框架,改框架将使你可以更轻松地构建神经网络。TensorFlow,PaddlePaddle,Torch,Caffe,Keras等机器学习框架可以极大地加速你的机器学习开发速度。所有这些框架也都有好多文档,你应该随时阅读学习。在此笔记本中,你将学习在TensorFlow中执行以下操作:
编程框架不仅可以缩短编码时间,而且有时可以进行优化以加快代码速度。
首先,导入库:
import math
import numpy as np
import h5py
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow.python.framework import ops
from tf_utils import load_dataset, random_mini_batches, convert_to_one_hot, predict
# tf.disable_v2_behavior()
# tf.compat.v1.disable_eager_execution()
%matplotlib inline
np.random.seed(1)
现在,你已经导入了库,我们将引导你完成其不同的应用程序。你将从一个示例开始:计算一个训练数据的损失。
l o s s = L ( y ^ , y ) = ( y ^ ( i ) − y ( i ) ) 2 (1) loss = \mathcal{L}(\hat{y}, y) = (\hat y^{(i)} - y^{(i)})^2 \tag{1} loss=L(y^,y)=(y^(i)−y(i))2(1)
# tf.compat.v1.disable_eager_execution()
y_hat = tf.constant(36, name = 'y_hat') # 定义y_hat常数。设置为36。
y = tf.constant(39, name = 'y') # 定义y,设为39
loss = tf.Variable((y - y_hat) ** 2, name = 'loss') # 为损失创建一个变量
init = tf.global_variables_initializer() # 当init稍后运行时(session.run(init)),损失变量将被初始化并准备进行计算
with tf.Session() as session: # 创建一个会话并打印输出
session.run(init) # 初始化变量
print(session.run(loss)) # 打印的损失
9
在TensorFlow中编写和运行程序包含以下步骤:
因此,当我们为损失创建变量时,我们仅将损失定义为其他数量的函数,但没有验证其值。为了验证它,我们必须运行init = tf.global_variables_initializer()
初始化损失变量,在最后一行中,我们终于能够验证loss的值并打印它。
现在让我们看一个简单的例子。运行下面的单元格:
a = tf.constant(2)
b = tf.constant(10)
c = tf.multiply(a, b)
print(c)
Tensor("Mul:0", shape=(), dtype=int32)
不出所料,看不到结果20!而是得到一个张量,是一个不具有shape属性且类型为"int32"的张量。你所做的所有操作都已放入"计算图"中,但你尚未运行此计算。为了实际将两个数字相乘,必须创建一个会话并运行它。
sess = tf.Session()
print(sess.run(c))
20
Great!总而言之,记住要初始化变量,创建一个会话并在该会话中运行操作。
接下来,你还必须了解placeholders(占位符)。占位符是一个对象,你只能稍后指定其值。
要为占位符指定值,你可以使用"feed dictionary"(feed_dict
变量)传入值。在下面,我们为x创建了一个占位符,以允许我们稍后再允许会话时传递数字。
# 在feed_dict中更改x的值
x = tf.placeholder(tf.int64, name = 'x')
print(sess.run(2 * x, feed_dict = {x : 3}))
sess.close()
6
当你首次定义x时,不必为其指定值。占位符只是一个变量,你在运行会话时才将数据分配给该变量。也就是说你在运行会话时向这些占位符“提供数据”。
当你指定计算所需的操作时,你在告诉TensorFlow如何构造计算图。计算图可以具有一些占位符,你将在稍后指定它们的值。最后,在运行会话时,你要告诉TensorFlow执行计算图。
让我们开始此编程练习,计算以下方程式: Y = W X + b Y = WX + b Y=WX+b,其中 W W W和 X X X是随机矩阵, b b b是随机变量。
练习:计算 W X + b WX + b WX+b,其中 W W W, X X X和 b b b是从随机正态分布中得到的, W W W的维度是(4, 3), X X X的维度为(3, 1), b b b的维度为(4, 1)。例如,下面是定义维度为(3, 1)的常量X的方法:
X = tf.constant(np.random.randn(3,1), name = "X")
你可能会发现以下函数很有用:
def linear_function():
np.random.seed(1)
X = tf.constant(np.random.randn(3, 1), name = "X")
W = tf.constant(np.random.randn(4, 3), name = "W")
b = tf.constant(np.random.randn(4,1), name = "b")
Y = tf.add(tf.matmul(W,X),b)
# 使用tf.Session()创建会话,并在要计算的变量上使用sess.run(…)运行它
sess = tf.Session()
result = sess.run(Y)
# 关闭会话
sess.close()
return result
print( "result = " + str(linear_function()))
result = [[-2.15657382]
[ 2.95891446]
[-1.08926781]
[-0.84538042]]
Great! 你刚刚实现了线性函数。TensorFlow提供了各种常用的神经网络函数,例如tf.sigmoid
和tf.softmax
。对于本练习,让我们计算输入的sigmoid函数值。
你将使用占位符变量x进行此练习。在运行会话时,应该使用feed字典传入输入z。在本练习中,你必须:
tf.sigmoid
定义计算Sigmoid所需的操作;练习:实现下面的Sigmoid函数。你应该使用以下内容:
tf.placeholder(tf.float32, name = "...")
tf.sigmoid(...)
sess.run(..., feed_dict = {x: z})
注意,在tensorflow中创建和使用会话有两种典型的方法:
方法一:
sess = tf.Session()
# 运行变量初始化(如果需要),运行操作
result = sess.run(..., feed_dict = {...})
sess.close() # 关闭会话
方法二:
with tf.Session() as sess:
# 运行变量初始化(如果需要),运行操作
result = sess.run(..., feed_dict = {...})
# 这将负责为您关闭会话
def sigmoid(z):
# 为x创建一个占位符,命名为“x”。
x = tf.placeholder(tf.float32, name = "x")
# 计算sigmoid(x)
sigmoid = tf.sigmoid(x)
# 创建一个会话,并运行它。请使用上面解释的方法2。
# 你应该使用feed_dict将z的值传递给x。
with tf.Session() as sess:
# 运行会话并调用输出“result”
result = sess.run(sigmoid, feed_dict={x : z})# 这里的sigmoid函数等于tf.sigmoid(x)
return result
print ("sigmoid(0) = " + str(sigmoid(0)))
print ("sigmoid(12) = " + str(sigmoid(12)))
sigmoid(0) = 0.5
sigmoid(12) = 0.9999938
总而言之,你知道如何:
你还可以使用内置函数来计算神经网络的损失。因此,对于 i = 1... m i = 1...m i=1...m,无需编写代码来将其为 a [ 2 ] ( i ) a^{[2](i)} a[2](i)和 y ( i ) y^{(i)} y(i)的函数来计算:
J = − 1 m ∑ i = 1 m ( y ( i ) log a [ 2 ] ( i ) + ( 1 − y ( i ) ) log ( 1 − a [ 2 ] ( i ) ) ) (2) J = - \frac{1}{m} \sum_{i = 1}^m \large ( \small y^{(i)} \log a^{ [2] (i)} + (1-y^{(i)})\log (1-a^{ [2] (i)} )\large )\small\tag{2} J=−m1i=1∑m(y(i)loga[2](i)+(1−y(i))log(1−a[2](i)))(2)
你可以使用tensorflow的一行代码中做到这一点!
练习:实现交叉熵损失,你将使用的函数是:
tf.nn.sigmoid_cross_entropy_with_logits(logits = ..., labels = ...)
你的代码应该输入z,计算出sigmoid(得到a),然后计算出交叉熵损失 J J J,所有这些操作都可以通过调用tf.nn.sigmoid_cross_entropy_with_logits
来完成:
− 1 m ∑ i = 1 m ( y ( i ) log σ ( z [ 2 ] ( i ) ) + ( 1 − y ( i ) ) log ( 1 − σ ( z [ 2 ] ( i ) ) ) (2) - \frac{1}{m} \sum_{i = 1}^m \large ( \small y^{(i)} \log \sigma(z^{[2](i)}) + (1-y^{(i)})\log (1-\sigma(z^{[2](i)})\large )\small\tag{2} −m1i=1∑m(y(i)logσ(z[2](i))+(1−y(i))log(1−σ(z[2](i)))(2)
# 计算损失
def cost(logits, labels):
"""
参数:
logits -- 包含z的向量,最后一个线性单位的输出(在最终sigmoid函数激活之前)
labels -- 标签向量y(1或0)
注意:我们在课堂上所说的z和y分别被称为logits和labels
在TensorFlow文档中。所以logits输入z, labels输入y。
"""
# 为“logits”(z)和“labels”(y)创建占位符
z = tf.placeholder(tf.float32, name = "z")
y = tf.placeholder(tf.float32, name = "y")
# 使用损失函数
cost = tf.nn.sigmoid_cross_entropy_with_logits(logits = z, labels = y)
# 创建会话,使用方法1
sess = tf.Session()
# 运行会话
cost = sess.run(cost, feed_dict = {z:logits, y:labels})
# 关闭会话
sess.close()
return cost
logits = sigmoid(np.array([0.2,0.4,0.7,0.9]))
cost = cost(logits, np.array([0,0,1,1]))
print ("cost = " + str(cost))
cost = [1.0053872 1.0366408 0.41385433 0.39956617]
在深度学习中,很多时候你会得到一个y向量,其数字范围从0到C-1,其中C是类的数量。例如C是4,那么你可能具有以下y向量,你将需要按以下方式对其进行转换:
这称为独热编码,因为在转换后的表示形式中,每一列中的一个元素正好是“hot”(设为1)。要以numpy格式进行此转换,你可能需要编写几行代码。在tensorflow中,你可以只使用一行代码:
tf.one_hot(labels, depth, axis)
练习:试下以下函数,以获取一个标签向量和 C C C类的总数,并返回一个独热编码。使用tf.one_hot()
来做到这一点。
def one_hot_matrix(labels, C):
"""
创建一个矩阵,其中第i行对应第i个类号,第j列对应第j个训练示例。如果例子j有一个标签i,那么条目(i,j)就是1。
参数:
labels -- 包含标签的向量
C -- 类的数量,热度维度的深度
"""
C =tf.constant(C, name = "C")
one_hot_matrix = tf.one_hot(labels, C, axis=0)
sess = tf.Session()
one_hot = sess.run(one_hot_matrix)
sess.close()
return one_hot
labels = np.array([1,2,3,0,2,1])
one_hot = one_hot_matrix(labels, C = 4)
print ("one_hot = " + str(one_hot))
one_hot = [[0. 0. 0. 1. 0. 0.]
[1. 0. 0. 0. 0. 1.]
[0. 1. 0. 0. 1. 0.]
[0. 0. 1. 0. 0. 0.]]
现在,你将学习如何初始化0和1的向量。 你将要调用的函数是tf.ones()
。要使用零初始化,可以改用tf.zeros()
。这些函数采用一个维度,并分别返回一个包含0和1的维度数组。
练习:实现以下函数以获取维度并返回维度数组。
tf.ones(shape)
def ones(shape):
ones = tf.ones(shape)
sess = tf.Session()
ones = sess.run(ones)
sess.close()
return ones
print ("ones = " + str(ones([3])))
ones = [1. 1. 1.]
在这一部分作业中,你将使用tensorflow构建神经网络。请记住,实现tensorflow模型包含两个部分:
让我们深入研究你要解决的问题!
一个下午,我们决定和一些朋友一起用计算机来解密手语。我们花了几个小时在白墙前拍照,并提出了以下数据集。现在,你的工作就是构建一种算法,以帮助语音障碍者和不懂手语的人的交流。
请注意,这是SIGNS数据集的子集。完整的数据集包含更多的手势。
这是每个数字的示例,以及如何解释标签的方式。这些是原始图片,然后我们将图像分辨率降低到64 x 64像素。
运行以下代码以加载数据集。
# 加载数据集
X_train_orig, Y_train_orig, X_test_orig, Y_test_orig, classes = load_dataset()
更改下面的索引并运行单元格以可视化数据集中的一些示例。
# 图片的例子
index = 0
plt.imshow(X_train_orig[index])
print ("y = " + str(np.squeeze(Y_train_orig[:, index])))
y = 5
通常先将图像数据集展平,然后除以255以对其进行归一化。最重要的是将每个标签转换为一个独热向量,如图1所示。运行下面的单元格即可转化。
# 将训练和测试图像压平
X_train_flatten = X_train_orig.reshape(X_train_orig.shape[0], -1).T
X_test_flatten = X_test_orig.reshape(X_test_orig.shape[0], -1).T
# 归一化图像向量
X_train = X_train_flatten/255.
X_test = X_test_flatten/255.
# 将训练和测试标签转换为一个独热矩阵
Y_train = convert_to_one_hot(Y_train_orig, 6)
Y_test = convert_to_one_hot(Y_test_orig, 6)
print ("number of training examples = " + str(X_train.shape[1]))
print ("number of test examples = " + str(X_test.shape[1]))
print ("X_train shape: " + str(X_train.shape))
print ("Y_train shape: " + str(Y_train.shape))
print ("X_test shape: " + str(X_test.shape))
print ("Y_test shape: " + str(Y_test.shape))
number of training examples = 1080
number of test examples = 120
X_train shape: (12288, 1080)
Y_train shape: (6, 1080)
X_test shape: (12288, 120)
Y_test shape: (6, 120)
注意 12288 = 64 × 64 × 3 12288 = 64 \times 64 \times 3 12288=64×64×3,每个图像均为正方形,64 x 64像素,其中3为RGB颜色。请确保理解这些数据的维度意义,然后再继续。
你的目标是建立一种能够高精度识别符号的算法。为此,你将构建一个tensorflow模型,该模型与你先前在numpy中为猫识别构建的tensorflow模型几乎相同(但现在使用softmax输出)。这是将numpy实现的模型与tensorflow进行比较的好机会。
模型为LINEAR-> RELU-> LINEAR-> RELU-> LINEAR-> SOFTMAX 。 SIGMOID输出层已转换为SOFTMAX。SOFTMAX层将SIGMOID应用到两个以上的类。
你的第一个任务是为X和X创建占位符,方便你以后再运行会话时传递训练数据。
练习:实现以下函数以在tensorflow中创建占位符。
def create_placeholders(n_x, n_y):
"""
创建tensorflow会话的占位符。
参数:
n_x -- 标量,图像向量的大小(num_px * num_px = 64 * 64 * 3 = 12288)
n_y -- 标量,类的数量(从0到5,因此-> 6)
"""
X = tf.placeholder(shape = [n_x, None], dtype = tf.float32)
Y = tf.placeholder(shape = [n_y, None], dtype = tf.float32)
return X, Y
X, Y = create_placeholders(12288, 6)
print ("X = " + str(X))
print ("Y = " + str(Y))
X = Tensor("Placeholder:0", shape=(12288, ?), dtype=float32)
Y = Tensor("Placeholder_1:0", shape=(6, ?), dtype=float32)
你的第二个任务是初始化tensorflow中的参数。
练习:实现以下函数以初始化tensorflow中的参数。使用权重的Xavier初始化和偏差的零初始化。维度如下,对于W1和b1,你可以使用:
W1 = tf.get_variable("W1", [25,12288], initializer = tf.contrib.layers.xavier_initializer(seed = 1))
b1 = tf.get_variable("b1", [25,1], initializer = tf.zeros_initializer())
请使用seed = 1来确保你的结果与我们的结果相符。
def initialize_parameters():
"""
使用tensorflow初始化参数来构建神经网络。形状:
W1 : [25, 12288]
b1 : [25, 1]
W2 : [12, 25]
b2 : [12, 1]
W3 : [6, 12]
b3 : [6, 1]
"""
tf.set_random_seed(1)
W1 = tf.get_variable("W1", [25,12288], initializer = tf.contrib.layers.xavier_initializer(seed = 1))
b1 = tf.get_variable("b1", [25,1], initializer = tf.zeros_initializer())
W2 = tf.get_variable("W2", [12,25], initializer = tf.contrib.layers.xavier_initializer(seed = 1))
b2 = tf.get_variable("b2", [12,1], initializer = tf.zeros_initializer())
W3 = tf.get_variable("W3", [6,12], initializer = tf.contrib.layers.xavier_initializer(seed = 1))
b3 = tf.get_variable("b3", [6,1], initializer = tf.zeros_initializer())
parameters = {"W1": W1,
"b1": b1,
"W2": W2,
"b2": b2,
"W3": W3,
"b3": b3}
return parameters
tf.reset_default_graph()
with tf.Session() as sess:
parameters = initialize_parameters()
print("W1 = " + str(parameters["W1"]))
print("b1 = " + str(parameters["b1"]))
print("W2 = " + str(parameters["W2"]))
print("b2 = " + str(parameters["b2"]))
W1 =
b1 =
W2 =
b2 =
你现在将在tensorflow中实现正向传播模块。该函数将接收参数字典,并将完成正向传递。你将使用的函数是:
tf.add(...,...)
进行加法f.matmul(...,...)
进行矩阵乘法tf.nn.relu(...)
以应用ReLU激活问题:实现神经网络的正向传递。我们为你注释了numpy等式,以便你可以将tensorflow实现与numpy实现进行比较。重要的是要注意,前向传播在z3处停止。原因是在tensorflow中,最后的线性层输出作为计算损失函数的输入。因此,你不需要a3!
def forward_propagation(X, parameters):
W1 = parameters['W1']
b1 = parameters['b1']
W2 = parameters['W2']
b2 = parameters['b2']
W3 = parameters['W3']
b3 = parameters['b3']
Z1 = tf.add(tf.matmul(W1,X),b1) # Z1 = np.dot(W1, X) + b1
A1 = tf.nn.relu(Z1) # A1 = relu(Z1)
Z2 = tf.add(tf.matmul(W2,A1),b2) # Z2 = np.dot(W2, a1) + b2
A2 = tf.nn.relu(Z2) # A2 = relu(Z2)
Z3 = tf.add(tf.matmul(W3,A2),b3) # Z3 = np.dot(W3,Z2) + b3
return Z3
tf.reset_default_graph()
with tf.Session() as sess:
X, Y = create_placeholders(12288, 6)
parameters = initialize_parameters()
Z3 = forward_propagation(X, parameters)
print("Z3 = " + str(Z3))
Z3 = Tensor("Add_2:0", shape=(6, ?), dtype=float32)
你可能已经注意到,正向传播不会输出任何缓存。当我们开始进行传播时,你将在下面理解为什么。
如前所述,使用以下方法很容易计算损失:
tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits = ..., labels = ...))
问题:实现以下损失函数。
tf.nn.softmax_cross_entropy_with_logits
的"logits
"和"labels
"输入应具有一样的维度(数据数,类别数)。 因此,我们为你转换了Z3和Y。tf.reduce_mean
是对所以数据进行求和。def compute_cost(Z3, Y):
logits = tf.transpose(Z3)
labels = tf.transpose(Y)
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits = logits, labels = labels))
return cost
tf.reset_default_graph()
with tf.Session() as sess:
X, Y = create_placeholders(12288, 6)
parameters = initialize_parameters()
Z3 = forward_propagation(X, parameters)
cost = compute_cost(Z3, Y)
print("cost = " + str(cost))
cost = Tensor("Mean:0", shape=(), dtype=float32)
所有反向传播和参数更新均可使用1行代码完成,将这部分合并到模型中非常容易。
计算损失函数之后,你将创建一个"optimizer
"对象。运行tf.session
时,必须与损失一起调用此对象。调用时,它将使用所选方法和学习率对给定的损失执行优化。
例如,对于梯度下降,优化器将是:
optimizer = tf.train.GradientDescentOptimizer(learning_rate = learning_rate).minimize(cost)
要进行优化,你可以执行以下操作:
_ , c = sess.run([optimizer, cost], feed_dict={X: minibatch_X, Y: minibatch_Y})
通过相反顺序的tensorflow图来计算反向传播。从损失到输入。
注意编码时,我们经常使用_作为“throwaway”变量来存储以后不再需要使用的值。这里_代表了我们不需要的optimizer
的评估值(而 c 代表了 cost变量的值)。
现在,将它们组合在一起!
练习:调用之前实现的函数构建完整模型。
def model(X_train, Y_train, X_test, Y_test, learning_rate = 0.0001,
num_epochs = 1500, minibatch_size = 32, print_cost = True):
ops.reset_default_graph() # 能够在不覆盖tf变量的情况下重新运行模型
tf.set_random_seed(1) # 为了保持一致的结果
seed = 3 # 为了保持一致的结果
(n_x, m) = X_train.shape # (n_x:输入大小,m:训练集中的样本数量)
n_y = Y_train.shape[0] # n_y:输出大小
costs = [] # 成本
# Step1:创建形状占位符(n_x, n_y)
X, Y = create_placeholders(n_x, n_y)
# Step2:初始化参数
parameters = initialize_parameters()
# Step3:前向传播:在tensorflow图中构建前向传播
Z3 = forward_propagation(X, parameters)
# Step4:代价函数:将代价函数添加到tensorflow图中
cost = compute_cost(Z3, Y)
# Step5:反向传播:定义tensorflow优化器。使用一个AdamOptimizer。
optimizer = tf.train.AdamOptimizer(learning_rate = learning_rate).minimize(cost)
# Step6:初始化所有变量
init = tf.global_variables_initializer()
# Step7:启动会话来计算tensorflow图
with tf.Session() as sess:
# Step8:运行初始化
sess.run(init)
# Step9:进行循环训练
for epoch in range(num_epochs):
epoch_cost = 0. # 定义与epoch相关的成本
num_minibatches = int(m / minibatch_size) # 在序列集中大小为minibatch_size的小批量的数量
seed = seed + 1
minibatches = random_mini_batches(X_train, Y_train, minibatch_size, seed)
for minibatch in minibatches:
# 选择一个minibatch
(minibatch_X, minibatch_Y) = minibatch
# 运行会话来执行“优化器”和“成本”,feedict应该包含一个小批量(X,Y)。
_ , minibatch_cost = sess.run([optimizer, cost], feed_dict={X: minibatch_X, Y: minibatch_Y})
epoch_cost += minibatch_cost / num_minibatches
if print_cost == True and epoch % 100 == 0:
print ("Cost after epoch %i: %f" % (epoch, epoch_cost))
if print_cost == True and epoch % 5 == 0:
costs.append(epoch_cost)
plt.plot(np.squeeze(costs))
plt.ylabel('cost')
plt.xlabel('iterations (per tens)')
plt.title("Learning rate =" + str(learning_rate))
plt.show()
# 让我们将参数保存在一个变量中
parameters = sess.run(parameters)
print ("Parameters have been trained!")
# 计算出正确的预测
correct_prediction = tf.equal(tf.argmax(Z3), tf.argmax(Y))
# 计算测试集上的精度
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
print ("Train Accuracy:", accuracy.eval({X: X_train, Y: Y_train}))
print ("Test Accuracy:", accuracy.eval({X: X_test, Y: Y_test}))
return parameters
运行以下单元格来训练你的模型!在我们的机器上大约需要5分钟。 你的“100epoch后的损失”应为1.016458。如果不是,请不要浪费时间。单击笔记本电脑上方栏中的正方形(⬛),以中断训练,然后尝试更正你的代码。如果损失正确,请稍等片刻,然后在5分钟内回来!
parameters = model(X_train, Y_train, X_test, Y_test)
Cost after epoch 0: 1.855702
Cost after epoch 100: 1.017255
Cost after epoch 200: 0.733184
Cost after epoch 300: 0.573071
Cost after epoch 400: 0.468573
Cost after epoch 500: 0.381228
Cost after epoch 600: 0.313815
Cost after epoch 700: 0.253624
Cost after epoch 800: 0.203897
Cost after epoch 900: 0.166472
Cost after epoch 1000: 0.146867
Cost after epoch 1100: 0.107288
Cost after epoch 1200: 0.086557
Cost after epoch 1300: 0.059360
Cost after epoch 1400: 0.052275
Parameters have been trained!
Train Accuracy: 0.9990741
Test Accuracy: 0.725
评价:
现在,你可以拍张手的照片并查看模型的输出。要做到这一点:
import scipy
from PIL import Image
from scipy import ndimage
## START CODE HERE ## (PUT YOUR IMAGE NAME)
my_image = "thumbs_up.jpg"
## END CODE HERE ##
# 我们会根据你的算法对你的图像进行预处理。
fname = my_image
image = np.array(ndimage.imread(fname, flatten=False))
my_image = scipy.misc.imresize(image, size=(64,64)).reshape((1, 64*64*3)).T
my_image_prediction = predict(my_image, parameters)
plt.imshow(image)
print("Your algorithm predicts: y = " + str(np.squeeze(my_image_prediction)))
Your algorithm predicts: y = 3
尽管你看到算法似乎对它进行了错误分类,但你确实值得“竖起大拇指”。原因是训练集不包含任何“竖起大拇指”,因此模型不知道如何处理! 我们称其为“数据不平衡”,它是下一章“构建机器学习项目”中的学习课程之一。
你应该记住: