2019-05-15 10:06:01 weixin_42807063 阅读数 386
  • python全栈习题课

    【程序员工具基础】图灵系统使用,Linux初步,DevOps 【Python基础语法】函数,OOP编程,调试技术 【Python高级语法】函数式编程,多线程,携程异步,IO编程,正则 【Web 编程基础 】Socket编程,WSGI,HTTP协议实战框架项目 【主流数据库】关系型非关系性三大主流数据库,不多说 【WEB实战开发框架】Flask,Django,twisted,tornado 【自动化测试】测试工程,测试脚本,自动化测试框架 【自动化运维】自动化部署工具,服务自动化搭建 【爬虫与反爬虫】ssl,js加密,ajax处理,模拟器selemium,验证码识别,Scrapy框架使用 【计算机数学基础】线性代数,微积分,统计概率,Python数学模块 【数据分析·处理】数据清洗,NLP,回归,贝叶斯,灰度预测,聚类,数据分析实战项目 【人工智能(AI)】回归,正则,决策树,贝叶斯,SVM,聚类,关联规则,神经网络,深度学习,手写字识别,猫狗分类,情感分析,推荐系统,目标检测,机器翻译

    393 人正在学习 去看看 刘英

非监督学习

监督学习的存在它的弊端,例如对我们人类还无法分辨和归类的事物,监督学习就无法完成,所以为了弥补这个缺陷,下面我们看一下新非监督学习,它可以让计算机学会进行更加复杂的分类。

分析过程

非监督学习的构建一般由三个部分组成,数据的预处理,神经网络的搭建,然后进行训练测试,训练测试生成数据集和模型,最后倒入已知数据,让计算机对我们输入的数据进行分类。

项目案例:在这里插入图片描述

猫狗识别

知识点:

1、数据的预处理
2、搭建神经网络
3、模型的训练与储存

项目分步分析:

第一步:创建六个文件夹
在这里插入图片描述
1、log文件夹,用于存放丢失数据和数据误差
2、modelsave文件夹用于存放训练好的模型
3、train_image文件夹用于,存放猫狗的图片,这些图片是作为训练模型的数据
4、train.py 用于进行数据的预处理和模型的搭建
5、model.py 搭建神经网络
6、test.py 测试搭建好的模型,用于猫狗识别

第二步:train_image文件内容
在这里插入图片描述
在train_image文件夹中穿件名为0的文件夹,用于存放猫的图片(数据),然后创建名为1的文件夹,用于存放狗的数据。
创建好0和1的文件之后,分别放入 猫和狗的图片。

第三步:train.py 文件第一部分的内容,对数据进行预处理,数据的预处理分为连个步骤,第一步是获取数据并生成标签集,第二不是将数据进行分批处理。

		#导入tensorflow 
		import tensorflow as tf
		#创建函数获取train_image中的文件,生成标签集合
		def get_files(file_path):
	 #两个文件,一个是用于存放图片路径,一个是用于对图片标记
	   class_train = []
	   label_train = []
	   #根据路径将图片遍历出来
	   for train_class in os.listdir(file_path):
	      #pic_name is the train image name
	      for pic_name in os.listdir(file_path + train_class):
		 #添加入前面创建好的列表当中
	         class_train.append(file_path + train_class + '/' + pic_name)
	         #train_class is 0,1,2,3,4....
	         label_train.append(train_class)
	   #将trainimage和trainlabel合并到二维数组(2,n)
	   temp = np.array([class_train, label_train])
	   #进行数据降维
	   temp = temp.transpose()
	   np.random.shuffle(temp)
	#获取降维后的数据
	   image_list = list(temp[:,0])
	   label_list = list(temp[:,1])
	   label_list = [int(i) for i in label_list]
	   return image_list, label_list
	
	def get_batches(image, label, resize_w, resize_h, batch_size, capacity):
	   #用TensorFlow进行数据字符的提取
	   image = tf.cast(image, tf.string)
	   #用TensorFlow进行特殊字符的标记,为64位
	   label = tf.cast(label, tf.int64)
	#让图片和标记形成队列
	   queue = tf.train.slice_input_producer([image, label])
	   label = queue[1]
	   image_temp = tf.read_file(queue[0])
	   image = tf.image.decode_jpeg(image_temp, channels = 3)
	   #宠幸标记图片型号
	   image = tf.image.resize_image_with_crop_or_pad(image, resize_w, resize_h)
	
	   image = tf.image.per_image_standardization(image)
	
	   image_batch, label_batch = tf.train.batch([image, label], batch_size = batch_size,
	      num_threads = 64,
	      capacity = capacity)
	   images_batch = tf.cast(image_batch, tf.float32)
	   labels_batch = tf.reshape(label_batch, [batch_size])
	   return images_batch, labels_batch

model.py 设计神经网络,神经网络的结构

conv1 卷积层 1
pooling1_lrn 池化层 1
conv2 卷积层 2
pooling2_lrn 池化层 2
local3 全连接层 1
local4 全连接层 2
softmax 全连接层 3

在这里插入图片描述
1、以上是网络神经的结构,我们来开始搭建,代码如下:

#导入tensorflow 
Im#port tensorflow as tf
#对数据分批处理
def inference(images, batch_size, n_classes):

卷积层1 conv1

with tf.variable_scope('conv1') as scope:
    weights = tf.Variable(tf.truncated_normal(shape=[3, 3, 3, 64], stddev=1.0, dtype=tf.float32),
                          name='weights', dtype=tf.float32)

    biases = tf.Variable(tf.constant(value=0.1, dtype=tf.float32, shape=[64]),
                         name='biases', dtype=tf.float32)

    conv = tf.nn.conv2d(images, weights, strides=[1, 1, 1, 1], padding='SAME')
    pre_activation = tf.nn.bias_add(conv, biases)
    conv1 = tf.nn.relu(pre_activation, name=scope.name)

池化层 1 pooling1

with tf.variable_scope('pooling1_lrn') as scope:
    pool1 = tf.nn.max_pool(conv1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='SAME', name='pooling1')
    norm1 = tf.nn.lrn(pool1, depth_radius=4, bias=1.0, alpha=0.001 / 9.0, beta=0.75, name='norm1')

卷积层2 conv2

with tf.variable_scope('conv2') as scope:
    weights = tf.Variable(tf.truncated_normal(shape=[3, 3, 64, 16], stddev=0.1, dtype=tf.float32),
                          name='weights', dtype=tf.float32)

    biases = tf.Variable(tf.constant(value=0.1, dtype=tf.float32, shape=[16]),
                         name='biases', dtype=tf.float32)

    conv = tf.nn.conv2d(norm1, weights, strides=[1, 1, 1, 1], padding='SAME')
    pre_activation = tf.nn.bias_add(conv, biases)
    conv2 = tf.nn.relu(pre_activation, name='conv2')

池化层 2 pooling2

with tf.variable_scope('pooling2_lrn') as scope:
    norm2 = tf.nn.lrn(conv2, depth_radius=4, bias=1.0, alpha=0.001 / 9.0, beta=0.75, name='norm2')
    pool2 = tf.nn.max_pool(norm2, ksize=[1, 3, 3, 1], strides=[1, 1, 1, 1], padding='SAME', name='pooling2')

全连接层1 local3

with tf.variable_scope('local3') as scope:
    reshape = tf.reshape(pool2, shape=[batch_size, -1])
    dim = reshape.get_shape()[1].value
    weights = tf.Variable(tf.truncated_normal(shape=[dim, 128], stddev=0.005, dtype=tf.float32),
                          name='weights', dtype=tf.float32)

    biases = tf.Variable(tf.constant(value=0.1, dtype=tf.float32, shape=[128]),
                         name='biases', dtype=tf.float32)

    local3 = tf.nn.relu(tf.matmul(reshape, weights) + biases, name=scope.name)

全连接层2 local4

with tf.variable_scope('local4') as scope:
    weights = tf.Variable(tf.truncated_normal(shape=[128, 128], stddev=0.005, dtype=tf.float32),
                          name='weights', dtype=tf.float32)

    biases = tf.Variable(tf.constant(value=0.1, dtype=tf.float32, shape=[128]),
                         name='biases', dtype=tf.float32)

    local4 = tf.nn.relu(tf.matmul(local3, weights) + biases, name='local4')

全连接层 3 softmax

with tf.variable_scope('softmax_linear') as scope:
    weights = tf.Variable(tf.truncated_normal(shape=[128, n_classes], stddev=0.005, dtype=tf.float32),
                          name='softmax_linear', dtype=tf.float32)

    biases = tf.Variable(tf.constant(value=0.1, dtype=tf.float32, shape=[n_classes]),
                         name='biases', dtype=tf.float32)

    softmax_linear = tf.add(tf.matmul(local4, weights), biases, name='softmax_linear')

return softmax_linear

剔除无用数据并获得loss

def losses(logits, labels):
    with tf.variable_scope('loss') as scope:
        cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=labels,
                                                                       name='xentropy_per_example')
        loss = tf.reduce_mean(cross_entropy, name='loss')
        tf.summary.scalar(scope.name + '/loss', loss)
    return loss
#进行数据优化
def trainning(loss, learning_rate):
    with tf.name_scope('optimizer'):
        optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)
        global_step = tf.Variable(0, name='global_step', trainable=False)
        train_op = optimizer.minimize(loss, global_step=global_step)
    return train_op


#显示精确度
def evaluation(logits, labels):
    with tf.variable_scope('accuracy') as scope:
        correct = tf.nn.in_top_k(logits, labels, 1)
        correct = tf.cast(correct, tf.float16)
        accuracy = tf.reduce_mean(correct)
        tf.summary.scalar(scope.name + '/accuracy', accuracy)
    return accuracy
第四步:train.py 文件第二部分的内容:训练数据,并将训练的模型存储
#导入所需要的功能库
import matplotlib.pyplot as plt
import numpy as np
import os
import PIL.Image as Image
import model

#loss数据文件存放路径
LOG_DIR = './log'
#生个数据模型存放路径
CHECK_POINT_DIR = './modelsave'

数据的预处理

下面是对特殊数据进行解释说明

N_CLASSES = 2  # 2个输出神经元,[1,0] 或者 [0,1]猫和狗的概率
IMG_W = 64  # 重新定义图片的大小,图片如果过大则训练比较慢
IMG_H = 64
BATCH_SIZE = 10  #每批数据的大小
CAPACITY = 20
MAX_STEP = 15000 # 训练的步数,应当 >= 10000
learning_rate = 0.0001 # 学习率,建议刚开始的 learning_rate <= 0.0001
#训练程序
def run_training():
   # 数据集
   train_dir='./train_image/'
   # 获取图片和标签集
   train,train_label = get_files(train_dir)
   # 生成批次
   train_batch, train_label_batch = get_batches(train, train_label, IMG_W, IMG_H, BATCH_SIZE, CAPACITY)
   # 进入模型
   train_logits = model.inference(train_batch, BATCH_SIZE, N_CLASSES)
   # 获取 loss
   train_loss = model.losses(train_logits, train_label_batch)
   # 训练
   train_op = model.trainning(train_loss, learning_rate)
   # 获取准确率
   train_acc = model.evaluation(train_logits, train_label_batch)
   # 合并 summary
   summary_op = tf.summary.merge_all()

   sess = tf.Session()
   # 保存summary
   train_writer = tf.summary.FileWriter(LOG_DIR, sess.graph)
   saver = tf.train.Saver()

   sess.run(tf.global_variables_initializer())

   coord = tf.train.Coordinator()

   threads = tf.train.start_queue_runners(sess=sess, coord=coord)

   try:
      for step in np.arange(1000):
         if coord.should_stop():
            break
         _, tra_loss, tra_acc = sess.run([train_op, train_loss, train_acc])

         if step % 10 == 0:
            print('Step %d, train loss=%.2f, train accuracy = %.2f%%' %(step, tra_loss, tra_acc))
            summary_str = sess.run(summary_op)-
            train_writer.add_summary(summary_str, step)
	  # 每隔2000步保存一下模型,模型保存在 checkpoint_path 中
         if (step + 1) == 1000:
            checkpoint_path = os.path.join(CHECK_POINT_DIR, 'model_ckpt')
            saver.save(sess, checkpoint_path, global_step=step)
   except tf.errors.OutOfRangeError:
      print ('Done training')
   finally:
      coord.request_stop()
   coord.join(threads)
if __name__=="__main__":
   run_training()

在这里插入图片描述

第五步:test.py 测试搭建好的模型,进行猫够识别,在网上随便下载一只猫或者狗,导入模型,进行识别,最终让电脑告诉我们我们放进去的到底是猫还是狗:
先导入要使用的功能库

#用于图形处理
from PIL import Image
import numpy as np
import tensorflow as tf
#用于数据可视化
import matplotlib.pyplot as plt
#导入神经网络
import model
#模型存放路径
CHECK_POINT_DIR = './modelsave'
#进行图像识别
def evaluate_one_image(image_array):
   with tf.Graph().as_default():
      BATCH_SIZE = 1  # 因为只读取一副图片 所以batch 设置为1
      N_CLASSES = 2  # 2个输出神经元,[1,0] 或者 [0,1]猫和狗的概率
      # 转化图片格式
      image = tf.cast(image_array, tf.float32)
      # 图片标准化
      image = tf.image.per_image_standardization(image)
      # 图片原来是三维的 [64,64,3] 重新定义图片形状 改为一个4D  四维的 tensor
      image = tf.reshape(image, [1, 64,64,3])
      logit = model.inference(image, BATCH_SIZE, N_CLASSES)
      # 因为 inference 的返回没有用激活函数,所以在这里对结果用softmax 激活
      logit = tf.nn.softmax(logit)
      # 定义saver
      saver = tf.train.Saver()
      with tf.Session() as sess:
         # print ('Reading checkpoints...')
         print ('从指定的路径中加载模型。。。。')
         # 将模型加载到sess 中
         ckpt = tf.train.get_checkpoint_state(CHECK_POINT_DIR)
         if ckpt and ckpt.model_checkpoint_path:
            global_step = ckpt.model_checkpoint_path.split('/')[-1].split('-')[-1]
            saver.restore(sess, ckpt.model_checkpoint_path)
            print('模型加载成功, 训练的步数为 %s' %global_step)
         else:
            print ('模型加载失败,,,文件没有找到')
         prediction = sess.run(logit)
         # 获取输出结果中最大概率的索引
         max_index = np.argmax(prediction)
         print (prediction)
         if max_index == 0:
            result = ('这是猫的概率: %.6f, 预测结果是 [%s]' %(prediction[:,0],','.join(str(i) for i in prediction[0])))
         else:
            result = ('这是狗的概率: %.6f, 预测结果是 [%s]' %(prediction[:,1],','.join(str(i) for i in prediction[0])))

     return result
if __name__ == '__main__':
   #打开要识别的图片
   image = Image.open('./005.jpg')
   # 显示出来
   plt.imshow(image)
   plt.show()
   image = image.resize([64,64])
   image = np.array(image)
   print(evaluate_one_image(image))

将下面这张长得很像狗的猫咪图片命名为005.jpg,导入进去进行测试

在这里插入图片描述

测试结果如下:
在这里插入图片描述

然后将下面这张长得很像猫的狗狗图片命名为006.jpg,导入进去进行测试
在这里插入图片描述

测试结果如下:
在这里插入图片描述

总结:
在这个案例中我们充分了解到非监督学习的优点,那就是对比监督学习使用起来十分的灵活,但是相对监督学习对输入和输出的数据都有一个提前预知不同,非监督学习的数据输出是未知和不可控的。这里我们还学习了神经网路的组成和搭建,通过神经网络,我们可以让计算机更像人类一样去识别未知的事物,更好的帮助人类对复杂的事情进行分类,比如博主主题分类,各种主题五花八门,人类分类起来很困难,这就可以用非监督学习,让算计帮助我们进行分类,从这里可以看出非监督学习是致力于解决较为复杂的识别的事物的。

2019-05-31 16:28:45 weixin_37813036 阅读数 3617
  • python全栈习题课

    【程序员工具基础】图灵系统使用,Linux初步,DevOps 【Python基础语法】函数,OOP编程,调试技术 【Python高级语法】函数式编程,多线程,携程异步,IO编程,正则 【Web 编程基础 】Socket编程,WSGI,HTTP协议实战框架项目 【主流数据库】关系型非关系性三大主流数据库,不多说 【WEB实战开发框架】Flask,Django,twisted,tornado 【自动化测试】测试工程,测试脚本,自动化测试框架 【自动化运维】自动化部署工具,服务自动化搭建 【爬虫与反爬虫】ssl,js加密,ajax处理,模拟器selemium,验证码识别,Scrapy框架使用 【计算机数学基础】线性代数,微积分,统计概率,Python数学模块 【数据分析·处理】数据清洗,NLP,回归,贝叶斯,灰度预测,聚类,数据分析实战项目 【人工智能(AI)】回归,正则,决策树,贝叶斯,SVM,聚类,关联规则,神经网络,深度学习,手写字识别,猫狗分类,情感分析,推荐系统,目标检测,机器翻译

    393 人正在学习 去看看 刘英

kaggle是一个为开发商和数据科学家提供举办机器学习竞赛、托管数据库、编写和分享代码的平台,在这上面有非常多的好项目、好资源可供机器学习、深度学习爱好者学习之用。碰巧最近入门了一门非常的深度学习框架:pytorch(如果你对pytorch不甚了解,请点击这里),所以今天我和大家一起用pytorch实现一个图像识别领域的入门项目:猫狗图像识别。
深度学习的基础就是数据,咱们先从数据谈起。此次使用的猫狗分类图像一共25000张,猫狗分别有12500张。下载地址:https://www.kaggle.com/c/dogs-vs-cats-redux-kernels-edition/data我们先来简单的看看都是一些什么图片。我们从下载文件里可以看到有两个文件夹:train和test1,分别用于训练和测试。打开train文件夹可以看到有25000 张小猫小狗的图片,图片名字为cat.0.jpg,cat.1.jpg,dog.0.jpg,dog.1.jpg。
在这里插入图片描述
在这里插入图片描述
仔细看小猫小狗,可以发现它们姿态不一,有的站着,有的眯着眼睛,有的甚至和其他可识别物体比如桶、人混在一起。同时,小猫们的图片尺寸也不一致,有的是竖放的长方形,有的是横放的长方形,但我们最终需要是合理尺寸的图片。所以需要进行图片处理,并把图片转化成Tensor作为模型的输入。代码如下:

data_transform = transforms.Compose([
    transforms.Resize(84),
    transforms.CenterCrop(84),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])

train_dataset = datasets.ImageFolder(root='./data2/train/', 
                                     transform=data_transform)
train_loader = torch.utils.data.DataLoader(train_dataset, 
                                           batch_size=batch_size, 
                                           shuffle=True,
                                           num_workers=num_workers)

为方便训练过程,需要把训练集进行处理:把猫狗的图片分别放在cat,dog文件夹中,并划分出一部分图片作为测试集(与下载的测试集不同)。代码如下:


# kaggle原始数据集地址
original_dataset_dir = 'E:\python ese\c_d\data\\train\\train'
total_num = int(len(os.listdir(original_dataset_dir)) / 2)
random_idx = np.array(range(total_num))
np.random.shuffle(random_idx)

# 待处理的数据集地址
base_dir = 'E:\python ese\c_d\data2'
if not os.path.exists(base_dir):
    os.mkdir(base_dir)

# 训练集、测试集的划分
sub_dirs = ['train', 'test']
animals = ['cats', 'dogs']
train_idx = random_idx[:int(total_num * 0.9)]
test_idx = random_idx[int(total_num * 0.9):]
numbers = [train_idx, test_idx]
for idx, sub_dir in enumerate(sub_dirs):
    dir = os.path.join(base_dir, sub_dir)
    if not os.path.exists(dir):
        os.mkdir(dir)
    for animal in animals:
        animal_dir = os.path.join(dir, animal)  #
        if not os.path.exists(animal_dir):
            os.mkdir(animal_dir)
        fnames = [animal[:-1] + '.{}.jpg'.format(i) for i in numbers[idx]]
        for fname in fnames:
            src = os.path.join(original_dataset_dir, fname)
            dst = os.path.join(animal_dir, fname)
            shutil.copyfile(src, dst)

        # 验证训练集、验证集、测试集的划分的照片数目
        print(animal_dir + ' total images : %d' % (len(os.listdir(animal_dir))))

紧接着我们了解一下特别适用于图像识别领域的神经网络:卷积神经网络。学习过神经网络的同学可能或多或少地听说过卷积神经网络。这是一种典型的多层神经网络,擅长处理图像特别是大图像的相关机器学习问题。卷积神经网络通过一系列的方法,成功地将大数据量的图像识别问题不断降维,最终使其能够被训练。CNN最早由Yann LeCun提出并应用在手写体识别上。一个典型的CNN网络架构如下:
在这里插入图片描述
这是一个典型的CNN架构,由卷基层、池化层、全连接层组合而成。其中卷基层与池化层配合,组成多个卷积组,逐层提取特征,最终完成分类。听到上述一连串的术语如果你有点蒙了,也别怕,因为这些复杂、抽象的技术都已经在pytorch中一一实现,我们要做的不过是正确的调用相关函数。

# 创建模型
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.maxpool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16 * 18 * 18, 1024)
        self.fc2 = nn.Linear(1024, 512)
        self.fc3 = nn.Linear(512, 2)

    def forward(self, x):
        x = self.maxpool(F.relu(self.conv1(x)))
        x = self.maxpool(F.relu(self.conv2(x)))
        x = x.view(-1, 16 * 18 * 18)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)

        return x


net = Net()

我们从conv1说起。conv1实际上就是定义一个卷积层,3,6,5分别是什么意思?3代表的是输入图像的像素数组的层数,一般来说就是你输入的图像的通道数,比如这里使用的小猫图像都是彩色图像,由R、G、B三个通道组成,所以数值为3;6代表的是我们希望进行6次卷积,每一次卷积都能生成不同的特征映射数组,用于提取小猫和小狗的6种特征。每一个特征映射结果最终都会被堆叠在一起形成一个图像输出,再作为下一步的输入;5就是过滤框架的尺寸,表示我们希望用一个5 * 5的矩阵去和图像中相同尺寸的矩阵进行点乘再相加,形成一个值。定义好了卷基层,我们接着定义池化层。池化层所做的事说来简单,其实就是因为大图片生成的像素矩阵实在太大了,我们需要用一个合理的方法在降维的同时又不失去物体特征,所以深度学习学者们想出了一个称为池化的技术,说白了就是从左上角开始,每四个元素(2 * 2)合并成一个元素,用这一个元素去代表四个元素的值,所以图像体积一下子降为原来的四分之一。再往下一行,我们又一次碰见了一个卷积层:conv2,和conv1一样,它的输入也是一个多层像素数组,输出也是一个多层像素数组,不同的是这一次完成的计算量更大了,我们看这里面的参数分别是6,16,5。之所以为6是因为conv1的输出层数为6,所以这里输入的层数就是6;16代表conv2的输出层数,和conv1一样,16代表着这一次卷积操作将会学习小猫小狗的16种映射特征,特征越多理论上能学习的效果就越好,大家可以尝试一下别的值,看看效果是否真的编变好。conv2使用的过滤框尺寸和conv1一样,所以不再重复。最后三行代码都是用于定义全连接网络的,接触过神经网络的应该就不再陌生了,主要是需要解释一下fc1。之前在学习的时候比较不理解的也是这一行,为什么是16 * 18 * 18呢?16很好理解,因为最后一次卷积生成的图像矩阵的高度就是16层,那18 * 18是怎么来的呢?我们回过头去看一行代码

transforms.CenterCrop(84)
在这行代码里我们把训练图像裁剪成一个84 * 84的正方形尺寸,所以图像最早输入就是一个3 * 84 * 84的数组。经过第一次5 * 5的卷积之后,我们可以得出卷积的结果是一个6 * 80 * 80的矩阵,这里的80就是因为我们使用了一个5 * 5的过滤框,当它从左上角第一个元素开始卷积后,过滤框的中心是从2到78,并不是从0到79,所以结果就是一个80 * 80的图像了。经过一个池化层之后,图像尺寸的宽和高都分别缩小到原来的1/2,所以变成40 * 40。紧接着又进行了一次卷积,和上一次一样,长宽都减掉4,变成36 * 36,然后应用了最后一层的池化,最终尺寸就是18 * 18。所以第一层全连接层的输入数据的尺寸是16 * 18 * 18。三个全连接层所做的事很类似,就是不断训练,最后输出一个二分类数值。net类的forward函数表示前向计算的整个过程。forward接受一个input,返回一个网络输出值,中间的过程就是一个调用init函数中定义的层的过程。F.relu是一个激活函数,把所有的非零值转化成零值。此次图像识别的最后关键一步就是真正的循环训练操作。

下面就可以开始训练了!


# 定义loss和optimizer
cirterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.0001, momentum=0.9)

def train():

    for epoch in range(epochs):
        running_loss = 0.0
        train_correct = 0
        train_total = 0
        for i, data in enumerate(train_loader, 0):
            inputs, train_labels = data
            if use_gpu:
                inputs, labels = Variable(inputs.cuda()), Variable(train_labels.cuda())
            else:
                inputs, labels = Variable(inputs), Variable(train_labels)
            optimizer.zero_grad()
            outputs = net(inputs)
            _, train_predicted = torch.max(outputs.data, 1)
            train_correct += (train_predicted == labels.data).sum()
            loss = cirterion(outputs, labels)
            loss.backward()
            optimizer.step()
            running_loss += loss.item()
            train_total += train_labels.size(0)

        print('train %d epoch loss: %.3f  acc: %.3f ' % (
            epoch + 1, running_loss / train_total, 100 * train_correct / train_total))
        # 模型测试
        correct = 0
        test_loss = 0.0
        test_total = 0
        test_total = 0
        net.eval()
        for data in test_loader:
            images, labels = data
            if use_gpu:
                images, labels = Variable(images.cuda()), Variable(labels.cuda())
            else:
                images, labels = Variable(images), Variable(labels)
            outputs = net(images)
            _, predicted = torch.max(outputs.data, 1)
            loss = cirterion(outputs, labels)
            test_loss += loss.item()
            test_total += labels.size(0)
            correct += (predicted == labels.data).sum()

        print('test  %d epoch loss: %.3f  acc: %.3f ' % (epoch + 1, test_loss / test_total, 100 * correct / test_total))

    torch.save(net, 'model.pt')


train()

完整代码:

# coding=utf-8
import os
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.autograd import Variable
from torch.utils.data import Dataset
from torchvision import transforms, datasets, models

# 随机种子设置
random_state = 42
np.random.seed(random_state)

# kaggle原始数据集地址
original_dataset_dir = 'E:\python ese\c_d\data\\train\\train'
total_num = int(len(os.listdir(original_dataset_dir)) / 2)
random_idx = np.array(range(total_num))
np.random.shuffle(random_idx)

# 待处理的数据集地址
base_dir = 'E:\python ese\c_d\data2'
if not os.path.exists(base_dir):
    os.mkdir(base_dir)

# 训练集、测试集的划分
sub_dirs = ['train', 'test']
animals = ['cats', 'dogs']
train_idx = random_idx[:int(total_num * 0.9)]
test_idx = random_idx[int(total_num * 0.9):]
numbers = [train_idx, test_idx]
for idx, sub_dir in enumerate(sub_dirs):
    dir = os.path.join(base_dir, sub_dir)
    if not os.path.exists(dir):
        os.mkdir(dir)
    for animal in animals:
        animal_dir = os.path.join(dir, animal)  #
        if not os.path.exists(animal_dir):
            os.mkdir(animal_dir)
        fnames = [animal[:-1] + '.{}.jpg'.format(i) for i in numbers[idx]]
        for fname in fnames:
            src = os.path.join(original_dataset_dir, fname)
            dst = os.path.join(animal_dir, fname)
            shutil.copyfile(src, dst)

        # 验证训练集、验证集、测试集的划分的照片数目
        print(animal_dir + ' total images : %d' % (len(os.listdir(animal_dir))))
    # coding=utf-8

# 配置参数
random_state = 1
torch.manual_seed(random_state)  # 设置随机数种子,确保结果可重复
torch.cuda.manual_seed(random_state)
torch.cuda.manual_seed_all(random_state)
np.random.seed(random_state)
# random.seed(random_state)

epochs = 10 # 训练次数
batch_size = 4  # 批处理大小
num_workers = 0  # 多线程的数目
use_gpu = torch.cuda.is_available()
PATH='E:\python ese\c_d\model.pt'
# 对加载的图像作归一化处理, 并裁剪为[224x224x3]大小的图像
data_transform = transforms.Compose([
    transforms.Resize(256),
    transforms.CenterCrop(224),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])

train_dataset = datasets.ImageFolder(root='./data2/train/',
                                     transform=data_transform)
train_loader = torch.utils.data.DataLoader(train_dataset,
                                           batch_size=batch_size,
                                           shuffle=True,
                                           num_workers=num_workers)

test_dataset = datasets.ImageFolder(root='./data2/test/', transform=data_transform)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=batch_size, shuffle=True, num_workers=num_workers)


# 创建模型
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.maxpool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16 * 53 * 53, 1024)
        self.fc2 = nn.Linear(1024, 512)
        self.fc3 = nn.Linear(512, 2)

    def forward(self, x):
        x = self.maxpool(F.relu(self.conv1(x)))
        x = self.maxpool(F.relu(self.conv2(x)))
        x = x.view(-1, 16 * 53 * 53)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)

        return x


net = Net()
if(os.path.exists('model.pt')):
    net=torch.load('model.pt')

if use_gpu:
    net = net.cuda()
print(net)

# 定义loss和optimizer
cirterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.0001, momentum=0.9)

def train():

    for epoch in range(epochs):
        running_loss = 0.0
        train_correct = 0
        train_total = 0
        for i, data in enumerate(train_loader, 0):
            inputs, train_labels = data
            if use_gpu:
                inputs, labels = Variable(inputs.cuda()), Variable(train_labels.cuda())
            else:
                inputs, labels = Variable(inputs), Variable(train_labels)
            optimizer.zero_grad()
            outputs = net(inputs)
            _, train_predicted = torch.max(outputs.data, 1)
            train_correct += (train_predicted == labels.data).sum()
            loss = cirterion(outputs, labels)
            loss.backward()
            optimizer.step()
            running_loss += loss.item()
            train_total += train_labels.size(0)

        print('train %d epoch loss: %.3f  acc: %.3f ' % (
            epoch + 1, running_loss / train_total, 100 * train_correct / train_total))
        # 模型测试
        correct = 0
        test_loss = 0.0
        test_total = 0
        test_total = 0
        net.eval()
        for data in test_loader:
            images, labels = data
            if use_gpu:
                images, labels = Variable(images.cuda()), Variable(labels.cuda())
            else:
                images, labels = Variable(images), Variable(labels)
            outputs = net(images)
            _, predicted = torch.max(outputs.data, 1)
            loss = cirterion(outputs, labels)
            test_loss += loss.item()
            test_total += labels.size(0)
            correct += (predicted == labels.data).sum()

        print('test  %d epoch loss: %.3f  acc: %.3f ' % (epoch + 1, test_loss / test_total, 100 * correct / test_total))

    torch.save(net, 'model.pt')


train()
2019-03-17 21:00:35 nuxun0998 阅读数 619
  • python全栈习题课

    【程序员工具基础】图灵系统使用,Linux初步,DevOps 【Python基础语法】函数,OOP编程,调试技术 【Python高级语法】函数式编程,多线程,携程异步,IO编程,正则 【Web 编程基础 】Socket编程,WSGI,HTTP协议实战框架项目 【主流数据库】关系型非关系性三大主流数据库,不多说 【WEB实战开发框架】Flask,Django,twisted,tornado 【自动化测试】测试工程,测试脚本,自动化测试框架 【自动化运维】自动化部署工具,服务自动化搭建 【爬虫与反爬虫】ssl,js加密,ajax处理,模拟器selemium,验证码识别,Scrapy框架使用 【计算机数学基础】线性代数,微积分,统计概率,Python数学模块 【数据分析·处理】数据清洗,NLP,回归,贝叶斯,灰度预测,聚类,数据分析实战项目 【人工智能(AI)】回归,正则,决策树,贝叶斯,SVM,聚类,关联规则,神经网络,深度学习,手写字识别,猫狗分类,情感分析,推荐系统,目标检测,机器翻译

    393 人正在学习 去看看 刘英

第二届人工智能竞赛——题目四、猫狗识别

一、简介

分类问题是机器学习中一个重要的任务,即找一个函数判断输入数据所属的类别,可以是二类别问题(是/不是),也可以是多类别问题(在多个类别中判断输入数据具体属于哪一个类别)。

二、题目要求

  1. 利用现有的模型对图片进行识别,判断图片上的动物是猫还是狗。
  2. 利用 QT 设计 UI 界面,界面要求:友好、功能完善、简介。
  3. 评估模型效果,准确率

三、参考资料

  1. https://github.com/xuetsing/cats-vs-dogs.git
  2. UI界面可用QT编写
2018-02-05 12:52:03 xcszjjh1991 阅读数 14316
  • python全栈习题课

    【程序员工具基础】图灵系统使用,Linux初步,DevOps 【Python基础语法】函数,OOP编程,调试技术 【Python高级语法】函数式编程,多线程,携程异步,IO编程,正则 【Web 编程基础 】Socket编程,WSGI,HTTP协议实战框架项目 【主流数据库】关系型非关系性三大主流数据库,不多说 【WEB实战开发框架】Flask,Django,twisted,tornado 【自动化测试】测试工程,测试脚本,自动化测试框架 【自动化运维】自动化部署工具,服务自动化搭建 【爬虫与反爬虫】ssl,js加密,ajax处理,模拟器selemium,验证码识别,Scrapy框架使用 【计算机数学基础】线性代数,微积分,统计概率,Python数学模块 【数据分析·处理】数据清洗,NLP,回归,贝叶斯,灰度预测,聚类,数据分析实战项目 【人工智能(AI)】回归,正则,决策树,贝叶斯,SVM,聚类,关联规则,神经网络,深度学习,手写字识别,猫狗分类,情感分析,推荐系统,目标检测,机器翻译

    393 人正在学习 去看看 刘英

 kaggle是一个为开发商和数据科学家提供举办机器学习竞赛、托管数据库、编写和分享代码的平台,在这上面有非常多的好项目、好资源可供机器学习、深度学习爱好者学习之用。碰巧最近入门了一门非常的深度学习框架:pytorch(如果你对pytorch不甚了解,请点击这里),所以今天我和大家一起用pytorch实现一个图像识别领域的入门项目:猫狗图像识别。

深度学习的基础就是数据,咱们先从数据谈起。此次使用的猫狗分类图像一共25000张,猫狗分别有12500张,我们先来简单的瞅瞅都是一些什么图片。

 我们从下载文件里可以看到有两个文件夹:train和test,分别用于训练和测试。以train为例,打开文件夹可以看到非常多的小猫图片,图片名字从

0.jpg一直编码到9999.jpg,一共有10000张图片用于训练。而test中的小猫只有2500张。仔细看小猫,可以发现它们姿态不一,有的站着,有的眯着眼

睛,有的甚至和其他可识别物体比如桶、人混在一起。同时,小猫们的图片尺寸也不一致,有的是竖放的长方形,有的是横放的长方形,但我们最终需

要是合理尺寸的正方形。小狗的图片也类似,在这里就不重复了。

 紧接着我们了解一下特别适用于图像识别领域的神经网络:卷积神经网络。学习过神经网络的同学可能或多或少地听说过卷积神经网络。这是一

典型的多层神经网络,擅长处理图像特别是大图像的相关机器学习问题。卷积神经网络通过一系列的方法,成功地将大数据量的图像识别问题不断

降维,最终使其能够被训练。CNN最早由Yann LeCun提出并应用在手写体识别上。一个典型的CNN网络架构如下:

 这是一个典型的CNN架构,由卷基层、池化层、全连接层组合而成。其中卷基层与池化层配合,组成多个卷积组,逐层提取特征,最终完成分类。

听到上述一连串的术语如果你有点蒙了,也别怕,因为这些复杂、抽象的技术都已经在pytorch中一一实现,我们要做的不过是正确的调用相关函数,

我在粘贴代码后都会做更详细、易懂的解释。

import os
import shutil
import torch
import collections
from torchvision import transforms,datasets
from __future__ import print_function, division
import os
import torch
import pylab
import pandas as pd
import torch.nn as nn
import torch.nn.functional as F
from torch.autograd import Variable
from skimage import io, transform
import numpy as np
import matplotlib.pyplot as plt
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms, utils

# Ignore warnings
import warnings
warnings.filterwarnings("ignore")

plt.ion()   # interactive mode
一个正常的CNN项目所需要的库还是蛮多的。
import math
from PIL import Image

class Resize(object):
    """Resize the input PIL Image to the given size.

    Args:
        size (sequence or int): Desired output size. If size is a sequence like
            (h, w), output size will be matched to this. If size is an int,
            smaller edge of the image will be matched to this number.
            i.e, if height > width, then image will be rescaled to
            (size * height / width, size)
        interpolation (int, optional): Desired interpolation. Default is
            ``PIL.Image.BILINEAR``
    """

    def __init__(self, size, interpolation=Image.BILINEAR):
        # assert isinstance(size, int) or (isinstance(size, collections.Iterable) and len(size) == 2)
        self.size = size
        self.interpolation = interpolation

    def __call__(self, img):
        w,h = img.size
        
        min_edge = min(img.size)
        rate = min_edge / self.size
        
        new_w = math.ceil(w / rate)
        new_h = math.ceil(h / rate)
        
        return img.resize((new_w,new_h))
这个称为Resize的库用于给图像进行缩放操作,本来是不需要亲自定义的,因为transforms.Resize已经实现这个功能了,但是由于目前还未知的原因,

我的库里没有提供这个函数,所以我需要亲自实现用来代替transforms.Resize。如果你的torch里面已经有了这个Resize函数就不用像我这样了。

data_transform = transforms.Compose([
    Resize(84),
    transforms.CenterCrop(84),
    transforms.ToTensor(),
    transforms.Normalize(mean = [0.5,0.5,0.5],std = [0.5,0.5,0.5])
])

train_dataset = datasets.ImageFolder(root = 'train/',transform = data_transform)
train_loader = torch.utils.data.DataLoader(train_dataset,batch_size = 4,shuffle = True,num_workers = 4)

test_dataset = datasets.ImageFolder(root = 'test/',transform = data_transform)
test_loader = torch.utils.data.DataLoader(test_dataset,batch_size = 4,shuffle = True,num_workers = 4)
transforms是一个提供针对数据(这里指的是图像)进行转化的操作库,Resize就是上上段代码提供的那个类,主要用于把一张图片缩放到某个尺寸,

在这里我们把需求暂定为要把图像缩放到84 x 84这个级别,这个就是可供调整的参数,大家为部署好项目以后可以试着修改这个参数,比如改成

200 x 200,你就发现你可以去玩一盘游戏了~_~。CenterCrop用于从中心裁剪图片,目标是一个长宽都为84的正方形,方便后续的计算。ToTenser()

就比较重要了,这个函数的目的就是读取图片像素并且转化为0-1的数字。Normalize作为垫底的一步也很关键,主要用于把图片数据集的数值转化为

标准差和均值都为0.5的数据集,这样数据值就从原来的0到1转变为-1到1。

class Net(nn.Module):
    def __init__(self):
        super(Net,self).__init__()
        
        self.conv1 = nn.Conv2d(3,6,5)
        self.pool = nn.MaxPool2d(2,2)
        self.conv2 = nn.Conv2d(6,16,5)
        self.fc1 = nn.Linear(16 * 18 * 18,800)
        self.fc2 = nn.Linear(800,120)
        self.fc3 = nn.Linear(120,2)
        
    def forward(self,x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1,16 * 18 * 18)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        
        return x

net = Net()
 好了,最复杂的一步就是这里了。在这里,我们首先定义了一个Net类,它封装了所以训练的步骤,包括卷积、池化、激活以及全连接操作。

 __init__函数首先定义了所需要的所有函数,这些函数都会在forward中调用。我们从conv1说起。conv1实际上就是定义一个卷积层,3,6,5分别是

什么意思?3代表的是输入图像的像素数组的层数,一般来说就是你输入的图像的通道数,比如这里使用的小猫图像都是彩色图像,由R、G、B三个通

道组成,所以数值为3;6代表的是我们希望进行6次卷积,每一次卷积都能生成不同的特征映射数组,用于提取小猫和小狗的6种特征。每一个特征映

射结果最终都会被堆叠在一起形成一个图像输出,再作为下一步的输入;5就是过滤框架的尺寸,表示我们希望用一个5 * 5的矩阵去和图像中相同尺寸

的矩阵进行点乘再相加,形成一个值。定义好了卷基层,我们接着定义池化层。池化层所做的事说来简单,其实就是因为大图片生成的像素矩阵实在太

大了,我们需要用一个合理的方法在降维的同时又不失去物体特征,所以深度学习学者们想出了一个称为池化的技术,说白了就是从左上角开始,每四

个元素(2 * 2)合并成一个元素,用这一个元素去代表四个元素的值,所以图像体积一下子降为原来的四分之一。再往下一行,我们又一次碰见了一个卷

基层:conv2,和conv1一样,它的输入也是一个多层像素数组,输出也是一个多层像素数组,不同的是这一次完成的计算量更大了,我们看这里面的参

数分别是6,16,5。之所以为6是因为conv1的输出层数为6,所以这里输入的层数就是6;16代表conv2的输出层数,和conv1一样,16代表着这一次卷

积操作将会学习小猫小狗的16种映射特征,特征越多理论上能学习的效果就越好,大家可以尝试一下别的值,看看效果是否真的编变好。conv2使用的

过滤框尺寸和conv1一样,所以不再重复。最后三行代码都是用于定义全连接网络的,接触过神经网络的应该就不再陌生了,主要是需要解释一下fc1。

之前在学习的时候比较不理解的也是这一行,为什么是16 * 18 * 18呢?16很好理解,因为最后一次卷积生成的图像矩阵的高度就是16层,那18 * 18是

怎么来的呢?我们回过头去看一行代码

transforms.CenterCrop(84)

在这行代码里我们把训练图像裁剪成一个84 * 84的正方形尺寸,所以图像最早输入就是一个3 * 84 * 84的数组。经过第一次5 * 5的卷积之后,

我们可以得出卷积的结果是一个6 * 80 * 80的矩阵,这里的80就是因为我们使用了一个5 * 5的过滤框,当它从左上角第一个元素开始卷积后,

过滤框的中心是从2到78,并不是从0到79,所以结果就是一个80 * 80的图像了。经过一个池化层之后,图像尺寸的宽和高都分别缩小到原来的

1/2,所以变成40 * 40。紧接着又进行了一次卷积,和上一次一样,长宽都减掉4,变成36 * 36,然后应用了最后一层的池化,最终尺寸就是

18 * 18。所以第一层全连接层的输入数据的尺寸是16 * 18 * 18。三个全连接层所做的事很类似,就是不断训练,最后输出一个二分类数值。

net类的forward函数表示前向计算的整个过程。forward接受一个input,返回一个网络输出值,中间的过程就是一个调用init函数中定义的层的过程。

F.relu是一个激活函数,把所有的非零值转化成零值。此次图像识别的最后关键一步就是真正的循环训练操作。

import torch.optim as optim

cirterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(),lr = 0.0001,momentum = 0.9)

for epoch in range(3):
    running_loss = 0.0
    
    for i,data in enumerate(train_loader,0):
        inputs,labels = data
        inputs,labels = Variable(inputs),Variable(labels)
        optimizer.zero_grad()
        outputs = net(inputs)
        loss = cirterion(outputs,labels)
        loss.backward()
        optimizer.step()
        
        running_loss += loss.data[0]
        
        if i % 2000 == 1999:
            print('[%d %5d] loss: %.3f' % (epoch + 1,i + 1,running_loss / 2000))
            running_loss = 0.0

print('finished training!')
[1  2000] loss: 0.691
[1  4000] loss: 0.687
[2  2000] loss: 0.671
[2  4000] loss: 0.657
[3  2000] loss: 0.628
[3  4000] loss: 0.626
finished training!
 在这里我们进行了三次训练,每次训练都是批量获取train_loader中的训练数据、梯度清零、计算输出值、计算误差、反向传播并修正模型。我们以每

2000次计算的平均误差作为观察值。可以看到每次训练,误差值都在不断变小,逐渐学习如何分类图像。代码相对性易懂,这里就不再赘述了。

correct = 0
total = 0

for data in test_loader:
    images,labels = data
    outputs = net(Variable(images))
    _,predicted = torch.max(outputs.data,1)
    total += labels.size(0)
    correct += (predicted == labels).sum()

print('Accuracy of the network on the 5000 test images: %d %%' % (100 * correct / total))
  终于来到模型准确度验证了,这也是开篇提到的test文件夹的用途之所在。程序到这一步时,net是一个已经训练好的神经网络了。传入一个

images阵,它会输出相应的分类值,我们拿到这个分类值与真实值做一个比较计算,就可以获得准确率。在我的计算机上当前准确率是66%,

在你的机器上可能值有所不同但不会相差太大。

最后我们做一个小总结。在pytorch中实现CNN其实并不复杂,理论性的底层都已经完成封装,我们只需要调用正确的函数即可。当前模型中的

各个参数都没有达到相对完美的状态,有兴趣的小伙伴可以多调整参数跑几次,训练结果不出意外会越来越好。另外,由于在一篇文章中既要

阐述CNN,又要贴项目代码会显得没有重点,我就没有两件事同时做,因为网上已经有很多很好的解释CNN的文章了,如果看了代码依然是满头

雾水的小伙伴可以先去搜关于CNN的文章,再回过头来看项目代码应该会更加清晰。第一次写关于自己的神经网络方面的文章,如有写得不好的

地方请大家多多见谅。










2019-07-21 16:12:30 banaoxie0070 阅读数 3391
  • python全栈习题课

    【程序员工具基础】图灵系统使用,Linux初步,DevOps 【Python基础语法】函数,OOP编程,调试技术 【Python高级语法】函数式编程,多线程,携程异步,IO编程,正则 【Web 编程基础 】Socket编程,WSGI,HTTP协议实战框架项目 【主流数据库】关系型非关系性三大主流数据库,不多说 【WEB实战开发框架】Flask,Django,twisted,tornado 【自动化测试】测试工程,测试脚本,自动化测试框架 【自动化运维】自动化部署工具,服务自动化搭建 【爬虫与反爬虫】ssl,js加密,ajax处理,模拟器selemium,验证码识别,Scrapy框架使用 【计算机数学基础】线性代数,微积分,统计概率,Python数学模块 【数据分析·处理】数据清洗,NLP,回归,贝叶斯,灰度预测,聚类,数据分析实战项目 【人工智能(AI)】回归,正则,决策树,贝叶斯,SVM,聚类,关联规则,神经网络,深度学习,手写字识别,猫狗分类,情感分析,推荐系统,目标检测,机器翻译

    393 人正在学习 去看看 刘英

最近一直在撸猫,为了猫主子的事情忧三愁四,皱纹多了不少,头发也掉了好几根,神态也多了几分忧郁,唯一不变的还是那份闲鱼的懒散和浪荡的心。

要说到深度学习图像分类的经典案例之一,那就是猫狗大战了。猫和狗在外观上的差别还是挺明显的,无论是体型、四肢、脸庞和毛发等等, 都是能通过肉眼很容易区分的。

那么如何让机器来识别猫和狗呢?这就需要使用卷积神经网络来实现了。

网上已经有不少人写过这案例了,我也来尝试下练练手。

完整代码:https://github.com/ADlead/Dogs-Cats.git

一. 数据集的准备

猫狗照片的数据集直接从kaggle官网(https://www.kaggle.com/c/dogs-vs-cats)下载即可,下载后解压,可以看到有训练集和测试集
在这里插入图片描述
train文件夹内容如下:
在这里插入图片描述
test1文件夹内容如下:
在这里插入图片描述

编写代码将图片存储成batch文件

import cv2 as cv
import os
import numpy as np
import random
import pickle
import time

start_time = time.time()

data_dir = './data'
batch_save_path = './batch_files'

# 创建batch文件存储的文件夹
os.makedirs(batch_save_path, exist_ok=True)

# 图片统一大小:100 * 100
# 训练集 20000:100个batch文件,每个文件200张图片
# 验证集 5000:一个测试文件,测试时 50张 x 100 批次

# 进入图片数据的目录,读取图片信息
all_data_files = os.listdir(os.path.join(data_dir, 'train/'))

# print(all_data_files)

# 打算数据的顺序
random.shuffle(all_data_files)

all_train_files = all_data_files[:20000]
all_test_files = all_data_files[20000:]

train_data = []
train_label = []
train_filenames = []

test_data = []
test_label = []
test_filenames = []

# 训练集
for each in all_train_files:
    img = cv.imread(os.path.join(data_dir,'train/',each),1)
    resized_img = cv.resize(img, (100,100))

    img_data = np.array(resized_img)
    train_data.append(img_data)
    if 'cat' in each:
        train_label.append(0)
    elif 'dog' in each:
        train_label.append(1)
    else:
        raise Exception('%s is wrong train file'%(each))
    train_filenames.append(each)

# 测试集
for each in all_test_files:
    img = cv.imread(os.path.join(data_dir,'train/',each), 1)
    resized_img = cv.resize(img, (100,100))

    img_data = np.array(resized_img)
    test_data.append(img_data)
    if 'cat' in each:
        test_label.append(0)
    elif 'dog' in each:
        test_label.append(1)
    else:
        raise Exception('%s is wrong test file'%(each))
    test_filenames.append(each)

print(len(train_data), len(test_data))

# 制作100个batch文件
start = 0
end = 200
for num in range(1, 101):
    batch_data = train_data[start: end]
    batch_label = train_label[start: end]
    batch_filenames = train_filenames[start: end]
    batch_name = 'training batch {} of 15'.format(num)

    all_data = {
    'data':batch_data,
    'label':batch_label,
    'filenames':batch_filenames,
    'name':batch_name
    }

    with open(os.path.join(batch_save_path, 'train_batch_{}'.format(num)), 'wb') as f:
        pickle.dump(all_data, f)

    start += 200
    end += 200

# 制作测试文件
all_test_data = {
    'data':test_data,
    'label':test_label,
    'filenames':test_filenames,
    'name':'test batch 1 of 1'
    }

with open(os.path.join(batch_save_path, 'test_batch'), 'wb') as f:
    pickle.dump(all_test_data, f)

end_time = time.time()
print('制作结束, 用时{}秒'.format(end_time - start_time))

运行程序后,文件就处理好了
在这里插入图片描述

二. 神经网络的编写

cnn卷积神经网络的编写如下,编写卷积层、池化层和全连接层的代码

conv1_1 = tf.layers.conv2d(x, 16, (3, 3), padding='same', activation=tf.nn.relu, name='conv1_1')
conv1_2 = tf.layers.conv2d(conv1_1, 16, (3, 3), padding='same', activation=tf.nn.relu, name='conv1_2')
pool1 = tf.layers.max_pooling2d(conv1_2, (2, 2), (2, 2), name='pool1')
conv2_1 = tf.layers.conv2d(pool1, 32, (3, 3), padding='same', activation=tf.nn.relu, name='conv2_1')
conv2_2 = tf.layers.conv2d(conv2_1, 32, (3, 3), padding='same', activation=tf.nn.relu, name='conv2_2')
pool2 = tf.layers.max_pooling2d(conv2_2, (2, 2), (2, 2), name='pool2')
conv3_1 = tf.layers.conv2d(pool2, 64, (3, 3), padding='same', activation=tf.nn.relu, name='conv3_1')
conv3_2 = tf.layers.conv2d(conv3_1, 64, (3, 3), padding='same', activation=tf.nn.relu, name='conv3_2')
pool3 = tf.layers.max_pooling2d(conv3_2, (2, 2), (2, 2), name='pool3')
conv4_1 = tf.layers.conv2d(pool3, 128, (3, 3), padding='same', activation=tf.nn.relu, name='conv4_1')
conv4_2 = tf.layers.conv2d(conv4_1, 128, (3, 3), padding='same', activation=tf.nn.relu, name='conv4_2')
pool4 = tf.layers.max_pooling2d(conv4_2, (2, 2), (2, 2), name='pool4')

flatten = tf.layers.flatten(pool4)
fc1 = tf.layers.dense(flatten, 512, tf.nn.relu)
fc1_dropout = tf.nn.dropout(fc1, keep_prob=keep_prob)
fc2 = tf.layers.dense(fc1, 256, tf.nn.relu)
fc2_dropout = tf.nn.dropout(fc2, keep_prob=keep_prob)
fc3 = tf.layers.dense(fc2, 2, None)

三. tensorflow计算图的搭建

然后,再搭建tensorflow的计算图,定义占位符,计算损失函数、预测值和准确率等等

self.x = tf.placeholder(tf.float32, [None, IMAGE_SIZE, IMAGE_SIZE, 3], 'input_data')
self.y = tf.placeholder(tf.int64, [None], 'output_data')
self.keep_prob = tf.placeholder(tf.float32)

# 图片输入网络中
fc = self.conv_net(self.x, self.keep_prob)
self.loss = tf.losses.sparse_softmax_cross_entropy(labels=self.y, logits=fc)
self.y_ = tf.nn.softmax(fc) # 计算每一类的概率
self.predict = tf.argmax(fc, 1)
self.acc = tf.reduce_mean(tf.cast(tf.equal(self.predict, self.y), tf.float32))
self.train_op = tf.train.AdamOptimizer(LEARNING_RATE).minimize(self.loss)
self.saver = tf.train.Saver(max_to_keep=1)

最后的saver是要将训练好的模型保存到本地。

四. 模型的训练和测试

然后编写训练部分的代码,训练步骤为1万步

acc_list = []
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())

    for i in range(TRAIN_STEP):
        train_data, train_label, _ = self.batch_train_data.next_batch(TRAIN_SIZE)

        eval_ops = [self.loss, self.acc, self.train_op]
        eval_ops_results = sess.run(eval_ops, feed_dict={
            self.x:train_data,
            self.y:train_label,
            self.keep_prob:0.7
        })
        loss_val, train_acc = eval_ops_results[0:2]

        acc_list.append(train_acc)
        if (i+1) % 100 == 0:
            acc_mean = np.mean(acc_list)
            print('step:{0},loss:{1:.5},acc:{2:.5},acc_mean:{3:.5}'.format(
                i+1,loss_val,train_acc,acc_mean
            ))
        if (i+1) % 1000 == 0:
            test_acc_list = []
            for j in range(TEST_STEP):
                test_data, test_label, _ = self.batch_test_data.next_batch(TRAIN_SIZE)
                acc_val = sess.run([self.acc],feed_dict={
                    self.x:test_data,
                    self.y:test_label,
                    self.keep_prob:1.0
            })
            test_acc_list.append(acc_val)
            print('[Test ] step:{0}, mean_acc:{1:.5}'.format(
                i+1, np.mean(test_acc_list)
            ))
    # 保存训练后的模型
    os.makedirs(SAVE_PATH, exist_ok=True)
    self.saver.save(sess, SAVE_PATH + 'my_model.ckpt')

训练结果如下
在这里插入图片描述
训练1万步后模型测试的平均准确率有0.82。

五. 识别和分类

最后,使用自己训练好的模型,把官网的测试图片(共12500张)识别后进行分类,并将分类后的图片分别写入到两个文件夹中,结果如下

分类为狗的图片如下:
狗类的图片
分类为猫的图片如下:
猫类的图片
可以看出,分类之后还有少数分类不对的结果。看来模型还有待提升,还可以调整网络参数、调整学习率和学习步数、使用图像增强等技术对模型识别准确率进行提高。

搞了一番,手和脚也有些累了。是时候撸撸猫继续闲鱼了。。

更多内容,可以到公众号 [ 浪学 ] 一起学习~

没有更多推荐了,返回首页