复现改造AlexNet,无法收敛,acc一直是0.5左右,检查了很多方面还是找不出问题
Created by: hubu-wangpei
如题,根据paddle的教程和图像隐写分析的模型,改造了AlexNet模型。但是在训练的时候,最后的全连接层输出的预测值都是比较小的值,在0附近(下面有图),经过sigmoid函数后的值都在0.5左右。导致acc一直在0.5上下,loss在0.69左右,试过很多网上的方法,都不行。训练集里正反例各一半,训练时,随机读取。下面是具体代码
import cv2
import random
import numpy as np
# 对读入的图像数据进行预处理
def transform_img(img):
#数据集是PGM格式的灰度图像,但是cv2读入的时候也是(256,256,3)即三通道
# 读入的图像数据格式是[H, W, C]
# 使用转置操作将其变成[C, H, W]
img = img[np.newaxis, :]
img = img.astype('float32')
#img.reshape(1,256,256)
# 将数据范围调整到[-1.0, 1.0]之间
img = img / 255.
img = img * 2.0 - 1.0
return img
# 定义训练集数据读取器
def data_loader(datadir, batch_size=10, mode = 'train'):
# 将datadir目录下的文件列出来,每条文件都要读入
filenames = os.listdir(datadir)
def reader():
if mode == 'train':
# 训练时随机打乱数据顺序
random.shuffle(filenames)
batch_imgs = []
batch_labels = []
#print(filenames[:10])
for name in filenames:
filepath = os.path.join(datadir, name)
img = cv2.imread(filepath,0)
img = transform_img(img)
if name[0] == 'c' :
# c开头的文件名表示载体图片,cover
# 属于负样本,标签为0
label = 0
elif name[0] == 's':
# S开头的是载密图像,属于正样本,标签为1
label = 1
else:
print(name)
raise('Not excepted file name')
# 每读取一个样本的数据,就将其放入数据列表中
batch_imgs.append(img)
batch_labels.append(label)
if len(batch_imgs) == batch_size:
# 当数据列表的长度等于batch_size的时候,
# 把这些数据当作一个mini-batch,并作为数据生成器的一个输出
imgs_array = np.array(batch_imgs).astype('float32')
labels_array = np.array(batch_labels).astype('float32').reshape(-1, 1)
yield imgs_array, labels_array
batch_imgs = []
batch_labels = []
if len(batch_imgs) > 0:
# 剩余样本数目不足一个batch_size的数据,一起打包成一个mini-batch
imgs_array = np.array(batch_imgs).astype('float32')
labels_array = np.array(batch_labels).astype('float32').reshape(-1, 1)
yield imgs_array, labels_array
return reader
##########################################################
import os
import random
import paddle
import paddle.fluid as fluid
import numpy as np
DATADIR = '/home/aistudio/data/data26700/train'
DATADIR2 = '/home/aistudio/data/data26700/valid'
# 定义训练过程
def train(model):
with fluid.dygraph.guard():
print('start training ... ')
model.train()
epoch_num = 5
# 定义优化器
opt = fluid.optimizer.AdadeltaOptimizer(learning_rate=0.0003, epsilon=1.0e-6, rho=0.95, parameter_list=model.parameters())
#opt = fluid.optimizer.Momentum(learning_rate=0.001, momentum=0.4, parameter_list=model.parameters())
#opt=fluid.optimizer.SGD(learning_rate=0.001,parameter_list=model.parameters())
# 定义数据读取器,训练数据读取器和验证数据读取器
train_loader = data_loader(DATADIR, batch_size=20, mode='train')
valid_loader = data_loader(DATADIR2,batch_size=20, mode='valid' )
for epoch in range(epoch_num):
accuracies = []
for batch_id, data in enumerate(train_loader()):
x_data, y_data = data
#print(x_data,y_data)
img = fluid.dygraph.to_variable(x_data)
label = fluid.dygraph.to_variable(y_data)
# 运行模型前向计算,得到预测值
logits = model(img)
# 进行loss计算
loss = fluid.layers.sigmoid_cross_entropy_with_logits(logits, label)
avg_loss = fluid.layers.mean(loss)
pred = fluid.layers.sigmoid(logits)
# 计算预测概率小于0.5的类别
pred2 = pred * (-1.0) + 1.0
# 得到两个类别的预测概率,并沿第一个维度级联
pred = fluid.layers.concat([pred2, pred], axis=1)
acc = fluid.layers.accuracy(pred, fluid.layers.cast(label, dtype='int64'))
accuracies.append(acc.numpy())
if batch_id % 100 == 0:
print(logits)
print("epoch: {}, batch_id: {}, acc is :{} loss is: {}".format(epoch, batch_id,np.mean(accuracies), avg_loss.numpy()))
# 反向传播,更新权重,清除梯度
avg_loss.backward()
opt.minimize(avg_loss)
model.clear_gradients()
model.eval()
accuracies = []
losses = []
for batch_id, data in enumerate(valid_loader()):
x_data, y_data = data
img = fluid.dygraph.to_variable(x_data)
label = fluid.dygraph.to_variable(y_data)
# 运行模型前向计算,得到预测值
logits = model(img)
# 二分类,sigmoid计算后的结果以0.5为阈值分两个类别
# 计算sigmoid后的预测概率,进行loss计算
pred = fluid.layers.sigmoid(logits)
loss = fluid.layers.sigmoid_cross_entropy_with_logits(logits, label)
# 计算预测概率小于0.5的类别
pred2 = pred * (-1.0) + 1.0
# 得到两个类别的预测概率,并沿第一个维度级联
pred = fluid.layers.concat([pred2, pred], axis=1)
acc = fluid.layers.accuracy(pred, fluid.layers.cast(label, dtype='int64'))
accuracies.append(acc.numpy())
losses.append(loss.numpy())
print("[validation] accuracy/loss: {}/{}".format(np.mean(accuracies), np.mean(losses)))
model.train()
# save params of model
fluid.save_dygraph(model.state_dict(), 'mnist')
# save optimizer state
fluid.save_dygraph(opt.state_dict(), 'mnist')
#####################################################
import numpy as np
import paddle
import paddle.fluid as fluid
from paddle.fluid.layer_helper import LayerHelper
from paddle.fluid.dygraph.nn import Conv2D, Pool2D, BatchNorm, Linear
from paddle.fluid.dygraph.base import to_variable
from paddle.fluid.initializer import NumpyArrayInitializer
# 定义 AlexNet 网络结构
class AlexNet(fluid.dygraph.Layer):
def __init__(self, name_scope, num_classes=1):
super(AlexNet, self).__init__(name_scope)
name_scope = self.full_name()
# AlexNet与LeNet一样也会同时使用卷积和池化层提取图像特征
# 与LeNet不同的是激活函数换成了‘relu’
SRM_kernel=np.load("/home/aistudio/work/SRM_Kernels.npy")
SRM_kernel=np.transpose(SRM_kernel,[3,2,0,1])
# self.conv0 = Conv2D(num_channels=1, num_filters=30, filter_size=[5, 5],
# param_attr=fluid.ParamAttr(
# initializer=NumpyArrayInitializer(value=SRM_kernel),trainable=False))
self.conv0 = Conv2D(num_channels=1, num_filters=30, filter_size=5, stride=1, padding=0)
self.conv1 = Conv2D(num_channels=30, num_filters=30, filter_size=3, stride=1, padding=0, act='relu')
self.conv2 = Conv2D(num_channels=30, num_filters=30, filter_size=3, stride=1, padding=0, act='relu')
self.conv3 = Conv2D(num_channels=30, num_filters=30, filter_size=3, stride=1, padding=0, act='relu')
self.pool3 = Pool2D(pool_size=2, pool_stride=2, pool_type='avg')
self.conv4 = Conv2D(num_channels=30, num_filters=32, filter_size=5, stride=1, padding=0, act='relu')
self.pool4 = Pool2D(pool_size=3, pool_stride=2, pool_type='avg')
self.conv5 = Conv2D(num_channels=32, num_filters=32, filter_size=5, stride=1, padding=0, act='relu')
self.pool5 = Pool2D(pool_size=3, pool_stride=2, pool_type='avg')
self.conv6 = Conv2D(num_channels=32, num_filters=32, filter_size=5, stride=1, padding=0, act='relu')
self.pool6 = Pool2D(pool_size=3, pool_stride=2, pool_type='avg')
self.bn=BatchNorm(32, act='relu')
self.conv7 = Conv2D(num_channels=32, num_filters=16, filter_size=3, stride=1, padding=0, act='relu')
self.conv8 = Conv2D(num_channels=16, num_filters=16, filter_size=3, stride=3, padding=0, act='relu')
#self.fc1 = fluid.layers.fc(input_dim=144, output_dim=1)
import math
stdv = 1.0 / math.sqrt(2048 * 1.0)
# 创建全连接层,输出大小为类别数目
self.fc1 = Linear(input_dim=144, output_dim=1)
def forward(self, x):
x=self.conv0(x)
#print("conv1-- kernel_size:{}, padding:{}, stride:{}".format(self.conv1.weight.shape, self.conv1._padding, self.conv1._stride))
x=fluid.layers.clip(x=x, min=-3.0, max=3.0)
x = self.conv1(x)
# print(x.shape)
x = self.conv2(x)
x = self.conv3(x)
x = self.pool3(x)
x = self.conv4(x)
x = self.pool4(x)
x = self.conv5(x)
x = self.pool5(x)
x = self.conv6(x)
x = self.pool6(x)
#x =self.bn(x)
x = self.conv7(x)
x = self.conv8(x)
x = fluid.layers.reshape(x, [x.shape[0], -1])
x=self.fc1(x)
return x
use_cuda = True
place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()
with fluid.dygraph.guard(place):
model = AlexNet("AlexNet")
train(model)
每一层卷积层又加了bachnorm,但还是不收敛,下面是训练的时候的数据