PyTorch 遷移學(xué)習(xí)實(shí)戰(zhàn)
1. 實(shí)驗(yàn)環(huán)境
- Jupyter Notebook
- Python 3.7
- PyTorch 1.4.0
2. 實(shí)驗(yàn)?zāi)康?/h2>
遷移學(xué)習(xí),讓機(jī)器擁有能夠“舉一反三”的能力。
本次實(shí)驗(yàn)就以“是螞蟻還是蜜蜂”為例,探索如何將已訓(xùn)練好的大網(wǎng)絡(luò)遷移到小數(shù)據(jù)集上,并經(jīng)過少量數(shù)據(jù)集的訓(xùn)練就讓它獲得非常出眾的效果。
3. 相關(guān)原理
使用 PyTorch 的數(shù)據(jù)集套件從本地加載數(shù)據(jù)的方法
遷移訓(xùn)練好的大型神經(jīng)網(wǎng)絡(luò)模型到自己模型中的方法
遷移學(xué)習(xí)與普通深度學(xué)習(xí)方法的效果區(qū)別
兩種遷移學(xué)習(xí)方法的區(qū)別
4. 實(shí)驗(yàn)步驟
# 下載實(shí)驗(yàn)所需數(shù)據(jù)并解壓 !wget http://labfile.oss.aliyuncs.com/courses/1073/transfer-data.zip !unzip transfer-data.zip
4.1 數(shù)據(jù)收集
實(shí)驗(yàn)中的數(shù)據(jù)是已經(jīng)準(zhǔn)備好的,訓(xùn)練數(shù)據(jù)集在 ./data/train 中,校驗(yàn)數(shù)據(jù)集在 ./data/val 中。(推薦直接到藍(lán)橋云課上進(jìn)行實(shí)驗(yàn))。如果使用自己的環(huán)境只需要自己準(zhǔn)備相關(guān)圖片數(shù)據(jù),并將代碼中的路徑改成你自己的數(shù)據(jù)集路徑。
#引入實(shí)驗(yàn)所需要的包 import torch import torch.nn as nn import torch.optim as optim from torch.autograd import Variable import torch.nn.functional as F import numpy as np import torchvision from torchvision import datasets, models, transforms import matplotlib.pyplot as plt import time import copy import os
4.1.1加載數(shù)據(jù)
使用 datasets 的 ImageFolder 方法就可以實(shí)現(xiàn)自動(dòng)加載數(shù)據(jù),因?yàn)閿?shù)據(jù)集中的數(shù)據(jù)可能分別在不同的文件夾中,要讓所有的數(shù)據(jù)一起加載。
# 數(shù)據(jù)存儲(chǔ)總路徑
data_dir = 'transfer-data'
# 圖像的大小為224*224
image_size = 224
# 從data_dir/train加載文件
# 加載的過程將會(huì)對圖像自動(dòng)作如下的圖像增強(qiáng)操作:
# 1. 隨機(jī)從原始圖像中切下來一塊224*224大小的區(qū)域
# 2. 隨機(jī)水平翻轉(zhuǎn)圖像
# 3. 將圖像的色彩數(shù)值標(biāo)準(zhǔn)化
train_dataset = datasets.ImageFolder(os.path.join(data_dir, 'train'),
transforms.Compose([
transforms.RandomResizedCrop(image_size),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
)
# 加載校驗(yàn)數(shù)據(jù)集,對每個(gè)加載的數(shù)據(jù)進(jìn)行如下處理:
# 1. 放大到256*256像素
# 2. 從中心區(qū)域切割下224*224大小的圖像區(qū)域
# 3. 將圖像的色彩數(shù)值標(biāo)準(zhǔn)化
val_dataset = datasets.ImageFolder(os.path.join(data_dir, 'val'),
transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(image_size),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
)
下面要為每個(gè)數(shù)據(jù)集創(chuàng)建數(shù)據(jù)加載器。
# 創(chuàng)建相應(yīng)的數(shù)據(jù)加載器 train_loader = torch.utils.data.DataLoader(train_dataset, batch_size = 4, shuffle = True, num_workers=4) val_loader = torch.utils.data.DataLoader(val_dataset, batch_size = 4, shuffle = True, num_workers=4) # 讀取得出數(shù)據(jù)中的分類類別數(shù) # 如果只有蜜蜂和螞蟻,那么是2 num_classes = len(train_dataset.classes) num_classes
輸出:2
4.1.2 GPU運(yùn)算
第一次了解GPU運(yùn)算是在第一篇博客PyTorch,簡單的了解了一下。
深度學(xué)習(xí)可以通過 GPU 并行運(yùn)算加速模型的訓(xùn)練。
PyTorch 是支持使用 GPU 并行運(yùn)算的。但是能不能使用 GPU 加速運(yùn)算還取決于硬件,支持 GPU 的硬件(顯卡)一般是比較昂貴的。
如果你想讓自己的程序能夠自動(dòng)識別 GPU 計(jì)算環(huán)境,并且在 GPU 不具備的情況下也能自動(dòng)使用 CPU 正常運(yùn)行,可以這么做:
這三個(gè)變量,之后會(huì)用來靈活判斷是否需要采用 GPU 運(yùn)算。
# 檢測本機(jī)器是否安裝GPU,將檢測結(jié)果記錄在布爾變量use_cuda中 use_cuda = torch.cuda.is_available() # 當(dāng)可用GPU的時(shí)候,將新建立的張量自動(dòng)加載到GPU中 dtype = torch.cuda.FloatTensor if use_cuda else torch.FloatTensor itype = torch.cuda.LongTensor if use_cuda else torch.LongTensor
4.2 數(shù)據(jù)預(yù)處理
該函數(shù)作用:將數(shù)據(jù)集中的某張圖片打印出來。
def imshow(inp, title=None):
# 將一張圖打印顯示出來,inp為一個(gè)張量,title為顯示在圖像上的文字
# 一般的張量格式為:channels * image_width * image_height
# 而一般的圖像為 image_width * image_height * channels
# 所以,需要將張量中的 channels 轉(zhuǎn)換到最后一個(gè)維度
inp = inp.numpy().transpose((1, 2, 0))
#由于在讀入圖像的時(shí)候所有圖像的色彩都標(biāo)準(zhǔn)化了,因此我們需要先調(diào)回去
mean = np.array([0.485, 0.456, 0.406])
std = np.array([0.229, 0.224, 0.225])
inp = std * inp + mean
inp = np.clip(inp, 0, 1)
#將圖像繪制出來
plt.imshow(inp)
if title is not None:
plt.title(title)
plt.pause(0.001) # 暫停一會(huì)是為了能夠?qū)D像顯示出來。
將訓(xùn)練數(shù)據(jù)集的第一個(gè) batch 繪制出來:
#獲取第一個(gè)圖像batch和標(biāo)簽 images, labels = next(iter(train_loader)) # 將這個(gè)batch中的圖像制成表格繪制出來 out = torchvision.utils.make_grid(images) imshow(out, title=[train_dataset.classes[x] for x in labels])

4.3 創(chuàng)建模型
該實(shí)驗(yàn)先訓(xùn)練一個(gè)普通的卷積神經(jīng)網(wǎng)絡(luò),但正確率勉強(qiáng)達(dá)到50%上下。模型預(yù)測的效果很差。因?yàn)樵搶?shí)驗(yàn)選用的是螞蟻和蜜蜂的圖像數(shù)據(jù),本身就很難識別,簡單的卷積神經(jīng)網(wǎng)絡(luò)應(yīng)付不了這種復(fù)雜的情況。其次,該實(shí)驗(yàn)的圖片訓(xùn)練樣本只有244個(gè),數(shù)量級太小。
代碼略
簡單卷積神經(jīng)網(wǎng)絡(luò)取得的效果:(黃色曲線是測試數(shù)據(jù)集錯(cuò)誤率,藍(lán)色曲線是訓(xùn)練數(shù)據(jù)集錯(cuò)誤率。)

因此,這里提到使用“加載已訓(xùn)練好的 ResNet 進(jìn)行遷移學(xué)習(xí)”。
ResNet 是微軟亞洲研究院何凱明團(tuán)隊(duì)開發(fā)的一種極深的特殊的卷積神經(jīng)網(wǎng)絡(luò)。該網(wǎng)絡(luò)的原始版本曾號稱是“史上最深的網(wǎng)絡(luò)”,有 152 層,在物體分類等任務(wù)上具有較高的準(zhǔn)確度。

考慮到原始的 ResNet 具有較大的復(fù)雜性,在本次實(shí)驗(yàn)中,實(shí)際遷移的是一個(gè)具有 18 層的精簡版的 ResNet。該網(wǎng)絡(luò)由 18 個(gè)串聯(lián)在一起的卷積模塊構(gòu)成,其中每一個(gè)卷積模塊都包括一層卷積一層池化。下面將加載 ResNet 模型,并觀察模型的組成部分。如果是第一次運(yùn)行,那么模型會(huì)被下載到 ~/.torch/models/ 文件夾中。
torch.utils.model_zoo.load_url('http://labfile.oss.aliyuncs.com/courses/1073/resnet18-5c106cde.pth')
# 加載模型庫中的residual network,并設(shè)置pretrained為true,這樣便可加載相應(yīng)的權(quán)重
net = models.resnet18(pretrained=True)
#如果存在GPU,就將網(wǎng)絡(luò)加載到GPU上
net = net.cuda() if use_cuda else net
# 將網(wǎng)絡(luò)的架構(gòu)打印出來
net
從模型的組成部分中,可以看到最后有一層全連接層,也就是 (fc): Linear(in_features=512, out_features=1000)。
4.3.1 構(gòu)建遷移模型
下面把 ResNet18 中的卷積模塊作為特征提取層遷移過來,用于提取局部特征。同時(shí),將 ResNet18 中最后的全連接層(fc)替換,構(gòu)建一個(gè)包含 512 個(gè)隱含節(jié)點(diǎn)的全連接層,后接兩個(gè)結(jié)點(diǎn)的輸出層,用于最后的分類輸出。
整個(gè)模型的前面大部分的結(jié)構(gòu)都是 ResNet,最后兩層被替換成了自定義的全連接層。

# 讀取最后線性層的輸入單元數(shù),這是前面各層卷積提取到的特征數(shù)量 num_ftrs = net.fc.in_features # 重新定義一個(gè)全新的線性層,它的輸出為2,原本是1000 net.fc = nn.Linear(num_ftrs, 2) #如果存在GPU則將網(wǎng)絡(luò)加載到GPU中 net.fc = net.fc.cuda() if use_cuda else net.fc criterion = nn.CrossEntropyLoss() #Loss函數(shù)的定義 # 將網(wǎng)絡(luò)的所有參數(shù)放入優(yōu)化器中 optimizer = optim.SGD(net.parameters(), lr = 0.0001, momentum=0.9)
4.3.2 訓(xùn)練模型+測試+繪制圖表
在訓(xùn)練階段,遷移過來的 ResNet 模塊的結(jié)構(gòu)和所有超參數(shù)都可以保持不變,但是權(quán)重參數(shù)則有可能被新的數(shù)據(jù)重新訓(xùn)練。是否要更新這些舊模塊的權(quán)重參數(shù)完全取決于我們采取的遷移學(xué)習(xí)方式。
遷移學(xué)習(xí)主要有兩種模式:預(yù)訓(xùn)練模式和固定值模式。
接下來會(huì)分別介紹
4.3.2.1 預(yù)訓(xùn)練模式
record = [] #記錄準(zhǔn)確率等數(shù)值的容器
#開始訓(xùn)練循環(huán)
num_epochs = 20
net.train(True) # 給網(wǎng)絡(luò)模型做標(biāo)記,標(biāo)志說模型在訓(xùn)練集上訓(xùn)練
best_model = net
best_r = 0.0
for epoch in range(num_epochs):
#optimizer = exp_lr_scheduler(optimizer, epoch)
train_rights = [] #記錄訓(xùn)練數(shù)據(jù)集準(zhǔn)確率的容器
train_losses = []
for batch_idx, (data, target) in enumerate(train_loader): #針對容器中的每一個(gè)批進(jìn)行循環(huán)
data, target = Variable(data), Variable(target) #將Tensor轉(zhuǎn)化為Variable,data為圖像,target為標(biāo)簽
#如果存在GPU則將變量加載到GPU中
if use_cuda:
data, target = data.cuda(), target.cuda()
output = net(data) #完成一次預(yù)測
loss = criterion(output, target) #計(jì)算誤差
optimizer.zero_grad() #清空梯度
loss.backward() #反向傳播
optimizer.step() #一步隨機(jī)梯度下降
right = rightness(output, target) #計(jì)算準(zhǔn)確率所需數(shù)值,返回正確的數(shù)值為(正確樣例數(shù),總樣本數(shù))
train_rights.append(right) #將計(jì)算結(jié)果裝到列表容器中
loss = loss.cpu() if use_cuda else loss
train_losses.append(loss.data.numpy())
#if batch_idx % 20 == 0: #每間隔100個(gè)batch執(zhí)行一次
#train_r為一個(gè)二元組,分別記錄訓(xùn)練集中分類正確的數(shù)量和該集合中總的樣本數(shù)
train_r = (sum([tup[0] for tup in train_rights]), sum([tup[1] for tup in train_rights]))
#在測試集上分批運(yùn)行,并計(jì)算總的正確率
net.eval() #標(biāo)志模型當(dāng)前為運(yùn)行階段
test_loss = 0
correct = 0
vals = []
#對測試數(shù)據(jù)集進(jìn)行循環(huán)
for data, target in val_loader:
#如果存在GPU則將變量加載到GPU中
if use_cuda:
data, target = data.cuda(), target.cuda()
data, target = Variable(data, requires_grad=True), Variable(target)
output = net(data) #將特征數(shù)據(jù)喂入網(wǎng)絡(luò),得到分類的輸出
val = rightness(output, target) #獲得正確樣本數(shù)以及總樣本數(shù)
vals.append(val) #記錄結(jié)果
#計(jì)算準(zhǔn)確率
val_r = (sum([tup[0] for tup in vals]), sum([tup[1] for tup in vals]))
val_ratio = 1.0*val_r[0].numpy()/val_r[1]
if val_ratio > best_r:
best_r = val_ratio
best_model = copy.deepcopy(net)
#打印準(zhǔn)確率等數(shù)值,其中正確率為本訓(xùn)練周期Epoch開始后到目前撮的正確率的平均值
print('訓(xùn)練周期: {} \tLoss: {:.6f}\t訓(xùn)練正確率: {:.2f}%, 校驗(yàn)正確率: {:.2f}%'.format(
epoch, np.mean(train_losses), 100. * train_r[0].numpy() / train_r[1], 100. * val_r[0].numpy()/val_r[1]))
record.append([np.mean(train_losses), 1. * train_r[0].data.numpy() / train_r[1], 1. * val_r[0].data.numpy() / val_r[1]])
#繪制訓(xùn)練誤差曲線
x = [x[0] for x in record]
y = [1 - x[1] for x in record]
z = [1 - x[2] for x in record]
#plt.plot(x)
plt.figure(figsize = (10, 7))
plt.plot(y)
plt.plot(z)
plt.xlabel('Epoch')
plt.ylabel('Error Rate')
測試模型,繪制分類效果
def visualize_model(model, num_images=6):
images_so_far = 0
fig = plt.figure(figsize=(15,10))
for i, data in enumerate(val_loader):
inputs, labels = data
inputs, labels = Variable(inputs), Variable(labels)
if use_cuda:
inputs, labels = inputs.cuda(), labels.cuda()
outputs = model(inputs)
_, preds = torch.max(outputs.data, 1)
preds = preds.cpu().numpy() if use_cuda else preds.numpy()
for j in range(inputs.size()[0]):
images_so_far += 1
ax = plt.subplot( 2,num_images//2, images_so_far)
ax.axis('off')
ax.set_title('predicted: {}'.format(val_dataset.classes[preds[j]]))
imshow(data[0][j])
if images_so_far == num_images:
return
visualize_model(net)
plt.ioff()
plt.show()

4.3.2.2 固定值模式
遷移過來的部分網(wǎng)絡(luò)在結(jié)構(gòu)和權(quán)重上都保持固定的數(shù)值不會(huì)改變。
要想讓模型在固定值模式下訓(xùn)練,需要先鎖定網(wǎng)絡(luò)模型相關(guān)位置的參數(shù)。鎖定的方法非常簡單,只要把網(wǎng)絡(luò)的梯度反傳標(biāo)志 requires_grad 設(shè)置為 False 就可以了。
# 加載residual網(wǎng)絡(luò)模型
net = torchvision.models.resnet18(pretrained=True)
# 將模型放入GPU中
net = net.cuda() if use_cuda else net
# 循環(huán)網(wǎng)絡(luò),將所有參數(shù)設(shè)為不更新梯度信息
for param in net.parameters():
param.requires_grad = False
# 將網(wǎng)絡(luò)最后一層線性層換掉
num_ftrs = net.fc.in_features
net.fc = nn.Linear(num_ftrs, 2)
net.fc = net.fc.cuda() if use_cuda else net.fc
criterion = nn.CrossEntropyLoss() #Loss函數(shù)的定義
# 僅將線性層的參數(shù)放入優(yōu)化器中
optimizer = optim.SGD(net.fc.parameters(), lr = 0.001, momentum=0.9)
#訓(xùn)練模型
record = [] #記錄準(zhǔn)確率等數(shù)值的容器
#開始訓(xùn)練循環(huán)
num_epochs = 4
net.train(True) # 給網(wǎng)絡(luò)模型做標(biāo)記,標(biāo)志說模型在訓(xùn)練集上訓(xùn)練
best_model = net
best_r = 0.0
for epoch in range(num_epochs):
#optimizer = exp_lr_scheduler(optimizer, epoch)
train_rights = [] #記錄訓(xùn)練數(shù)據(jù)集準(zhǔn)確率的容器
train_losses = []
for batch_idx, (data, target) in enumerate(train_loader): #針對容器中的每一個(gè)批進(jìn)行循環(huán)
data, target = Variable(data), Variable(target) #將Tensor轉(zhuǎn)化為Variable,data為圖像,target為標(biāo)簽
if use_cuda:
data, target = data.cuda(), target.cuda()
output = net(data) #完成一次預(yù)測
loss = criterion(output, target) #計(jì)算誤差
optimizer.zero_grad() #清空梯度
loss.backward() #反向傳播
optimizer.step() #一步隨機(jī)梯度下降
right = rightness(output, target) #計(jì)算準(zhǔn)確率所需數(shù)值,返回正確的數(shù)值為(正確樣例數(shù),總樣本數(shù))
train_rights.append(right) #將計(jì)算結(jié)果裝到列表容器中
loss = loss.cpu() if use_cuda else loss
train_losses.append(loss.data.numpy())
#train_r為一個(gè)二元組,分別記錄訓(xùn)練集中分類正確的數(shù)量和該集合中總的樣本數(shù)
train_r = (sum([tup[0] for tup in train_rights]), sum([tup[1] for tup in train_rights]))
#在測試集上分批運(yùn)行,并計(jì)算總的正確率
net.eval() #標(biāo)志模型當(dāng)前為運(yùn)行階段
test_loss = 0
correct = 0
vals = []
#對測試數(shù)據(jù)集進(jìn)行循環(huán)
for data, target in val_loader:
data, target = Variable(data, requires_grad=True), Variable(target)
if use_cuda:
data, target = data.cuda(), target.cuda()
output = net(data) #將特征數(shù)據(jù)喂入網(wǎng)絡(luò),得到分類的輸出
val = rightness(output, target) #獲得正確樣本數(shù)以及總樣本數(shù)
vals.append(val) #記錄結(jié)果
#計(jì)算準(zhǔn)確率
val_r = (sum([tup[0] for tup in vals]), sum([tup[1] for tup in vals]))
val_ratio = 1.0*val_r[0].numpy()/val_r[1]
if val_ratio > best_r:
best_r = val_ratio
best_model = copy.deepcopy(net)
#打印準(zhǔn)確率等數(shù)值,其中正確率為本訓(xùn)練周期Epoch開始后到目前撮的正確率的平均值
print('訓(xùn)練周期: {} \tLoss: {:.6f}\t訓(xùn)練正確率: {:.2f}%, 校驗(yàn)正確率: {:.2f}%'.format(
epoch, np.mean(train_losses), 100. * train_r[0].numpy() / train_r[1], 100. * val_r[0].numpy()/val_r[1]))
record.append([np.mean(train_losses), 1. * train_r[0].data.numpy() / train_r[1], 1. * val_r[0].data.numpy() / val_r[1]])
# 繪制誤差曲線
x = [x[0] for x in record]
y = [1 - x[1] for x in record]
z = [1 - x[2] for x in record]
#plt.plot(x)
plt.figure(figsize = (10, 7))
plt.plot(y)
plt.plot(z)
plt.xlabel('Epoch')
plt.ylabel('Error Rate')
#展示分類結(jié)果
visualize_model(best_model)
plt.ioff()
plt.show()

4.4 結(jié)論
該實(shí)驗(yàn)中,預(yù)訓(xùn)練遷移模型取得的效果整體的錯(cuò)誤率比簡單卷積神經(jīng)網(wǎng)絡(luò)低了很多。訓(xùn)練錯(cuò)誤率可以穩(wěn)定在 0.02 之下,測試錯(cuò)誤率大約在 0.07 左右。因?yàn)樵陬A(yù)訓(xùn)練模式下,模型對訓(xùn)練數(shù)據(jù)的擬合性比較強(qiáng),所以訓(xùn)練錯(cuò)誤率與測試錯(cuò)誤率差別較大。
在固定值遷移模式下,訓(xùn)練錯(cuò)誤率可以在 0.02 ~ 0.04 之間,比預(yù)訓(xùn)練模式稍高。測試錯(cuò)誤率大約在 0.07 左右,與預(yù)訓(xùn)練模式差不多。
因?yàn)楣潭ㄖ的J芥i定了大部分權(quán)重,模型對訓(xùn)練數(shù)據(jù)的擬合性沒那么強(qiáng),所以訓(xùn)練錯(cuò)誤率與測試錯(cuò)誤率的差別也沒那么大。
到此這篇關(guān)于PyTorch 遷移學(xué)習(xí)實(shí)戰(zhàn)的文章就介紹到這了,更多相關(guān)PyTorch 遷移內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用scrapy實(shí)現(xiàn)爬網(wǎng)站例子和實(shí)現(xiàn)網(wǎng)絡(luò)爬蟲(蜘蛛)的步驟
本文分二個(gè)示例,第一個(gè)是個(gè)簡單的爬網(wǎng)站的小例子,第二個(gè)例子實(shí)現(xiàn)目是從一個(gè)網(wǎng)站的列表頁抓取文章列表,然后存入數(shù)據(jù)庫中,數(shù)據(jù)庫包括文章標(biāo)題、鏈接、時(shí)間,大家參考使用吧2014-01-01
Python編程實(shí)現(xiàn)二分法和牛頓迭代法求平方根代碼
這篇文章主要介紹了Python編程實(shí)現(xiàn)二分法和牛頓迭代法求平方根代碼,具有一定參考價(jià)值,需要的朋友可以了解下。2017-12-12
jupyter 使用Pillow包顯示圖像時(shí)inline顯示方式
這篇文章主要介紹了jupyter 使用Pillow包顯示圖像時(shí)inline顯示方式,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-04-04
python requests 庫請求帶有文件參數(shù)的接口實(shí)例
今天小編就為大家分享一篇python requests 庫請求帶有文件參數(shù)的接口實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-01-01
Python+PyQt5實(shí)現(xiàn)開發(fā)Memcached客戶端
這篇文章主要介紹了如何使用Python和PyQt5來制作一個(gè)Memcached客戶端,以便我們可以輕松地與Memcached服務(wù)器進(jìn)行交互,感興趣的小伙伴可以了解一下2023-06-06
pytorch報(bào)錯(cuò)問題:ValueError: num_samples should be
這篇文章主要介紹了pytorch報(bào)錯(cuò)問題:ValueError: num_samples should be a positive integer value, but got num_samples=0的解決方案,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-02-02
解決import tensorflow導(dǎo)致jupyter內(nèi)核死亡的問題
這篇文章主要介紹了解決import tensorflow導(dǎo)致jupyter內(nèi)核死亡的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02

