tensorflow2.xは、dataset.mapによって引き起こされるtf.py_functionとtf.numpy_functionに関する問題です。

はじめに:テンソルフローは巨大なシステムです。多くの機能があり、多くの従来の操作が実装されていますが、すべての操作を網羅する方法は常にありません。指定された機能を実現するために、独自の操作ロジックを定義する必要がある場合があります。しかし、それはそれほど単純ではないことがわかりました。この記事は、tf.data.DataSetを記述し、一元化された要約を作成するときに発生した問題であり、次の概念が含まれます。

EagerTensorとTensor、tf.py_functionとtf.numpy_function、dataset.mapなど

1.問題の説明

解決する必要のある問題は、filesフォルダーに保存されている3つのテキストファイルです。名前はfile1.txt、file2.txt、file3.txtです。内容は次のとおりです。

file1.txt

1,2,3,4,5

file2.txt

11,22,33,44,55

file3.txt

111,222,333,444,555

各ファイルのタグは1、2、および3です。ここで、ワンホットエンコードされていると仮定すると、カテゴリはそれぞれです。

[[1,0,0]、[0,1,0]、[0,0,1]]

まず、これら3つのサンプルをデータセットの標準パイプラインで読み取って、トレーニングのためにニューラルネットワークに配置できるようにする必要があります。もちろん、各テキストファイルを読み取る必要があり、datase.map()関数を使用する必要があります。 。コードは次のとおりです。

X=["file1.txt","file2.txt","file3.txt"]
Y=[[1,0,0],[0,1,0],[0,0,1]]
 
# 构建dataset对象
dataset = tf.data.Dataset.from_tensor_slices((X,Y))  # 第一步:构造dataset对象 
 
# 对每一个dataset的元素,实际上就是一个example进行解析
dataset = dataset.map(read_file)
 
for features,label in dataset:
    print(features)
    print(label)
    print("===========================================================")

 

解析関数read_fileは次のとおりです

def read_file(filename,label):
    tf.print(type(filename))
    tf.print(type(label))
    
    # filename_ = filename.numpy()
    # label_ = label.numpy()
    
    filename = "./files/" + filename
    tf.print("/")
    
    f =  open(filename,mode="r")
    s =f.readline()
    x_ =s.split(',')
    result =[]
    for i in x_:
        result.append(int(i))
    
    return result,label


コードは問題ないように見えますが、実行時に実際には次のエラーが表示されます。

TypeError: expected str, bytes or os.PathLike object, not Tensor

間違った場所は

f =  open(filename,mode="r")

意味は非常に単純です。つまり、ファイルを読み取るファイル名は、Tensorオブジェクトではなく、strまたはパスを表すオブジェクトである必要があります。

注:この問題は2日間私を悩ませました。私は解決策を見つけるためにグーグルで長い間検索しました。中国語の検索はほとんど適切な答えがありません。

では、どうすればよいでしょうか。

非常に単純なようです。ファイル名とラベルはTensorであると彼が言ったので、Tensorの値を読み取るだけで済みます。文字列を取得しないでください。実際、それは本当です、tensorflow2.x It t.numpy()を使用してテンソルの値を取得できることを示していますが、これら2つのメソッドを使用すると、それでも間違っていることがわかり、次のエラーが表示されます。

filename_ = filename.numpy()
label_ = label.numpy()
AttributeError: 'Tensor' object has no attribute 'numpy'

Tensorがnumpy属性を持たないのはどうしてですか?t.numpy()を介してテンソルの値を取得しませんか?これは実際には次の質問につながります。

 

2つ目は、tf.EagerTensorとtf.Tensorを区別することです。

2.1簡単な例

いくつかの簡単な例を見てください。

 
In [59]: a = tf.constant([1,2,3,4,5])
 
In [60]: a
Out[60]: <tf.Tensor: shape=(5,), dtype=int32, numpy=array([1, 2, 3, 4, 5])>
 
In [61]: type(a)
Out[61]: tensorflow.python.framework.ops.EagerTensor

2つの問題が見つかりました:

(1)ここで、aは確かにテンソルであり、属性numpyを持っているので、a.numpy()を介してその値を取得できます。

(2)そのタイプは本質的にEagerTensorであり、

上記のTensorにnumpy属性がない理由は、次のようになっているためです。 

<class 'tensorflow.python.framework.ops.Tensor'>   # 类型
 
tf.Tensor([102 102 102], shape=(3,), dtype=int64)  # Tensor

したがって、tensorflow 2.xでは、numpyで取得できる値はすべて、EagerTensorを参照しますが、次の形式で印刷および表示されます。

 <tf.Tensor: ... ...>

そして、Tensorとは正確には何ですか?これは実際には静的グラフの一種のテンソルです。現在ダイナミックライブラリを使用していますが、バックグラウンドでグラフを作成するプロセスがあります。Tensorの値は時間内に取得できませんが、データの後に取得する必要があります。tensorflow1.x静的グラフでは、 Tensorの値を取得するには、次のメソッドを使用する必要があります。

with tf.Session() as sess:
    result = sess.run([t])  # 获取Tensor t 的值
    print(result)
    
    # 或者是
    result = t.eval()

2.2tensorflow2.xを使用する際の注意事項

EagerTensorとTensorの使用に関する注意事項

(1)使用するtf.print(tensor)代わりに、計算結果を印刷して確認したいprint(tensor.numpy())

使用がtf.print(tensor)でき、静的またはコンテンツのテンソルを描画動的地図の両方を印刷することができ、そしてprint(tensor.numpy())のみ動画で使用することができるだけEagerTensorを使用することができ、以下では、正しい証明です。

(2)tensor.gpu()、tensor.cpu()の代わりにtf.deviceを使用します

新しいバージョンでテンソルが作成されると、優先度の高いデバイスに自動的に割り当てられます。たとえば、GPUがある場合、テンソルはGPUに直接割り当てられます。

# 需要GPU版本才能看出创建的张量会直接放置到gpu上!CPU版本不行
import tensorflow as tf
print(tf.test.is_gpu_available())
# True
r = tf.random.normal((3, 4))
print(r.device)
# '/job:localhost/replica:0/task:0/device:GPU:0'

新しいデバイスの特定のバージョンでは、EagerTensor直接.cpu().gpu()メソッドは対応するテンソルデバイスに直接移動しますが、移動tf.Tensorしませんでした。このメソッドはtf.device、作成されたスコープの両方の操作と互換性があります。gpuの下にテンソルを作成し、sin操作のためにcpuに移動するエラーの例は次のとおりです。

(3)テンソルをトラバースせず、ベクトル化された演算を使用してみてください

EagerTensorトラバースすることはできますが、できtf.Tensorないので、テンソルをトラバースしないようにして、動的画像と静止画像の互換性だけでなく、ベクトル化後の速度の向上も非常に大きいため、ベクトル化操作の実行方法を検討してください。

2.3分析と理解、

このように理解できます、

EagerTensorはリアルタイムであり、その値はいつでも取得できます。つまり、numpyから取得できます。

テンソルは非リアルタイムであり、静的グラフのコンポーネントです。データが供給され、操作が完了した場合にのみ、テンソルの値を取得できます。

では、なぜdatastep.map(function)

解析関数関数に渡されるパラメーター、つまり、上記のread_file(filename、label)のファイル名とラベルはTensor?

データセットdataset.mapの場合、サンプルの各セットのマップにマップされた関数操作を事前に実行するのではなく、使用する前にサンプルを取り出すたびに関数操作を実行する必要があることをデータセットに通知するだけです。 、したがって、データセットが繰り返されるたびに関数呼び出しが呼び出されますが、事前パラメーターのファイル名とラベルは単なる「ピット」です。データは、反復中および操作中にこの「ピット」を埋めるために使用されますが、データは入力されていますが、ファイル名とラベルはEagerTensorではなくTensorであるため、上記の問題が発生します。

注:2つの問題:

(1)TensorとEagerTensorを直接変換する方法はありません

(2)Python関数でTensorの値を取得できないため、Python関数でTensorを直接使用することはできません。

3つ目は、tensorflowがPythonコードと相互作用する方法-tf.py_function

関数の実装を自分で定義する必要があります。Pythonで記述された関数がTensorと直接対話する方法はないので、どうすればよいでしょうか。

tensorflow 2.xバージョンは、自己定義関数を実装するための関数tf.py_functionを提供します。

3.1関数プロトタイプ

tf.py_function(func, inp, Tout, name=None)

役割: Python関数をラップして、Pythonの母親がテンソルフローと対話できるようにします

パラメータ:

func:自分で定義したPython関数の名前

inp: Python関数のパラメーターリストを自分で定義し、リストの形式で記述します。[tensor1、tensor2、tensor3]リストの各要素はTensorオブジェクトです。

         定義された関数パラメータとの一致に注意してください

Tout:カスタムPython関数の戻り値に対応します。

  • Toutが[tf.string、tf、int64、tf.float]などのリストの場合、カスタム関数には3つの戻り値があります。つまり、3つのテンソルが返され、各テンソルの要素タイプはそれに対応します。
  • Toutの値がtf.int64のように1つしかない場合は、カスタム関数が整数リストまたは整数テンソルを返すことを意味します。
  • Toutに値がない場合は、カスタム関数が値を返さないことを意味します

 

3.2上記の問題の解決策

(1)独自のPython関数を定義する

# dataset.map函数没有直接使用它,而是先用tf.py_function来包装他
def read_file(filename,label):
    tf.print(type(filename))     # 包装之后类型不再是Tensor,而是EagerTensor
    tf.print(type(label))
    
    filename_ = filename.numpy() # 因为是EagerTensor,可以使用numpy获取值,在tensorflow中,字符串以byte存储,所以它的值是  b'xxxxx'  的形式
    label_ = label.numpy()
    
    new_filename = filename_.decode()  # 将byte解码得到str
    new_filename = "./files/" + new_filename
    
    # 先在的new_filename就是纯python字符串了,可以直接打开了
    f =  open(new_filename,mode="r")
    s =f.readline()
    x_ =s.split(',')
    result =[]
    for i in x_:
        result.append(int(i))
    
    return result,label  # 返回,result是一个列表list

(2)tf.py_functionを使用して、自分で定義したpython関数をラップする関数を定義します

z 注意参数的匹配以及类型的匹配
def wrap_function(x,y):
    x, y = tf.py_function(read_file, inp=[x, y], Tout=[tf.int32, tf.int32])
    return x,y

もちろん、ラッパー関数を記述せずに、ラムダ式を1つのステップで直接使用することもできます。

tf.py_function()を使用して読み取り関数read_fileをここでラップしない場合、read_fileの2つのパラメーターは両方ともTensorです。

tf.py_function()を使用してread_file関数をラップした後、そのパラメーターはEagerTensorになります。

なぜそうなのかというと、まだはっきりしていませんが、偉大な神様が教えてくれることを願っています!

それは次のとおりです。

dataset = dataset.map(lambda x, y: tf.py_function(read_file, inp=[x, y], Tout=[tf.int32, tf.int32]))

 

(3)データセットのパイプラインの準備

X=["file1.txt","file2.txt","file3.txt"]
Y=[[1,0,0],[0,1,0],[0,0,1]]
 
dataset = tf.data.Dataset.from_tensor_slices((X,Y))  # 第一步:构造dataset对象 
 
dataset = dataset.map(wrap_function)
 
dataset=dataset.repeat(3)       # 重复三次                                   
dataset=dataset.batch(3)        # 每次3个样本一个batch
 
 
for features,label in dataset:
    print(features)
    print(label)
    print("=================================================================")

結果は次のとおりです。

tf.Tensor(
[[  1   2   3   4   5]
 [ 11  22  33  44  55]
 [111 222 333 444 555]], shape=(3, 5), dtype=int32)
tf.Tensor(
[[1 0 0]
 [0 1 0]
 [0 0 1]], shape=(3, 3), dtype=int32)
=======================================================================================================
tf.Tensor(
[[  1   2   3   4   5]
 [ 11  22  33  44  55]
 [111 222 333 444 555]], shape=(3, 5), dtype=int32)
tf.Tensor(
[[1 0 0]
 [0 1 0]
 [0 0 1]], shape=(3, 3), dtype=int32)
=======================================================================================================
tf.Tensor(
[[  1   2   3   4   5]
 [ 11  22  33  44  55]
 [111 222 333 444 555]], shape=(3, 5), dtype=int32)
tf.Tensor(
[[1 0 0]
 [0 1 0]
 [0 0 1]], shape=(3, 3), dtype=int32)
=======================================================================================================

現在の結果は完全に一貫していることがわかります!

3.3TensorとEagerTensorに関する詳細説明

注:EagerTensorは、Pythonコードと直接対話することも、操作を繰り返し容易にすることもできます。実際には、Pythonとの直接対話をサポートしていないのはTensorです。次の例に示すように、これには注意が必要です。

(1)EagerTensorとPython関数間の相互作用

def iterate_tensor(tensor):
    tf.print(type(tensor))  # EagerTensor
    (x1, x2, x3), (x4, x5, x6) = tensor
    return tf.stack([x2, x4, x6])
 
 
const = tf.constant(range(6), shape=(2, 3)) # EagerTensor
o = iterate_tensor(const)
print(o)
'''运行结果为:
<class 'tensorflow.python.framework.ops.EagerTensor'>
tf.Tensor([1 3 5], shape=(3,), dtype=int32)
'''

(2)TensorとPython関数間の相互作用

次のように、tf.functionを使用して関数を装飾します。

@tf.function
def iterate_tensor(tensor):
    tf.print(type(tensor))  # Tensor
    (x1, x2, x3), (x4, x5, x6) = tensor
    return tf.stack([x2, x4, x6])
 
 
const = tf.constant(range(6), shape=(2, 3)) # EagerTensor
o = iterate_tensor(const)
print(o)

tf.functionはPython関数を装飾するために使用されるため、静的グラフ操作にコンパイルされます。この時点で、テンソルはTensorになるため、上記のコードは正しくありません。

OperatorNotAllowedInGraphError: iterating over `tf.Tensor` is not allowed: AutoGraph did not convert this function. Try decorating it directly with @tf.function.

テンソルがテンソルになり、反復操作ができなくなり、エラーが発生することがわかります。

概要:EagerTensorとtf.Tensorを必ず区別してください

動的グラフの下で作成されたテンソルはEagerTensor(参照方法はfrom tensorflow.python.framework.ops import EagerTensor)であり、静的グラフの下で作成されたテンソルはtf.Tensorです。EagerTensorそしてtf.Tensor、非常に似ていますが、完全に同じはありませんがEagerTensor、いくつかの一意のメソッドに依存している場合、静的な図になりますtf.Tensorこれらのメソッドのエラーはありません

テンソルがEagerTensorなのかTensorなのかわからないことがよくありますか?最も簡単な方法は

tf.print(type(tensor_name))

表示するには

 

第四に、補足-tf.py_functionとtf.numpy_functionについて

すべての機能を完全にカバーするにはまだ十分ではないTensorFlow非常に多くのOp(len(dir(tf.raw_ops))約1,227があることを認める必要がありますnumpy。したがって、場合によっては、のロジックを表現するのに適したOp(またはOpの組み合わせ)が見つからないことがあります。上記のnumpy関数もかなり良いので、変換してから計算を使ってからEagerTensor変換することは許さないと考える人もいるかもしれません。正直で実用的である方が良いです。(もちろん、自分でOpカーネルを作成し、コンパイルして使用し、カスタムOpサマリーを作成するための余分な時間があるかどうかを確認できます。現在、私はまだ初期の2.0サマリーのフラグを入力する必要があります。 > <)numpynumpyTensor,tf.functiontf.numpy_function

詳細について

tf.py_function

tf.numpy_function

の使用については、次の例を参照してください

おすすめ

転載: blog.csdn.net/yxpandjay/article/details/109053539