数据来源于吴恩达L2HW3(SIGNS 数据集),训练集包含1800张64*64像素的彩色图片,图片内容为手势,表示从0到5的数字,所要做的是搭建较深的神经网络,以实现图片分类。测试集包含120张图片。
数据集读取:
def load_dataset():
%cd '/content/drive/MyDrive/Colab Notebooks/吴恩达L2HW3/dataset'
train_dataset = h5py.File('train_signs.h5', "r")
train_set_x_orig = np.array(train_dataset["train_set_x"][:]) # your train set features
train_set_y_orig = np.array(train_dataset["train_set_y"][:]) # your train set labels
test_dataset = h5py.File('test_signs.h5', "r")
test_set_x_orig = np.array(test_dataset["test_set_x"][:]) # your test set features
test_set_y_orig = np.array(test_dataset["test_set_y"][:]) # your test set labels
classes = np.array(test_dataset["list_classes"][:]) # the list of classes
train_set_y_orig = train_set_y_orig.reshape((1, train_set_y_orig.shape[0]))
test_set_y_orig = test_set_y_orig.reshape((1, test_set_y_orig.shape[0]))
return train_set_x_orig, train_set_y_orig, test_set_x_orig, test_set_y_orig, classes
X_train_orig , Y_train_orig , X_test_orig , Y_test_orig , classes = load_dataset()
index = 12
plt.imshow(X_train_orig[index])
plt.show()
print(X_train_orig.shape)#1080张图片,64*64*3
Y_train_orig.shape
数据预处理 :
train.sign.h5文件包含的是训练集,train_set_x为64*64*3*1800的tensor,1800为样本数,train_set_y为所对应的类别,维度为6*1080,需要首先每一样本数据进行归一化(/255),之后进行flatten才可输入模型,flatten之后的维度为(122280,1800)(X_train)
X_train_flatten=X_train_orig.reshape(X_train_orig.shape[0], -1).T
X_train_flatten.shape#每一列代表一个样本
X_test_flatten = X_test_orig.reshape(X_test_orig.shape[0], -1).T
#归一化
X_train_flatten=X_train_flatten/255
X_test_flatten=X_test_flatten/255
对训练集进行随机划分(Mini-Batch):
def random_mini_batches(X,Y,mini_batch_size,seed):
m=X.shape[1]
mini_batches=[]
np.random.seed(seed)
permutation=list(np.random.permutation(m))
shuffled_X=X[:,permutation]
shuffled_Y=Y[:,permutation]
num_complete_minibatches=math.floor(m/mini_batch_size)
for k in range(num_complete_minibatches):
mini_batch_X=shuffled_X[:,k*mini_batch_size:(k+1)*mini_batch_size]
mini_batch_Y=shuffled_Y[:,k*mini_batch_size:(k+1)*mini_batch_size]
mini_batch=(mini_batch_X,mini_batch_Y)
mini_batches.append(mini_batch)
if m % mini_batch_size != 0:
mini_batch_X = shuffled_X[:,num_complete_minibatches*mini_batch_size:m]
mini_batch_Y = shuffled_Y[:,num_complete_minibatches*mini_batch_size:m]
mini_batch = (mini_batch_X,mini_batch_Y)
mini_batches.append(mini_batch)
return mini_batches
shuffle:如下所示,创建训练集(X,Y)的随机打乱版本。X和Y中的每一列代表一个训练示例。随机打乱是在X和Y之间同步完成的。
Partition:将打乱后的(X,Y)划分为大小为mini_batch_size
(此处为32)的小批处理。训练示例的数量并不总是可以被mini_batch_size
整除。最后的小批量可能较小。
模型搭建:全连接层-->relu-->全连接层-->relu-->全连接层
class Model(torch.nn.Module):
def __init__(self,n_x,h1,h2,n_y):
super(Model,self).__init__()
self.linear1=torch.nn.Linear(n_x,h1)#(上一层特征数,该层神经元数)
self.relu1=torch.nn.ReLU()
self.linear2=torch.nn.Linear(h1,h2)
self.relu2=torch.nn.ReLU()
self.linear3=torch.nn.Linear(h2,n_y)
self.model=torch.nn.Sequential(self.linear1,self.relu1,self.linear2,self.relu2,self.linear3)
def forward(self,x):
return self.model(x)
训练数据输入模型:
m=Model(X_train_flatten.shape[0],25,12,6)#隐藏层神经元数为25,12,6最后一层输出对应类别的概率
num = torch.cuda.device_count()
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
X_train_flatten = torch.from_numpy(X_train_flatten).to(torch.float32).to(device)
Y_train = torch.from_numpy(Y_train_orig).to(torch.float32).to(device)
X_test_flatten = torch.from_numpy(X_test_flatten).to(torch.float32).to(device)
Y_test = torch.from_numpy(Y_test_orig).to(torch.float32).to(device)
模型参数的设定:
m.to(device)
epoch_num = 2000
learning_rate = 0.0001
minibatch_size = 32
seed = 3
costs = []
optimizer = torch.optim.Adam(m.model.parameters(), lr=learning_rate)
loss_func = torch.nn.CrossEntropyLoss()
模型训练:
for epoch in range(epoch_num):
num_minibatches = int(X_train_flatten.shape[1] / minibatch_size)
minibatches = random_mini_batches(X_train_flatten, Y_train, minibatch_size, seed)
epoch_cost = 0
for minibatch in minibatches:
(minibatch_X, minibatch_Y) = minibatch
y_pred = m.forward(minibatch_X.T)
y = minibatch_Y.T
y = y.view(-1)
loss = loss_func(y_pred, y.long())
epoch_cost = epoch_cost + loss.item()#在pytorch里用item取出这个唯一的元素
optimizer.zero_grad()
loss.backward()
optimizer.step()
epoch_cost = epoch_cost / (num_minibatches + 1)
if epoch % 5 == 0:
costs.append(epoch_cost)
# 是否打印:
if epoch % 100 == 0:
print("epoch = " + str(epoch) + " epoch_cost = " + str(epoch_cost))
这里需要注意:计算损失时,我们需要将预测标签值y_pred和实际标签值y传入损失函数中,y_pred的维度为(n,6),而y的维度为(n),交叉熵函数(pytorch)会在内部将y转换为one-hot形式,y的维度会变成(n,6)。而在tensorflow框架中,损失函数不会帮我们完成one-hot的转换,我们要自己完成。
epoch = 0 epoch_cost = 1.7447822058902067
epoch = 100 epoch_cost = 1.0144566087161793
epoch = 200 epoch_cost = 0.8499525382238275
epoch = 300 epoch_cost = 0.7405223215327543
epoch = 400 epoch_cost = 0.6508408206350663
epoch = 500 epoch_cost = 0.5719360849436592
epoch = 600 epoch_cost = 0.5000492202885011
epoch = 700 epoch_cost = 0.4312421894248794
epoch = 800 epoch_cost = 0.36556195949806886
epoch = 900 epoch_cost = 0.3063356779954013
epoch = 1000 epoch_cost = 0.25039714048890505
epoch = 1100 epoch_cost = 0.19280040614745197
epoch = 1200 epoch_cost = 0.14023028938647578
epoch = 1300 epoch_cost = 0.10207015522481765
epoch = 1400 epoch_cost = 0.11564182287410778
epoch = 1500 epoch_cost = 0.09902713168412447
epoch = 1600 epoch_cost = 0.06645032955224023
epoch = 1700 epoch_cost = 0.045455615638810044
epoch = 1800 epoch_cost = 0.07567436467198764
epoch = 1900 epoch_cost = 0.02966493705068441
#模型保存:
torch.save(m,'/content/drive/MyDrive/Colab Notebooks/吴恩达L2HW3/图片数字分辨.pth')
测试集上的表现:
y_test_pred=m.forward(X_test_flatten.T)
y = Y_test.T
y = y.view(-1)
loss = loss_func(y_test_pred, y.long())
y_model_pred=[]
for i in range(X_test_flatten.shape[1]):
y_model_pred.append(torch.argmax(y_test_pred[i],dim=0).item())
for index in range(X_test_flatten.shape[1]):
plt.imshow(X_test_orig[index])
plt.show()
print(y_model_pred[index])
0
0
0
0
2