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

2023-10-27

记录

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

前提

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

题目分析

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

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

提取码:ddxz
–来自百度网盘超级会员V3的分享
下面是训练集里面一些的图片,
fake:
在这里插入图片描述
real:
在这里插入图片描述
数据集只有一千多张照片,而要在一千多张照片里面去训练出一个比较好的网络模型是比较难的,而这份代码最后实现的效果也只是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)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

神经网络学习——图像篡改 的相关文章

随机推荐

  • 积分电路与低通滤波器

    一种积分电路如图1所示 当函数发生器输出方波时 理论上一个理想的积分器应该输出三角波 然而 实际应用中 在积分电容两端常常并联一个大电阻 如图2所示 这是因为实际应用中的运放具有输入失调电压和偏置电流 如果在实际应用中按照图1所示搭建积分电
  • ready()事件与load()事件的区别

    页面加载时触发ready 事件 ready 事件类似于onLoad 事件 但前者只要页面的DOM结构加载后便触发 而后者必须在页面全部元素加载成功才触发 ready 可以写多个 按顺序执行 此外 下列写法是相等的 document read
  • 深入理解Java虚拟机jvm-栈溢出-对象引用过多java.lang.StackOverflowError

    对象引用过多 示例 结果 原因分析 示例 栈溢出 栈内存过小 对象引用过多 java lang StackOverflowError 输出 stack length 344 public class Demo3 private static
  • CTFshow sql注入 上篇(web171-220)

    目录 前言 题目 web 171 万能密码 web 172 回显内容过滤 base64或者hex编码绕过 web 173 回显内容过滤 base64或者hex编码绕过 web 174 布尔盲注丶trim盲注丶replace替换字符 web
  • Cmake 中 file、message和add_executable解析

    file 为cmake中文件操作时用的语句 比如文件的创建 读写 等操作都是通过file来操作的 GLOB file GLOB variable RELATIVE path FOLLOW SYMLINKS globbing expressi
  • DVWA靶场下的sql注入之文件读写

    DVWA的安装配置在我上一篇文章上写过了 不知道的可以去看看 这里直接讲sql注入如何获得文件读写权限 sql注入读写的根本条件 1 数据库用户得是高权限用户 root 2 数据库下的secure file priv不是null 如果是也可
  • 文档在线预览(三)使用js前端实现word、excel、pdf、ppt 在线预览

    关于实现文档在线预览的做法 之前文章提到了的两种实现方式 1 通过将文档转成图片 详见 文档在线预览 一 通过将txt word pdf转成图片实现在线预览功能 2 将文档转成html 详见 文档在线预览 二 word pdf文件转html
  • 运放自激振荡的补偿

    运放的相位补偿 为了让运放能够正常工作 电路中常在输入与输出之间加一相位补偿电容 1 关于补偿电容 理论计算有是有的 但是到了设计成熟阶段好象大部分人都是凭借以前的调试经验了 一般对于电容大小的取值要考虑到系统的频响 简单点说加的电容越大
  • 职场工作与生活

    序言 和很多在CSDN的博主一样 大家在工作之后就很少或者是不再回到CSDN 确实自己也一年多没上了 因为可能当初大家在这就是为了记录和分享当初自己学习技术的东西 而大家走出象牙塔开始工作后 发生了很大的转变 在国内大多数搞技术的工作要求保
  • Beam数据流水线——Pipeline

    目录 Beam简介 基本概念 数据流水线 Beam数据流水线的应用 Beam数据流水线的处理模型 Beam数据流水线的错误处理 单Transform错误处理 多步骤Transform错误处理 Beam简介 Apache Beam 是Goog
  • 工厂的进化

    本文从一个简单示例的需求不断衍化过程 来分析理解简单工厂 工厂方法 抽象工厂模式 首先看一下初始示例 public interface Car public void drive public class BenzCar implement
  • js 实现刷新页面 保留当前tab切换状态

    div class mes tab div class tab tit flexbetween span 报考指南 span span 考研院校 span span 考研专业 span span 备考资料 span span 复试调剂 sp
  • ImportError: No module named typing

    python版本 2 7 错误 使用pip时出现该错误 Traceback most recent call last File C Python27 Scripts pip script py line 9 in load entry p
  • iframe如何发送请求_Vue 中使用 Iframe 踩坑记

    背景 创业项目使用的 Vue 开发前端 最近在开发的一个需求涉及到了 Iframe 的使用 为了让父子页面能够正常通信 头都搞大了 不过最终是解决了问题 写篇文章记录下 利人利己 难点 之前没有在 Vue 中使用过 Iframe 网上的相关
  • 【环境搭建】Docker上搭建sqli-labs漏洞环境

    目录 1 sqli labs简介 2 Docker搭建sqli labs 3 总结 参考文献 1 sqli labs简介 sq Ii labs是一款学习SQL注入的开源平台 共有75种不同类型的注入 官方介绍如下 SQLI LABS is
  • 基于VMD-SSA-LSTM的多维时序光伏功率预测

    目录 1 主要内容 变分模态分解 VMD 麻雀搜索算法SSA 长短期记忆网络LSTM 2 部分代码 3 程序结果 4 下载链接 1 主要内容 之前分享了预测的程序基于LSTM的负荷和可再生能源出力预测 核心部分复现 该程序预测效果比较好 并
  • RT-Thread uart2串口dma idle接收不断帧

    硬件STM32F407 IDE使用RT Thread Studio uart2串口使用这两个引脚 功能 IO端口 UART2 TX PA2 UART2 RX PA3 UART2 DMA接收配置 先使能DMA接收 RX缓冲区可以稍微调大些 b
  • Vuetify笔记(5):data-tables组件

    v data table 用于显示表格数据 功能包括排序 搜索 分页 行内编辑 头部提示以及行选择 而我们在实际应用中使用最多的就是服务端分页和排序 如果你从后台加载数据 并希望显示结果之前进行分页和排序 你可以使用 total items
  • 对象的构造和析构

    对象的构造和析构 1 对象的初始化和清理 构造函数 和 析构函数 被编译器自动调用完成对象初始化和对象清理工作 2 构造函数 和 析构函数 构造函数写法 与类名相同 没有返回值 不写void 可以有参数 可以发生重载 构造函数由编译器自动调
  • 神经网络学习——图像篡改

    记录 这是课堂上做的一个关于图像篡改识别的题目 因为前后花的时间比较多 虽然最后实现的效果也不怎么行 但是这个过程踩了很多坑 这里记录一下 文章目录 记录 前提 题目分析 网络搭建 依赖包 数据读取处理 网络搭建 训练参数 预测函数 模型保