神经网络学习——图像篡改

记录

这是课堂上做的一个关于图像篡改识别的题目,因为前后花的时间比较多,虽然最后实现的效果也不怎么行,但是这个过程踩了很多坑,这里记录一下。

文章目录

    • 记录
    • 前提
    • 题目分析
    • 网络搭建
      • 依赖包
      • 数据读取处理
      • 网络搭建
      • 训练参数
      • 预测函数
      • 模型保存
    • 完整源码
      • 训练以及预测的完整源码:
      • 预测的分模块源码

前提

  • 必要的GPU训练环境
  • 基础的神经网络知识
  • 这里用的环境:
    tensorflow2.8
    python3.9

题目分析

这个题目就是一个给定的数据集,里面包含训练集和测试集,需要通过训练让算法能够识别出来一张照片是否被篡改,可以上知乎搜索一下与数字图像篡改有关的文章,一般来说用传统的算法都比较难分辨,而网上也比较少统计现成的算法,而神经网络是比较常用的方式,所以就自己学着搭了一个九层的卷积神经网络,最后的识别效果相比于其他使用Resnet18等一些常规的网络差别不是很大,这个很大程度也只是因为数据集太小了。
这里提供数据集:链接:

https://pan.baidu.com/s/1g1BMMklZnU_wiUWB0Jne0Q

提取码:ddxz
–来自百度网盘超级会员V3的分享
下面是训练集里面一些的图片,
fake:
神经网络学习——图像篡改_第1张图片
real:
神经网络学习——图像篡改_第2张图片
数据集只有一千多张照片,而要在一千多张照片里面去训练出一个比较好的网络模型是比较难的,而这份代码最后实现的效果也只是65%左右的识别正确率,而我们通过人工测试得到的参考准确率大约为75%。
这里面话可以给大家推荐一个其他的真假人脸的数据集,下面这个数据集有14万的照片:

https://www.kaggle.com/xhlulu/140k-real-and-fake-faces

但是要注意这两个数据的特征不一样,也就是说在用第二个数据来训练在第一个数据集的测试集是没有办法正确预测的(最起码在我这个模型里面是这样)。

网络搭建

用到的网络层:卷积层、池化层、平直层、全连接层
这些基本的概念大家可以自行学习,因为我的这份代码是用的TensorFlow框架搭建的,建议没基础的同学可以去参考这个从零搭建神经网络:

https://blog.csdn.net/weixin_44127327/article/details/121795916

依赖包

from keras.models import Sequential
from keras.layers import Conv2D, Flatten, Dense,MaxPool2D
import numpy as np
from keras.preprocessing import image
from keras.callbacks import EarlyStopping, ModelCheckpoint
import tensorflow as tf
from keras.preprocessing.image import ImageDataGenerator
import matplotlib.pyplot as plt
import os

try:
    from tensorflow.python.util import module_wrapper as deprecation
except ImportError:
    from tensorflow.python.util import deprecation_wrapper as deprecation
deprecation._PER_MODULE_WARNING_LIMIT = 0

数据读取处理

#定义batchsize
nbatch = 128
train_datagen = ImageDataGenerator(#数据集生成器,这里做了数据增强
    rescale=1./255,
    rotation_range=10.,
    width_shift_range=0.1,
    height_shift_range=0.1,
    zoom_range=0.2,
    horizontal_flip=True)

test_datagen = ImageDataGenerator(rescale = 1./255)

training_set = train_datagen.flow_from_directory('dataset/real_and_fake_face_training',#训练集路径
                                                 target_size=(128,128),
                                                 batch_size =nbatch,
                                                 class_mode = 'binary')

test_set = test_datagen.flow_from_directory('dataset/real_and_fake_face_validation',#验证集路径
                                            target_size=(128,128),
                                            batch_size =nbatch,
                                            class_mode = 'binary')

网络搭建

这里面就是卷积池化、卷积池化,这里并没有用上什么技巧性的东西

model = Sequential()

model.add(Conv2D(32, kernel_size=(3, 3),
                 activation='relu',
                 input_shape=(128,128,3)))
#output (128-3)/1+1=126
model.add(MaxPool2D(pool_size=(2,2)))#这里的步长默认为池化核尺寸
#outpu (126-2)/2+1=63
model.add(Conv2D(64, kernel_size=(3, 3),
                 activation='relu'))
#output=(63-3)/1+1=61
model.add(MaxPool2D(pool_size=(2,2)))
#output=(61-2)/2+1=30
model.add(Conv2D(128, kernel_size=(3, 3),
                 activation='relu'))
#output=(30-3)+1=28
model.add(MaxPool2D(pool_size=(2,2)))
#output=(28-2)/2+1=14
model.add(Flatten())
#output=14*14*128=25088
model.add(Dense(activation="relu",
                units=256))

model.add(Dense(activation="sigmoid",
                units=1))

model.summary()         #输出网络结构

训练参数

model.compile(optimizer = 'adam',
              loss = 'binary_crossentropy',
              metrics = ['accuracy'])



callbacks_list = [
    EarlyStopping(monitor='val_loss', patience=5),
   #model.save('.\\static_model\\static_my_model_test.h5'),
    ModelCheckpoint(filepath='.\\static_model\\my_model.hdf5', monitor='val_loss', save_best_only=True, mode ='max'),

]


history = model.fit_generator(
        training_set,
        steps_per_epoch=12, #这里面需要注意这个 这个是每个epoch的分步操作,最好能够设置为训练集总数/batchsize
        epochs=10,
        validation_data=test_set,
        validation_steps=4, #这个同理,但是这个是对验证集的总数来说
        callbacks = callbacks_list #设置断电回调函数
    )

预测函数

这里的预测函数,可以根据需要自行调整,重点是需要使用model.predict(test_image)

def ImagePrediction(loc):
    testlen=len(os.listdir(loc))
    print("len(os.listdir(loc))=",len(os.listdir(loc)))
    pre_array=np.zeros(testlen)
    labels_array=np.loadtxt(",\\dataset\\label.txt",usecols=0)
    human_labels_array = np.loadtxt(".\\dataset\\human_label.txt", usecols=0)
    #print("labels_array=",labels_array)
    for i in range(1,len(os.listdir(loc))+1):
        path=loc+"\\img{}.jpg".format(i)
        #print("path=",path)
        test_image = image.load_img(path, target_size = (128,128))
        #plt.axis('off')
        #plt.imshow(test_image)
        test_image = image.img_to_array(test_image)
        test_image = np.expand_dims(test_image, axis =0)
        result = model.predict(test_image)
        if result[0][0] == 1:
            predictions = 'Real'
            pre_array[i-1]=1
        else:
            predictions = 'Fake'
            pre_array[i - 1] =-1
        #print('Prediction: ',predictions)
        print("第{}幅图:{}".format(i,predictions))
    #print("pre_array=",pre_array)
    turenum=0
    human_truenum=0
    for i in range(testlen):
        if pre_array[i]==labels_array[i]:
            turenum+=1
        if human_labels_array[i]==labels_array[i]:
            human_truenum+=1
    accuracy=turenum/testlen
    ##
    Ref_accuarcy=human_truenum/testlen
    print("Ref_accuarcy=",Ref_accuarcy,"accuracy=",accuracy)

模型保存

这里面的代码是直接把训练和预测放一起了,但是最好把两个分开,每次训练完把模型保存下来,方便下次的测试使用,而不用每次都重新训练。
模型保存的函数:

model.save('.\\static_model\\static_my_model.h5')

需要使用就加载:

model = load_model('.\\static_model\\static_my_model.h5')

完整源码

训练以及预测的完整源码:

from keras.models import Sequential
from keras.layers import Conv2D, Flatten, Dense,MaxPool2D
import numpy as np
from keras.preprocessing import image
from keras.callbacks import EarlyStopping, ModelCheckpoint
import tensorflow as tf
from keras.preprocessing.image import ImageDataGenerator
import matplotlib.pyplot as plt
import os

try:
    from tensorflow.python.util import module_wrapper as deprecation
except ImportError:
    from tensorflow.python.util import deprecation_wrapper as deprecation
deprecation._PER_MODULE_WARNING_LIMIT = 0

#定义batchsize
nbatch = 128
train_datagen = ImageDataGenerator(
    rescale=1./255,
    #rotation_range=10.,
    #width_shift_range=0.1,
    #height_shift_range=0.1,
    #zoom_range=0.2,
    #horizontal_flip=True
    )

test_datagen = ImageDataGenerator(rescale = 1./255)

training_set = train_datagen.flow_from_directory('dataset/teach_train',
                                                 target_size=(128,128),
                                                 batch_size =nbatch,
                                                 class_mode = 'binary')

test_set = test_datagen.flow_from_directory('dataset/github_val',
                                            target_size=(128,128),
                                            batch_size =nbatch,
                                            class_mode = 'binary')


h1 = plt.hist(training_set.classes, bins=range(0,3), alpha=0.8, color='blue', edgecolor='black')
h2 = plt.hist(test_set.classes,  bins=range(0,3), alpha=0.8, color='red', edgecolor='black')
plt.ylabel('# of instances')
plt.xlabel('Class')
plt.show()
"""for X, y in training_set:
    print(X.shape, y.shape)
    plt.figure(figsize=(16,16))
    for i in range(16):
        plt.subplot(4,4,i+1)
        plt.axis('off')
        plt.title('Label: ')
        img = np.uint8(255*X[i,:,:,0])
        plt.imshow(img, cmap='gray')
    break
plt.show()"""

model = Sequential()

model.add(Conv2D(32, kernel_size=(3, 3),
                 activation='relu',
                 input_shape=(128,128,3)))
#output (128-3)/1+1=126
model.add(MaxPool2D(pool_size=(2,2)))#这里的步长默认为池化核尺寸
#outpu (126-2)/2+1=63
model.add(Conv2D(64, kernel_size=(3, 3),
                 activation='relu'))
#output=(63-3)/1+1=61
model.add(MaxPool2D(pool_size=(2,2)))
#output=(61-2)/2+1=30
model.add(Conv2D(128, kernel_size=(3, 3),
                 activation='relu'))
#output=(30-3)+1=28
model.add(MaxPool2D(pool_size=(2,2)))
#output=(28-2)/2+1=14
model.add(Flatten())
#output=14*14*128=25088
model.add(Dense(activation="relu",
                units=256))

model.add(Dense(activation="sigmoid",
                units=1))

model.summary()

model.compile(optimizer = 'adam',
              loss = 'binary_crossentropy',
              metrics = ['accuracy'])



callbacks_list = [
    EarlyStopping(monitor='val_loss', patience=5),
   #model.save('.\\static_model\\static_my_model_test.h5'),
    ModelCheckpoint(filepath='.\\static_model\\my_model.hdf5', monitor='val_loss', save_best_only=True, mode ='max'),

]


history = model.fit_generator(
        training_set,
        steps_per_epoch=12, #这里面需要注意这个 这个是每个epoch的分步操作,最好能够设置为训练集总数/batchsize
        epochs=10,
        validation_data=test_set,
        validation_steps=4, #这个同理,但是这个是对验证集的总数来说
        callbacks = callbacks_list #设置断电回调函数
    )

print(training_set.class_indices)




def ImagePrediction(loc):
    testlen=len(os.listdir(loc))
    print("len(os.listdir(loc))=",len(os.listdir(loc)))
    pre_array=np.zeros(testlen)
    labels_array=np.loadtxt(",\\dataset\\label.txt",usecols=0)
    human_labels_array = np.loadtxt(".\\dataset\\human_label.txt", usecols=0)
    #print("labels_array=",labels_array)
    for i in range(1,len(os.listdir(loc))+1):
        path=loc+"\\img{}.jpg".format(i)
        #print("path=",path)
        test_image = image.load_img(path, target_size = (128,128))
        #plt.axis('off')
        #plt.imshow(test_image)
        test_image = image.img_to_array(test_image)
        test_image = np.expand_dims(test_image, axis =0)
        result = model.predict(test_image)
        if result[0][0] == 1:
            predictions = 'Real'
            pre_array[i-1]=1
        else:
            predictions = 'Fake'
            pre_array[i - 1] =-1
        #print('Prediction: ',predictions)
        print("第{}幅图:{}".format(i,predictions))
    #print("pre_array=",pre_array)
    turenum=0
    human_truenum=0
    for i in range(testlen):
        if pre_array[i]==labels_array[i]:
            turenum+=1
        if human_labels_array[i]==labels_array[i]:
            human_truenum+=1
    accuracy=turenum/testlen
    ##
    Ref_accuarcy=human_truenum/testlen
    print("Ref_accuarcy=",Ref_accuarcy,"accuracy=",accuracy)





#下面填写图片路径进行测试
img =".\\dataset\\real_and_fake_face_testing\\real_and_fake_face_testing"
test_image_1 = ImagePrediction(img)

plt.figure(figsize=(16,6))
plt.subplot(1,2,1)
nepochs=len(history.history['loss'])
plt.plot(range(nepochs), history.history['loss'],     'r-', label='train')
plt.plot(range(nepochs), history.history['val_loss'], 'b-', label='val')
plt.legend(prop={'size': 20})
plt.ylabel('loss')
plt.xlabel('# of epochs')
plt.subplot(1,2,2)
plt.plot(range(nepochs), history.history['accuracy'],     'r-', label='train')
plt.plot(range(nepochs), history.history['val_accuracy'], 'b-', label='val')
plt.legend(prop={'size': 20})
plt.ylabel('accuracy')
plt.xlabel('# of epochs')
plt.show()
model.save('.\\static_model\\static_my_model.h5')

预测的分模块源码

这个是为了方便可以独立加载不同的训练参数的模型来进行测试

from keras.models import Sequential
from keras.layers import Conv2D, Flatten, Dense,MaxPool2D
import numpy as np
from keras.preprocessing import image
from keras.callbacks import EarlyStopping, ModelCheckpoint
import tensorflow as tf
from keras.preprocessing.image import ImageDataGenerator
import matplotlib.pyplot as plt
from keras.models import load_model
import os

try:
    from tensorflow.python.util import module_wrapper as deprecation
except ImportError:
    from tensorflow.python.util import deprecation_wrapper as deprecation
deprecation._PER_MODULE_WARNING_LIMIT = 0

import tensorflow as tf
gpus = tf.config.experimental.list_physical_devices(device_type='GPU')
tf.config.experimental.set_virtual_device_configuration(gpus[0], [tf.config.experimental.
                                                        VirtualDeviceConfiguration(memory_limit=2048)])  # 限制最大显存使用1G



def ImagePrediction(loc):
    testlen=len(os.listdir(loc))
    print("len(os.listdir(loc))=",len(os.listdir(loc)))
    pre_array=np.zeros(testlen)
    labels_array=np.loadtxt(".\\dataset\\label.txt",usecols=0)
    human_labels_array = np.loadtxt(".\\dataset\\human_label.txt", usecols=0)
    #print("labels_array=",labels_array)
    for i in range(1,len(os.listdir(loc))+1):
        path=loc+"\\img{}.jpg".format(i)
        #print("path=",path)
        test_image = image.load_img(path, target_size = (128,128))
        #plt.axis('off')
        #plt.imshow(test_image)
        test_image = image.img_to_array(test_image)
        test_image = np.expand_dims(test_image, axis =0)
        result = model.predict(test_image)
        if result[0][0] == 1:
            predictions = 'Real'
            pre_array[i-1]=1
        else:
            predictions = 'Fake'
            pre_array[i - 1] =-1
        #print('Prediction: ',predictions)
        print("第{}幅图:{},pred={}".format(i,predictions,pre_array[i - 1]))
    #print("pre_array=",pre_array)
    turenum=0
    human_truenum=0
    for i in range(testlen):
        if pre_array[i]==labels_array[i]:
            turenum+=1
            print("第{}个正确".format(i+1))
        if human_labels_array[i]==labels_array[i]:
            human_truenum+=1
            #print("第{}个正确".format(i))
    accuracy=turenum/testlen
    ##
    Ref_accuarcy=human_truenum/testlen
    print("Ref_accuarcy=",Ref_accuarcy,"accuracy=",accuracy,"正确个数=",turenum)



#下面填写图片路径进行测试

model = load_model('.\\static_model\\static_my_model.h5')
img =".\\dataset\\real_and_fake_face_testing\\real_and_fake_face_testing"
test_image_1 = ImagePrediction(img)

你可能感兴趣的:(学习记录,人工智能,卷积神经网络)