Python 使用TensorFlow Keras API进行数据扩充

Python 使用TensorFlow Keras API进行数据扩充,python,tensorflow,keras,Python,Tensorflow,Keras,以下代码允许在每个历元结束时将训练集的图像旋转90º 从skimage.io导入imread 从skimage.transform导入调整大小,旋转 将numpy作为np导入 导入tensorflow作为tf 从tensorflow进口keras 从tensorflow.keras导入图层 从keras.utils导入序列 从keras.models导入顺序 从keras.2d开始,激活、变平、致密 #模型架构(虚拟) 模型=顺序() add(Conv2D(32,(3,3),input_shap

以下代码允许在每个历元结束时将训练集的图像旋转90º

从skimage.io导入imread
从skimage.transform导入调整大小,旋转
将numpy作为np导入
导入tensorflow作为tf
从tensorflow进口keras
从tensorflow.keras导入图层
从keras.utils导入序列
从keras.models导入顺序
从keras.2d开始,激活、变平、致密
#模型架构(虚拟)
模型=顺序()
add(Conv2D(32,(3,3),input_shape=(15,15,4)))
添加(激活('relu'))
model.add(展平())
模型.添加(密度(1))
添加(激活('sigmoid'))
model.compile(loss='binary\u crossentropy',
优化器='rmsprop',
指标=[‘准确度’])
#数据迭代器
类CIFAR10序列(序列):
def uuu init uuu(self、文件名、标签、批大小):
self.filename,self.labels=文件名,标签
self.batch\u size=批次大小
自转角=[0,90180270]
自电流角度idx=0
#方法循环通过可用角度
def更改角度(自身):
自电流角度idx+=1
如果self.current\u angle\u idx>=len(self.angles):
自电流角度idx=0
定义(自我):
返回int(np.ceil(len(self.filenames)/float(self.batch_size)))
#读取、调整和旋转图像并返回一批图像
def uu getitem uu(self,idx):
角度=自身角度[自身当前角度]
打印(f“旋转角度:{Angle}”)
batch\u x=self.filename[idx*self.batch\u size:(idx+1)*self.batch\u size]
批次y=self.labels[idx*self.batch\u size:(idx+1)*self.batch\u size]
返回np.array([
旋转(调整大小(imread(文件名),(15,15)),角度)
对于批处理(x)中的文件名,np.array(批处理(y))
#在epoch结束时挂接到的自定义回调
类CustomCallback(keras.callbacks.Callback):
定义初始化(自身,顺序):
self.sequence=序列
#每个历元结束后,更改下一历元的旋转
def on_epoch_end(self、epoch、logs=None):
self.sequence.change_angle()
#创建数据读取器
sequence=CIFAR10Sequence([“f1.PNG”]*10[0,1]*5,8)
#在自定义回拨中安装模型和挂钩
model.fit(sequence,epochs=10,callbacks=[CustomCallback(sequence)])
如何修改代码,使图像在每个历元中发生旋转

期望输出:

Epoch 1/10
Rotating Angle: 0
Rotating Angle: 90
Rotating Angle: 180
Rotating Angle: 270

Epoch 2/10
Rotating Angle: 0
Rotating Angle: 90
Rotating Angle: 180
Rotating Angle: 270

(...)

Epoch 10/10
Rotating Angle: 0
Rotating Angle: 90
Rotating Angle: 180
Rotating Angle: 270
换句话说,我如何编写一个回调函数,它在一个历元的“结束”运行,改变角度值并在同一历元上继续训练(而不改变到下一历元)

提前谢谢


注意:代码积分来自“mujjiga”。

因为您有一个自定义序列生成器,所以您可以创建一个在历元开始或结束时运行的函数。这是您可以放置代码来修改图像的地方。文档位于[此处][1]

Epoch-level methods (training only)
on_epoch_begin(self, epoch, logs=None)
Called at the beginning of an epoch during training.

on_epoch_end(self, epoch, logs=None)
Called at the end of an epoch during training.


  [1]: https://keras.io/guides/writing_your_own_callbacks/

无需为此创建
CustomCallback
;最后,您希望在培训期间得到增强

解决方案是以概率应用旋转操作

# read, resize and rotate the image and return a batch of images
def __getitem__(self, idx):
    angle = self.angles[self.current_angle_idx]
    print(f"Rotating Angle: {angle}")
    batch_x = self.filenames[idx * self.batch_size:(idx + 1) * self.batch_size]
    batch_y = self.labels[idx * self.batch_size:(idx + 1) * self.batch_size]
    #These new lines (say we augment with probability > 0.5)
    #Number between 0 and 1
    images = []
    for filename in batch_x:
        probability = random.random()
        apply_rotate = probability > 0.5
        if apply_rotate:
            images.append(rotate(resize(imread(filename), (15, 15)), angle))
        else:
            images.append(resize(imread(filename), (15, 15)))
    return np.array(images), np.array(batch_y)

问题是怎么做?如何创建一个在一个历元结束时运行的函数来更改角度值并在同一历元上继续训练(而不更改到下一历元)?抱歉,我误解了这个问题。我认为您可以使用列批处理开始(self,batch,logs=None)上的def和列批处理结束(self,batch,logs=None)上的..def来实现这一点。您可以在同一时期内更改每个批次的轮换,当我使用“开始”列上的
和“结束”列上的
函数时,我能做的最好的事情就是每批只改变一次角度,获得类似的输出:历元1/10批次0旋转0º批次1旋转90º批次2旋转180º批次3旋转270º批次4旋转0º(…)当期望的输出是每批应用四次旋转时,如:Epoch 1/10批次0旋转0º旋转90º旋转180º旋转270º批次1旋转0º旋转90º旋转180º旋转270º(…)当我在Epoch\u begin()上使用
在Epoch\u end()上使用
时,会出现类似的问题
功能,但带有年代。我能做的最好的事情就是每个历元改变一次角度,而不是每个历元改变四次。我认为最优雅的解决方案是使用
CustomCallback
,但我真的不知道该怎么做。另一种解决方案(虽然不那么优雅,但可能是独特的)可能是修改
\uuu getitem\uuu()
函数?顺便说一下,即使将代码的倒数第二行改为else:images.append(resize(imread(filename),(15,15)))并取消CustomCallback,我也无法运行代码来检查其最终结果。你能给出你建议的完整代码吗?因为这就是扩充的意思。我完全同意你的观点。我接受了你的回答。我认为这是一个有趣的方法,肯定解决了我的问题。非常感谢,祝你好运!没问题,Timbus。事实上,没有你的允许,我不太愿意进行修改。我这么做只是因为我不想再打扰你,也因为我只能在修改代码后接受你的回答。我很高兴你不在乎,很高兴知道。世界需要更多像你这样的人。再次感谢Timbus。