python-3.x - Keras - 我如何训练多类模型?
问题描述
我是机器学习的新手,我遵循了一些 youtube 指南,并且能够仅使用 2 类图像从头开始制作图像分类器。
但是现在我很迷茫。我不确定如何制作多类图像分类器。不过,我收集了一些线索,例如使用"categorical_crossentrpy"
and softmax
。但我的问题是如何在将图像送入训练之前处理图像?
所以我有 3 个文件夹,每个文件夹大约有 2000 张图片:Tree
, Foilage
&Stump
我可以model.fit
使用binary_crossentropy
and来执行sigmoid
。但是,损失和 val_loss 为负值。
当我尝试model.fit
使用categorical_crossentropy
and运行softmax
时,它会抛出这个错误:
ValueError: You are passing a target array of shape (460, 1) while using as loss `categorical_crossentropy`. `categorical_crossentropy` expects targets to be binary matrices (1s and 0s) of shape (samples, classes). If your targets are integer classes, you can convert them to the expected format via:
from keras.utils import to_categorical
y_binary = to_categorical(y_int)
Alternatively, you can use the loss function `sparse_categorical_crossentropy` instead, which does expect integer targets.
这是处理代码:顺便说一下,我所有的代码都是用 Jupyter 编写的。很抱歉,如果它很乱。我已经尽力了。
import numpy as np
import matplotlib.pyplot as plt
import os
import cv2
from tqdm import tqdm
DATADIR = "assets"
CATEGORIES = ["Tree", "Stump", "Ground"]
for category in CATEGORIES:
path = os.path.join(DATADIR,category)
for img in os.listdir(path):
img_array = cv2.imread(os.path.join(path,img) ,cv2.IMREAD_GRAYSCALE)
plt.imshow(img_array, cmap='gray')
plt.show()
break
break
print(img_array)
print(img_array.shape)
IMG_SIZE = 150
new_array = cv2.resize(img_array, (IMG_SIZE, IMG_SIZE))
plt.imshow(new_array, cmap='gray')
plt.show()
new_array = cv2.resize(img_array, (IMG_SIZE, IMG_SIZE))
plt.imshow(new_array, cmap='gray')
plt.show()
training_data = []
def create_training_data():
for category in CATEGORIES:
path = os.path.join(DATADIR,category)
class_num = CATEGORIES.index(category)
for img in tqdm(os.listdir(path)):
try:
img_array = cv2.imread(os.path.join(path,img) ,cv2.IMREAD_GRAYSCALE)
new_array = cv2.resize(img_array, (IMG_SIZE, IMG_SIZE))
training_data.append([new_array, class_num])
except Exception as e:
print(e)
create_training_data()
print(len(training_data))
import random
random.shuffle(training_data)
X = []
y = []
for features,label in training_data:
X.append(features)
y.append(label)
#print(X[0].reshape(-1, IMG_SIZE, IMG_SIZE, 1))
X = np.array(X).reshape(-1, IMG_SIZE, IMG_SIZE, 1)
# y_len = len(y)
# y = np.array(y).reshape((y_len, 1))
print(y)
import pickle
pickle_out = open("X.pickle","wb")
pickle.dump(X, pickle_out)
pickle_out.close()
pickle_out = open("y.pickle","wb")
pickle.dump(y, pickle_out)
pickle_out.close()
这是制作模型的代码:
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Activation, Flatten
from tensorflow.keras.layers import Conv2D, MaxPooling2D
from tensorflow.keras.callbacks import TensorBoard
import pickle
import time
import keras
pickle_in = open("X.pickle","rb")
X = pickle.load(pickle_in)
pickle_in = open("y.pickle","rb")
y = pickle.load(pickle_in)
# y = keras.utils.to_categorical(y, num_classes = 3)
# print(y)
X = X/255.0
dense_layers = [0, 1, 2]
layer_sizes = [32, 64, 128]
conv_layers = [1, 2, 3]
for dense_layer in dense_layers:
for layer_size in layer_sizes:
for conv_layer in conv_layers:
NAME = "{}-conv-{}-nodes-{}-dense-{}".format(conv_layer, layer_size, dense_layer, int(time.time()))
print(NAME)
model = Sequential()
model.add(Conv2D(layer_size, (3, 3), input_shape=X.shape[1:]))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
for l in range(conv_layer-1):
model.add(Conv2D(layer_size, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
for _ in range(dense_layer):
model.add(Dense(layer_size))
model.add(Activation('relu'))
model.add(Dense(1)) # this value no change ah
model.add(Activation('softmax'))
tensorboard = TensorBoard(log_dir="logs/{}".format(NAME))
model.compile(loss='categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'],
)
model.fit(X, y,
batch_size=32,
epochs=1,
validation_split=0.3,
callbacks=[tensorboard])
我希望能够训练一个包含 3 个类的模型。
解决方案
您的代码中有几个错误。首先,最终的密集层必须具有与标签数量相同的大小(在您的情况下为 3):
model.add(Dense(1)) # Change this to be 3
model.add(Activation('softmax'))
在单个输出上使用 softmax 没有任何意义。
此外,您需要将标签向量 (y) 转换为 one-hot-encoding 表示,这样您将拥有的不是类 0,1 和 2 :([1,0,0], [0,1,0], [0,0,1]
我假设您还没有根据当前的输出的形状):
import numpy as np
num_classes = 3
y.reshape(-1) # your initial classes
Y = np.eye(num_classes )[y]
推荐阅读
- redis - 使用 Spring Data Redis 2.0.3 的缓存管理器
- javascript - HTML / Javascript - 尝试以页面指针为指导
- java - pdfbox 将 acroform 保存为普通 pdf
- javascript - 如何使用 JavaScript 使有效的 xml 文件看起来干净整洁
- rxjs - 可观察的 .map 不是函数
- linux - 删除具有写入组权限的文件
- jmeter - JMeter 变量未在 POST 请求中使用
- c++ - 在 C++/CLR 项目中引用 NuGet 包时编译器警告 C4691
- systemc - SC_CTHREAD 中的时钟类型
- python - 为什么我的数据没有被屏蔽?