点击上方AI派,订阅我!此刻开始我们一起学习进步!
AI派在读学生小姐姐Beyonce
Java实战项目练习群
长按识别下方二维码,按需求添加

扫码添加Beyonce小姐姐

扫码关注
进Java学习大礼包
1、项目流程的简介
项目的主题框架使用为PyTorch的形式实现,而模型的选择为DCGAN模型,数据集的获取是通过爬虫从网络中获取的数据,然后通过目标检测获取妹子们的头像。
2、项目主题部分
2.1、数据集的获取
这里获取的图片都是乃木坂46成员的图片,一方面我作为饭乃团的SDD,里面的成员我都喜欢,另一方面,风格上也大致相似,可能会有利于训练。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import os
import re
import urllib
import json
import socket
import urllib
import urllib2
import pdb
# 设置超时
import time
timeout = 5
socket.setdefaulttimeout(timeout)
class Crawler:
# 睡眠时长
__time_sleep = 0.1
__amount = 0
__start_amount = 0
__counter = 0
# 获取图片url内容等
# t 下载图片时间间隔
def __init__(self, t=0.1):
self.time_sleep = t
# 开始获取
def __getImages(self, word=u'美女'):
search = urllib.quote(word)
# pn int 图片数
pn = self.__start_amount
while pn < self.__amount:
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0'}
url = 'http://image.baidu.com/search/avatarjson?tn=resultjsonavatarnew&ie=utf-8&word=' + search + '&cg=girl&pn=' + str(
pn) + '&rn=60&itg=0&z=0&fr=&width=&height=&lm=-1&ic=0&s=0&st=-1&gsm=1e0000001e'
# 设置header防ban
try:
time.sleep(self.time_sleep)
req = urllib2.Request(url=url, headers=headers)
page = urllib2.urlopen(req)
data = page.read().decode('utf8')
except UnicodeDecodeError as e:
print('-----UnicodeDecodeErrorurl:', url)
except urllib2.URLError as e:
print("-----urlErrorurl:", url)
except socket.timeout as e:
print("-----socket timout:", url)
else:
# 解析json
json_data = json.loads(data)
self.__saveImage(json_data, word)
# 读取下一页
print(u"下载下一页")
pn += 60
finally:
page.close()
print(u"下载任务结束")
return
# 保存图片
def __saveImage(self, json, word):
# pdb.set_trace()
cnname = word.decode('utf-8').encode('gb2312')
savefolder = "./test/" + word
savefolder = savefolder.decode('utf-8').encode('gb2312')
if not os.path.exists(savefolder):
os.mkdir(savefolder)
# 判断名字是否重复,获取图片长度
self.__counter = len(os.listdir(savefolder)) + 1
for info in json['imgs']:
try:
if self.__downloadImage(info, word) == False:
self.__counter -= 1
except urllib2.HTTPError as urllib_err:
print(urllib_err)
pass
except Exception as err:
time.sleep(1)
print(err);
print(u"产生未知错误,放弃保存")
continue
finally:
showstr = word+":图+1,已有" + str(self.__counter) + "张图"
print(showstr.decode('utf-8').encode('gb2312'))
self.__counter += 1
return
# 下载图片
def __downloadImage(self, info, word):
# pdb.set_trace()
time.sleep(self.time_sleep)
fix = self.__getFix(info['objURL'])
savepath = './test/' + word + '/' + str(self.__counter) + str(fix)
savepath = savepath.decode('utf-8').encode('gb2312')
urllib.urlretrieve(info['objURL'], savepath)
# 获取后缀名
def __getFix(self, name):
m = re.search(r'\.[^\.]*$', name)
if m.group(0) and len(m.group(0)) <= 5:
return m.group(0)
else:
return '.jpeg'
# 获取前缀
def __getPrefix(self, name):
return name[:name.find('.')]
# page_number 需要抓取数据页数 总抓取图片数量为 页数x60
# start_page 起始页数
def start(self, word, spider_page_num=1, start_page=1):
self.__start_amount = (start_page - 1) * 60
self.__amount = spider_page_num * 60 + self.__start_amount
self.__getImages(word)
member = ['秋元真夏','生田绘梨花','生驹里奈','伊藤万理华','井上小百合','卫藤美彩','川后阳菜','川村真洋','斋藤飞鸟','斋藤千春','斉藤优里','樱井玲香','白石麻衣','深川麻衣','桥本奈奈未','高山一実','中田花奈','中元日芽香','西野七濑','能条爱未','樋口日奈','星野南','永岛圣罗','伊藤宁宁','畠中清罗','松村沙友理','若月佑美','和田玛雅','松井玲奈','渡边迷离爱','柏幸奈','新内真衣','北野日奈子','堀未央奈','伊藤卡琳','寺田兰世','佐佐木琴子','山崎怜奈','伊藤纯奈','铃木绚音','相乐伊织','伊藤理理杏','岩本莲加','梅泽美波','大园桃子','久保史绪里','阪口珠美','佐藤枫','中村丽乃','向井叶月','山下美月','吉田绫乃克莉丝蒂','与田祐希']
crawler = Crawler(0.05)
for membername in member:
crawler.start(membername, 17)
# crawler.start('二次元 性感', 3, 3)
# crawler.start('帅哥', 5)
2.1.1、目标检测获取头像
这部分其实用到的是opencv中自带的adaboost的目标检测算法,人脸检测的话使用haar特征可以去的不错的效果。
这方面如果要去补学术方面的知识的话,建议出门右手边谷歌adaboost。
import cv2
import sys
import os.path
from glob import glob
def detect(filename, cascade_file="haarcascade_frontalface_alt.xml"):
if not os.path.isfile(cascade_file):
raise RuntimeError("%s: not found" % cascade_file)
cascade = cv2.CascadeClassifier(cascade_file)
image = cv2.imread(filename)
if image==None: # read failure and skip this image
return
if image.shape[2]==1: # drop gray images
return
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.equalizeHist(gray)
faces = cascade.detectMultiScale(gray,
# detector options
scaleFactor=1.1,
minNeighbors=3,
minSize=(96, 96))
for i, (x, y, w, h) in enumerate(faces):
face = image[y: y + h, x:x + w, :]
face = cv2.resize(face, (96, 96))
save_filename = '%s-%d.jpg' % (os.path.basename(filename).split('.')[0], i)
cv2.imwrite("face/" + save_filename, face)
if __name__ == '__main__':
if os.path.exists('face') is False:
os.makedirs('face')
file_list = glob('./test/ikoma/*.jp*')
for filename in file_list:
print filename
detect(filename)
事实上,检测人脸可以使用一些deep learning的网络,准确度会高,但是通常速度上会比基于adaboost算法的要慢,因此在这里我并未使用人脸检测的深度学习的网络。
2.1.2、DCGAN
DCGAN网络设计中采用了当时对CNN比较流行的改进方案:
(1)将空间池化层用卷积层替代,这种替代只需要将卷积的步长stride设置为大于1的数值。改进的意义是下采样过程不再是固定的抛弃某些位置的像素值,而是可以让网络自己去学习下采样方式。
(2)将全连接层去除,(我前面关于VGG的文章分析了全连接层是如何大幅度增加网络参数数量的);作者通过实验发现了全局均值池化有助于模型的稳定性但是降低了模型的收敛速度;作者在这里说明了他是通过将生成器输入的噪声reshape成4D的张量,来实现不用全连接而是用卷积的。
(3)采用BN层,BN的全称是Batch Normalization,是一种用于常用于卷积层后面的归一化方法,起到帮助网络的收敛等作用。作者实验中发现对所有的层都使用BN会造成采样的震荡(我也不理解什么是采样的震荡,我猜是生成图像趋于同样的模式或者生成图像质量忽高忽低)和网络不稳定。

在训练过程中,生成网络G的目标就是尽量生成真实的图片去欺骗判别网络D。而D的目标就是尽量把G生成的图片和真实的图片分别开来。这样,G和D构成了一个动态的“博弈过程”。
以上只是大致说了一下GAN的核心原理,如何用数学语言描述呢?这里直接摘录论文里的公式:

简单分析一下这个公式:
整个式子由两项构成。x表示真实图片,z表示输入G网络的噪声,而G(z)表示G网络生成的图片。
D(x)表示D网络判断真实图片是否真实的概率(因为x就是真实的,所以对于D来说,这个值越接近1越好)。而D(G(z))是D网络判断G生成的图片的是否真实的概率。
G的目的:上面提到过,D(G(z))是D网络判断G生成的图片是否真实的概率,G应该希望自己生成的图片“越接近真实越好”。也就是说,G希望D(G(z))尽可能得大,这时V(D, G)会变小。因此我们看到式子的最前面的记号是min_G。
D的目的:D的能力越强,D(x)应该越大,D(G(x))应该越小。这时V(D,G)会变大。因此式子对于D来说是求最大(max_D)
那么如何用随机梯度下降法训练D和G?论文中也给出了算法:

这里红框圈出的部分是我们要额外注意的。第一步我们训练D,D是希望V(G, D)越大越好,所以是加上梯度(ascending)。第二步训练G时,V(G, D)越小越好,所以是减去梯度(descending)。整个训练过程交替进行。
# Generator Code
class Generator(nn.Module):
def __init__(self, ngpu):
super(Generator, self).__init__()
self.ngpu = ngpu
self.main = nn.Sequential(
# input is Z, going into a convolution
nn.ConvTranspose2d( nz, ngf * 8, 4, 1, 0, bias=False),
nn.BatchNorm2d(ngf * 8),
nn.ReLU(True),
# state size. (ngf*8) x 4 x 4
nn.ConvTranspose2d(ngf * 8, ngf * 4, 4, 2, 1, bias=False),
nn.BatchNorm2d(ngf * 4),
nn.ReLU(True),
# state size. (ngf*4) x 8 x 8
nn.ConvTranspose2d( ngf * 4, ngf * 2, 4, 2, 1, bias=False),
nn.BatchNorm2d(ngf * 2),
nn.ReLU(True),
# state size. (ngf*2) x 16 x 16
nn.ConvTranspose2d( ngf * 2, ngf, 4, 2, 1, bias=False),
nn.BatchNorm2d(ngf),
nn.ReLU(True),
# state size. (ngf) x 32 x 32
nn.ConvTranspose2d( ngf, nc, 4, 2, 1, bias=False),
nn.Tanh()
# state size. (nc) x 64 x 64
)
def forward(self, input):
return self.main(input)
class Discriminator(nn.Module):
def __init__(self, ngpu):
super(Discriminator, self).__init__()
self.ngpu = ngpu
self.main = nn.Sequential(
# input is (nc) x 64 x 64
nn.Conv2d(nc, ndf, 4, 2, 1, bias=False),
nn.LeakyReLU(0.2, inplace=True),
# state size. (ndf) x 32 x 32
nn.Conv2d(ndf, ndf * 2, 4, 2, 1, bias=False),
nn.BatchNorm2d(ndf * 2),
nn.LeakyReLU(0.2, inplace=True),
# state size. (ndf*2) x 16 x 16
nn.Conv2d(ndf * 2, ndf * 4, 4, 2, 1, bias=False),
nn.BatchNorm2d(ndf * 4),
nn.LeakyReLU(0.2, inplace=True),
# state size. (ndf*4) x 8 x 8
nn.Conv2d(ndf * 4, ndf * 8, 4, 2, 1, bias=False),
nn.BatchNorm2d(ndf * 8),
nn.LeakyReLU(0.2, inplace=True),
# state size. (ndf*8) x 4 x 4
nn.Conv2d(ndf * 8, 1, 4, 1, 0, bias=False),
nn.Sigmoid()
)
def forward(self, input):
return self.main(input)
2.2、测试结果

epoch=1

epoch=10

epoch=100
训练过程展示
参考:
https://github.com/kong36088/BaiduImageSpider
https://link.zhihu.com/?target=http%3A//kinolien.github.io/gitzip/
https://zhuanlan.zhihu.com/p/24767059
关注公众号,回复【DCGAN】即可获得完整的项目代码以及文档说明。
文末福利
各位猿们,还在为记不住API发愁吗,哈哈哈,最近发现了国外大师整理了一份Python代码速查表和Pycharm快捷键sheet,火爆国外,这里分享给大家。
这个是一份Python代码速查表

下面的宝藏图片是2张(windows && Mac)高清的PyCharm快捷键一览图

怎样获取呢?可以添加我们的AI派团队的程Beyonce
一定要备注【高清图】哦
????????????????????

➕我们的Beyonce小姐姐微信要记得备注【高清图】哦
来都来了,喜欢的话就请分享、点赞、在看三连再走吧~~~

220



被折叠的 条评论
为什么被折叠?



