python-3.x - CNN - 如何使用 keras 正确获取 val_loss 和 val_acc?
问题描述
显微镜图像为 .tif 格式,并具有以下规格:
- 颜色模型:R(ed)G(reen)B(lue)
- 尺寸:2048 x 1536 像素
- 像素尺度:0.42 μm x 0.42 μm
- 内存空间:10-20 MB(大约)
- 标签类型:图像方面
- 4 级:良性、侵入性、原位、正常
CNN科杜:
from keras.models import Sequential
from keras.layers import Conv2D
from keras.layers import MaxPooling2D
from keras.layers import Flatten
from keras.layers import Dense
classifier = Sequential()
classifier.add(Conv2D(32, (3, 3), input_shape = (64, 64, 3), activation = 'relu'))
classifier.add(MaxPooling2D(pool_size = (2, 2)))
classifier.add(Conv2D(32, (3, 3), activation = 'relu'))
classifier.add(MaxPooling2D(pool_size = (2, 2)))
classifier.add(Flatten())
classifier.add(Dense(activation = 'relu', units = 128))
classifier.add(Dense(activation = 'softmax', units = 4))
classifier.compile(optimizer = 'adam', loss = 'sparse_categorical_crossentropy', metrics = ['accuracy'])
from keras.preprocessing.image import ImageDataGenerator
train_datagen = ImageDataGenerator(rescale = 1./255,
shear_range = 0.2,
zoom_range = 0.2,
horizontal_flip = True)
test_datagen = ImageDataGenerator(rescale = 1./255,
shear_range = 0.2,
zoom_range = 0.2,
horizontal_flip = True)
training_set = train_datagen.flow_from_directory('BioImaging2015/breasthistology/Training_data',
target_size = (64, 64),
batch_size = 1,
class_mode = 'binary')
test_set = test_datagen.flow_from_directory('BioImaging2015/breasthistology/Test_data',
target_size = (64, 64),
batch_size = 1,
class_mode = 'binary')
classifier.fit_generator(training_set,
samples_per_epoch = 5000,
nb_epoch = 20,
validation_data = test_set,
nb_val_samples = len(test_set))
数据:
Found 249 images belonging to 4 classes.
Found 36 images belonging to 4 classes.
起初 test_data 在一个文件中。但他给出了一个错误
Found 0 images belonging to 0 classes.
然后我把它做成了4个文件。
输出:
Epoch 1/20
5000/5000 [==============================] - 1056s 211ms/step - loss: 1.3914 - acc: 0.2754 - val_loss: 1.3890 - val_acc: 0.2500
Epoch 2/20
5000/5000 [==============================] - 1056s 211ms/step - loss: 1.2874 - acc: 0.3740 - val_loss: 1.6325 - val_acc: 0.3333
Epoch 3/20
5000/5000 [==============================] - 1056s 211ms/step - loss: 0.7412 - acc: 0.7098 - val_loss: 1.4916 - val_acc: 0.4722
Epoch 4/20
5000/5000 [==============================] - 1056s 211ms/step - loss: 0.3380 - acc: 0.8780 - val_loss: 1.4263 - val_acc: 0.5278
Epoch 5/20
5000/5000 [==============================] - 1057s 211ms/step - loss: 0.1912 - acc: 0.9346 - val_loss: 2.1176 - val_acc: 0.4722
Epoch 6/20
5000/5000 [==============================] - 1103s 221ms/step - loss: 0.1296 - acc: 0.9568 - val_loss: 2.8661 - val_acc: 0.4167
Epoch 7/20
5000/5000 [==============================] - 1182s 236ms/step - loss: 0.0964 - acc: 0.9698 - val_loss: 3.5154 - val_acc: 0.3611
Epoch 8/20
5000/5000 [==============================] - 1245s 249ms/step - loss: 0.0757 - acc: 0.9790 - val_loss: 3.6839 - val_acc: 0.3889
Epoch 9/20
3540/5000 [====================>.........] - ETA: 5:54 - loss: 0.0664 - acc: 0.9819
以下是我的理解:
- 损失在减少,acc 在增加。因此,这表明模型经过了良好的训练。
我的问题是:
- val_acc 正在减少,而 val_loss 正在增加。为什么?这是过拟合?如果我写 dropout,acc 和 val_acc 不会增加。两损不减。
- 在 9 个 epoch 之后,acc 仍在增加。那么我应该使用更多的纪元并在 acc 停止增加时停止吗?或者我应该在 val_acc 停止增加的地方停下来?但是 val_acc 没有增加。
- cnn网络是否正确?我看不出问题出在哪里。
变化:
loss = 'sparse_categorical_crossentropy' -> loss = 'categorical_crossentropy'
class_mode = 'binary' -> class_mode = 'categorical'
输出2:
Epoch 1/20
5000/5000 [==============================] - 1009s 202ms/step - loss: 1.3878 - acc: 0.2752 - val_loss: 1.3893 - val_acc: 0.2500
Epoch 2/20
5000/5000 [==============================] - 1089s 218ms/step - loss: 1.3844 - acc: 0.2774 - val_loss: 1.3895 - val_acc: 0.2500
Epoch 3/20
5000/5000 [==============================] - 1045s 209ms/step - loss: 1.3847 - acc: 0.2764 - val_loss: 1.3894 - val_acc: 0.2500
Epoch 4/20
5000/5000 [==============================] - 1077s 215ms/step - loss: 1.3843 - acc: 0.2764 - val_loss: 1.3885 - val_acc: 0.2500
Epoch 5/20
5000/5000 [==============================] - 1051s 210ms/step - loss: 1.3841 - acc: 0.2768 - val_loss: 1.3887 - val_acc: 0.2500
Epoch 6/20
5000/5000 [==============================] - 1050s 210ms/step - loss: 1.3841 - acc: 0.2782 - val_loss: 1.3891 - val_acc: 0.2500
Epoch 7/20
5000/5000 [==============================] - 1053s 211ms/step - loss: 1.3836 - acc: 0.2780 - val_loss: 1.3900 - val_acc: 0.2500
解决方案
class_mode='binary'
由于您在最后一层有四个类和 softmax 激活,因此您对forflow_from_directory()
和loss='sparse_categorical_crossentropy'
for的选择似乎不太可能classifier.compile()
是正确的。以这种方式生成的标签没有意义。
class_mode='binary'
将生成[0,1,1,0,1,1,...]
仅对是/否预测有意义的形式的标签(因此是“二进制”),而loss='sparse_categorical_crossentropy'
期望形式的标签[1,3,2,4,3,2,1,2,...]
(每个类一个整数)。
尝试class_mode='categorical'
,loss='categorical_crossentropy'
而不是。这将生成 one-hot-encoded 标签,例如
[[0,0,1,0],
[0,1,0,0],
[0,0,0,1],
... ]
这正是loss='categorical_crossentropy'
期望得到的。最后一层的选择activation='softmax'
也非常适合这一点,因为它确保最后一层中的四个值总和为1
。
关于你的问题:
- 是的,由于标签不正确(它们没有意义),您很可能面临过度拟合。您的模型基本上是在学习随机标签(训练数据),因此在其他随机标签(验证数据)上效果不佳。
val_acc
当停止增加时你应该停止。是的,在您的情况下,这一点已经在两个时代之后达到。但对于好的模型,这是一种常见的做法。你的理解有一个缺陷:在训练数据上表现出色并不是目标!请记住,最后,您希望您的模型预测它以前从未见过的图片,因此只有验证数据才能告诉您真相。(实际上,最好有另一个在训练期间从未接触过的测试数据集,并在调用fit
或fit_generator
.- 实际网络是正确的,只是您的数据不正确(如上所述)。但是,如果在我建议的修复之后它仍然表现不佳,您将需要在卷积层中尝试更多数量的特征,并添加更多的卷积层。在中间层之后以 0.2 到 0.5 的速率退出始终是避免过度拟合的好方法。您将需要试验这些设置。
推荐阅读
- c# - WPF 从异步方法更新 UI
- python - Python散列二分搜索
- django - Django:加载 iframe 时如何获取父 url
- sqlite - 在 Android Studio 中将项目添加到第二个表 SQLite 什么都不做
- java - 如何在旋转后重新创建 LinearLayout 视图?
- javascript - 需要帮助自动刷新离线页面
- python - 从其他项目模块上的函数调用 JSON 数据以用于请求
- python - 数据框并在 for 循环中更新新列值
- python - 如何通过python的ezdxf或dxfwrite添加标签或标签(cad文件中的相同内容)?
- java - SpringData/Hibernate @ManyToOne 在不应该时自动级联